Framework support cas@1.2
Test: Manual bug: 141783130 Change-Id: I62d42ad51444b8d58282f5d6992ba6f2169dd6d3
This commit is contained in:
parent
658b4ca415
commit
43cab92abe
@ -326,8 +326,9 @@ java_library {
|
||||
"framework-protos",
|
||||
"game-driver-protos",
|
||||
"android.hidl.base-V1.0-java",
|
||||
"android.hardware.cas-V1.1-java",
|
||||
"android.hardware.cas-V1.0-java",
|
||||
"android.hardware.cas-V1.1-java",
|
||||
"android.hardware.cas-V1.2-java",
|
||||
"android.hardware.contexthub-V1.0-java",
|
||||
"android.hardware.gnss-V1.0-java",
|
||||
"android.hardware.health-V1.0-java-constants",
|
||||
|
@ -24793,11 +24793,13 @@ package android.media {
|
||||
|
||||
public final class MediaCas implements java.lang.AutoCloseable {
|
||||
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
|
||||
ctor public MediaCas(int, @Nullable String, int) throws android.media.MediaCasException.UnsupportedCasException;
|
||||
method public void close();
|
||||
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
|
||||
method protected void finalize();
|
||||
method public static boolean isSystemIdSupported(int);
|
||||
method public android.media.MediaCas.Session openSession() throws android.media.MediaCasException;
|
||||
method @Nullable public android.media.MediaCas.Session openSession(int, int) throws android.media.MediaCasException;
|
||||
method public void processEmm(@NonNull byte[], int, int) throws android.media.MediaCasException;
|
||||
method public void processEmm(@NonNull byte[]) throws android.media.MediaCasException;
|
||||
method public void provision(@NonNull String) throws android.media.MediaCasException;
|
||||
@ -24805,10 +24807,32 @@ package android.media {
|
||||
method public void sendEvent(int, int, @Nullable byte[]) throws android.media.MediaCasException;
|
||||
method public void setEventListener(@Nullable android.media.MediaCas.EventListener, @Nullable android.os.Handler);
|
||||
method public void setPrivateData(@NonNull byte[]) throws android.media.MediaCasException;
|
||||
field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0
|
||||
field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1
|
||||
field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9
|
||||
field public static final int SCRAMBLING_MODE_AES_ECB = 10; // 0xa
|
||||
field public static final int SCRAMBLING_MODE_AES_SCTE52 = 11; // 0xb
|
||||
field public static final int SCRAMBLING_MODE_DVB_CISSA_V1 = 6; // 0x6
|
||||
field public static final int SCRAMBLING_MODE_DVB_CSA1 = 1; // 0x1
|
||||
field public static final int SCRAMBLING_MODE_DVB_CSA2 = 2; // 0x2
|
||||
field public static final int SCRAMBLING_MODE_DVB_CSA3_ENHANCE = 5; // 0x5
|
||||
field public static final int SCRAMBLING_MODE_DVB_CSA3_MINIMAL = 4; // 0x4
|
||||
field public static final int SCRAMBLING_MODE_DVB_CSA3_STANDARD = 3; // 0x3
|
||||
field public static final int SCRAMBLING_MODE_DVB_IDSA = 7; // 0x7
|
||||
field public static final int SCRAMBLING_MODE_MULTI2 = 8; // 0x8
|
||||
field public static final int SCRAMBLING_MODE_RESERVED = 0; // 0x0
|
||||
field public static final int SCRAMBLING_MODE_TDES_ECB = 12; // 0xc
|
||||
field public static final int SCRAMBLING_MODE_TDES_SCTE52 = 13; // 0xd
|
||||
field public static final int SESSION_USAGE_LIVE = 0; // 0x0
|
||||
field public static final int SESSION_USAGE_PLAYBACK = 1; // 0x1
|
||||
field public static final int SESSION_USAGE_RECORD = 2; // 0x2
|
||||
field public static final int SESSION_USAGE_TIMESHIFT = 3; // 0x3
|
||||
}
|
||||
|
||||
public static interface MediaCas.EventListener {
|
||||
method public void onEvent(@NonNull android.media.MediaCas, int, int, @Nullable byte[]);
|
||||
method public default void onPluginStatusUpdate(@NonNull android.media.MediaCas, int, int);
|
||||
method public default void onResourceLost(@NonNull android.media.MediaCas);
|
||||
method public default void onSessionEvent(@NonNull android.media.MediaCas, @NonNull android.media.MediaCas.Session, int, int, @Nullable byte[]);
|
||||
}
|
||||
|
||||
@ -24819,6 +24843,7 @@ package android.media {
|
||||
|
||||
public final class MediaCas.Session implements java.lang.AutoCloseable {
|
||||
method public void close();
|
||||
method @NonNull public byte[] getSessionId();
|
||||
method public void processEcm(@NonNull byte[], int, int) throws android.media.MediaCasException;
|
||||
method public void processEcm(@NonNull byte[]) throws android.media.MediaCasException;
|
||||
method public void sendSessionEvent(int, int, @Nullable byte[]) throws android.media.MediaCasException;
|
||||
@ -24831,6 +24856,9 @@ package android.media {
|
||||
public static final class MediaCasException.DeniedByServerException extends android.media.MediaCasException {
|
||||
}
|
||||
|
||||
public static final class MediaCasException.InsufficientResourceException extends android.media.MediaCasException {
|
||||
}
|
||||
|
||||
public static final class MediaCasException.NotProvisionedException extends android.media.MediaCasException {
|
||||
}
|
||||
|
||||
@ -28817,6 +28845,19 @@ package android.media.tv {
|
||||
field public static final int TIME_SHIFT_STATUS_UNSUPPORTED = 1; // 0x1
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 4; // 0x4
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3; // 0x3
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_BLACKOUT = 16; // 0x10
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_CARD_INVALID = 15; // 0xf
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_CARD_MUTE = 14; // 0xe
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_INSUFFICIENT_OUTPUT_PROTECTION = 7; // 0x7
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_LICENSE_EXPIRED = 10; // 0xa
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_NEED_ACTIVATION = 11; // 0xb
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_NEED_PAIRING = 12; // 0xc
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_NO_CARD = 13; // 0xd
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED = 8; // 0x8
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_REBOOTING = 17; // 0x11
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN = 18; // 0x12
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE = 6; // 0x6
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = 5; // 0x5
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_TUNING = 1; // 0x1
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = 0; // 0x0
|
||||
field public static final int VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL = 2; // 0x2
|
||||
@ -28838,6 +28879,11 @@ package android.media.tv {
|
||||
method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(@NonNull String, @NonNull String);
|
||||
method @Nullable public abstract android.media.tv.TvInputService.Session onCreateSession(String);
|
||||
method @Nullable public android.media.tv.TvInputService.Session onCreateSession(@NonNull String, @NonNull String);
|
||||
field public static final int PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND = 100; // 0x64
|
||||
field public static final int PRIORITY_HINT_USE_CASE_TYPE_LIVE = 400; // 0x190
|
||||
field public static final int PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK = 300; // 0x12c
|
||||
field public static final int PRIORITY_HINT_USE_CASE_TYPE_RECORD = 500; // 0x1f4
|
||||
field public static final int PRIORITY_HINT_USE_CASE_TYPE_SCAN = 200; // 0xc8
|
||||
field public static final String SERVICE_INTERFACE = "android.media.tv.TvInputService";
|
||||
field public static final String SERVICE_META_DATA = "android.media.tv.input";
|
||||
}
|
||||
|
@ -16,13 +16,15 @@
|
||||
|
||||
package android.media;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
|
||||
import android.hardware.cas.V1_0.ICas;
|
||||
import android.hardware.cas.V1_0.IMediaCasService;
|
||||
import android.hardware.cas.V1_1.ICasListener;
|
||||
import android.hardware.cas.V1_2.ICasListener;
|
||||
import android.media.MediaCasException.*;
|
||||
import android.media.tv.TvInputService.PriorityHintUseCaseType;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
@ -34,6 +36,8 @@ import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.Singleton;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
@ -100,28 +104,185 @@ public final class MediaCas implements AutoCloseable {
|
||||
private static final String TAG = "MediaCas";
|
||||
private ICas mICas;
|
||||
private android.hardware.cas.V1_1.ICas mICasV11;
|
||||
private android.hardware.cas.V1_2.ICas mICasV12;
|
||||
private EventListener mListener;
|
||||
private HandlerThread mHandlerThread;
|
||||
private EventHandler mEventHandler;
|
||||
private @PriorityHintUseCaseType int mPriorityHint;
|
||||
private String mTvInputServiceSessionId;
|
||||
|
||||
/**
|
||||
* Scrambling modes used to open cas sessions.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = "SCRAMBLING_MODE_",
|
||||
value = {SCRAMBLING_MODE_RESERVED, SCRAMBLING_MODE_DVB_CSA1, SCRAMBLING_MODE_DVB_CSA2,
|
||||
SCRAMBLING_MODE_DVB_CSA3_STANDARD,
|
||||
SCRAMBLING_MODE_DVB_CSA3_MINIMAL, SCRAMBLING_MODE_DVB_CSA3_ENHANCE,
|
||||
SCRAMBLING_MODE_DVB_CISSA_V1, SCRAMBLING_MODE_DVB_IDSA,
|
||||
SCRAMBLING_MODE_MULTI2, SCRAMBLING_MODE_AES128, SCRAMBLING_MODE_AES_ECB,
|
||||
SCRAMBLING_MODE_AES_SCTE52, SCRAMBLING_MODE_TDES_ECB, SCRAMBLING_MODE_TDES_SCTE52})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ScramblingMode {}
|
||||
|
||||
/**
|
||||
* DVB (Digital Video Broadcasting) reserved mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_RESERVED =
|
||||
android.hardware.cas.V1_2.ScramblingMode.RESERVED;
|
||||
/**
|
||||
* DVB (Digital Video Broadcasting) Common Scrambling Algorithm (CSA) 1.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_DVB_CSA1 =
|
||||
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA1;
|
||||
/**
|
||||
* DVB CSA 2.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_DVB_CSA2 =
|
||||
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA2;
|
||||
/**
|
||||
* DVB CSA 3 in standard mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_DVB_CSA3_STANDARD =
|
||||
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_STANDARD;
|
||||
/**
|
||||
* DVB CSA 3 in minimally enhanced mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_DVB_CSA3_MINIMAL =
|
||||
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_MINIMAL;
|
||||
/**
|
||||
* DVB CSA 3 in fully enhanced mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_DVB_CSA3_ENHANCE =
|
||||
android.hardware.cas.V1_2.ScramblingMode.DVB_CSA3_ENHANCE;
|
||||
/**
|
||||
* DVB Common IPTV Software-oriented Scrambling Algorithm (CISSA) Version 1.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_DVB_CISSA_V1 =
|
||||
android.hardware.cas.V1_2.ScramblingMode.DVB_CISSA_V1;
|
||||
/**
|
||||
* ATIS-0800006 IIF Default Scrambling Algorithm (IDSA).
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_DVB_IDSA =
|
||||
android.hardware.cas.V1_2.ScramblingMode.DVB_IDSA;
|
||||
/**
|
||||
* A symmetric key algorithm.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_MULTI2 =
|
||||
android.hardware.cas.V1_2.ScramblingMode.MULTI2;
|
||||
/**
|
||||
* Advanced Encryption System (AES) 128-bit Encryption mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_AES128 =
|
||||
android.hardware.cas.V1_2.ScramblingMode.AES128;
|
||||
/**
|
||||
* Advanced Encryption System (AES) Electronic Code Book (ECB) mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_AES_ECB =
|
||||
android.hardware.cas.V1_2.ScramblingMode.AES_ECB;
|
||||
/**
|
||||
* Advanced Encryption System (AES) Society of Cable Telecommunications Engineers (SCTE) 52
|
||||
* mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_AES_SCTE52 =
|
||||
android.hardware.cas.V1_2.ScramblingMode.AES_SCTE52;
|
||||
/**
|
||||
* Triple Data Encryption Algorithm (TDES) Electronic Code Book (ECB) mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_TDES_ECB =
|
||||
android.hardware.cas.V1_2.ScramblingMode.TDES_ECB;
|
||||
/**
|
||||
* Triple Data Encryption Algorithm (TDES) Society of Cable Telecommunications Engineers (SCTE)
|
||||
* 52 mode.
|
||||
*/
|
||||
public static final int SCRAMBLING_MODE_TDES_SCTE52 =
|
||||
android.hardware.cas.V1_2.ScramblingMode.TDES_SCTE52;
|
||||
|
||||
/**
|
||||
* Usages used to open cas sessions.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = "SESSION_USAGE_",
|
||||
value = {SESSION_USAGE_LIVE, SESSION_USAGE_PLAYBACK, SESSION_USAGE_RECORD,
|
||||
SESSION_USAGE_TIMESHIFT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface SessionUsage {}
|
||||
/**
|
||||
* Cas session is used to descramble live streams.
|
||||
*/
|
||||
public static final int SESSION_USAGE_LIVE = android.hardware.cas.V1_2.SessionIntent.LIVE;
|
||||
/**
|
||||
* Cas session is used to descramble recoreded streams.
|
||||
*/
|
||||
public static final int SESSION_USAGE_PLAYBACK =
|
||||
android.hardware.cas.V1_2.SessionIntent.PLAYBACK;
|
||||
/**
|
||||
* Cas session is used to descramble live streams and encrypt local recorded content
|
||||
*/
|
||||
public static final int SESSION_USAGE_RECORD = android.hardware.cas.V1_2.SessionIntent.RECORD;
|
||||
/**
|
||||
* Cas session is used to descramble live streams , encrypt local recorded content and playback
|
||||
* local encrypted content.
|
||||
*/
|
||||
public static final int SESSION_USAGE_TIMESHIFT =
|
||||
android.hardware.cas.V1_2.SessionIntent.TIMESHIFT;
|
||||
|
||||
/**
|
||||
* Plugin status events sent from cas system.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = "PLUGIN_STATUS_",
|
||||
value = {PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED, PLUGIN_STATUS_SESSION_NUMBER_CHANGED})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface PluginStatus {}
|
||||
|
||||
/**
|
||||
* The event to indicate that the status of CAS system is changed by the removal or insertion of
|
||||
* physical CAS modules.
|
||||
*/
|
||||
public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED =
|
||||
android.hardware.cas.V1_2.StatusEvent.PLUGIN_PHYSICAL_MODULE_CHANGED;
|
||||
/**
|
||||
* The event to indicate that the number of CAS system's session is changed.
|
||||
*/
|
||||
public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED =
|
||||
android.hardware.cas.V1_2.StatusEvent.PLUGIN_SESSION_NUMBER_CHANGED;
|
||||
|
||||
private static final Singleton<IMediaCasService> sService = new Singleton<IMediaCasService>() {
|
||||
@Override
|
||||
protected IMediaCasService create() {
|
||||
try {
|
||||
Log.d(TAG, "Tried to get cas@1.1 service");
|
||||
android.hardware.cas.V1_1.IMediaCasService serviceV11 =
|
||||
android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
|
||||
if (serviceV11 != null) {
|
||||
return serviceV11;
|
||||
}
|
||||
} catch (Exception eV1_1) {
|
||||
try {
|
||||
Log.d(TAG, "Tried to get cas@1.0 service");
|
||||
return IMediaCasService.getService(true /*wait*/);
|
||||
} catch (Exception eV1_0) {
|
||||
Log.d(TAG, "Failed to get cas@1.0 service");
|
||||
Log.d(TAG, "Trying to get cas@1.2 service");
|
||||
android.hardware.cas.V1_2.IMediaCasService serviceV12 =
|
||||
android.hardware.cas.V1_2.IMediaCasService.getService(true /*wait*/);
|
||||
if (serviceV12 != null) {
|
||||
return serviceV12;
|
||||
}
|
||||
} catch (Exception eV1_2) {
|
||||
Log.d(TAG, "Failed to get cas@1.2 service");
|
||||
}
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Trying to get cas@1.1 service");
|
||||
android.hardware.cas.V1_1.IMediaCasService serviceV11 =
|
||||
android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
|
||||
if (serviceV11 != null) {
|
||||
return serviceV11;
|
||||
}
|
||||
} catch (Exception eV1_1) {
|
||||
Log.d(TAG, "Failed to get cas@1.1 service");
|
||||
}
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Trying to get cas@1.0 service");
|
||||
return IMediaCasService.getService(true /*wait*/);
|
||||
} catch (Exception eV1_0) {
|
||||
Log.d(TAG, "Failed to get cas@1.0 service");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@ -139,6 +300,7 @@ public final class MediaCas implements AutoCloseable {
|
||||
private void cleanupAndRethrowIllegalState() {
|
||||
mICas = null;
|
||||
mICasV11 = null;
|
||||
mICasV12 = null;
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@ -146,6 +308,8 @@ public final class MediaCas implements AutoCloseable {
|
||||
|
||||
private static final int MSG_CAS_EVENT = 0;
|
||||
private static final int MSG_CAS_SESSION_EVENT = 1;
|
||||
private static final int MSG_CAS_STATUS_EVENT = 2;
|
||||
private static final int MSG_CAS_RESOURCE_LOST = 3;
|
||||
private static final String SESSION_KEY = "sessionId";
|
||||
private static final String DATA_KEY = "data";
|
||||
|
||||
@ -164,6 +328,10 @@ public final class MediaCas implements AutoCloseable {
|
||||
mListener.onSessionEvent(MediaCas.this,
|
||||
createFromSessionId(sessionId), msg.arg1, msg.arg2,
|
||||
bundle.getByteArray(DATA_KEY));
|
||||
} else if (msg.what == MSG_CAS_STATUS_EVENT) {
|
||||
mListener.onPluginStatusUpdate(MediaCas.this, msg.arg1, msg.arg2);
|
||||
} else if (msg.what == MSG_CAS_RESOURCE_LOST) {
|
||||
mListener.onResourceLost(MediaCas.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -189,6 +357,12 @@ public final class MediaCas implements AutoCloseable {
|
||||
msg.setData(bundle);
|
||||
mEventHandler.sendMessage(msg);
|
||||
}
|
||||
@Override
|
||||
public void onStatusUpdate(byte status, int arg)
|
||||
throws RemoteException {
|
||||
mEventHandler.sendMessage(mEventHandler.obtainMessage(
|
||||
EventHandler.MSG_CAS_STATUS_EVENT, status, arg));
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Describe a CAS plugin with its CA_system_ID and string name.
|
||||
@ -257,7 +431,7 @@ public final class MediaCas implements AutoCloseable {
|
||||
final ArrayList<Byte> mSessionId;
|
||||
|
||||
Session(@NonNull ArrayList<Byte> sessionId) {
|
||||
mSessionId = sessionId;
|
||||
mSessionId = new ArrayList<Byte>(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -363,6 +537,19 @@ public final class MediaCas implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Session Id.
|
||||
*
|
||||
* @return session Id of the session.
|
||||
*
|
||||
* @throws IllegalStateException if the MediaCas instance is not valid.
|
||||
*/
|
||||
@NonNull
|
||||
public byte[] getSessionId() {
|
||||
validateInternalStates();
|
||||
return toBytes(mSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the session.
|
||||
*
|
||||
@ -445,14 +632,23 @@ public final class MediaCas implements AutoCloseable {
|
||||
public MediaCas(int CA_system_id) throws UnsupportedCasException {
|
||||
try {
|
||||
IMediaCasService service = getService();
|
||||
android.hardware.cas.V1_1.IMediaCasService serviceV11 =
|
||||
android.hardware.cas.V1_2.IMediaCasService serviceV12 =
|
||||
android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
|
||||
if (serviceV12 == null) {
|
||||
android.hardware.cas.V1_1.IMediaCasService serviceV11 =
|
||||
android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
|
||||
if (serviceV11 == null) {
|
||||
Log.d(TAG, "Used cas@1_0 interface to create plugin");
|
||||
mICas = service.createPlugin(CA_system_id, mBinder);
|
||||
if (serviceV11 == null) {
|
||||
Log.d(TAG, "Used cas@1_0 interface to create plugin");
|
||||
mICas = service.createPlugin(CA_system_id, mBinder);
|
||||
} else {
|
||||
Log.d(TAG, "Used cas@1.1 interface to create plugin");
|
||||
mICas = mICasV11 = serviceV11.createPluginExt(CA_system_id, mBinder);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Used cas@1.1 interface to create plugin");
|
||||
mICas = mICasV11 = serviceV11.createPluginExt(CA_system_id, mBinder);
|
||||
Log.d(TAG, "Used cas@1.2 interface to create plugin");
|
||||
mICas = mICasV11 = mICasV12 =
|
||||
android.hardware.cas.V1_2.ICas
|
||||
.castFrom(serviceV12.createPluginExt(CA_system_id, mBinder));
|
||||
}
|
||||
} catch(Exception e) {
|
||||
Log.e(TAG, "Failed to create plugin: " + e);
|
||||
@ -465,6 +661,24 @@ public final class MediaCas implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a CA system of the specified system id.
|
||||
*
|
||||
* @param casSystemId The system id of the CA system.
|
||||
* @param tvInputServiceSessionId The Id of the session opened in TV Input Service (TIS)
|
||||
* {@link android.media.tv.TvInputService#onCreateSession(String, String)}
|
||||
* @param priorityHint priority hint from the use case type for new created CAS system.
|
||||
*
|
||||
* @throws UnsupportedCasException if the device does not support the
|
||||
* specified CA system.
|
||||
*/
|
||||
public MediaCas(int casSystemId, @Nullable String tvInputServiceSessionId,
|
||||
@PriorityHintUseCaseType int priorityHint) throws UnsupportedCasException {
|
||||
this(casSystemId);
|
||||
mPriorityHint = priorityHint;
|
||||
mTvInputServiceSessionId = tvInputServiceSessionId;
|
||||
}
|
||||
|
||||
IHwBinder getBinder() {
|
||||
validateInternalStates();
|
||||
|
||||
@ -476,6 +690,7 @@ public final class MediaCas implements AutoCloseable {
|
||||
* to receives scheme-specific notifications from a MediaCas instance.
|
||||
*/
|
||||
public interface EventListener {
|
||||
|
||||
/**
|
||||
* Notify the listener of a scheme-specific event from the CA system.
|
||||
*
|
||||
@ -501,6 +716,27 @@ public final class MediaCas implements AutoCloseable {
|
||||
int event, int arg, @Nullable byte[] data) {
|
||||
Log.d(TAG, "Received MediaCas Session event");
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the listener that the cas plugin status is updated.
|
||||
*
|
||||
* @param mediaCas the MediaCas object to receive this event.
|
||||
* @param status the plugin status which is updated.
|
||||
* @param arg an integer whose meaning is specific to the status to be updated.
|
||||
*/
|
||||
default void onPluginStatusUpdate(@NonNull MediaCas mediaCas, @PluginStatus int status,
|
||||
int arg) {
|
||||
Log.d(TAG, "Received MediaCas Plugin Status event");
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the listener that the session resources was lost.
|
||||
*
|
||||
* @param mediaCas the MediaCas object to receive this event.
|
||||
*/
|
||||
default void onResourceLost(@NonNull MediaCas mediaCas) {
|
||||
Log.d(TAG, "Received MediaCas Resource Reclaim event");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -563,6 +799,20 @@ public final class MediaCas implements AutoCloseable {
|
||||
mSession = createFromSessionId(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
private class OpenSession_1_2_Callback implements
|
||||
android.hardware.cas.V1_2.ICas.openSession_1_2Callback {
|
||||
|
||||
public Session mSession;
|
||||
public int mStatus;
|
||||
|
||||
@Override
|
||||
public void onValues(int status, ArrayList<Byte> sessionId) {
|
||||
mStatus = status;
|
||||
mSession = createFromSessionId(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a session to descramble one or more streams scrambled by the
|
||||
* conditional access system.
|
||||
@ -587,6 +837,40 @@ public final class MediaCas implements AutoCloseable {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a session with usage and scrambling information, so that descrambler can be configured
|
||||
* to descramble one or more streams scrambled by the conditional access system.
|
||||
*
|
||||
* @param sessionUsage used for the created session.
|
||||
* @param scramblingMode used for the created session.
|
||||
*
|
||||
* @return session the newly opened session.
|
||||
*
|
||||
* @throws IllegalStateException if the MediaCas instance is not valid.
|
||||
* @throws MediaCasException for CAS-specific errors.
|
||||
* @throws MediaCasStateException for CAS-specific state exceptions.
|
||||
*/
|
||||
@Nullable
|
||||
public Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode)
|
||||
throws MediaCasException {
|
||||
validateInternalStates();
|
||||
|
||||
if (mICasV12 == null) {
|
||||
Log.d(TAG, "Open Session with scrambling mode is only supported by cas@1.2+ interface");
|
||||
throw new UnsupportedCasException("Open Session with scrambling mode is not supported");
|
||||
}
|
||||
|
||||
try {
|
||||
OpenSession_1_2_Callback cb = new OpenSession_1_2_Callback();
|
||||
mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
|
||||
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
|
||||
return cb.mSession;
|
||||
} catch (RemoteException e) {
|
||||
cleanupAndRethrowIllegalState();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a received EMM packet to the CA system.
|
||||
*
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
package android.media;
|
||||
|
||||
import android.hardware.cas.V1_0.Status;
|
||||
import android.hardware.cas.V1_2.Status;
|
||||
|
||||
/**
|
||||
* Base class for MediaCas exceptions
|
||||
@ -85,4 +85,15 @@ public class MediaCasException extends Exception {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when an operation on a MediaCas object is attempted
|
||||
* and hardware resources are not sufficient to allocate, due to client's lower priority.
|
||||
*/
|
||||
public static final class InsufficientResourceException extends MediaCasException {
|
||||
/** @hide */
|
||||
public InsufficientResourceException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ package android.media;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import android.hardware.cas.V1_0.Status;
|
||||
import android.hardware.cas.V1_2.Status;
|
||||
|
||||
/**
|
||||
* Base class for MediaCas runtime exceptions
|
||||
@ -48,39 +47,60 @@ public class MediaCasStateException extends IllegalStateException {
|
||||
|
||||
String diagnosticInfo = "";
|
||||
switch (err) {
|
||||
case Status.ERROR_CAS_UNKNOWN:
|
||||
diagnosticInfo = "General CAS error";
|
||||
break;
|
||||
case Status.ERROR_CAS_NO_LICENSE:
|
||||
diagnosticInfo = "No license";
|
||||
break;
|
||||
case Status.ERROR_CAS_LICENSE_EXPIRED:
|
||||
diagnosticInfo = "License expired";
|
||||
break;
|
||||
case Status.ERROR_CAS_SESSION_NOT_OPENED:
|
||||
diagnosticInfo = "Session not opened";
|
||||
break;
|
||||
case Status.ERROR_CAS_CANNOT_HANDLE:
|
||||
diagnosticInfo = "Unsupported scheme or data format";
|
||||
break;
|
||||
case Status.ERROR_CAS_INVALID_STATE:
|
||||
diagnosticInfo = "Invalid CAS state";
|
||||
break;
|
||||
case Status.ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
|
||||
diagnosticInfo = "Insufficient output protection";
|
||||
break;
|
||||
case Status.ERROR_CAS_TAMPER_DETECTED:
|
||||
diagnosticInfo = "Tamper detected";
|
||||
break;
|
||||
case Status.ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
|
||||
diagnosticInfo = "Not initialized";
|
||||
break;
|
||||
case Status.ERROR_CAS_DECRYPT:
|
||||
diagnosticInfo = "Decrypt error";
|
||||
break;
|
||||
default:
|
||||
diagnosticInfo = "Unknown CAS state exception";
|
||||
break;
|
||||
case Status.ERROR_CAS_UNKNOWN:
|
||||
diagnosticInfo = "General CAS error";
|
||||
break;
|
||||
case Status.ERROR_CAS_NO_LICENSE:
|
||||
diagnosticInfo = "No license";
|
||||
break;
|
||||
case Status.ERROR_CAS_LICENSE_EXPIRED:
|
||||
diagnosticInfo = "License expired";
|
||||
break;
|
||||
case Status.ERROR_CAS_SESSION_NOT_OPENED:
|
||||
diagnosticInfo = "Session not opened";
|
||||
break;
|
||||
case Status.ERROR_CAS_CANNOT_HANDLE:
|
||||
diagnosticInfo = "Unsupported scheme or data format";
|
||||
break;
|
||||
case Status.ERROR_CAS_INVALID_STATE:
|
||||
diagnosticInfo = "Invalid CAS state";
|
||||
break;
|
||||
case Status.ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION:
|
||||
diagnosticInfo = "Insufficient output protection";
|
||||
break;
|
||||
case Status.ERROR_CAS_TAMPER_DETECTED:
|
||||
diagnosticInfo = "Tamper detected";
|
||||
break;
|
||||
case Status.ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED:
|
||||
diagnosticInfo = "Not initialized";
|
||||
break;
|
||||
case Status.ERROR_CAS_DECRYPT:
|
||||
diagnosticInfo = "Decrypt error";
|
||||
break;
|
||||
case Status.ERROR_CAS_NEED_ACTIVATION:
|
||||
diagnosticInfo = "Need Activation";
|
||||
break;
|
||||
case Status.ERROR_CAS_NEED_PAIRING:
|
||||
diagnosticInfo = "Need Pairing";
|
||||
break;
|
||||
case Status.ERROR_CAS_NO_CARD:
|
||||
diagnosticInfo = "No Card";
|
||||
break;
|
||||
case Status.ERROR_CAS_CARD_MUTE:
|
||||
diagnosticInfo = "Card Muted";
|
||||
break;
|
||||
case Status.ERROR_CAS_CARD_INVALID:
|
||||
diagnosticInfo = "Card Invalid";
|
||||
break;
|
||||
case Status.ERROR_CAS_BLACKOUT:
|
||||
diagnosticInfo = "Blackout";
|
||||
break;
|
||||
case Status.ERROR_CAS_REBOOTING:
|
||||
diagnosticInfo = "Rebooting";
|
||||
break;
|
||||
default:
|
||||
diagnosticInfo = "Unknown CAS state exception";
|
||||
break;
|
||||
}
|
||||
throw new MediaCasStateException(err, msg,
|
||||
String.format("%s (err=%d)", diagnosticInfo, err));
|
||||
|
@ -110,12 +110,20 @@ public final class TvInputManager {
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
|
||||
VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
|
||||
VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
|
||||
VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
|
||||
VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY, VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_INSUFFICIENT_OUTPUT_PROTECTION,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_NO_LICENSE, VIDEO_UNAVAILABLE_REASON_CAS_LICENSE_EXPIRED,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_NEED_ACTIVATION, VIDEO_UNAVAILABLE_REASON_CAS_NEED_PAIRING,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_NO_CARD, VIDEO_UNAVAILABLE_REASON_CAS_CARD_MUTE,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_CARD_INVALID, VIDEO_UNAVAILABLE_REASON_CAS_BLACKOUT,
|
||||
VIDEO_UNAVAILABLE_REASON_CAS_REBOOTING, VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN})
|
||||
public @interface VideoUnavailableReason {}
|
||||
|
||||
static final int VIDEO_UNAVAILABLE_REASON_START = 0;
|
||||
static final int VIDEO_UNAVAILABLE_REASON_END = 5;
|
||||
static final int VIDEO_UNAVAILABLE_REASON_END = 18;
|
||||
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
@ -151,9 +159,88 @@ public final class TvInputManager {
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* the source is not physically connected, for example the HDMI cable is not connected.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = 5;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* the resource is not enough to meet requirement.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_INSUFFICIENT_RESOURCE = 6;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* the output protection level enabled on the device is not sufficient to meet the requirements
|
||||
* in the license policy.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_INSUFFICIENT_OUTPUT_PROTECTION = 7;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* the PVR record is not allowed by the license policy.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_PVR_RECORDING_NOT_ALLOWED = 8;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* no license keys have been provided.
|
||||
* @hide
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = VIDEO_UNAVAILABLE_REASON_END;
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_NO_LICENSE = 9;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* Using a license in whhich the keys have expired.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_LICENSE_EXPIRED = 10;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* the device need be activated.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_NEED_ACTIVATION = 11;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* the device need be paired.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_NEED_PAIRING = 12;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* smart card is missed.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_NO_CARD = 13;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* smart card is muted.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_CARD_MUTE = 14;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* smart card is invalid.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_CARD_INVALID = 15;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* of a geographical blackout.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_BLACKOUT = 16;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* CAS system is rebooting.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_REBOOTING = 17;
|
||||
/**
|
||||
* Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
|
||||
* {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
|
||||
* of unknown CAS error.
|
||||
*/
|
||||
public static final int VIDEO_UNAVAILABLE_REASON_CAS_UNKNOWN = VIDEO_UNAVAILABLE_REASON_END;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
|
@ -17,6 +17,7 @@
|
||||
package android.media.tv;
|
||||
|
||||
import android.annotation.FloatRange;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@ -58,6 +59,8 @@ import android.widget.FrameLayout;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -95,6 +98,53 @@ public abstract class TvInputService extends Service {
|
||||
*/
|
||||
public static final String SERVICE_META_DATA = "android.media.tv.input";
|
||||
|
||||
/**
|
||||
* Prioirity hint from use case types.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(prefix = "PRIORITY_HINT_USE_CASE_TYPE_",
|
||||
value = {PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND, PRIORITY_HINT_USE_CASE_TYPE_SCAN,
|
||||
PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, PRIORITY_HINT_USE_CASE_TYPE_LIVE,
|
||||
PRIORITY_HINT_USE_CASE_TYPE_RECORD})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface PriorityHintUseCaseType {}
|
||||
|
||||
/**
|
||||
* Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
|
||||
* Background.
|
||||
* TODO Link: Tuner#Tuner(Context, string, int).
|
||||
*/
|
||||
public static final int PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND = 100;
|
||||
|
||||
/**
|
||||
* Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
|
||||
* Scan.
|
||||
* TODO Link: Tuner#Tuner(Context, string, int).
|
||||
*/
|
||||
public static final int PRIORITY_HINT_USE_CASE_TYPE_SCAN = 200;
|
||||
|
||||
/**
|
||||
* Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
|
||||
* Playback.
|
||||
* TODO Link: Tuner#Tuner(Context, string, int).
|
||||
*/
|
||||
public static final int PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK = 300;
|
||||
|
||||
/**
|
||||
* Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
|
||||
* Live.
|
||||
* TODO Link: Tuner#Tuner(Context, string, int).
|
||||
*/
|
||||
public static final int PRIORITY_HINT_USE_CASE_TYPE_LIVE = 400;
|
||||
|
||||
/**
|
||||
* Use case of priority hint for {@link android.media.MediaCas#MediaCas(int, String , int)}:
|
||||
* Record.
|
||||
* TODO Link: Tuner#Tuner(Context, string, int).
|
||||
*/
|
||||
public static final int PRIORITY_HINT_USE_CASE_TYPE_RECORD = 500;
|
||||
|
||||
/**
|
||||
* Handler instance to handle request from TV Input Manager Service. Should be run in the main
|
||||
* looper to be synchronously run with {@code Session.mHandler}.
|
||||
|
Loading…
x
Reference in New Issue
Block a user