diff options
7 files changed, 390 insertions, 30 deletions
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING index 954ee3c99346..dae9b5ea6a43 100644 --- a/core/java/android/os/TEST_MAPPING +++ b/core/java/android/os/TEST_MAPPING @@ -27,6 +27,19 @@ ] }, { + "file_patterns": [ + "[^/]*(Vibrator|Vibration)[^/]*\\.java", + "vibrator/.*" + ], + "name": "CtsVibratorTestCases", + "options": [ + {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, + {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"}, + {"exclude-annotation": "org.junit.Ignore"} + ] + }, + { "file_patterns": ["Bugreport[^/]*\\.java"], "name": "BugreportManagerTestCases", "options": [ diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 7e275607e36f..1ea155a6a623 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -82,6 +82,13 @@ public abstract class InfoMediaManager extends MediaManager { private static final String TAG = "InfoMediaManager"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + /** Checked exception that signals the specified package is not present in the system. */ + public static class PackageNotAvailableException extends Exception { + public PackageNotAvailableException(String message) { + super(message); + } + } + protected String mPackageName; private MediaDevice mCurrentConnectedDevice; private final LocalBluetoothManager mBluetoothManager; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java new file mode 100644 index 000000000000..70956e9221e2 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2023 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 com.android.settingslib.media; + +import android.annotation.SuppressLint; +import android.app.Notification; +import android.content.Context; +import android.media.MediaRoute2Info; +import android.media.MediaRouter2; +import android.media.MediaRouter2.RoutingController; +import android.media.MediaRouter2Manager; +import android.media.RouteDiscoveryPreference; +import android.media.RouteListingPreference; +import android.media.RoutingSessionInfo; +import android.text.TextUtils; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.settingslib.bluetooth.LocalBluetoothManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +/** Implements {@link InfoMediaManager} using {@link MediaRouter2}. */ +@SuppressLint("MissingPermission") +public final class RouterInfoMediaManager extends InfoMediaManager { + + private static final String TAG = "RouterInfoMediaManager"; + + private final MediaRouter2 mRouter; + private final MediaRouter2Manager mRouterManager; + + private final Executor mExecutor = Executors.newSingleThreadExecutor(); + + private final RouteCallback mRouteCallback = new RouteCallback(); + private final TransferCallback mTransferCallback = new TransferCallback(); + private final ControllerCallback mControllerCallback = new ControllerCallback(); + private final RouteListingPreferenceCallback mRouteListingPreferenceCallback = + new RouteListingPreferenceCallback(); + + // TODO: b/192657812 - Create factory method in InfoMediaManager to return + // RouterInfoMediaManager or ManagerInfoMediaManager based on flag. + public RouterInfoMediaManager( + Context context, + String packageName, + Notification notification, + LocalBluetoothManager localBluetoothManager) throws PackageNotAvailableException { + super(context, packageName, notification, localBluetoothManager); + + // TODO: b/291277292 - Change optional package name for a mandatory uid. + if (packageName == null) { + packageName = context.getPackageName(); + } + + mRouter = MediaRouter2.getInstance(context, packageName); + + if (mRouter == null) { + throw new PackageNotAvailableException( + "Package name " + packageName + " does not exist."); + } + mRouterManager = MediaRouter2Manager.getInstance(context); + } + + @Override + protected void startScanOnRouter() { + mRouter.registerRouteCallback(mExecutor, mRouteCallback, RouteDiscoveryPreference.EMPTY); + mRouter.registerRouteListingPreferenceCallback(mExecutor, mRouteListingPreferenceCallback); + mRouter.registerTransferCallback(mExecutor, mTransferCallback); + mRouter.registerControllerCallback(mExecutor, mControllerCallback); + mRouter.startScan(); + } + + @Override + public void stopScan() { + mRouter.stopScan(); + mRouter.unregisterControllerCallback(mControllerCallback); + mRouter.unregisterTransferCallback(mTransferCallback); + mRouter.unregisterRouteListingPreferenceCallback(mRouteListingPreferenceCallback); + mRouter.unregisterRouteCallback(mRouteCallback); + } + + @Override + protected boolean connectDeviceWithoutPackageName(@NonNull MediaDevice device) { + if (device.mRouteInfo == null) { + return false; + } + + RoutingController controller = mRouter.getSystemController(); + mRouter.transfer(controller, device.mRouteInfo); + return true; + } + + @Override + protected void transferToRoute(@NonNull MediaRoute2Info route) { + mRouter.transferTo(route); + } + + @Override + protected void selectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { + RoutingController controller = getControllerForSession(info); + if (controller != null) { + controller.selectRoute(route); + } + } + + @Override + protected void deselectRoute(@NonNull MediaRoute2Info route, @NonNull RoutingSessionInfo info) { + RoutingController controller = getControllerForSession(info); + if (controller != null) { + controller.deselectRoute(route); + } + } + + @Override + protected void releaseSession(@NonNull RoutingSessionInfo sessionInfo) { + RoutingController controller = getControllerForSession(sessionInfo); + if (controller != null) { + controller.release(); + } + } + + @NonNull + @Override + protected List<MediaRoute2Info> getSelectableRoutes(@NonNull RoutingSessionInfo info) { + RoutingController controller = getControllerForSession(info); + if (controller == null) { + return Collections.emptyList(); + } + + // Filter out selected routes. + List<String> selectedRouteIds = controller.getRoutingSessionInfo().getSelectedRoutes(); + return controller.getSelectableRoutes().stream() + .filter(route -> !selectedRouteIds.contains(route.getId())) + .collect(Collectors.toList()); + } + + @NonNull + @Override + protected List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo info) { + RoutingController controller = getControllerForSession(info); + if (controller == null) { + return Collections.emptyList(); + } + + return controller.getDeselectableRoutes(); + } + + @NonNull + @Override + protected List<MediaRoute2Info> getSelectedRoutes(@NonNull RoutingSessionInfo info) { + RoutingController controller = getControllerForSession(info); + if (controller == null) { + return Collections.emptyList(); + } + return controller.getSelectedRoutes(); + } + + @Override + protected void setSessionVolume(@NonNull RoutingSessionInfo info, int volume) { + // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager call as + // MR2 filters information by package name. + mRouterManager.setSessionVolume(info, volume); + } + + @Override + protected void setRouteVolume(@NonNull MediaRoute2Info route, int volume) { + mRouter.setRouteVolume(route, volume); + } + + @Nullable + @Override + protected RouteListingPreference getRouteListingPreference() { + return mRouter.getRouteListingPreference(); + } + + @NonNull + @Override + protected List<RoutingSessionInfo> getRemoteSessions() { + // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager call as + // MR2 filters information by package name. + return mRouterManager.getRemoteSessions(); + } + + @NonNull + @Override + protected List<RoutingSessionInfo> getRoutingSessionsForPackage() { + return mRouter.getControllers().stream() + .map(RoutingController::getRoutingSessionInfo) + .collect(Collectors.toList()); + } + + @Nullable + @Override + protected RoutingSessionInfo getRoutingSessionById(@NonNull String sessionId) { + // TODO: b/291277292 - Implement MediaRouter2-based solution. Keeping MR2Manager calls as + // MR2 filters information by package name. + + for (RoutingSessionInfo sessionInfo : getRemoteSessions()) { + if (TextUtils.equals(sessionInfo.getId(), sessionId)) { + return sessionInfo; + } + } + + RoutingSessionInfo systemSession = mRouterManager.getSystemRoutingSession(null); + return TextUtils.equals(systemSession.getId(), sessionId) ? systemSession : null; + } + + @NonNull + @Override + protected List<MediaRoute2Info> getAllRoutes() { + return mRouter.getAllRoutes(); + } + + @NonNull + @Override + protected List<MediaRoute2Info> getAvailableRoutesFromRouter() { + return mRouter.getRoutes(); + } + + @NonNull + @Override + protected List<MediaRoute2Info> getTransferableRoutes(@NonNull String packageName) { + List<MediaRoute2Info> transferableRoutes = new ArrayList<>(); + + List<RoutingController> controllers = mRouter.getControllers(); + RoutingController activeController = controllers.get(controllers.size() - 1); + RoutingSessionInfo sessionInfo = activeController.getRoutingSessionInfo(); + List<MediaRoute2Info> routes = mRouter.getRoutes(); + + for (MediaRoute2Info route : routes) { + boolean isCrossDeviceTransfer = sessionInfo.isSystemSession() ^ route.isSystemRoute(); + + // Always show remote routes if transfer is local -> remote or viceversa regardless of + // whether route is in transferable routes list. + if (sessionInfo.getTransferableRoutes().contains(route.getId()) + || isCrossDeviceTransfer) { + transferableRoutes.add(route); + } + } + + return transferableRoutes; + } + + @Nullable + private RoutingController getControllerForSession(@NonNull RoutingSessionInfo sessionInfo) { + return mRouter.getController(sessionInfo.getId()); + } + + private final class RouteCallback extends MediaRouter2.RouteCallback { + @Override + public void onRoutesUpdated(@NonNull List<MediaRoute2Info> routes) { + refreshDevices(); + } + + @Override + public void onPreferredFeaturesChanged(@NonNull List<String> preferredFeatures) { + refreshDevices(); + } + } + + private final class TransferCallback extends MediaRouter2.TransferCallback { + @Override + public void onTransfer( + @NonNull RoutingController oldController, + @NonNull RoutingController newController) { + rebuildDeviceList(); + notifyCurrentConnectedDeviceChanged(); + } + + @Override + public void onTransferFailure(@NonNull MediaRoute2Info requestedRoute) { + // Do nothing. + } + + @Override + public void onStop(@NonNull RoutingController controller) { + refreshDevices(); + } + + @Override + public void onRequestFailed(int reason) { + dispatchOnRequestFailed(reason); + } + } + + private final class ControllerCallback extends MediaRouter2.ControllerCallback { + @Override + public void onControllerUpdated(@NonNull RoutingController controller) { + refreshDevices(); + } + } + + private final class RouteListingPreferenceCallback + extends MediaRouter2.RouteListingPreferenceCallback { + @Override + public void onRouteListingPreferenceChanged(@Nullable RouteListingPreference preference) { + notifyRouteListingPreferenceUpdated(preference); + refreshDevices(); + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java index 708bb5507f10..19315803c740 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java @@ -98,8 +98,6 @@ import java.util.List; @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) public class MediaOutputControllerTest extends SysuiTestCase { - - private static final String TEST_PACKAGE_NAME = "com.test.package.name"; private static final String TEST_DEVICE_1_ID = "test_device_1_id"; private static final String TEST_DEVICE_2_ID = "test_device_2_id"; private static final String TEST_DEVICE_3_ID = "test_device_3_id"; @@ -167,6 +165,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { final Notification mNotification = mock(Notification.class); private Context mSpyContext; + private String mPackageName = null; private MediaOutputController mMediaOutputController; private LocalMediaManager mLocalMediaManager; private List<MediaController> mMediaControllers = new ArrayList<>(); @@ -177,12 +176,14 @@ public class MediaOutputControllerTest extends SysuiTestCase { @Before public void setUp() { + mPackageName = mContext.getPackageName(); + MockitoAnnotations.initMocks(this); mContext.setMockPackageManager(mPackageManager); mSpyContext = spy(mContext); final UserHandle userHandle = mock(UserHandle.class); when(mUserTracker.getUserHandle()).thenReturn(userHandle); - when(mSessionMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(mSessionMediaController.getPackageName()).thenReturn(mPackageName); when(mSessionMediaController.getPlaybackState()).thenReturn(mPlaybackState); mMediaControllers.add(mSessionMediaController); when(mMediaSessionManager.getActiveSessionsForUser(any(), @@ -193,7 +194,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn( mCachedBluetoothDeviceManager); - mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, + mMediaOutputController = new MediaOutputController(mSpyContext, mPackageName, mMediaSessionManager, mLocalBluetoothManager, mStarter, mNotifCollection, mDialogLaunchAnimator, mNearbyMediaDevicesManager, mAudioManager, mPowerExemptionManager, @@ -231,7 +232,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mNotifCollection.getAllNotifs()).thenReturn(entryList); when(entry.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(mNotification); - when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(sbn.getPackageName()).thenReturn(mPackageName); mNotification.extras = bundle; when(bundle.getParcelable(Notification.EXTRA_MEDIA_SESSION, MediaSession.Token.class)).thenReturn(token); @@ -339,8 +340,8 @@ public class MediaOutputControllerTest extends SysuiTestCase { public void tryToLaunchMediaApplication_intentNotNull_startActivity() { when(mDialogLaunchAnimator.createActivityLaunchController(any(View.class))).thenReturn( mController); - Intent intent = new Intent(TEST_PACKAGE_NAME); - doReturn(intent).when(mPackageManager).getLaunchIntentForPackage(TEST_PACKAGE_NAME); + Intent intent = new Intent(mPackageName); + doReturn(intent).when(mPackageManager).getLaunchIntentForPackage(mPackageName); mMediaOutputController.start(mCallback); mMediaOutputController.tryToLaunchMediaApplication(mDialogLaunchView); @@ -355,7 +356,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { mController); mMediaOutputController.start(mCallback); when(mLocalMediaManager.getLinkedItemComponentName()).thenReturn( - new ComponentName(TEST_PACKAGE_NAME, "")); + new ComponentName(mPackageName, "")); mMediaOutputController.tryToLaunchInAppRoutingIntent(TEST_DEVICE_1_ID, mDialogLaunchView); @@ -891,7 +892,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mNotifCollection.getAllNotifs()).thenReturn(entryList); when(entry.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(notification); - when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(sbn.getPackageName()).thenReturn(mPackageName); when(notification.isMediaNotification()).thenReturn(true); when(notification.getLargeIcon()).thenReturn(null); @@ -910,7 +911,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mNotifCollection.getAllNotifs()).thenReturn(entryList); when(entry.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(notification); - when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(sbn.getPackageName()).thenReturn(mPackageName); when(notification.isMediaNotification()).thenReturn(true); when(notification.getLargeIcon()).thenReturn(icon); @@ -929,7 +930,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mNotifCollection.getAllNotifs()).thenReturn(entryList); when(entry.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(notification); - when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(sbn.getPackageName()).thenReturn(mPackageName); when(notification.isMediaNotification()).thenReturn(false); when(notification.getLargeIcon()).thenReturn(icon); @@ -947,7 +948,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mNotifCollection.getAllNotifs()).thenReturn(entryList); when(entry.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(notification); - when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(sbn.getPackageName()).thenReturn(mPackageName); when(notification.isMediaNotification()).thenReturn(true); when(notification.getSmallIcon()).thenReturn(null); @@ -966,7 +967,7 @@ public class MediaOutputControllerTest extends SysuiTestCase { when(mNotifCollection.getAllNotifs()).thenReturn(entryList); when(entry.getSbn()).thenReturn(sbn); when(sbn.getNotification()).thenReturn(notification); - when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME); + when(sbn.getPackageName()).thenReturn(mPackageName); when(notification.isMediaNotification()).thenReturn(true); when(notification.getSmallIcon()).thenReturn(icon); diff --git a/services/core/java/com/android/server/vibrator/TEST_MAPPING b/services/core/java/com/android/server/vibrator/TEST_MAPPING index f0a7e470f8fd..92b327d9abff 100644 --- a/services/core/java/com/android/server/vibrator/TEST_MAPPING +++ b/services/core/java/com/android/server/vibrator/TEST_MAPPING @@ -1,21 +1,10 @@ { - "presubmit": [ + "imports": [ { - "name": "FrameworksVibratorServicesTests", - "options": [ - {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, - {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, - {"exclude-annotation": "androidx.test.filters.FlakyTest"}, - {"exclude-annotation": "org.junit.Ignore"} - ] - } - ], - "postsubmit": [ + "path": "frameworks/base/services/tests/vibrator" + }, { - "name": "FrameworksVibratorServicesTests", - "options": [ - {"exclude-annotation": "org.junit.Ignore"} - ] + "path": "cts/tests/vibrator" } ] } diff --git a/services/core/jni/TEST_MAPPING b/services/core/jni/TEST_MAPPING new file mode 100644 index 000000000000..ea44d06b9fc3 --- /dev/null +++ b/services/core/jni/TEST_MAPPING @@ -0,0 +1,16 @@ +{ + "presubmit": [ + { + "file_patterns": [ + "[^/]*(vibrator)[^/]*\\.[^/]*" + ], + "name": "CtsVibratorTestCases", + "options": [ + {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, + {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"}, + {"exclude-annotation": "org.junit.Ignore"} + ] + } + ] +} diff --git a/services/tests/vibrator/TEST_MAPPING b/services/tests/vibrator/TEST_MAPPING index 22b72fa4ff9e..f0a7e470f8fd 100644 --- a/services/tests/vibrator/TEST_MAPPING +++ b/services/tests/vibrator/TEST_MAPPING @@ -1,7 +1,21 @@ { - "imports": [ + "presubmit": [ { - "path": "frameworks/base/services/core/java/com/android/server/vibrator" + "name": "FrameworksVibratorServicesTests", + "options": [ + {"exclude-annotation": "android.platform.test.annotations.LargeTest"}, + {"exclude-annotation": "android.platform.test.annotations.FlakyTest"}, + {"exclude-annotation": "androidx.test.filters.FlakyTest"}, + {"exclude-annotation": "org.junit.Ignore"} + ] + } + ], + "postsubmit": [ + { + "name": "FrameworksVibratorServicesTests", + "options": [ + {"exclude-annotation": "org.junit.Ignore"} + ] } ] } |