Merge "Add API to register AttributionSource of TV App to TIS"

This commit is contained in:
Yixiao Luo 2023-01-26 00:21:50 +00:00 committed by Gerrit Code Review
commit 9a2db08346
8 changed files with 79 additions and 34 deletions

View File

@ -25917,6 +25917,7 @@ package android.media.tv {
method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(@NonNull String, @NonNull String); method @Nullable public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(@NonNull String, @NonNull String);
method @Nullable public abstract android.media.tv.TvInputService.Session onCreateSession(@NonNull String); method @Nullable public abstract android.media.tv.TvInputService.Session onCreateSession(@NonNull String);
method @Nullable public android.media.tv.TvInputService.Session onCreateSession(@NonNull String, @NonNull String); method @Nullable public android.media.tv.TvInputService.Session onCreateSession(@NonNull String, @NonNull String);
method @Nullable public android.media.tv.TvInputService.Session onCreateSession(@NonNull String, @NonNull String, @NonNull android.content.AttributionSource);
field public static final int PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND = 100; // 0x64 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_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_PLAYBACK = 300; // 0x12c
@ -26077,6 +26078,7 @@ package android.media.tv {
method public String getSelectedTrack(int); method public String getSelectedTrack(int);
method public java.util.List<android.media.tv.TvTrackInfo> getTracks(int); method public java.util.List<android.media.tv.TvTrackInfo> getTracks(int);
method public boolean onUnhandledInputEvent(android.view.InputEvent); method public boolean onUnhandledInputEvent(android.view.InputEvent);
method public void overrideTvAppAttributionSource(@NonNull android.content.AttributionSource);
method public void reset(); method public void reset();
method public void selectTrack(int, String); method public void selectTrack(int, String);
method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle); method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);

View File

