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 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, @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_LIVE = 400; // 0x190
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 java.util.List<android.media.tv.TvTrackInfo> getTracks(int);
method public boolean onUnhandledInputEvent(android.view.InputEvent);
method public void overrideTvAppAttributionSource(@NonNull android.content.AttributionSource);
method public void reset();
method public void selectTrack(int, String);
method public void sendAppPrivateCommand(@NonNull String, android.os.Bundle);

View File

@ -16,6 +16,7 @@
package android.media.tv;
import android.content.AttributionSource;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Rect;
@ -62,7 +63,7 @@ interface ITvInputManager {
void addBlockedRating(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);
void releaseSession(in IBinder sessionToken, int userId);
int getClientPid(in String sessionId);

View File

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

View File

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

View File

@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.AttributionSource;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
@ -53,9 +54,7 @@ import android.view.InputEventSender;
import android.view.KeyEvent;
import android.view.Surface;
import android.view.View;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@ -1835,13 +1834,15 @@ public final class TvInputManager {
* of the given 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 handler A {@link Handler} that the session creation will be delivered to.
* @hide
*/
public void createSession(@NonNull String inputId, @NonNull final SessionCallback callback,
@NonNull Handler handler) {
createSessionInternal(inputId, false, callback, handler);
public void createSession(@NonNull String inputId,
@NonNull AttributionSource tvAppAttributionSource,
@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.
* {@see TvInputService#PriorityHintUseCaseType}.
* @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
* or background status.
@ -1917,11 +1918,11 @@ public final class TvInputManager {
*/
public void createRecordingSession(@NonNull String inputId,
@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,
SessionCallback callback, Handler handler) {
private void createSessionInternal(String inputId, AttributionSource tvAppAttributionSource,
boolean isRecordingSession, SessionCallback callback, Handler handler) {
Preconditions.checkNotNull(inputId);
Preconditions.checkNotNull(callback);
Preconditions.checkNotNull(handler);
@ -1930,7 +1931,8 @@ public final class TvInputManager {
int seq = mNextSeq++;
mSessionCallbackRecordMap.put(seq, record);
try {
mService.createSession(mClient, inputId, isRecordingSession, seq, mUserId);
mService.createSession(
mClient, inputId, tvAppAttributionSource, isRecordingSession, seq, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@ -2101,8 +2103,8 @@ public final class TvInputManager {
* @param deviceId The device ID to acquire Hardware for.
* @param info The TV input which will use the acquired Hardware.
* @param tvInputSessionId a String returned to TIS when the session was created.
* {@see TvInputService#onCreateSession(String, String)}. If null, the client will be
* treated as a background app.
* {@see TvInputService#onCreateSession(String, String, AttributionSource)}. If null, the
* client will be treated as a background app.
* @param priorityHint The use case of the client. {@see TvInputService#PriorityHintUseCaseType}
* @param executor the executor on which the listener would be invoked.
* @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.Service;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.AttributionSource;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
@ -57,10 +58,8 @@ import android.view.ViewRootImpl;
import android.view.WindowManager;
import android.view.accessibility.CaptioningManager;
import android.widget.FrameLayout;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@ -171,7 +170,7 @@ public abstract class TvInputService extends Service {
@Override
public void createSession(InputChannel channel, ITvInputSessionCallback cb,
String inputId, String sessionId) {
String inputId, String sessionId, AttributionSource tvAppAttributionSource) {
if (channel == null) {
Log.w(TAG, "Creating session without input channel");
}
@ -183,6 +182,7 @@ public abstract class TvInputService extends Service {
args.arg2 = cb;
args.arg3 = inputId;
args.arg4 = sessionId;
args.arg5 = tvAppAttributionSource;
mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION,
args).sendToTarget();
}
@ -369,6 +369,24 @@ public abstract class TvInputService extends Service {
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}.
*
@ -1107,7 +1125,7 @@ public abstract class TvInputService extends Service {
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
*/
@ -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) {
}
@ -2444,8 +2462,10 @@ public abstract class TvInputService extends Service {
ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2;
String inputId = (String) args.arg3;
String sessionId = (String) args.arg4;
AttributionSource tvAppAttributionSource = (AttributionSource) args.arg5;
args.recycle();
Session sessionImpl = onCreateSession(inputId, sessionId);
Session sessionImpl =
onCreateSession(inputId, sessionId, tvAppAttributionSource);
if (sessionImpl == null) {
try {
// Failed to create a session.
@ -2481,7 +2501,7 @@ public abstract class TvInputService extends Service {
proxySession.mServiceHandler = mServiceHandler;
TvInputManager manager = (TvInputManager) getSystemService(
Context.TV_INPUT_SERVICE);
manager.createSession(hardwareInputId,
manager.createSession(hardwareInputId, tvAppAttributionSource,
proxySession.mHardwareSessionCallback, mServiceHandler);
} else {
SomeArgs someArgs = SomeArgs.obtain();

View File

@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.AttributionSource;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@ -51,7 +52,6 @@ import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.List;
@ -111,6 +111,7 @@ public class TvView extends ViewGroup {
private int mSurfaceViewTop;
private int mSurfaceViewBottom;
private TimeShiftPositionCallback mTimeShiftPositionCallback;
private AttributionSource mTvAppAttributionSource;
private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
@Override
@ -185,6 +186,7 @@ public class TvView extends ViewGroup {
mDefStyleAttr = defStyleAttr;
resetSurfaceView();
mTvInputManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE);
mTvAppAttributionSource = getContext().getAttributionSource();
}
/**
@ -303,6 +305,22 @@ public class TvView extends ViewGroup {
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.
*
@ -355,7 +373,8 @@ public class TvView extends ViewGroup {
// is obsolete and should ignore it.
mSessionCallback = new MySessionCallback(inputId, channelUri, params);
if (mTvInputManager != null) {
mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
mTvInputManager.createSession(
inputId, mTvAppAttributionSource, mSessionCallback, mHandler);
}
}
}
@ -526,7 +545,8 @@ public class TvView extends ViewGroup {
resetInternal();
mSessionCallback = new MySessionCallback(inputId, recordedProgramUri);
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.UserIdInt;
import android.app.ActivityManager;
import android.content.AttributionSource;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@ -90,7 +91,6 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.InputChannel;
import android.view.Surface;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
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.server.IoThread;
import com.android.server.SystemService;
import dalvik.annotation.optimization.NeverCompile;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@ -813,7 +811,7 @@ public final class TvInputManagerService extends SystemService {
@GuardedBy("mLock")
private boolean createSessionInternalLocked(ITvInputService service, IBinder sessionToken,
int userId) {
int userId, AttributionSource tvAppAttributionSource) {
UserState userState = getOrCreateUserStateLocked(userId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (DEBUG) {
@ -832,8 +830,8 @@ public final class TvInputManagerService extends SystemService {
service.createRecordingSession(
callback, sessionState.inputId, sessionState.sessionId);
} else {
service.createSession(
channels[1], callback, sessionState.inputId, sessionState.sessionId);
service.createSession(channels[1], callback, sessionState.inputId,
sessionState.sessionId, tvAppAttributionSource);
}
} catch (RemoteException e) {
Slog.e(TAG, "error in createSession", e);
@ -1485,7 +1483,8 @@ public final class TvInputManagerService extends SystemService {
@Override
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 callingPid = Binder.getCallingPid();
final int resolvedUserId = resolveCallingUserId(callingPid, callingUid,
@ -1556,7 +1555,7 @@ public final class TvInputManagerService extends SystemService {
if (serviceState.service != null) {
if (!createSessionInternalLocked(serviceState.service, sessionToken,
resolvedUserId)) {
resolvedUserId, tvAppAttributionSource)) {
removeSessionStateLocked(sessionToken, resolvedUserId);
}
} else {
@ -3113,7 +3112,8 @@ public final class TvInputManagerService extends SystemService {
// And create sessions, if any.
for (IBinder sessionToken : serviceState.sessionTokens) {
if (!createSessionInternalLocked(serviceState.service, sessionToken, mUserId)) {
if (!createSessionInternalLocked(
serviceState.service, sessionToken, mUserId, null)) {
tokensToBeRemoved.add(sessionToken);
}
}