TIAF: Add IApp setup & start flow

Bug: 208651882
Bug: 208651889
Test: mmm
Change-Id: Ic8f92bd438fb9f04836dee634e51fcc0ffe22fd2
This commit is contained in:
shubang
2021-12-01 02:55:06 -08:00
parent 69e7905abf
commit 938ec458a0
20 changed files with 498 additions and 53 deletions

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) 2021 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 AitInfo;

View File

@@ -0,0 +1,87 @@
/*
* Copyright (C) 2021 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.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
/**
* AIT info.
* @hide
*/
public final class AitInfo implements Parcelable {
static final String TAG = "AitInfo";
public static final Creator<AitInfo> CREATOR = new Creator<AitInfo>() {
@Override
public AitInfo createFromParcel(Parcel in) {
return new AitInfo(in);
}
@Override
public AitInfo[] newArray(int size) {
return new AitInfo[size];
}
};
private final int mType;
private final int mVersion;
private AitInfo(Parcel in) {
mType = in.readInt();
mVersion = in.readInt();
}
/**
* Constructs AIT info.
*/
public AitInfo(int type, int version) {
mType = type;
mVersion = version;
}
/**
* Gets type.
*/
public int getType() {
return mType;
}
/**
* Gets version.
*/
public int getVersion() {
return mVersion;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeInt(mVersion);
}
@Override
public String toString() {
return "type=" + mType + ";version=" + mVersion;
}
}

View File

