Support multiple tracks in TV Input framework.
Added API: getTracks/selectTrack/unselectTrack/onTrackInfoChanged (onVideo/Audio/ClosedCaptionStreamChanged callbacks are removed in favor of onTrackInfoChanged) Use cases: audio and closed caption track selection Background: go/tif-multi-track Bug:14073704, Bug:14121898, Bug: 16049453 Change-Id: I199ed16f690d4e757da0bb30c8bc8222a6fa1d7a
This commit is contained in:
@@ -16140,6 +16140,7 @@ package android.media.tv {
|
||||
public abstract class TvInputService.Session implements android.view.KeyEvent.Callback {
|
||||
ctor public TvInputService.Session();
|
||||
method public void dispatchChannelRetuned(android.net.Uri);
|
||||
method public void dispatchTrackInfoChanged(java.util.List<android.media.tv.TvTrackInfo>);
|
||||
method public android.view.View onCreateOverlayView();
|
||||
method public boolean onGenericMotionEvent(android.view.MotionEvent);
|
||||
method public boolean onKeyDown(int, android.view.KeyEvent);
|
||||
@@ -16147,26 +16148,61 @@ package android.media.tv {
|
||||
method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
|
||||
method public boolean onKeyUp(int, android.view.KeyEvent);
|
||||
method public abstract void onRelease();
|
||||
method public boolean onSelectTrack(android.media.tv.TvTrackInfo);
|
||||
method public abstract void onSetStreamVolume(float);
|
||||
method public abstract boolean onSetSurface(android.view.Surface);
|
||||
method public boolean onTouchEvent(android.view.MotionEvent);
|
||||
method public boolean onTrackballEvent(android.view.MotionEvent);
|
||||
method public abstract boolean onTune(android.net.Uri);
|
||||
method public boolean onUnselectTrack(android.media.tv.TvTrackInfo);
|
||||
method public void setOverlayViewEnabled(boolean);
|
||||
}
|
||||
|
||||
public final class TvTrackInfo implements android.os.Parcelable {
|
||||
method public boolean containsKey(java.lang.String);
|
||||
method public int describeContents();
|
||||
method public boolean getBoolean(java.lang.String);
|
||||
method public int getInt(java.lang.String);
|
||||
method public java.lang.String getString(java.lang.String);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public static final java.lang.String KEY_CHANNEL_COUNT = "channel-count";
|
||||
field public static final java.lang.String KEY_HEIGHT = "height";
|
||||
field public static final java.lang.String KEY_IS_SELECTED = "is-selected";
|
||||
field public static final java.lang.String KEY_LANGUAGE = "language";
|
||||
field public static final java.lang.String KEY_SAMPLE_RATE = "sample-rate";
|
||||
field public static final java.lang.String KEY_TAG = "tag";
|
||||
field public static final java.lang.String KEY_TYPE = "type";
|
||||
field public static final java.lang.String KEY_WIDTH = "width";
|
||||
field public static final int VALUE_TYPE_AUDIO = 0; // 0x0
|
||||
field public static final int VALUE_TYPE_SUBTITLE = 2; // 0x2
|
||||
field public static final int VALUE_TYPE_VIDEO = 1; // 0x1
|
||||
}
|
||||
|
||||
public static final class TvTrackInfo.Builder {
|
||||
ctor public TvTrackInfo.Builder(int, java.lang.String, boolean);
|
||||
ctor public TvTrackInfo.Builder(android.media.tv.TvTrackInfo);
|
||||
method public android.media.tv.TvTrackInfo build();
|
||||
method public android.media.tv.TvTrackInfo.Builder putBoolean(java.lang.String, boolean);
|
||||
method public android.media.tv.TvTrackInfo.Builder putInt(java.lang.String, int);
|
||||
method public android.media.tv.TvTrackInfo.Builder putString(java.lang.String, java.lang.String);
|
||||
}
|
||||
|
||||
public class TvView extends android.view.ViewGroup {
|
||||
ctor public TvView(android.content.Context);
|
||||
ctor public TvView(android.content.Context, android.util.AttributeSet);
|
||||
ctor public TvView(android.content.Context, android.util.AttributeSet, int);
|
||||
method public boolean dispatchUnhandledInputEvent(android.view.InputEvent);
|
||||
method public java.util.List<android.media.tv.TvTrackInfo> getTracks();
|
||||
method protected void onLayout(boolean, int, int, int, int);
|
||||
method public boolean onUnhandledInputEvent(android.view.InputEvent);
|
||||
method public void reset();
|
||||
method public void selectTrack(android.media.tv.TvTrackInfo);
|
||||
method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
|
||||
method public void setStreamVolume(float);
|
||||
method public void setTvInputListener(android.media.tv.TvView.TvInputListener);
|
||||
method public void tune(java.lang.String, android.net.Uri);
|
||||
method public void unselectTrack(android.media.tv.TvTrackInfo);
|
||||
field public static final int ERROR_BUSY = 0; // 0x0
|
||||
field public static final int ERROR_TV_INPUT_DISCONNECTED = 1; // 0x1
|
||||
}
|
||||
@@ -16179,6 +16215,8 @@ package android.media.tv {
|
||||
ctor public TvView.TvInputListener();
|
||||
method public void onChannelRetuned(java.lang.String, android.net.Uri);
|
||||
method public void onError(java.lang.String, int);
|
||||
method public void onTrackInfoChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>);
|
||||
method public void onVideoSizeChanged(java.lang.String, int, int);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.media.tv;
|
||||
import android.content.ComponentName;
|
||||
import android.media.tv.ITvInputSession;
|
||||
import android.net.Uri;
|
||||
import android.media.tv.TvTrackInfo;
|
||||
import android.os.Bundle;
|
||||
import android.view.InputChannel;
|
||||
|
||||
@@ -32,8 +33,6 @@ oneway interface ITvInputClient {
|
||||
void onAvailabilityChanged(in String inputId, boolean isAvailable);
|
||||
void onSessionReleased(int seq);
|
||||
void onSessionEvent(in String name, in Bundle args, int seq);
|
||||
void onVideoStreamChanged(int width, int height, boolean interlaced, int seq);
|
||||
void onAudioStreamChanged(int channelCount, int seq);
|
||||
void onClosedCaptionStreamChanged(boolean hasClosedCaption, int seq);
|
||||
void onChannelRetuned(in Uri channelUri, int seq);
|
||||
void onTrackInfoChanged(in List<TvTrackInfo> tracks, int seq);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.media.tv.ITvInputHardwareCallback;
|
||||
import android.media.tv.ITvInputClient;
|
||||
import android.media.tv.TvInputHardwareInfo;
|
||||
import android.media.tv.TvInputInfo;
|
||||
import android.media.tv.TvTrackInfo;
|
||||
import android.net.Uri;
|
||||
import android.view.Surface;
|
||||
|
||||
@@ -44,6 +45,8 @@ interface ITvInputManager {
|
||||
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
|
||||
void setVolume(in IBinder sessionToken, float volume, int userId);
|
||||
void tune(in IBinder sessionToken, in Uri channelUri, int userId);
|
||||
void selectTrack(in IBinder sessionToken, in TvTrackInfo track, int userId);
|
||||
void unselectTrack(in IBinder sessionToken, in TvTrackInfo track, int userId);
|
||||
|
||||
void createOverlayView(in IBinder sessionToken, in IBinder windowToken, in Rect frame,
|
||||
int userId);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.media.tv;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.media.tv.TvTrackInfo;
|
||||
import android.net.Uri;
|
||||
import android.view.Surface;
|
||||
|
||||
@@ -32,6 +33,8 @@ oneway interface ITvInputSession {
|
||||
// is to introduce some new concepts that will solve a number of problems in audio policy today.
|
||||
void setVolume(float volume);
|
||||
void tune(in Uri channelUri);
|
||||
void selectTrack(in TvTrackInfo track);
|
||||
void unselectTrack(in TvTrackInfo track);
|
||||
|
||||
void createOverlayView(in IBinder windowToken, in Rect frame);
|
||||
void relayoutOverlayView(in Rect frame);
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.media.tv;
|
||||
|
||||
import android.media.tv.ITvInputSession;
|
||||
import android.net.Uri;
|
||||
import android.media.tv.TvTrackInfo;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
@@ -28,8 +29,6 @@ import android.os.Bundle;
|
||||
oneway interface ITvInputSessionCallback {
|
||||
void onSessionCreated(ITvInputSession session);
|
||||
void onSessionEvent(in String name, in Bundle args);
|
||||
void onVideoStreamChanged(int width, int height, boolean interlaced);
|
||||
void onAudioStreamChanged(int channelCount);
|
||||
void onClosedCaptionStreamChanged(boolean hasClosedCaption);
|
||||
void onChannelRetuned(in Uri channelUri);
|
||||
void onTrackInfoChanged(in List<TvTrackInfo> tracks);
|
||||
}
|
||||
|
||||
@@ -44,9 +44,11 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
|
||||
private static final int DO_SET_SURFACE = 2;
|
||||
private static final int DO_SET_VOLUME = 3;
|
||||
private static final int DO_TUNE = 4;
|
||||
private static final int DO_CREATE_OVERLAY_VIEW = 5;
|
||||
private static final int DO_RELAYOUT_OVERLAY_VIEW = 6;
|
||||
private static final int DO_REMOVE_OVERLAY_VIEW = 7;
|
||||
private static final int DO_SELECT_TRACK = 5;
|
||||
private static final int DO_UNSELECT_TRACK = 6;
|
||||
private static final int DO_CREATE_OVERLAY_VIEW = 7;
|
||||
private static final int DO_RELAYOUT_OVERLAY_VIEW = 8;
|
||||
private static final int DO_REMOVE_OVERLAY_VIEW = 9;
|
||||
|
||||
private final HandlerCaller mCaller;
|
||||
|
||||
@@ -96,6 +98,14 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
|
||||
mTvInputSessionImpl.tune((Uri) msg.obj);
|
||||
return;
|
||||
}
|
||||
case DO_SELECT_TRACK: {
|
||||
mTvInputSessionImpl.selectTrack((TvTrackInfo) msg.obj);
|
||||
return;
|
||||
}
|
||||
case DO_UNSELECT_TRACK: {
|
||||
mTvInputSessionImpl.unselectTrack((TvTrackInfo) msg.obj);
|
||||
return;
|
||||
}
|
||||
case DO_CREATE_OVERLAY_VIEW: {
|
||||
SomeArgs args = (SomeArgs) msg.obj;
|
||||
mTvInputSessionImpl.createOverlayView((IBinder) args.arg1, (Rect) args.arg2);
|
||||
@@ -137,6 +147,16 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
|
||||
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_TUNE, channelUri));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectTrack(TvTrackInfo track) {
|
||||
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_SELECT_TRACK, track));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unselectTrack(TvTrackInfo track) {
|
||||
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_UNSELECT_TRACK, track));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createOverlayView(IBinder windowToken, Rect frame) {
|
||||
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_CREATE_OVERLAY_VIEW, windowToken,
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.view.Surface;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -88,42 +89,6 @@ public final class TvInputManager {
|
||||
public void onSessionReleased(Session session) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called at the beginning of the playback of a channel and later when the format of
|
||||
* the video stream has been changed.
|
||||
*
|
||||
* @param session A {@link TvInputManager.Session} associated with this callback
|
||||
* @param width The width of the video.
|
||||
* @param height The height of the video.
|
||||
* @param interlaced whether the video is interlaced mode or planer mode.
|
||||
* @hide
|
||||
*/
|
||||
public void onVideoStreamChanged(Session session, int width, int height,
|
||||
boolean interlaced) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called at the beginning of the playback of a channel and later when the format of
|
||||
* the audio stream has been changed.
|
||||
*
|
||||
* @param session A {@link TvInputManager.Session} associated with this callback
|
||||
* @param channelCount The number of channels in the audio stream.
|
||||
* @hide
|
||||
*/
|
||||
public void onAudioStreamChanged(Session session, int channelCount) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called at the beginning of the playback of a channel and later when the closed
|
||||
* caption stream has been changed.
|
||||
*
|
||||
* @param session A {@link TvInputManager.Session} associated with this callback
|
||||
* @param hasClosedCaption Whether the stream has closed caption or not.
|
||||
* @hide
|
||||
*/
|
||||
public void onClosedCaptionStreamChanged(Session session, boolean hasClosedCaption) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the channel of this session is changed by the underlying TV input
|
||||
* with out any {@link TvInputManager.Session#tune(Uri)} request.
|
||||
@@ -134,6 +99,15 @@ public final class TvInputManager {
|
||||
public void onChannelRetuned(Session session, Uri channelUri) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the track information of the session has been changed.
|
||||
*
|
||||
* @param session A {@link TvInputManager.Session} associated with this callback
|
||||
* @param tracks A list which includes track information.
|
||||
*/
|
||||
public void onTrackInfoChanged(Session session, List<TvTrackInfo> tracks) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when a custom event has been sent from this session.
|
||||
*
|
||||
@@ -176,34 +150,6 @@ public final class TvInputManager {
|
||||
});
|
||||
}
|
||||
|
||||
public void postVideoStreamChanged(final int width, final int height,
|
||||
final boolean interlaced) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSessionCallback.onVideoStreamChanged(mSession, width, height, interlaced);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void postAudioStreamChanged(final int channelCount) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSessionCallback.onAudioStreamChanged(mSession, channelCount);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void postClosedCaptionStreamChanged(final boolean hasClosedCaption) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSessionCallback.onClosedCaptionStreamChanged(mSession, hasClosedCaption);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void postChannelRetuned(final Uri channelUri) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
@@ -213,6 +159,16 @@ public final class TvInputManager {
|
||||
});
|
||||
}
|
||||
|
||||
public void postTrackInfoChanged(final List<TvTrackInfo> tracks) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mSession.setTracks(tracks);
|
||||
mSessionCallback.onTrackInfoChanged(mSession, tracks);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void postSessionEvent(final String eventType, final Bundle eventArgs) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
@@ -300,42 +256,6 @@ public final class TvInputManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoStreamChanged(int width, int height, boolean interlaced, int seq) {
|
||||
synchronized (mSessionCallbackRecordMap) {
|
||||
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
|
||||
if (record == null) {
|
||||
Log.e(TAG, "Callback not found for seq " + seq);
|
||||
return;
|
||||
}
|
||||
record.postVideoStreamChanged(width, height, interlaced);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioStreamChanged(int channelCount, int seq) {
|
||||
synchronized (mSessionCallbackRecordMap) {
|
||||
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
|
||||
if (record == null) {
|
||||
Log.e(TAG, "Callback not found for seq " + seq);
|
||||
return;
|
||||
}
|
||||
record.postAudioStreamChanged(channelCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosedCaptionStreamChanged(boolean hasClosedCaption, int seq) {
|
||||
synchronized (mSessionCallbackRecordMap) {
|
||||
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
|
||||
if (record == null) {
|
||||
Log.e(TAG, "Callback not found for seq " + seq);
|
||||
return;
|
||||
}
|
||||
record.postClosedCaptionStreamChanged(hasClosedCaption);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelRetuned(Uri channelUri, int seq) {
|
||||
synchronized (mSessionCallbackRecordMap) {
|
||||
@@ -348,6 +268,18 @@ public final class TvInputManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackInfoChanged(List<TvTrackInfo> tracks, int seq) {
|
||||
synchronized (mSessionCallbackRecordMap) {
|
||||
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
|
||||
if (record == null) {
|
||||
Log.e(TAG, "Callback not found for seq " + seq);
|
||||
return;
|
||||
}
|
||||
record.postTrackInfoChanged(tracks);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionEvent(String eventType, Bundle eventArgs, int seq) {
|
||||
synchronized (mSessionCallbackRecordMap) {
|
||||
@@ -550,6 +482,7 @@ public final class TvInputManager {
|
||||
private IBinder mToken;
|
||||
private TvInputEventSender mSender;
|
||||
private InputChannel mChannel;
|
||||
private List<TvTrackInfo> mTracks;
|
||||
|
||||
/** @hide */
|
||||
private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
|
||||
@@ -633,6 +566,7 @@ public final class TvInputManager {
|
||||
Log.w(TAG, "The session has been already released");
|
||||
return;
|
||||
}
|
||||
mTracks = null;
|
||||
try {
|
||||
mService.tune(mToken, channelUri, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
@@ -640,6 +574,65 @@ public final class TvInputManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a track.
|
||||
*
|
||||
* @param track the track to be selected.
|
||||
* @see #getTracks()
|
||||
*/
|
||||
public void selectTrack(TvTrackInfo track) {
|
||||
if (track == null) {
|
||||
throw new IllegalArgumentException("track cannot be null");
|
||||
}
|
||||
if (mToken == null) {
|
||||
Log.w(TAG, "The session has been already released");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mService.selectTrack(mToken, track, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unselect a track.
|
||||
*
|
||||
* @param track the track to be selected.
|
||||
* @see #getTracks()
|
||||
*/
|
||||
public void unselectTrack(TvTrackInfo track) {
|
||||
if (track == null) {
|
||||
throw new IllegalArgumentException("track cannot be null");
|
||||
}
|
||||
if (mToken == null) {
|
||||
Log.w(TAG, "The session has been already released");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mService.unselectTrack(mToken, track, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list which includes track information. May return {@code null} if the
|
||||
* information is not available.
|
||||
* @see #selectTrack(TvTrackInfo)
|
||||
* @see #unselectTrack(TvTrackInfo)
|
||||
*/
|
||||
public List<TvTrackInfo> getTracks() {
|
||||
if (mTracks == null) {
|
||||
return null;
|
||||
}
|
||||
return new ArrayList<TvTrackInfo>(mTracks);
|
||||
}
|
||||
|
||||
private void setTracks(List<TvTrackInfo> tracks) {
|
||||
mTracks = tracks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an overlay view. Once the overlay view is created, {@link #relayoutOverlayView}
|
||||
* should be called whenever the layout of its containing view is changed.
|
||||
|
||||
@@ -44,6 +44,8 @@ import android.view.WindowManager;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.os.SomeArgs;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The TvInputService class represents a TV input or source such as HDMI or built-in tuner which
|
||||
* provides pass-through video or broadcast TV programs.
|
||||
@@ -219,72 +221,6 @@ public abstract class TvInputService extends Service {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the change on the format of the video stream. This is expected to be called at the
|
||||
* beginning of the playback and later when the format has been changed.
|
||||
*
|
||||
* @param width The width of the video.
|
||||
* @param height The height of the video.
|
||||
* @param interlaced Whether the video is interlaced mode or planer mode.
|
||||
* @hide
|
||||
*/
|
||||
public void dispatchVideoStreamChanged(final int width, final int height,
|
||||
final boolean interlaced) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "dispatchVideoSizeChanged");
|
||||
mSessionCallback.onVideoStreamChanged(width, height, interlaced);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "error in dispatchVideoSizeChanged");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the change on the format of the audio stream. This is expected to be called at the
|
||||
* beginning of the playback and later when the format has been changed.
|
||||
*
|
||||
* @param channelNumber The number of channels in the audio stream.
|
||||
* @hide
|
||||
*/
|
||||
public void dispatchAudioStreamChanged(final int channelNumber) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "dispatchAudioStreamChanged");
|
||||
mSessionCallback.onAudioStreamChanged(channelNumber);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "error in dispatchAudioStreamChanged");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the change on the closed caption stream. This is expected to be called at the
|
||||
* beginning of the playback and later when the stream has been changed.
|
||||
*
|
||||
* @param hasClosedCaption Whether the stream has closed caption or not.
|
||||
* @hide
|
||||
*/
|
||||
public void dispatchClosedCaptionStreamChanged(final boolean hasClosedCaption) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "dispatchClosedCaptionStreamChanged");
|
||||
mSessionCallback.onClosedCaptionStreamChanged(hasClosedCaption);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "error in dispatchClosedCaptionStreamChanged");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the channel of the session is retuned by TV input.
|
||||
*
|
||||
@@ -304,6 +240,30 @@ public abstract class TvInputService extends Service {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the change on the track information. This is expected to be called whenever a
|
||||
* track is added/removed and the metadata of a track is modified.
|
||||
*
|
||||
* @param tracks A list which includes track information.
|
||||
*/
|
||||
public void dispatchTrackInfoChanged(final List<TvTrackInfo> tracks) {
|
||||
if (!TvTrackInfo.checkSanity(tracks)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Two or more selected tracks for a track type.");
|
||||
}
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "dispatchTrackInfoChanged");
|
||||
mSessionCallback.onTrackInfoChanged(tracks);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "error in dispatchTrackInfoChanged");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the session is released.
|
||||
*/
|
||||
@@ -334,6 +294,38 @@ public abstract class TvInputService extends Service {
|
||||
*/
|
||||
public abstract boolean onTune(Uri channelUri);
|
||||
|
||||
/**
|
||||
* Selects a given track.
|
||||
* <p>
|
||||
* If it is called multiple times on the same type of track (ie. Video, Audio, Text), the
|
||||
* track selected previously should be unselected in the implementation of this method.
|
||||
* Also, if the select operation was successful, the implementation should call
|
||||
* {@link #dispatchTrackInfoChanged(List)} to report the updated track information.
|
||||
* </p>
|
||||
* @param track The track to be selected.
|
||||
* @return {@code true} if the select operation was successful, {@code false} otherwise.
|
||||
* @see #dispatchTrackInfoChanged(TvTrackInfo[])
|
||||
* @see TvTrackInfo#KEY_IS_SELECTED
|
||||
*/
|
||||
public boolean onSelectTrack(TvTrackInfo track) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unselects a given track.
|
||||
* <p>
|
||||
* If the unselect operation was successful, the implementation should call
|
||||
* {@link #dispatchTrackInfoChanged(List)} to report the updated track information.
|
||||
* </p>
|
||||
* @param track The track to be unselected.
|
||||
* @return {@code true} if the unselect operation was successful, {@code false} otherwise.
|
||||
* @see #dispatchTrackInfoChanged(TvTrackInfo[])
|
||||
* @see TvTrackInfo#KEY_IS_SELECTED
|
||||
*/
|
||||
public boolean onUnselectTrack(TvTrackInfo track) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when an application requests to create an overlay view. Each session
|
||||
* implementation can override this method and return its own view.
|
||||
@@ -499,6 +491,22 @@ public abstract class TvInputService extends Service {
|
||||
// TODO: Handle failure.
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #onSelectTrack}.
|
||||
*/
|
||||
void selectTrack(TvTrackInfo track) {
|
||||
onSelectTrack(track);
|
||||
// TODO: Handle failure.
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #onUnselectTrack}.
|
||||
*/
|
||||
void unselectTrack(TvTrackInfo track) {
|
||||
onUnselectTrack(track);
|
||||
// TODO: Handle failure.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an overlay view. This calls {@link #onCreateOverlayView} to get a view to attach
|
||||
* to the overlay window.
|
||||
|
||||
19
media/java/android/media/tv/TvTrackInfo.aidl
Normal file
19
media/java/android/media/tv/TvTrackInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.tv;
|
||||
|
||||
parcelable TvTrackInfo;
|
||||
292
media/java/android/media/tv/TvTrackInfo.java
Normal file
292
media/java/android/media/tv/TvTrackInfo.java
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.tv;
|
||||
|
||||
import android.media.MediaFormat;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Encapsulates the format of tracks played in {@link TvInputService}.
|
||||
*/
|
||||
public final class TvTrackInfo implements Parcelable {
|
||||
/**
|
||||
* A key describing the type of this track. The associated value is an integer and it should be
|
||||
* one of {@link #VALUE_TYPE_AUDIO}, {@link #VALUE_TYPE_VIDEO}, and {@link #VALUE_TYPE_SUBTITLE}.
|
||||
* <p>
|
||||
* This is a required key.
|
||||
* </p>
|
||||
*/
|
||||
public static final String KEY_TYPE = "type";
|
||||
|
||||
/**
|
||||
* A key describing the language of the track, using either ISO 639-1 or 639-2/T codes.
|
||||
* If the language is unknown or could not be determined, the corresponding value will be "und".
|
||||
* The associated value is a string.
|
||||
* <p>
|
||||
* This is a required key.
|
||||
* </p>
|
||||
*/
|
||||
public static final String KEY_LANGUAGE = MediaFormat.KEY_LANGUAGE;
|
||||
|
||||
/**
|
||||
* A key describing whether this track is selected for the playback.
|
||||
* The associated value is a boolean.
|
||||
* <p>
|
||||
* This is a required key.
|
||||
* </p>
|
||||
*/
|
||||
public static final String KEY_IS_SELECTED = "is-selected";
|
||||
|
||||
/**
|
||||
* A key describing the sample rate of an audio track.
|
||||
* The associated value is an integer.
|
||||
*/
|
||||
public static final String KEY_SAMPLE_RATE = MediaFormat.KEY_SAMPLE_RATE;
|
||||
|
||||
/**
|
||||
* A key describing the number of channels in an audio track.
|
||||
* The associated value is an integer.
|
||||
*/
|
||||
public static final String KEY_CHANNEL_COUNT = MediaFormat.KEY_CHANNEL_COUNT;
|
||||
|
||||
/**
|
||||
* A key describing the width of the content in a video track.
|
||||
* The associated value is an integer.
|
||||
*/
|
||||
public static final String KEY_WIDTH = MediaFormat.KEY_WIDTH;
|
||||
|
||||
/**
|
||||
* A key describing the height of the content in a video track.
|
||||
* The associated value is an integer.
|
||||
*/
|
||||
public static final String KEY_HEIGHT = MediaFormat.KEY_HEIGHT;
|
||||
|
||||
/**
|
||||
* A key describing a tag associated with this track. Expected to be used as an identifier with
|
||||
* in a session. The associated value is a string.
|
||||
*/
|
||||
public static final String KEY_TAG = "tag";
|
||||
|
||||
/**
|
||||
* The type value for audio track.
|
||||
*/
|
||||
public static final int VALUE_TYPE_AUDIO = 0;
|
||||
|
||||
/**
|
||||
* The type value for video track.
|
||||
*/
|
||||
public static final int VALUE_TYPE_VIDEO = 1;
|
||||
|
||||
/**
|
||||
* The type value for subtitle track.
|
||||
*/
|
||||
public static final int VALUE_TYPE_SUBTITLE = 2;
|
||||
|
||||
private final Bundle mBundle;
|
||||
|
||||
private TvTrackInfo(Bundle bundle) {
|
||||
mBundle = new Bundle(bundle);
|
||||
}
|
||||
|
||||
private TvTrackInfo(Parcel in) {
|
||||
mBundle = in.readBundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is only one or zero selected track per track type.
|
||||
*
|
||||
* @param tracks a list including tracks which will be checked.
|
||||
* @return true if there is only one or zero selected track per track type, false otherwise
|
||||
* @hide
|
||||
*/
|
||||
public static boolean checkSanity(List<TvTrackInfo> tracks) {
|
||||
int selectedAudioTracks = 0;
|
||||
int selectedVideoTracks = 0;
|
||||
int selectedSubtitleTracks = 0;
|
||||
for (TvTrackInfo track : tracks) {
|
||||
if (track.getBoolean(KEY_IS_SELECTED)) {
|
||||
int type = track.getInt(KEY_TYPE);
|
||||
if (type == VALUE_TYPE_AUDIO) {
|
||||
selectedAudioTracks++;
|
||||
} else if (type == VALUE_TYPE_VIDEO) {
|
||||
selectedVideoTracks++;
|
||||
} else if (type == VALUE_TYPE_SUBTITLE) {
|
||||
selectedSubtitleTracks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectedAudioTracks > 1 || selectedVideoTracks > 1 || selectedSubtitleTracks > 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given key is contained in the metadata
|
||||
*
|
||||
* @param key A String key
|
||||
* @return true If the key exists in this metadata, false otherwise
|
||||
*/
|
||||
public boolean containsKey(String key) {
|
||||
return mBundle.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value associated with the given key, or null if no mapping of
|
||||
* the desired type exists for the given key or a null value is explicitly
|
||||
* associated with the key.
|
||||
*
|
||||
* @param key The key the value is stored under
|
||||
* @return A String value, or null
|
||||
*/
|
||||
public String getString(String key) {
|
||||
return mBundle.getString(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value associated with the given key, or 0L if no integer exists
|
||||
* for the given key.
|
||||
*
|
||||
* @param key The key the value is stored under
|
||||
* @return An integer value
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
return mBundle.getInt(key, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value associated with the given key, or false if no integer exists
|
||||
* for the given key.
|
||||
*
|
||||
* @param key The key the value is stored under
|
||||
* @return A boolean value
|
||||
*/
|
||||
public boolean getBoolean(String key) {
|
||||
return mBundle.getBoolean(key, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeBundle(mBundle);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<TvTrackInfo> CREATOR
|
||||
= new Parcelable.Creator<TvTrackInfo>() {
|
||||
@Override
|
||||
public TvTrackInfo createFromParcel(Parcel in) {
|
||||
return new TvTrackInfo(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TvTrackInfo[] newArray(int size) {
|
||||
return new TvTrackInfo[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A builder class for creating {@link TvTrackInfo} objects.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private final Bundle mBundle;
|
||||
|
||||
/**
|
||||
* Create a {@link Builder}. Any field that should be included in the
|
||||
* {@link TvTrackInfo} must be added.
|
||||
*
|
||||
* @param type The type of the track.
|
||||
* @param language The language of the track, using either ISO 639-1 or 639-2/T codes.
|
||||
* "und" if the language is unknown.
|
||||
* @param isSelected Whether this track is selected for the playback or not.
|
||||
*/
|
||||
public Builder(int type, String language, boolean isSelected) {
|
||||
if (type != VALUE_TYPE_AUDIO
|
||||
&& type != VALUE_TYPE_VIDEO
|
||||
&& type != VALUE_TYPE_SUBTITLE) {
|
||||
throw new IllegalArgumentException("Unknown type: " + type);
|
||||
}
|
||||
mBundle = new Bundle();
|
||||
putInt(KEY_TYPE, type);
|
||||
putString(KEY_LANGUAGE, language);
|
||||
putBoolean(KEY_IS_SELECTED, isSelected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Builder using a {@link TvTrackInfo} instance to set the
|
||||
* initial values. All fields in the source metadata will be included in
|
||||
* the new metadata. Fields can be overwritten by adding the same key.
|
||||
*
|
||||
* @param source The source {@link TvTrackInfo} instance
|
||||
*/
|
||||
public Builder(TvTrackInfo source) {
|
||||
mBundle = new Bundle(source.mBundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a String value into the track.
|
||||
*
|
||||
* @param key The key for referencing this value
|
||||
* @param value The String value to store
|
||||
* @return The Builder to allow chaining
|
||||
*/
|
||||
public Builder putString(String key, String value) {
|
||||
mBundle.putString(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an integer value into the track.
|
||||
*
|
||||
* @param key The key for referencing this value
|
||||
* @param value The integer value to store
|
||||
* @return The Builder to allow chaining
|
||||
*/
|
||||
public Builder putInt(String key, int value) {
|
||||
mBundle.putInt(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a boolean value into the track.
|
||||
*
|
||||
* @param key The key for referencing this value
|
||||
* @param value The boolean value to store
|
||||
* @return The Builder to allow chaining
|
||||
*/
|
||||
public Builder putBoolean(String key, boolean value) {
|
||||
mBundle.putBoolean(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TvTrackInfo} instance with the specified fields.
|
||||
*
|
||||
* @return The new {@link TvTrackInfo} instance
|
||||
*/
|
||||
public TvTrackInfo build() {
|
||||
return new TvTrackInfo(mBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package android.media.tv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.media.MediaPlayer.TrackInfo;
|
||||
import android.media.tv.TvInputManager.Session;
|
||||
import android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
|
||||
import android.media.tv.TvInputManager.SessionCallback;
|
||||
@@ -37,6 +38,8 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewRootImpl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* View playing TV
|
||||
*/
|
||||
@@ -57,6 +60,8 @@ public class TvView extends ViewGroup {
|
||||
*/
|
||||
public static final int ERROR_TV_INPUT_DISCONNECTED = 1;
|
||||
|
||||
private static final int VIDEO_SIZE_VALUE_UNKNOWN = 0;
|
||||
|
||||
private final Handler mHandler = new Handler();
|
||||
private TvInputManager.Session mSession;
|
||||
private final SurfaceView mSurfaceView;
|
||||
@@ -69,6 +74,8 @@ public class TvView extends ViewGroup {
|
||||
private OnUnhandledInputEventListener mOnUnhandledInputEventListener;
|
||||
private boolean mHasStreamVolume;
|
||||
private float mStreamVolume;
|
||||
private int mVideoWidth = VIDEO_SIZE_VALUE_UNKNOWN;
|
||||
private int mVideoHeight = VIDEO_SIZE_VALUE_UNKNOWN;
|
||||
|
||||
private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
@@ -208,6 +215,44 @@ public class TvView extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a track.
|
||||
* <p>
|
||||
* If it is called multiple times on the same type of track (ie. Video, Audio, Text), the track
|
||||
* selected in previous will be unselected.
|
||||
* </p>
|
||||
* @param track the track to be selected.
|
||||
* @see #getTracks()
|
||||
*/
|
||||
public void selectTrack(TvTrackInfo track) {
|
||||
if (mSession != null) {
|
||||
mSession.selectTrack(track);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unselect a track.
|
||||
*
|
||||
* @param track the track to be unselected.
|
||||
* @see #getTracks()
|
||||
*/
|
||||
public void unselectTrack(TvTrackInfo track) {
|
||||
if (mSession != null) {
|
||||
mSession.unselectTrack(track);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list which includes of track information. May return {@code null} if the
|
||||
* information is not available.
|
||||
*/
|
||||
public List<TvTrackInfo> getTracks() {
|
||||
if (mSession == null) {
|
||||
return null;
|
||||
}
|
||||
return mSession.getTracks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an unhandled input event to the next receiver.
|
||||
* <p>
|
||||
@@ -401,6 +446,23 @@ public class TvView extends ViewGroup {
|
||||
location[0] + getWidth(), location[1] + getHeight());
|
||||
}
|
||||
|
||||
private void updateVideoSize(List<TvTrackInfo> tracks) {
|
||||
for (TvTrackInfo track : tracks) {
|
||||
if (track.getBoolean(TvTrackInfo.KEY_IS_SELECTED)
|
||||
&& track.getInt(TvTrackInfo.KEY_TYPE) == TvTrackInfo.VALUE_TYPE_VIDEO) {
|
||||
int width = track.getInt(TvTrackInfo.KEY_WIDTH);
|
||||
int height = track.getInt(TvTrackInfo.KEY_HEIGHT);
|
||||
if (width != mVideoWidth || height != mVideoHeight) {
|
||||
mVideoWidth = width;
|
||||
mVideoHeight = height;
|
||||
if (mListener != null) {
|
||||
mListener.onVideoSizeChanged(mSessionCallback.mInputId, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to receive various status updates on the {@link TvView}.
|
||||
*/
|
||||
@@ -418,41 +480,13 @@ public class TvView extends ViewGroup {
|
||||
|
||||
/**
|
||||
* This is invoked when the view is tuned to a specific channel and starts decoding video
|
||||
* stream from there. It is also called later when the video format is changed.
|
||||
* stream from there. It is also called later when the video size is changed.
|
||||
*
|
||||
* @param inputId The ID of the TV input bound to this view.
|
||||
* @param width The width of the video.
|
||||
* @param height The height of the video.
|
||||
* @param interlaced {@code true} if the video is interlaced, {@code false} if the video is
|
||||
* progressive.
|
||||
* @hide
|
||||
*/
|
||||
public void onVideoStreamChanged(String inputId, int width, int height,
|
||||
boolean interlaced) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is invoked when the view is tuned to a specific channel and starts decoding audio
|
||||
* stream from there. It is also called later when the audio format is changed.
|
||||
*
|
||||
* @param inputId The ID of the TV input bound to this view.
|
||||
* @param channelCount The number of channels in the audio stream.
|
||||
* @hide
|
||||
*/
|
||||
public void onAudioStreamChanged(String inputId, int channelCount) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is invoked when the view is tuned to a specific channel and starts decoding data
|
||||
* stream that includes subtitle information from the channel. It is also called later when
|
||||
* the information disappears or appears.
|
||||
*
|
||||
* @param inputId The ID of the TV input bound to this view.
|
||||
* @param hasClosedCaption {@code true} if the stream contains closed caption, {@code false}
|
||||
* otherwise.
|
||||
* @hide
|
||||
*/
|
||||
public void onClosedCaptionStreamChanged(String inputId, boolean hasClosedCaption) {
|
||||
public void onVideoSizeChanged(String inputId, int width, int height) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,6 +499,15 @@ public class TvView extends ViewGroup {
|
||||
public void onChannelRetuned(String inputId, Uri channelUri) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when the track information has been changed.
|
||||
*
|
||||
* @param inputId The ID of the TV input bound to this view.
|
||||
* @param tracks A list which includes track information.
|
||||
*/
|
||||
public void onTrackInfoChanged(String inputId, List<TvTrackInfo> tracks) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This is invoked when a custom event from the bound TV input is sent to this view.
|
||||
*
|
||||
@@ -533,44 +576,15 @@ public class TvView extends ViewGroup {
|
||||
|
||||
@Override
|
||||
public void onSessionReleased(Session session) {
|
||||
if (this == mSessionCallback) {
|
||||
mSessionCallback = null;
|
||||
}
|
||||
mSession = null;
|
||||
mSessionCallback = null;
|
||||
if (mListener != null) {
|
||||
mListener.onError(mInputId, ERROR_TV_INPUT_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoStreamChanged(Session session, int width, int height,
|
||||
boolean interlaced) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onVideoSizeChanged(" + width + ", " + height + ")");
|
||||
}
|
||||
if (mListener != null) {
|
||||
mListener.onVideoStreamChanged(mInputId, width, height, interlaced);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioStreamChanged(Session session, int channelCount) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onAudioStreamChanged(" + channelCount + ")");
|
||||
}
|
||||
if (mListener != null) {
|
||||
mListener.onAudioStreamChanged(mInputId, channelCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosedCaptionStreamChanged(Session session, boolean hasClosedCaption) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onClosedCaptionStreamChanged(" + hasClosedCaption + ")");
|
||||
}
|
||||
if (mListener != null) {
|
||||
mListener.onClosedCaptionStreamChanged(mInputId, hasClosedCaption);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelRetuned(Session session, Uri channelUri) {
|
||||
if (DEBUG) {
|
||||
@@ -581,9 +595,26 @@ public class TvView extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackInfoChanged(Session session, List<TvTrackInfo> tracks) {
|
||||
if (this != mSessionCallback) {
|
||||
return;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onTrackInfoChanged()");
|
||||
}
|
||||
updateVideoSize(tracks);
|
||||
if (mListener != null) {
|
||||
mListener.onTrackInfoChanged(mInputId, tracks);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionEvent(TvInputManager.Session session, String eventType,
|
||||
Bundle eventArgs) {
|
||||
if (this != mSessionCallback) {
|
||||
return;
|
||||
}
|
||||
if (mListener != null) {
|
||||
mListener.onEvent(mInputId, eventType, eventArgs);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import android.media.tv.TvContract;
|
||||
import android.media.tv.TvInputHardwareInfo;
|
||||
import android.media.tv.TvInputInfo;
|
||||
import android.media.tv.TvInputService;
|
||||
import android.media.tv.TvTrackInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
@@ -431,59 +432,6 @@ public final class TvInputManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoStreamChanged(int width, int height, boolean interlaced) {
|
||||
synchronized (mLock) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "onVideoStreamChanged(" + width + ", " + height + ")");
|
||||
}
|
||||
if (sessionState.mSession == null || sessionState.mClient == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sessionState.mClient.onVideoStreamChanged(width, height, interlaced,
|
||||
sessionState.mSeq);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "error in onVideoStreamChanged");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioStreamChanged(int channelCount) {
|
||||
synchronized (mLock) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "onAudioStreamChanged(" + channelCount + ")");
|
||||
}
|
||||
if (sessionState.mSession == null || sessionState.mClient == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sessionState.mClient.onAudioStreamChanged(channelCount, sessionState.mSeq);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "error in onAudioStreamChanged");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosedCaptionStreamChanged(boolean hasClosedCaption) {
|
||||
synchronized (mLock) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "onClosedCaptionStreamChanged(" + hasClosedCaption + ")");
|
||||
}
|
||||
if (sessionState.mSession == null || sessionState.mClient == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sessionState.mClient.onClosedCaptionStreamChanged(hasClosedCaption,
|
||||
sessionState.mSeq);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "error in onClosedCaptionStreamChanged");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChannelRetuned(Uri channelUri) {
|
||||
synchronized (mLock) {
|
||||
@@ -505,6 +453,24 @@ public final class TvInputManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTrackInfoChanged(List<TvTrackInfo> tracks) {
|
||||
synchronized (mLock) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "onTrackInfoChanged(" + tracks + ")");
|
||||
}
|
||||
if (sessionState.mSession == null || sessionState.mClient == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
sessionState.mClient.onTrackInfoChanged(tracks,
|
||||
sessionState.mSeq);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "error in onTrackInfoChanged");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSessionEvent(String eventType, Bundle eventArgs) {
|
||||
synchronized (mLock) {
|
||||
@@ -894,6 +860,46 @@ public final class TvInputManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectTrack(IBinder sessionToken, TvTrackInfo track, int userId) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
|
||||
userId, "selectTrack");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
getSessionLocked(sessionToken, callingUid, resolvedUserId).selectTrack(
|
||||
track);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "error in selectTrack", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unselectTrack(IBinder sessionToken, TvTrackInfo track, int userId) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
|
||||
userId, "unselectTrack");
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
getSessionLocked(sessionToken, callingUid, resolvedUserId).unselectTrack(
|
||||
track);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "error in unselectTrack", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createOverlayView(IBinder sessionToken, IBinder windowToken, Rect frame,
|
||||
int userId) {
|
||||
|
||||
Reference in New Issue
Block a user