@ -16,6 +16,7 @@
package android.media.tv; package android.media.tv;
import android.content.AttributionSource;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Intent; import android.content.Intent;
import android.graphics.Rect; import android.graphics.Rect;
@ -62,7 +63,7 @@ interface ITvInputManager {
void addBlockedRating(in String rating, int userId); void addBlockedRating(in String rating, int userId);
void removeBlockedRating(in String rating, int userId); void removeBlockedRating(in String rating, int userId);
void createSession(in ITvInputClient client, in String inputId, boolean isRecordingSession, void createSession(in ITvInputClient client, in String inputId, in AttributionSource tvAppAttributionSource, boolean isRecordingSession,
int seq, int userId); int seq, int userId);
void releaseSession(in IBinder sessionToken, int userId); void releaseSession(in IBinder sessionToken, int userId);
int getClientPid(in String sessionId); int getClientPid(in String sessionId);

View File

@ -16,6 +16,7 @@
package android.media.tv; package android.media.tv;
import android.content.AttributionSource;
import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.tv.ITvInputServiceCallback; import android.media.tv.ITvInputServiceCallback;
import android.media.tv.ITvInputSessionCallback; import android.media.tv.ITvInputSessionCallback;
@ -30,7 +31,7 @@ interface ITvInputService {
oneway void registerCallback(in ITvInputServiceCallback callback); oneway void registerCallback(in ITvInputServiceCallback callback);
oneway void unregisterCallback(in ITvInputServiceCallback callback); oneway void unregisterCallback(in ITvInputServiceCallback callback);
oneway void createSession(in InputChannel channel, in ITvInputSessionCallback callback, oneway void createSession(in InputChannel channel, in ITvInputSessionCallback callback,
in String inputId, in String sessionId); in String inputId, in String sessionId, in AttributionSource tvAppAttributionSource);
oneway void createRecordingSession(in ITvInputSessionCallback callback, in String inputId, oneway void createRecordingSession(in ITvInputSessionCallback callback, in String inputId,
in String sessionId); in String sessionId);
List<String> getAvailableExtensionInterfaceNames(); List<String> getAvailableExtensionInterfaceNames();

View File

@ -30,7 +30,6 @@ import android.view.InputChannel;
import android.view.InputEvent; import android.view.InputEvent;
import android.view.InputEventReceiver; import android.view.InputEventReceiver;
import android.view.Surface; import android.view.Surface;
import com.android.internal.os.HandlerCaller; import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs; import com.android.internal.os.SomeArgs;

View File

@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi; import android.annotation.SystemApi;
import android.annotation.SystemService; import android.annotation.SystemService;
import android.annotation.TestApi; import android.annotation.TestApi;
import android.content.AttributionSource;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Rect; import android.graphics.Rect;
@ -53,9 +54,7 @@ import android.view.InputEventSender;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Surface; import android.view.Surface;
import android.view.View; import android.view.View;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
@ -1835,13 +1834,15 @@ public final class TvInputManager {
* of the given TV input. * of the given TV input.
* *
* @param inputId The ID of the TV input. * @param inputId The ID of the TV input.
* @param tvAppAttributionSource The Attribution Source of the TV App.
* @param callback A callback used to receive the created session. * @param callback A callback used to receive the created session.
* @param handler A {@link Handler} that the session creation will be delivered to. * @param handler A {@link Handler} that the session creation will be delivered to.
* @hide * @hide
*/ */
public void createSession(@NonNull String inputId, @NonNull final SessionCallback callback, public void createSession(@NonNull String inputId,
@NonNull Handler handler) { @NonNull AttributionSource tvAppAttributionSource,
createSessionInternal(inputId, false, callback, handler); @NonNull final SessionCallback callback, @NonNull Handler handler) {
createSessionInternal(inputId, tvAppAttributionSource, false, callback, handler);
} }
/** /**
@ -1866,7 +1867,7 @@ public final class TvInputManager {
* @param useCase the use case type of the client. * @param useCase the use case type of the client.
* {@see TvInputService#PriorityHintUseCaseType}. * {@see TvInputService#PriorityHintUseCaseType}.
* @param sessionId the unique id of the session owned by the client. * @param sessionId the unique id of the session owned by the client.
* {@see TvInputService#onCreateSession(String, String)}. * {@see TvInputService#onCreateSession(String, String, AttributionSource)}.
* *
* @return the use case priority value for the given use case type and the client's foreground * @return the use case priority value for the given use case type and the client's foreground
* or background status. * or background status.
@ -1917,11 +1918,11 @@ public final class TvInputManager {
*/ */
public void createRecordingSession(@NonNull String inputId, public void createRecordingSession(@NonNull String inputId,
@NonNull final SessionCallback callback, @NonNull Handler handler) { @NonNull final SessionCallback callback, @NonNull Handler handler) {
createSessionInternal(inputId, true, callback, handler); createSessionInternal(inputId, null, true, callback, handler);
} }
private void createSessionInternal(String inputId, boolean isRecordingSession, private void createSessionInternal(String inputId, AttributionSource tvAppAttributionSource,
SessionCallback callback, Handler handler) { boolean isRecordingSession, SessionCallback callback, Handler handler) {
Preconditions.checkNotNull(inputId); Preconditions.checkNotNull(inputId);
Preconditions.checkNotNull(callback); Preconditions.checkNotNull(callback);
Preconditions.checkNotNull(handler); Preconditions.checkNotNull(handler);
@ -1930,7 +1931,8 @@ public final class TvInputManager {
int seq = mNextSeq++; int seq = mNextSeq++;
mSessionCallbackRecordMap.put(seq, record); mSessionCallbackRecordMap.put(seq, record);
try { try {
mService.createSession(mClient, inputId, isRecordingSession, seq, mUserId); mService.createSession(
mClient, inputId, tvAppAttributionSource, isRecordingSession, seq, mUserId);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@ -2101,8 +2103,8 @@ public final class TvInputManager {
* @param deviceId The device ID to acquire Hardware for. * @param deviceId The device ID to acquire Hardware for.
* @param info The TV input which will use the acquired Hardware. * @param info The TV input which will use the acquired Hardware.
* @param tvInputSessionId a String returned to TIS when the session was created. * @param tvInputSessionId a String returned to TIS when the session was created.
* {@see TvInputService#onCreateSession(String, String)}. If null, the client will be * {@see TvInputService#onCreateSession(String, String, AttributionSource)}. If null, the
* treated as a background app. * client will be treated as a background app.
* @param priorityHint The use case of the client. {@see TvInputService#PriorityHintUseCaseType} * @param priorityHint The use case of the client. {@see TvInputService#PriorityHintUseCaseType}
* @param executor the executor on which the listener would be invoked. * @param executor the executor on which the listener would be invoked.
* @param callback A callback to receive updates on Hardware. * @param callback A callback to receive updates on Hardware.

View File

@ -26,6 +26,7 @@ import android.annotation.SystemApi;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.Service; import android.app.Service;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
@ -57,10 +58,8 @@ import android.view.ViewRootImpl;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.accessibility.CaptioningManager; import android.view.accessibility.CaptioningManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import com.android.internal.os.SomeArgs; import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
@ -171,7 +170,7 @@ public abstract class TvInputService extends Service {
@Override @Override
public void createSession(InputChannel channel, ITvInputSessionCallback cb, public void createSession(InputChannel channel, ITvInputSessionCallback cb,
String inputId, String sessionId) { String inputId, String sessionId, AttributionSource tvAppAttributionSource) {
if (channel == null) { if (channel == null) {
Log.w(TAG, "Creating session without input channel"); Log.w(TAG, "Creating session without input channel");
} }
@ -183,6 +182,7 @@ public abstract class TvInputService extends Service {
args.arg2 = cb; args.arg2 = cb;
args.arg3 = inputId; args.arg3 = inputId;
args.arg4 = sessionId; args.arg4 = sessionId;
args.arg5 = tvAppAttributionSource;
mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION,
args).sendToTarget(); args).sendToTarget();
} }
@ -369,6 +369,24 @@ public abstract class TvInputService extends Service {
return onCreateSession(inputId); return onCreateSession(inputId);
} }
/**
* Returns a concrete implementation of {@link Session}.
*
* <p>For any apps that needs sessionId to request tuner resources from TunerResourceManager and
* needs to specify custom AttributionSource to AudioTrack, it needs to override this method to
* get the sessionId and AttrubutionSource passed. When no overriding, this method calls {@link
* #onCreateSession(String, String)} defaultly.
*
* @param inputId The ID of the TV input associated with the session.
* @param sessionId the unique sessionId created by TIF when session is created.
* @param tvAppAttributionSource The Attribution Source of the TV App.
*/
@Nullable
public Session onCreateSession(@NonNull String inputId, @NonNull String sessionId,
@NonNull AttributionSource tvAppAttributionSource) {
return onCreateSession(inputId, sessionId);
}
/** /**
* Returns a concrete implementation of {@link RecordingSession}. * Returns a concrete implementation of {@link RecordingSession}.
* *
@ -1107,7 +1125,7 @@ public abstract class TvInputService extends Service {
public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume); public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume);
/** /**
* called when broadcast info is requested. * Called when broadcast info is requested.
* *
* @param request broadcast info request * @param request broadcast info request
*/ */
@ -1115,7 +1133,7 @@ public abstract class TvInputService extends Service {
} }
/** /**
* called when broadcast info is removed. * Called when broadcast info is removed.
*/ */
public void onRemoveBroadcastInfo(int requestId) { public void onRemoveBroadcastInfo(int requestId) {
} }
@ -2444,8 +2462,10 @@ public abstract class TvInputService extends Service {
ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2; ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2;
String inputId = (String) args.arg3; String inputId = (String) args.arg3;
String sessionId = (String) args.arg4; String sessionId = (String) args.arg4;
AttributionSource tvAppAttributionSource = (AttributionSource) args.arg5;
args.recycle(); args.recycle();
Session sessionImpl = onCreateSession(inputId, sessionId); Session sessionImpl =
onCreateSession(inputId, sessionId, tvAppAttributionSource);
if (sessionImpl == null) { if (sessionImpl == null) {
try { try {
// Failed to create a session. // Failed to create a session.
@ -2481,7 +2501,7 @@ public abstract class TvInputService extends Service {
proxySession.mServiceHandler = mServiceHandler; proxySession.mServiceHandler = mServiceHandler;
TvInputManager manager = (TvInputManager) getSystemService( TvInputManager manager = (TvInputManager) getSystemService(
Context.TV_INPUT_SERVICE); Context.TV_INPUT_SERVICE);
manager.createSession(hardwareInputId, manager.createSession(hardwareInputId, tvAppAttributionSource,
proxySession.mHardwareSessionCallback, mServiceHandler); proxySession.mHardwareSessionCallback, mServiceHandler);
} else { } else {
SomeArgs someArgs = SomeArgs.obtain(); SomeArgs someArgs = SomeArgs.obtain();

View File

@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.RequiresPermission; import android.annotation.RequiresPermission;
import android.annotation.SystemApi; import android.annotation.SystemApi;
import android.content.AttributionSource;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
@ -51,7 +52,6 @@ import android.view.SurfaceView;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewRootImpl; import android.view.ViewRootImpl;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.List; import java.util.List;
@ -111,6 +111,7 @@ public class TvView extends ViewGroup {
private int mSurfaceViewTop; private int mSurfaceViewTop;
private int mSurfaceViewBottom; private int mSurfaceViewBottom;
private TimeShiftPositionCallback mTimeShiftPositionCallback; private TimeShiftPositionCallback mTimeShiftPositionCallback;
private AttributionSource mTvAppAttributionSource;
private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
@Override @Override
@ -185,6 +186,7 @@ public class TvView extends ViewGroup {
mDefStyleAttr = defStyleAttr; mDefStyleAttr = defStyleAttr;
resetSurfaceView(); resetSurfaceView();
mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE); mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
mTvAppAttributionSource = getContext().getAttributionSource();
} }
/** /**
@ -303,6 +305,22 @@ public class TvView extends ViewGroup {
mSession.setStreamVolume(volume); mSession.setStreamVolume(volume);
} }
/**
* Override default attribution source of TV App.
*
* <p>An attribution source of TV App is used to attribute work to TV Input Service.
* The default attribution source is created by {@link Context#getAttributionSource()}.
* Call this method before calling {@link #tune(String, Uri, Bundle)} or {@link
* #timeShiftPlay(String, Uri)} to override the default attribution source.
*
* @param tvAppAttributionSource The attribution source of the TV App.
*/
public void overrideTvAppAttributionSource(@NonNull AttributionSource tvAppAttributionSource) {
if (tvAppAttributionSource != null) {
mTvAppAttributionSource = tvAppAttributionSource;
}
}
/** /**
* Tunes to a given channel. * Tunes to a given channel.
* *
@ -355,7 +373,8 @@ public class TvView extends ViewGroup {
// is obsolete and should ignore it. // is obsolete and should ignore it.
mSessionCallback = new MySessionCallback(inputId, channelUri, params); mSessionCallback = new MySessionCallback(inputId, channelUri, params);
if (mTvInputManager != null) { if (mTvInputManager != null) {
mTvInputManager.createSession(inputId, mSessionCallback, mHandler); mTvInputManager.createSession(
inputId, mTvAppAttributionSource, mSessionCallback, mHandler);
} }
} }
} }
@ -526,7 +545,8 @@ public class TvView extends ViewGroup {
resetInternal(); resetInternal();
mSessionCallback = new MySessionCallback(inputId, recordedProgramUri); mSessionCallback = new MySessionCallback(inputId, recordedProgramUri);
if (mTvInputManager != null) { if (mTvInputManager != null) {
mTvInputManager.createSession(inputId, mSessionCallback, mHandler); mTvInputManager.createSession(
inputId, mTvAppAttributionSource, mSessionCallback, mHandler);
} }
} }
} }

View File

@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.content.AttributionSource;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
@ -90,7 +91,6 @@ import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import android.view.InputChannel; import android.view.InputChannel;
import android.view.Surface; import android.view.Surface;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor; import com.android.internal.content.PackageMonitor;
@ -101,9 +101,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread; import com.android.server.IoThread;
import com.android.server.SystemService; import com.android.server.SystemService;
import dalvik.annotation.optimization.NeverCompile; import dalvik.annotation.optimization.NeverCompile;
import java.io.File; import java.io.File;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -813,7 +811,7 @@ public final class TvInputManagerService extends SystemService {
@GuardedBy("mLock") @GuardedBy("mLock")
private boolean createSessionInternalLocked(ITvInputService service, IBinder sessionToken, private boolean createSessionInternalLocked(ITvInputService service, IBinder sessionToken,
int userId) { int userId, AttributionSource tvAppAttributionSource) {
UserState userState = getOrCreateUserStateLocked(userId); UserState userState = getOrCreateUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken); SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (DEBUG) { if (DEBUG) {
@ -832,8 +830,8 @@ public final class TvInputManagerService extends SystemService {
service.createRecordingSession( service.createRecordingSession(
callback, sessionState.inputId, sessionState.sessionId); callback, sessionState.inputId, sessionState.sessionId);
} else { } else {
service.createSession( service.createSession(channels[1], callback, sessionState.inputId,
channels[1], callback, sessionState.inputId, sessionState.sessionId); sessionState.sessionId, tvAppAttributionSource);
} }
} catch (RemoteException e) { } catch (RemoteException e) {
Slog.e(TAG, "error in createSession", e); Slog.e(TAG, "error in createSession", e);
@ -1485,7 +1483,8 @@ public final class TvInputManagerService extends SystemService {
@Override @Override
public void createSession(final ITvInputClient client, final String inputId, public void createSession(final ITvInputClient client, final String inputId,
boolean isRecordingSession, int seq, int userId) { AttributionSource tvAppAttributionSource, boolean isRecordingSession, int seq,
int userId) {
final int callingUid = Binder.getCallingUid(); final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid(); final int callingPid = Binder.getCallingPid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
@ -1556,7 +1555,7 @@ public final class TvInputManagerService extends SystemService {
if (serviceState.service != null) { if (serviceState.service != null) {
if (!createSessionInternalLocked(serviceState.service, sessionToken, if (!createSessionInternalLocked(serviceState.service, sessionToken,
resolvedUserId)) { resolvedUserId, tvAppAttributionSource)) {
removeSessionStateLocked(sessionToken, resolvedUserId); removeSessionStateLocked(sessionToken, resolvedUserId);
} }
} else { } else {
@ -3113,7 +3112,8 @@ public final class TvInputManagerService extends SystemService {
// And create sessions, if any. // And create sessions, if any.
for (IBinder sessionToken : serviceState.sessionTokens) { for (IBinder sessionToken : serviceState.sessionTokens) {
if (!createSessionInternalLocked(serviceState.service, sessionToken, mUserId)) { if (!createSessionInternalLocked(
serviceState.service, sessionToken, mUserId, null)) {
tokensToBeRemoved.add(sessionToken); tokensToBeRemoved.add(sessionToken);
} }
} }