@@ -17,12 +17,13 @@
package android.media.tv;
import android.content.ComponentName;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.ITvInputSession;
import android.net.Uri;
import android.media.tv.TvTrackInfo;
import android.os.Bundle;
import android.view.InputChannel;
import android.media.tv.BroadcastInfoResponse;
/**
* Interface a client of the ITvInputManager implements, to identify itself and receive information
@@ -44,9 +45,10 @@ oneway interface ITvInputClient {
void onTimeShiftStatusChanged(int status, int seq);
void onTimeShiftStartPositionChanged(long timeMs, int seq);
void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
void onAitInfoUpdated(in AitInfo aitInfo, int seq);
void onTuned(in Uri channelUri, int seq);
// For the recording session
void onTuned(int seq, in Uri channelUri);
void onRecordingStopped(in Uri recordedProgramUri, int seq);
void onError(int error, int seq);

View File

@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Rect;
import android.media.PlaybackParams;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.DvbDeviceInfo;
import android.media.tv.ITvInputClient;
import android.media.tv.ITvInputHardware;
@@ -35,7 +36,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.view.Surface;
import android.media.tv.BroadcastInfoRequest;
/**
* Interface to the TV input manager service.
@@ -73,6 +73,8 @@ interface ITvInputManager {
void setCaptionEnabled(in IBinder sessionToken, boolean enabled, int userId);
void selectTrack(in IBinder sessionToken, int type, in String trackId, int userId);
void setIAppNotificationEnabled(in IBinder sessionToken, boolean enabled, int userId);
void sendAppPrivateCommand(in IBinder sessionToken, in String action, in Bundle data,
int userId);

View File

@@ -18,11 +18,11 @@ package android.media.tv;
import android.graphics.Rect;
import android.media.PlaybackParams;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
import android.os.Bundle;
import android.view.Surface;
import android.media.tv.BroadcastInfoRequest;
/**
* Sub-interface of ITvInputService which is created per session and has its own context.
@@ -41,6 +41,8 @@ oneway interface ITvInputSession {
void setCaptionEnabled(boolean enabled);
void selectTrack(int type, in String trackId);
void setIAppNotificationEnabled(boolean enable);
void appPrivateCommand(in String action, in Bundle data);
void createOverlayView(in IBinder windowToken, in Rect frame);

View File

@@ -16,11 +16,12 @@
package android.media.tv;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.ITvInputSession;
import android.net.Uri;
import android.media.tv.TvTrackInfo;
import android.os.Bundle;
import android.media.tv.BroadcastInfoResponse;
/**
* Helper interface for ITvInputSession to allow the TV input to notify the system service when a
@@ -41,6 +42,7 @@ oneway interface ITvInputSessionCallback {
void onTimeShiftStatusChanged(int status);
void onTimeShiftStartPositionChanged(long timeMs);
void onTimeShiftCurrentPositionChanged(long timeMs);
void onAitInfoUpdated(in AitInfo aitInfo);
// For the recording session
void onTuned(in Uri channelUri);

View File

@@ -71,6 +71,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
private static final int DO_PAUSE_RECORDING = 22;
private static final int DO_RESUME_RECORDING = 23;
private static final int DO_REQUEST_BROADCAST_INFO = 24;
private static final int DO_SET_IAPP_NOTIFICATION_ENABLED = 25;
private final boolean mIsRecordingSession;
private final HandlerCaller mCaller;
@@ -239,6 +240,10 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mTvInputSessionImpl.requestBroadcastInfo((BroadcastInfoRequest) msg.obj);
break;
}
case DO_SET_IAPP_NOTIFICATION_ENABLED: {
mTvInputSessionImpl.setIAppNotificationEnabled((Boolean) msg.obj);
break;
}
default: {
Log.w(TAG, "Unhandled message code: " + msg.what);
break;
@@ -306,6 +311,12 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_SELECT_TRACK, type, trackId));
}
@Override
public void setIAppNotificationEnabled(boolean enabled) {
mCaller.executeOrSendMessage(
mCaller.obtainMessageO(DO_SET_IAPP_NOTIFICATION_ENABLED, enabled));
}
@Override
public void appPrivateCommand(String action, Bundle data) {
mCaller.executeOrSendMessage(mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action,

View File

@@ -627,14 +627,20 @@ public final class TvInputManager {
public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
}
// For the recording session only
/**
* This is called when the recording session has been tuned to the given channel and is
* ready to start recording.
* This is called when AIT info is updated.
* @param session A {@link TvInputManager.Session} associated with this callback.
* @param aitInfo The current AIT info.
*/
public void onAitInfoUpdated(Session session, AitInfo aitInfo) {
}
/**
* This is called when the session has been tuned to the given channel.
*
* @param channelUri The URI of a channel.
*/
void onTuned(Session session, Uri channelUri) {
public void onTuned(Session session, Uri channelUri) {
}
// For the recording session only
@@ -807,12 +813,23 @@ public final class TvInputManager {
});
}
// For the recording session only
void postAitInfoUpdated(final AitInfo aitInfo) {
mHandler.post(new Runnable() {
@Override
public void run() {
mSessionCallback.onAitInfoUpdated(mSession, aitInfo);
}
});
}
void postTuned(final Uri channelUri) {
mHandler.post(new Runnable() {
@Override
public void run() {
mSessionCallback.onTuned(mSession, channelUri);
if (mSession.mIAppNotificationEnabled && mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyTuned(channelUri);
}
}
});
}
@@ -838,12 +855,16 @@ public final class TvInputManager {
}
void postBroadcastInfoResponse(final BroadcastInfoResponse response) {
mHandler.post(new Runnable() {
@Override
public void run() {
mSession.getIAppSession().notifyBroadcastInfoResponse(response);
}
});
if (mSession.mIAppNotificationEnabled) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (mSession.getIAppSession() != null) {
mSession.getIAppSession().notifyBroadcastInfoResponse(response);
}
}
});
}
}
}
@@ -1209,7 +1230,19 @@ public final class TvInputManager {
}
@Override
public void onTuned(int seq, Uri channelUri) {
public void onAitInfoUpdated(AitInfo aitInfo, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
Log.e(TAG, "Callback not found for seq " + seq);
return;
}
record.postAitInfoUpdated(aitInfo);
}
}
@Override
public void onTuned(Uri channelUri, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
if (record == null) {
@@ -1217,6 +1250,13 @@ public final class TvInputManager {
return;
}
record.postTuned(channelUri);
// TODO: synchronized and wrap the channelUri
if (record.mSession.mIAppNotificationEnabled) {
TvIAppManager.Session iappSession = record.mSession.mIAppSession;
if (iappSession != null) {
iappSession.notifyTuned(channelUri);
}
}
}
}
@@ -2068,6 +2108,7 @@ public final class TvInputManager {
private int mVideoHeight;
private TvIAppManager.Session mIAppSession;
private boolean mIAppNotificationEnabled = false;
private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) {
@@ -2339,6 +2380,25 @@ public final class TvInputManager {
throw new IllegalArgumentException("invalid type: " + type);
}
/**
* Enables interactive app notification.
* @param enabled {@code true} if you want to enable interactive app notifications.
* {@code false} otherwise.
* @hide
*/
public void setIAppNotificationEnabled(boolean enabled) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.setIAppNotificationEnabled(mToken, enabled, mUserId);
mIAppNotificationEnabled = enabled;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Responds to onTracksChanged() and updates the internal track information. Returns true if
* there is an update.

View File

@@ -827,6 +827,27 @@ public abstract class TvInputService extends Service {
});
}
/**
* Notifies AIT info updated.
* @hide
*/
public void notifyAitInfoUpdated(@NonNull final AitInfo aitInfo) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@Override
public void run() {
try {
if (DEBUG) Log.d(TAG, "notifyAitInfoUpdated");
if (mSessionCallback != null) {
mSessionCallback.onAitInfoUpdated(aitInfo);
}
} catch (RemoteException e) {
Log.w(TAG, "error in notifyAitInfoUpdated", e);
}
}
});
}
/**
* Assigns a size and position to the surface passed in {@link #onSetSurface}. The position
* is relative to the overlay view that sits on top of this surface.
@@ -1020,6 +1041,14 @@ public abstract class TvInputService extends Service {
return false;
}
/**
* Enables or disables interactive app notification.
* @param enabled {@code true} to enable, {@code false} to disable.
* @hide
*/
public void onSetIAppNotificationEnabled(boolean enabled) {
}
/**
* Processes a private command sent from the application to the TV input. This can be used
* to provide domain-specific features that are only known between certain TV inputs and
@@ -1368,6 +1397,13 @@ public abstract class TvInputService extends Service {
// TODO: Handle failure.
}
/**
* Calls {@link #onSetIAppNotificationEnabled}.
*/
void setIAppNotificationEnabled(boolean enabled) {
onSetIAppNotificationEnabled(enabled);
}
/**
* Calls {@link #onAppPrivateCommand}.
*/

