blob: 0abb85229ffcf13c000cae0fab41126ce2449342 [file] [log] [blame]
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.session.MediaSessionManager;
import android.os.Bundle;
import android.os.IBinder;
import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Represents an ongoing {@link MediaSession2} or a {@link MediaSessionService2}.
* If it's representing a session service, it may not be ongoing.
* <p>
* This may be passed to apps by the session owner to allow them to create a
* {@link MediaController2} to communicate with the session.
* <p>
* It can be also obtained by {@link MediaSessionManager}.
* @hide
*/
// TODO(jaewan): Move Token to updatable!
public final class SessionToken2 {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
public @interface TokenType {
}
public static final int TYPE_SESSION = 0;
public static final int TYPE_SESSION_SERVICE = 1;
public static final int TYPE_LIBRARY_SERVICE = 2;
private static final String KEY_TYPE = "android.media.token.type";
private static final String KEY_PACKAGE_NAME = "android.media.token.package_name";
private static final String KEY_SERVICE_NAME = "android.media.token.service_name";
private static final String KEY_ID = "android.media.token.id";
private static final String KEY_SESSION_BINDER = "android.media.token.session_binder";
private final @TokenType int mType;
private final String mPackageName;
private final String mServiceName;
private final String mId;
private final IMediaSession2 mSessionBinder;
/**
* Constructor for the token.
*
* @hide
* @param type type
* @param packageName package name
* @param id id
* @param serviceName name of service. Can be {@code null} if it's not an service.
* @param sessionBinder binder for this session. Can be {@code null} if it's service.
* @hide
*/
// TODO(jaewan): UID is also needed.
// TODO(jaewan): Unhide
public SessionToken2(@TokenType int type, @NonNull String packageName, @NonNull String id,
@Nullable String serviceName, @Nullable IMediaSession2 sessionBinder) {
// TODO(jaewan): Add sanity check.
mType = type;
mPackageName = packageName;
mId = id;
mServiceName = serviceName;
mSessionBinder = sessionBinder;
}
public int hashCode() {
final int prime = 31;
return mType
+ prime * (mPackageName.hashCode()
+ prime * (mId.hashCode()
+ prime * ((mServiceName != null ? mServiceName.hashCode() : 0)
+ prime * (mSessionBinder != null ? mSessionBinder.asBinder().hashCode() : 0))));
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SessionToken2 other = (SessionToken2) obj;
if (!mPackageName.equals(other.getPackageName())
|| !mServiceName.equals(other.getServiceName())
|| !mId.equals(other.getId())
|| mType != other.getType()) {
return false;
}
if (mSessionBinder == other.getSessionBinder()) {
return true;
} else if (mSessionBinder == null || other.getSessionBinder() == null) {
return false;
}
return mSessionBinder.asBinder().equals(other.getSessionBinder().asBinder());
}
@Override
public String toString() {
return "SessionToken {pkg=" + mPackageName + " id=" + mId + " type=" + mType
+ " service=" + mServiceName + " binder=" + mSessionBinder + "}";
}
/**
* @return package name
*/
public String getPackageName() {
return mPackageName;
}
/**
* @return id
*/
public String getId() {
return mId;
}
/**
* @return type of the token
* @see #TYPE_SESSION
* @see #TYPE_SESSION_SERVICE
*/
public @TokenType int getType() {
return mType;
}
/**
* @return session binder.
* @hide
*/
public @Nullable IMediaSession2 getSessionBinder() {
return mSessionBinder;
}
/**
* @return service name if it's session service.
* @hide
*/
public @Nullable String getServiceName() {
return mServiceName;
}
/**
* Create a token from the bundle, exported by {@link #toBundle()}.
*
* @param bundle
* @return
*/
public static SessionToken2 fromBundle(@NonNull Bundle bundle) {
if (bundle == null) {
return null;
}
final @TokenType int type = bundle.getInt(KEY_TYPE, -1);
final String packageName = bundle.getString(KEY_PACKAGE_NAME);
final String serviceName = bundle.getString(KEY_SERVICE_NAME);
final String id = bundle.getString(KEY_ID);
final IBinder sessionBinder = bundle.getBinder(KEY_SESSION_BINDER);
// Sanity check.
switch (type) {
case TYPE_SESSION:
if (!(sessionBinder instanceof IMediaSession2)) {
throw new IllegalArgumentException("Session needs sessionBinder");
}
break;
case TYPE_SESSION_SERVICE:
if (TextUtils.isEmpty(serviceName)) {
throw new IllegalArgumentException("Session service needs service name");
}
if (sessionBinder != null && !(sessionBinder instanceof IMediaSession2)) {
throw new IllegalArgumentException("Invalid session binder");
}
break;
default:
throw new IllegalArgumentException("Invalid type");
}
if (TextUtils.isEmpty(packageName) || id == null) {
throw new IllegalArgumentException("Package name nor ID cannot be null.");
}
// TODO(jaewan): Revisit here when we add connection callback to the session for individual
// controller's permission check. With it, sessionBinder should be available
// if and only if for session, not session service.
return new SessionToken2(type, packageName, id, serviceName,
sessionBinder != null ? IMediaSession2.Stub.asInterface(sessionBinder) : null);
}
/**
* Create a {@link Bundle} from this token to share it across processes.
*
* @return Bundle
*/
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putString(KEY_PACKAGE_NAME, mPackageName);
bundle.putString(KEY_SERVICE_NAME, mServiceName);
bundle.putString(KEY_ID, mId);
bundle.putInt(KEY_TYPE, mType);
bundle.putBinder(KEY_SESSION_BINDER,
mSessionBinder != null ? mSessionBinder.asBinder() : null);
return bundle;
}
}