Merge "Allow apps with BLUETOOTH permission to control system routing" into udc-dev am: 0871ce45cf am: 2e27842bd3
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23135277 Change-Id: Ic589cf73a2421294a5fe5e5c3cb6d9716512946b Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -134,6 +134,21 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks through the pending transitions for a opening transaction that matches the provided
|
||||
* `taskView`.
|
||||
* @param taskView the pending transition should be for this.
|
||||
*/
|
||||
private PendingTransition findPendingOpeningTransition(TaskViewTaskController taskView) {
|
||||
for (int i = mPending.size() - 1; i >= 0; --i) {
|
||||
if (mPending.get(i).mTaskView != taskView) continue;
|
||||
if (TransitionUtil.isOpeningType(mPending.get(i).mType)) {
|
||||
return mPending.get(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks through the pending transitions for one matching `taskView`.
|
||||
* @param taskView the pending transition should be for this.
|
||||
@@ -149,6 +164,19 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the pending transitions for a given `taskView`.
|
||||
* @param taskView the pending transition should be for this.
|
||||
*/
|
||||
ArrayList<PendingTransition> findAllPending(TaskViewTaskController taskView) {
|
||||
ArrayList<PendingTransition> list = new ArrayList<>();
|
||||
for (int i = mPending.size() - 1; i >= 0; --i) {
|
||||
if (mPending.get(i).mTaskView != taskView) continue;
|
||||
list.add(mPending.get(i));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private PendingTransition findPending(IBinder claimed) {
|
||||
for (int i = 0; i < mPending.size(); ++i) {
|
||||
if (mPending.get(i).mClaimed != claimed) continue;
|
||||
@@ -249,9 +277,10 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
|
||||
// Task view isn't visible, the bounds will next visibility update.
|
||||
return;
|
||||
}
|
||||
if (hasPending()) {
|
||||
// There is already a transition in-flight, the window bounds will be set in
|
||||
// prepareOpenAnimation.
|
||||
PendingTransition pendingOpen = findPendingOpeningTransition(taskView);
|
||||
if (pendingOpen != null) {
|
||||
// There is already an opening transition in-flight, the window bounds will be
|
||||
// set in prepareOpenAnimation (via the window crop) if needed.
|
||||
return;
|
||||
}
|
||||
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
|
||||
@@ -45,6 +45,8 @@ import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
@@ -58,6 +60,12 @@ public class TaskViewTransitionsTest extends ShellTestCase {
|
||||
ActivityManager.RunningTaskInfo mTaskInfo;
|
||||
@Mock
|
||||
WindowContainerToken mToken;
|
||||
@Mock
|
||||
TaskViewTaskController mTaskViewTaskController2;
|
||||
@Mock
|
||||
ActivityManager.RunningTaskInfo mTaskInfo2;
|
||||
@Mock
|
||||
WindowContainerToken mToken2;
|
||||
|
||||
TaskViewTransitions mTaskViewTransitions;
|
||||
|
||||
@@ -73,10 +81,16 @@ public class TaskViewTransitionsTest extends ShellTestCase {
|
||||
mTaskInfo.token = mToken;
|
||||
mTaskInfo.taskId = 314;
|
||||
mTaskInfo.taskDescription = mock(ActivityManager.TaskDescription.class);
|
||||
when(mTaskViewTaskController.getTaskInfo()).thenReturn(mTaskInfo);
|
||||
|
||||
mTaskInfo2 = new ActivityManager.RunningTaskInfo();
|
||||
mTaskInfo2.token = mToken2;
|
||||
mTaskInfo2.taskId = 315;
|
||||
mTaskInfo2.taskDescription = mock(ActivityManager.TaskDescription.class);
|
||||
when(mTaskViewTaskController2.getTaskInfo()).thenReturn(mTaskInfo2);
|
||||
|
||||
mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions));
|
||||
mTaskViewTransitions.addTaskView(mTaskViewTaskController);
|
||||
when(mTaskViewTaskController.getTaskInfo()).thenReturn(mTaskInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,7 +133,7 @@ public class TaskViewTransitionsTest extends ShellTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetTaskBounds_taskVisibleWithPending_noTransaction() {
|
||||
public void testSetTaskBounds_taskVisibleWithPendingOpen_noTransaction() {
|
||||
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
|
||||
|
||||
mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, true);
|
||||
@@ -134,6 +148,43 @@ public class TaskViewTransitionsTest extends ShellTestCase {
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetTaskBounds_taskVisibleWithPendingChange_transition() {
|
||||
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
|
||||
|
||||
mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, true);
|
||||
|
||||
// Consume the pending transition from visibility change
|
||||
TaskViewTransitions.PendingTransition pending =
|
||||
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
|
||||
assertThat(pending).isNotNull();
|
||||
mTaskViewTransitions.startAnimation(pending.mClaimed,
|
||||
mock(TransitionInfo.class),
|
||||
new SurfaceControl.Transaction(),
|
||||
new SurfaceControl.Transaction(),
|
||||
mock(Transitions.TransitionFinishCallback.class));
|
||||
// Verify it was consumed
|
||||
TaskViewTransitions.PendingTransition checkPending =
|
||||
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
|
||||
assertThat(checkPending).isNull();
|
||||
|
||||
// Test that set bounds creates a new transition
|
||||
mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
|
||||
new Rect(0, 0, 100, 100));
|
||||
assertThat(mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE))
|
||||
.isNotNull();
|
||||
|
||||
// Test that set bounds again (with different bounds) creates another transition
|
||||
mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
|
||||
new Rect(0, 0, 300, 200));
|
||||
List<TaskViewTransitions.PendingTransition> pendingList =
|
||||
mTaskViewTransitions.findAllPending(mTaskViewTaskController)
|
||||
.stream()
|
||||
.filter(pendingTransition -> pendingTransition.mType == TRANSIT_CHANGE)
|
||||
.toList();
|
||||
assertThat(pendingList.size()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetTaskBounds_sameBounds_noTransaction() {
|
||||
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
|
||||
@@ -161,6 +212,16 @@ public class TaskViewTransitionsTest extends ShellTestCase {
|
||||
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE);
|
||||
assertThat(pendingBounds).isNotNull();
|
||||
|
||||
// Test that setting same bounds with in-flight transition doesn't cause another one
|
||||
mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
|
||||
new Rect(0, 0, 100, 100));
|
||||
List<TaskViewTransitions.PendingTransition> pendingList =
|
||||
mTaskViewTransitions.findAllPending(mTaskViewTaskController)
|
||||
.stream()
|
||||
.filter(pendingTransition -> pendingTransition.mType == TRANSIT_CHANGE)
|
||||
.toList();
|
||||
assertThat(pendingList.size()).isEqualTo(1);
|
||||
|
||||
// Consume the pending bounds transaction
|
||||
mTaskViewTransitions.startAnimation(pendingBounds.mClaimed,
|
||||
mock(TransitionInfo.class),
|
||||
@@ -180,6 +241,42 @@ public class TaskViewTransitionsTest extends ShellTestCase {
|
||||
assertThat(pendingBounds2).isNull();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSetTaskBounds_taskVisibleWithDifferentTaskViewPendingChange_transition() {
|
||||
assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
|
||||
|
||||
mTaskViewTransitions.addTaskView(mTaskViewTaskController2);
|
||||
|
||||
mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, true);
|
||||
|
||||
// Consume the pending transition from visibility change
|
||||
TaskViewTransitions.PendingTransition pending =
|
||||
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
|
||||
assertThat(pending).isNotNull();
|
||||
mTaskViewTransitions.startAnimation(pending.mClaimed,
|
||||
mock(TransitionInfo.class),
|
||||
new SurfaceControl.Transaction(),
|
||||
new SurfaceControl.Transaction(),
|
||||
mock(Transitions.TransitionFinishCallback.class));
|
||||
// Verify it was consumed
|
||||
TaskViewTransitions.PendingTransition checkPending =
|
||||
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_TO_FRONT);
|
||||
assertThat(checkPending).isNull();
|
||||
|
||||
// Set the second taskview as visible & check that it has a pending transition
|
||||
mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController2, true);
|
||||
TaskViewTransitions.PendingTransition pending2 =
|
||||
mTaskViewTransitions.findPending(mTaskViewTaskController2, TRANSIT_TO_FRONT);
|
||||
assertThat(pending2).isNotNull();
|
||||
|
||||
// Test that set bounds on the first taskview will create a new transition
|
||||
mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
|
||||
new Rect(0, 0, 100, 100));
|
||||
assertThat(mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE))
|
||||
.isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetTaskVisibility_taskRemoved_noNPE() {
|
||||
mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
|
||||
|
||||
@@ -57,6 +57,30 @@ public final class MediaRoute2Info implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The {@link #getOriginalId() original id} of the route that represents the built-in media
|
||||
* route.
|
||||
*
|
||||
* <p>A route with this id will only be visible to apps with permission to do system routing,
|
||||
* which means having {@link android.Manifest.permission#BLUETOOTH_CONNECT} and {@link
|
||||
* android.Manifest.permission#BLUETOOTH_SCAN}, or {@link
|
||||
* android.Manifest.permission#MODIFY_AUDIO_ROUTING}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String ROUTE_ID_DEVICE = "DEVICE_ROUTE";
|
||||
|
||||
/**
|
||||
* The {@link #getOriginalId() original id} of the route that represents the default system
|
||||
* media route.
|
||||
*
|
||||
* <p>A route with this id will be visible to apps with no permission over system routing. See
|
||||
* {@link #ROUTE_ID_DEVICE} for details.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String ROUTE_ID_DEFAULT = "DEFAULT_ROUTE";
|
||||
|
||||
/** @hide */
|
||||
@IntDef({CONNECTION_STATE_DISCONNECTED, CONNECTION_STATE_CONNECTING,
|
||||
CONNECTION_STATE_CONNECTED})
|
||||
|
||||
@@ -42,13 +42,10 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/* package */ final class AudioPoliciesDeviceRouteController implements DeviceRouteController {
|
||||
|
||||
private static final String TAG = "APDeviceRoutesController";
|
||||
|
||||
private static final String DEVICE_ROUTE_ID = "DEVICE_ROUTE";
|
||||
|
||||
@NonNull
|
||||
private final Context mContext;
|
||||
@NonNull
|
||||
@@ -182,10 +179,12 @@ import java.util.Objects;
|
||||
|
||||
synchronized (this) {
|
||||
return new MediaRoute2Info.Builder(
|
||||
DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString())
|
||||
.setVolumeHandling(mAudioManager.isVolumeFixed()
|
||||
? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
|
||||
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
|
||||
MediaRoute2Info.ROUTE_ID_DEVICE,
|
||||
mContext.getResources().getText(name).toString())
|
||||
.setVolumeHandling(
|
||||
mAudioManager.isVolumeFixed()
|
||||
? MediaRoute2Info.PLAYBACK_VOLUME_FIXED
|
||||
: MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
|
||||
.setVolume(mDeviceVolume)
|
||||
.setVolumeMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
|
||||
.setType(type)
|
||||
|
||||
@@ -28,6 +28,7 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -75,8 +76,10 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -97,6 +100,17 @@ class MediaRouter2ServiceImpl {
|
||||
private static final String KEY_SCANNING_PACKAGE_MINIMUM_IMPORTANCE =
|
||||
"scanning_package_minimum_importance";
|
||||
|
||||
/**
|
||||
* Contains the list of bluetooth permissions that are required to do system routing.
|
||||
*
|
||||
* <p>Alternatively, apps that hold {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} are
|
||||
* also allowed to do system routing.
|
||||
*/
|
||||
private static final String[] BLUETOOTH_PERMISSIONS_FOR_SYSTEM_ROUTING =
|
||||
new String[] {
|
||||
Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN
|
||||
};
|
||||
|
||||
private static int sPackageImportanceForScanning = DeviceConfig.getInt(
|
||||
MEDIA_BETTER_TOGETHER_NAMESPACE,
|
||||
/* name */ KEY_SCANNING_PACKAGE_MINIMUM_IMPORTANCE,
|
||||
@@ -142,6 +156,7 @@ class MediaRouter2ServiceImpl {
|
||||
}
|
||||
};
|
||||
|
||||
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
|
||||
/* package */ MediaRouter2ServiceImpl(Context context) {
|
||||
mContext = context;
|
||||
mActivityManager = mContext.getSystemService(ActivityManager.class);
|
||||
@@ -155,12 +170,28 @@ class MediaRouter2ServiceImpl {
|
||||
screenOnOffIntentFilter.addAction(ACTION_SCREEN_OFF);
|
||||
|
||||
mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter);
|
||||
mContext.getPackageManager().addOnPermissionsChangeListener(this::onPermissionsChanged);
|
||||
|
||||
DeviceConfig.addOnPropertiesChangedListener(MEDIA_BETTER_TOGETHER_NAMESPACE,
|
||||
ActivityThread.currentApplication().getMainExecutor(),
|
||||
this::onDeviceConfigChange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when there's a change in the permissions of an app.
|
||||
*
|
||||
* @param uid The uid of the app whose permissions changed.
|
||||
*/
|
||||
private void onPermissionsChanged(int uid) {
|
||||
synchronized (mLock) {
|
||||
Optional<RouterRecord> affectedRouter =
|
||||
mAllRouterRecords.values().stream().filter(it -> it.mUid == uid).findFirst();
|
||||
if (affectedRouter.isPresent()) {
|
||||
affectedRouter.get().maybeUpdateSystemRoutingPermissionLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start of methods that implement MediaRouter2 operations.
|
||||
|
||||
@NonNull
|
||||
@@ -1511,6 +1542,7 @@ class MediaRouter2ServiceImpl {
|
||||
public final int mPid;
|
||||
public final boolean mHasConfigureWifiDisplayPermission;
|
||||
public final boolean mHasModifyAudioRoutingPermission;
|
||||
public final AtomicBoolean mHasBluetoothRoutingPermission;
|
||||
public final int mRouterId;
|
||||
|
||||
public RouteDiscoveryPreference mDiscoveryPreference;
|
||||
@@ -1528,15 +1560,47 @@ class MediaRouter2ServiceImpl {
|
||||
mPid = pid;
|
||||
mHasConfigureWifiDisplayPermission = hasConfigureWifiDisplayPermission;
|
||||
mHasModifyAudioRoutingPermission = hasModifyAudioRoutingPermission;
|
||||
mHasBluetoothRoutingPermission = new AtomicBoolean(fetchBluetoothPermission());
|
||||
mRouterId = mNextRouterOrManagerId.getAndIncrement();
|
||||
}
|
||||
|
||||
private boolean fetchBluetoothPermission() {
|
||||
boolean hasBluetoothRoutingPermission = true;
|
||||
for (String permission : BLUETOOTH_PERMISSIONS_FOR_SYSTEM_ROUTING) {
|
||||
hasBluetoothRoutingPermission &=
|
||||
mContext.checkPermission(permission, mPid, mUid)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
return hasBluetoothRoutingPermission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the corresponding router has permission to query and control system
|
||||
* routes.
|
||||
*/
|
||||
public boolean hasSystemRoutingPermission() {
|
||||
return mHasModifyAudioRoutingPermission;
|
||||
return mHasModifyAudioRoutingPermission || mHasBluetoothRoutingPermission.get();
|
||||
}
|
||||
|
||||
public void maybeUpdateSystemRoutingPermissionLocked() {
|
||||
boolean oldSystemRoutingPermissionValue = hasSystemRoutingPermission();
|
||||
mHasBluetoothRoutingPermission.set(fetchBluetoothPermission());
|
||||
boolean newSystemRoutingPermissionValue = hasSystemRoutingPermission();
|
||||
if (oldSystemRoutingPermissionValue != newSystemRoutingPermissionValue) {
|
||||
Map<String, MediaRoute2Info> routesToReport =
|
||||
newSystemRoutingPermissionValue
|
||||
? mUserRecord.mHandler.mLastNotifiedRoutesToPrivilegedRouters
|
||||
: mUserRecord.mHandler.mLastNotifiedRoutesToNonPrivilegedRouters;
|
||||
notifyRoutesUpdated(routesToReport.values().stream().toList());
|
||||
|
||||
List<RoutingSessionInfo> sessionInfos =
|
||||
mUserRecord.mHandler.mSystemProvider.getSessionInfos();
|
||||
RoutingSessionInfo systemSessionToReport =
|
||||
newSystemRoutingPermissionValue && !sessionInfos.isEmpty()
|
||||
? sessionInfos.get(0)
|
||||
: mUserRecord.mHandler.mSystemProvider.getDefaultSessionInfo();
|
||||
notifySessionInfoChanged(systemSessionToReport);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
@@ -1559,6 +1623,14 @@ class MediaRouter2ServiceImpl {
|
||||
pw.println(indent + "mPid=" + mPid);
|
||||
pw.println(indent + "mHasConfigureWifiDisplayPermission="
|
||||
+ mHasConfigureWifiDisplayPermission);
|
||||
pw.println(
|
||||
indent
|
||||
+ "mHasModifyAudioRoutingPermission="
|
||||
+ mHasModifyAudioRoutingPermission);
|
||||
pw.println(
|
||||
indent
|
||||
+ "mHasBluetoothRoutingPermission="
|
||||
+ mHasBluetoothRoutingPermission.get());
|
||||
pw.println(indent + "hasSystemRoutingPermission=" + hasSystemRoutingPermission());
|
||||
pw.println(indent + "mRouterId=" + mRouterId);
|
||||
|
||||
@@ -1580,6 +1652,19 @@ class MediaRouter2ServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the corresponding router an update for the given session.
|
||||
*
|
||||
* <p>Note: These updates are not directly visible to the app.
|
||||
*/
|
||||
public void notifySessionInfoChanged(RoutingSessionInfo sessionInfo) {
|
||||
try {
|
||||
mRouter.notifySessionInfoChanged(sessionInfo);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify session info changed. Router probably died.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered copy of {@code routes} that contains only the routes that are {@link
|
||||
* MediaRoute2Info#isVisibleTo visible} to the router corresponding to this record.
|
||||
@@ -2471,11 +2556,7 @@ class MediaRouter2ServiceImpl {
|
||||
@NonNull List<RouterRecord> routerRecords,
|
||||
@NonNull RoutingSessionInfo sessionInfo) {
|
||||
for (RouterRecord routerRecord : routerRecords) {
|
||||
try {
|
||||
routerRecord.mRouter.notifySessionInfoChanged(sessionInfo);
|
||||
} catch (RemoteException ex) {
|
||||
Slog.w(TAG, "Failed to notify session info changed. Router probably died.", ex);
|
||||
}
|
||||
routerRecord.notifySessionInfoChanged(sessionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.media;
|
||||
|
||||
import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
@@ -137,6 +138,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
|
||||
private final String mDefaultAudioRouteId;
|
||||
private final String mBluetoothA2dpRouteId;
|
||||
|
||||
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
|
||||
public MediaRouterService(Context context) {
|
||||
mService2 = new MediaRouter2ServiceImpl(context);
|
||||
mContext = context;
|
||||
|
||||
@@ -55,7 +55,6 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
|
||||
SystemMediaRoute2Provider.class.getPackage().getName(),
|
||||
SystemMediaRoute2Provider.class.getName());
|
||||
|
||||
static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE";
|
||||
static final String SYSTEM_SESSION_ID = "SYSTEM_SESSION";
|
||||
|
||||
private final AudioManager mAudioManager;
|
||||
@@ -170,7 +169,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
|
||||
Bundle sessionHints) {
|
||||
// Assume a router without MODIFY_AUDIO_ROUTING permission can't request with
|
||||
// a route ID different from the default route ID. The service should've filtered.
|
||||
if (TextUtils.equals(routeId, DEFAULT_ROUTE_ID)) {
|
||||
if (TextUtils.equals(routeId, MediaRoute2Info.ROUTE_ID_DEFAULT)) {
|
||||
mCallback.onSessionCreated(this, requestId, mDefaultSessionInfo);
|
||||
return;
|
||||
}
|
||||
@@ -213,7 +212,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
|
||||
|
||||
@Override
|
||||
public void transferToRoute(long requestId, String sessionId, String routeId) {
|
||||
if (TextUtils.equals(routeId, DEFAULT_ROUTE_ID)) {
|
||||
if (TextUtils.equals(routeId, MediaRoute2Info.ROUTE_ID_DEFAULT)) {
|
||||
// The currently selected route is the default route.
|
||||
return;
|
||||
}
|
||||
@@ -326,10 +325,11 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
|
||||
builder.addTransferableRoute(deviceRoute.getId());
|
||||
}
|
||||
mSelectedRouteId = selectedRoute.getId();
|
||||
mDefaultRoute = new MediaRoute2Info.Builder(DEFAULT_ROUTE_ID, selectedRoute)
|
||||
.setSystemRoute(true)
|
||||
.setProviderId(mUniqueId)
|
||||
.build();
|
||||
mDefaultRoute =
|
||||
new MediaRoute2Info.Builder(MediaRoute2Info.ROUTE_ID_DEFAULT, selectedRoute)
|
||||
.setSystemRoute(true)
|
||||
.setProviderId(mUniqueId)
|
||||
.build();
|
||||
builder.addSelectedRoute(mSelectedRouteId);
|
||||
|
||||
for (MediaRoute2Info route : mBluetoothRouteController.getTransferableRoutes()) {
|
||||
@@ -363,12 +363,13 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
|
||||
}
|
||||
mSessionInfos.clear();
|
||||
mSessionInfos.add(newSessionInfo);
|
||||
mDefaultSessionInfo = new RoutingSessionInfo.Builder(
|
||||
SYSTEM_SESSION_ID, "" /* clientPackageName */)
|
||||
.setProviderId(mUniqueId)
|
||||
.setSystemSession(true)
|
||||
.addSelectedRoute(DEFAULT_ROUTE_ID)
|
||||
.build();
|
||||
mDefaultSessionInfo =
|
||||
new RoutingSessionInfo.Builder(
|
||||
SYSTEM_SESSION_ID, "" /* clientPackageName */)
|
||||
.setProviderId(mUniqueId)
|
||||
.setSystemSession(true)
|
||||
.addSelectedRoute(MediaRoute2Info.ROUTE_ID_DEFAULT)
|
||||
.build();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user