View File

@@ -472,7 +472,7 @@ public class TvRecordingClient {
}
@Override
void onTuned(TvInputManager.Session session, Uri channelUri) {
public void onTuned(TvInputManager.Session session, Uri channelUri) {
if (DEBUG) {
Log.d(TAG, "onTuned()");
}

View File

@@ -34,8 +34,6 @@ import android.media.PlaybackParams;
import android.media.tv.TvInputManager.Session;
import android.media.tv.TvInputManager.Session.FinishedInputEventCallback;
import android.media.tv.TvInputManager.SessionCallback;
import android.media.tv.interactive.TvIAppManager;
import android.media.tv.interactive.TvIAppView;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -482,6 +480,18 @@ public class TvView extends ViewGroup {
return mSession.getSelectedTrack(type);
}
/**
* Enables interactive app notification.
* @param enabled {@code true} if you want to enable interactive app notifications.
* {@code false} otherwise.
* @hide
*/
public void setIAppNotificationEnabled(boolean enabled) {
if (mSession != null) {
mSession.setIAppNotificationEnabled(enabled);
}
}
/**
* Plays a given recorded TV program.
*
@@ -1050,6 +1060,24 @@ public class TvView extends ViewGroup {
public void onTimeShiftStatusChanged(
String inputId, @TvInputManager.TimeShiftStatus int status) {
}
/**
* This is called when the AIT info has been updated.
*
* @param aitInfo The current AIT info.
* @hide
*/
public void onAitInfoUpdated(String inputId, AitInfo aitInfo) {
}
/**
* This is called when the session has been tuned to the given channel.
*
* @param channelUri The URI of a channel.
* @hide
*/
public void onTuned(String inputId, Uri channelUri) {
}
}
/**
@@ -1346,5 +1374,33 @@ public class TvView extends ViewGroup {
mTimeShiftPositionCallback.onTimeShiftCurrentPositionChanged(mInputId, timeMs);
}
}
@Override
public void onAitInfoUpdated(Session session, AitInfo aitInfo) {
if (DEBUG) {
Log.d(TAG, "onAitInfoUpdated(aitInfo=" + aitInfo + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onAitInfoUpdated - session not created");
return;
}
if (mCallback != null) {
mCallback.onAitInfoUpdated(mInputId, aitInfo);
}
}
@Override
public void onTuned(Session session, Uri channelUri) {
if (DEBUG) {
Log.d(TAG, "onTuned(channelUri=" + channelUri + ")");
}
if (this != mSessionCallback) {
Log.w(TAG, "onTuned - session not created");
return;
}
if (mCallback != null) {
mCallback.onTuned(mInputId, channelUri);
}
}
}
}

View File

@@ -17,6 +17,7 @@
package android.media.tv.interactive;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoRequest;
import android.view.InputChannel;
/**

View File

@@ -17,10 +17,11 @@
package android.media.tv.interactive;
import android.graphics.Rect;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.interactive.ITvIAppClient;
import android.media.tv.interactive.ITvIAppManagerCallback;
import android.media.tv.interactive.TvIAppInfo;
import android.media.tv.BroadcastInfoResponse;
import android.net.Uri;
import android.view.Surface;
/**
@@ -29,10 +30,12 @@ import android.view.Surface;
*/
interface ITvIAppManager {
List<TvIAppInfo> getTvIAppServiceList(int userId);
void prepare(String tiasId, int type, int userId);
void startIApp(in IBinder sessionToken, int userId);
void createSession(
in ITvIAppClient client, in String iAppServiceId, int type, int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId);
void notifyTuned(in IBinder sessionToken, in Uri channelUri, int userId);
void setSurface(in IBinder sessionToken, in Surface surface, int userId);
void dispatchSurfaceChanged(in IBinder sessionToken, int format, int width, int height,
int userId);

View File

@@ -30,4 +30,5 @@ oneway interface ITvIAppService {
void unregisterCallback(in ITvIAppServiceCallback callback);
void createSession(in InputChannel channel, in ITvIAppSessionCallback callback,
in String iAppServiceId, int type);
void prepare(int type);
}

View File

@@ -17,6 +17,8 @@
package android.media.tv.interactive;
import android.graphics.Rect;
import android.net.Uri;
import android.media.tv.BroadcastInfoResponse;
import android.view.Surface;
import android.media.tv.BroadcastInfoResponse;
@@ -27,6 +29,7 @@ import android.media.tv.BroadcastInfoResponse;
oneway interface ITvIAppSession {
void startIApp();
void release();
void notifyTuned(in Uri channelUri);
void setSurface(in Surface surface);
void dispatchSurfaceChanged(int format, int width, int height);
void notifyBroadcastInfoResponse(in BroadcastInfoResponse response);

View File

@@ -16,6 +16,7 @@
package android.media.tv.interactive;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.interactive.ITvIAppSession;
import android.media.tv.BroadcastInfoRequest;

View File

@@ -24,6 +24,7 @@ import android.graphics.Rect;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.TvInputManager;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -333,6 +334,18 @@ public final class TvIAppManager {
}
}
/**
* Prepares TV IApp service for the given type.
* @hide
*/
public void prepare(String tvIAppServiceId, int type) {
try {
mService.prepare(tvIAppServiceId, type, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Registers a {@link TvIAppManager.TvIAppCallback}.
*
@@ -596,6 +609,21 @@ public final class TvIAppManager {
releaseInternal();
}
/**
* Notifies IAPP session when a channels is tuned.
*/
public void notifyTuned(Uri channelUri) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
mService.notifyTuned(mToken, channelUri, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private void flushPendingEventsLocked() {
mHandler.removeMessages(InputEventHandler.MSG_FLUSH_INPUT_EVENT);

View File

@@ -28,6 +28,7 @@ import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.IBinder;
@@ -117,10 +118,23 @@ public abstract class TvIAppService extends Service {
mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args)
.sendToTarget();
}
@Override
public void prepare(int type) {
onPrepare(type);
}
};
return tvIAppServiceBinder;
}
/**
* Prepares TV IApp service for the given type.
* @hide
*/
public void onPrepare(int type) {
// TODO: make it abstract when unhide
}
/**
* Returns a concrete implementation of {@link Session}.
@@ -236,14 +250,6 @@ public abstract class TvIAppService extends Service {
public void onSurfaceChanged(int format, int width, int height) {
}
/**
* Called when a broadcast info response is received from TIS.
*
* @param response response received from TIS.
*/
public void onNotifyBroadcastInfoResponse(BroadcastInfoResponse response) {
}
/**
* Called when the size of the media view is changed by the application.
*
@@ -275,6 +281,20 @@ public abstract class TvIAppService extends Service {
public void onRelease() {
}
/**
* Called when the corresponding TV input tuned to a channel.
* @hide
*/
public void onTuned(Uri channelUri) {
}
/**
* Called when a broadcast info response is received.
* @hide
*/
public void onBroadcastInfoResponse(BroadcastInfoResponse response) {
}
/**
* TODO: JavaDoc of APIs related to input events.
* @hide
@@ -362,6 +382,10 @@ public abstract class TvIAppService extends Service {
});
}
/**
* Requests broadcast related information from the related TV input.
* @param request
*/
public void requestBroadcastInfo(@NonNull final BroadcastInfoRequest request) {
executeOrPostRunnableOnMainThread(new Runnable() {
@MainThread
@@ -401,6 +425,25 @@ public abstract class TvIAppService extends Service {
removeMediaView(true);
}
void notifyTuned(Uri channelUri) {
if (DEBUG) {
Log.d(TAG, "notifyTuned (channelUri=" + channelUri + ")");
}
onTuned(channelUri);
}
/**
* Calls {@link #onBroadcastInfoResponse}.
*/
void notifyBroadcastInfoResponse(BroadcastInfoResponse response) {
if (DEBUG) {
Log.d(TAG, "notifyBroadcastInfoResponse (requestId="
+ response.getRequestId() + ")");
}
onBroadcastInfoResponse(response);
}
/**
* Takes care of dispatching incoming input events and tells whether the event was handled.
*/
@@ -467,18 +510,6 @@ public abstract class TvIAppService extends Service {
onSurfaceChanged(format, width, height);
}
/**
*
* Calls {@link #notifyBroadcastInfoResponse}.
*/
void notifyBroadcastInfoResponse(BroadcastInfoResponse response) {
if (DEBUG) {
Log.d(TAG, "notifyBroadcastInfoResponse (requestId="
+ response.getRequestId() + ")");
}
onNotifyBroadcastInfoResponse(response);
}
private void executeOrPostRunnableOnMainThread(Runnable action) {
synchronized (mLock) {
if (mSessionCallback == null) {
@@ -656,6 +687,11 @@ public abstract class TvIAppService extends Service {
mSessionImpl.release();
}
@Override
public void notifyTuned(Uri channelUri) {
mSessionImpl.notifyTuned(channelUri);
}
@Override
public void setSurface(Surface surface) {
mSessionImpl.setSurface(surface);

View File

@@ -44,6 +44,7 @@ import android.graphics.Rect;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.PlaybackParams;
import android.media.tv.AitInfo;
import android.media.tv.BroadcastInfoRequest;
import android.media.tv.BroadcastInfoResponse;
import android.media.tv.DvbDeviceInfo;
@@ -1760,6 +1761,26 @@ public final class TvInputManagerService extends SystemService {
}
}
@Override
public void setIAppNotificationEnabled(IBinder sessionToken, boolean enabled, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "setIAppNotificationEnabled");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId)
.setIAppNotificationEnabled(enabled);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in setIAppNotificationEnabled", e);
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void sendAppPrivateCommand(IBinder sessionToken, String command, Bundle data,
int userId) {
@@ -3341,7 +3362,23 @@ public final class TvInputManagerService extends SystemService {
}
}
// For the recording session only
@Override
public void onAitInfoUpdated(AitInfo aitInfo) {
synchronized (mLock) {
if (DEBUG) {
Slog.d(TAG, "onAitInfoUpdated(" + aitInfo + ")");
}
if (mSessionState.session == null || mSessionState.client == null) {
return;
}
try {
mSessionState.client.onAitInfoUpdated(aitInfo, mSessionState.seq);
} catch (RemoteException e) {
Slog.e(TAG, "error in onAitInfoUpdated", e);
}
}
}
@Override
public void onTuned(Uri channelUri) {
synchronized (mLock) {
@@ -3352,7 +3389,7 @@ public final class TvInputManagerService extends SystemService {
return;
}
try {
mSessionState.client.onTuned(mSessionState.seq, channelUri);
mSessionState.client.onTuned(channelUri, mSessionState.seq);
} catch (RemoteException e) {
Slog.e(TAG, "error in onTuned", e);
}

View File

@@ -40,6 +40,7 @@ import android.media.tv.interactive.ITvIAppSession;
import android.media.tv.interactive.ITvIAppSessionCallback;
import android.media.tv.interactive.TvIAppInfo;
import android.media.tv.interactive.TvIAppService;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
@@ -523,11 +524,6 @@ public class TvIAppManagerService extends SystemService {
removeSessionStateLocked(state.mSessionToken, state.mUserId);
}
private SessionState getSessionState(IBinder sessionToken) {
// TODO: implement user state and get session from it.
return null;
}
private int resolveCallingUserId(int callingPid, int callingUid, int requestedUserId,
String methodName) {
return ActivityManager.handleIncomingUser(callingPid, callingUid, requestedUserId, false,
@@ -606,6 +602,32 @@ public class TvIAppManagerService extends SystemService {
}
}
@Override
public void prepare(String tiasId, int type, int userId) {
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
Binder.getCallingUid(), userId, "prepare");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
TvIAppState iAppState = userState.mIAppMap.get(tiasId);
if (iAppState == null) {
Slogf.e(TAG, "failed to prepare TIAS - unknown TIAS id " + tiasId);
return;
}
ComponentName componentName = iAppState.mInfo.getComponent();
ServiceState serviceState = userState.mServiceStateMap.get(componentName);
if (serviceState != null) {
serviceState.mService.prepare(type);
}
}
} catch (RemoteException e) {
Slogf.e(TAG, "error in prepare", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void createSession(final ITvIAppClient client, final String iAppServiceId, int type,
int seq, int userId) {
@@ -688,18 +710,54 @@ public class TvIAppManagerService extends SystemService {
}
}
@Override
public void notifyTuned(IBinder sessionToken, Uri channelUri, int userId) {
if (DEBUG) {
Slogf.d(TAG, "notifyTuned(sessionToken=" + sessionToken
+ ", Uri=" + channelUri + ")");
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "notifyTuned");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).notifyTuned(channelUri);
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in notifyTuned", e);
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void startIApp(IBinder sessionToken, int userId) {
if (DEBUG) {
Slogf.d(TAG, "BinderService#start(userId=%d)", userId);
}
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "notifyTuned");
SessionState sessionState = null;
final long identity = Binder.clearCallingIdentity();
try {
SessionState sessionState = getSessionState(sessionToken);
if (sessionState != null && sessionState.mSession != null) {
sessionState.mSession.startIApp();
synchronized (mLock) {
try {
sessionState = getSessionStateLocked(sessionToken, callingUid,
resolvedUserId);
getSessionLocked(sessionState).startIApp();
} catch (RemoteException | SessionNotFoundException e) {
Slogf.e(TAG, "error in start", e);
}
}
} catch (RemoteException e) {
Slogf.e(TAG, "error in start", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
}