diff --git a/services/core/java/com/android/server/media/MediaFeatureFlagManager.java b/services/core/java/com/android/server/media/MediaFeatureFlagManager.java index 70ee38f8f7b0f..f55550509f46a 100644 --- a/services/core/java/com/android/server/media/MediaFeatureFlagManager.java +++ b/services/core/java/com/android/server/media/MediaFeatureFlagManager.java @@ -17,6 +17,8 @@ package com.android.server.media; import android.annotation.StringDef; +import android.app.ActivityThread; +import android.app.Application; import android.provider.DeviceConfig; import java.lang.annotation.ElementType; @@ -31,10 +33,13 @@ import java.lang.annotation.Target; */ private static final String NAMESPACE_MEDIA_BETTER_TOGETHER = "media_better_together"; - @StringDef(prefix = "FEATURE_", value = { - FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER - }) - @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) + @StringDef( + prefix = "FEATURE_", + value = { + FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER, + FEATURE_SCANNING_MINIMUM_PACKAGE_IMPORTANCE + }) + @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @Retention(RetentionPolicy.SOURCE) /* package */ @interface MediaFeatureFlag {} @@ -46,6 +51,13 @@ import java.lang.annotation.Target; FEATURE_AUDIO_STRATEGIES_IS_USING_LEGACY_CONTROLLER = "BluetoothRouteController__enable_legacy_bluetooth_routes_controller"; + /** + * Whether to use IMPORTANCE_FOREGROUND (i.e. 100) or IMPORTANCE_FOREGROUND_SERVICE (i.e. 125) + * as the minimum package importance for scanning. + */ + /* package */ static final @MediaFeatureFlag String + FEATURE_SCANNING_MINIMUM_PACKAGE_IMPORTANCE = "scanning_package_minimum_importance"; + private static final MediaFeatureFlagManager sInstance = new MediaFeatureFlagManager(); private MediaFeatureFlagManager() { @@ -63,4 +75,29 @@ import java.lang.annotation.Target; public boolean getBoolean(@MediaFeatureFlag String key, boolean defaultValue) { return DeviceConfig.getBoolean(NAMESPACE_MEDIA_BETTER_TOGETHER, key, defaultValue); } + + /** + * Returns an int value from {@link DeviceConfig} from the system_time namespace, or {@code + * defaultValue} if there is no explicit value set. + */ + public int getInt(@MediaFeatureFlag String key, int defaultValue) { + return DeviceConfig.getInt(NAMESPACE_MEDIA_BETTER_TOGETHER, key, defaultValue); + } + + /** + * Adds a listener to react for changes in media feature flags values. Future calls to this + * method with the same listener will replace the old namespace and executor. + * + * @param onPropertiesChangedListener The listener to add. + */ + public void addOnPropertiesChangedListener( + DeviceConfig.OnPropertiesChangedListener onPropertiesChangedListener) { + Application currentApplication = ActivityThread.currentApplication(); + if (currentApplication != null) { + DeviceConfig.addOnPropertiesChangedListener( + NAMESPACE_MEDIA_BETTER_TOGETHER, + currentApplication.getMainExecutor(), + onPropertiesChangedListener); + } + } } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 3c97aaf87e9c5..087c5bb2fa489 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -24,12 +24,12 @@ import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getProviderId; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; +import static com.android.server.media.MediaFeatureFlagManager.FEATURE_SCANNING_MINIMUM_PACKAGE_IMPORTANCE; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.ActivityThread; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -92,15 +92,11 @@ class MediaRouter2ServiceImpl { // in MediaRouter2, remove this constant and replace the usages with the real request IDs. private static final long DUMMY_REQUEST_ID = -1; - private static final String MEDIA_BETTER_TOGETHER_NAMESPACE = "media_better_together"; - - private static final String KEY_SCANNING_PACKAGE_MINIMUM_IMPORTANCE = - "scanning_package_minimum_importance"; - - private static int sPackageImportanceForScanning = DeviceConfig.getInt( - MEDIA_BETTER_TOGETHER_NAMESPACE, - /* name */ KEY_SCANNING_PACKAGE_MINIMUM_IMPORTANCE, - /* defaultValue */ IMPORTANCE_FOREGROUND_SERVICE); + private static int sPackageImportanceForScanning = + MediaFeatureFlagManager.getInstance() + .getInt( + FEATURE_SCANNING_MINIMUM_PACKAGE_IMPORTANCE, + IMPORTANCE_FOREGROUND_SERVICE); private final Context mContext; private final UserManagerInternal mUserManagerInternal; @@ -156,9 +152,8 @@ class MediaRouter2ServiceImpl { mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter); - DeviceConfig.addOnPropertiesChangedListener(MEDIA_BETTER_TOGETHER_NAMESPACE, - ActivityThread.currentApplication().getMainExecutor(), - this::onDeviceConfigChange); + MediaFeatureFlagManager.getInstance() + .addOnPropertiesChangedListener(this::onDeviceConfigChange); } // Start of methods that implement MediaRouter2 operations. @@ -1002,9 +997,11 @@ class MediaRouter2ServiceImpl { return; } - Slog.i(TAG, TextUtils.formatSimple( - "setSessionVolumeWithRouter2 | router: %d, session: %s, volume: %d", - routerRecord.mRouterId, uniqueSessionId, volume)); + Slog.i( + TAG, + TextUtils.formatSimple( + "setSessionVolumeWithRouter2 | router: %d, session: %s, volume: %d", + routerRecord.mRouterId, uniqueSessionId, volume)); routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::setSessionVolumeOnHandler, @@ -1021,9 +1018,11 @@ class MediaRouter2ServiceImpl { return; } - Slog.i(TAG, TextUtils.formatSimple( - "releaseSessionWithRouter2 | router: %d, session: %s", - routerRecord.mRouterId, uniqueSessionId)); + Slog.i( + TAG, + TextUtils.formatSimple( + "releaseSessionWithRouter2 | router: %d, session: %s", + routerRecord.mRouterId, uniqueSessionId)); routerRecord.mUserRecord.mHandler.sendMessage( obtainMessage(UserHandler::releaseSessionOnHandler, @@ -1100,8 +1099,11 @@ class MediaRouter2ServiceImpl { // TODO: UserRecord <-> routerRecord, why do they reference each other? // How about removing mUserRecord from routerRecord? routerRecord.mUserRecord.mHandler.sendMessage( - obtainMessage(UserHandler::notifyDiscoveryPreferenceChangedToManager, - routerRecord.mUserRecord.mHandler, routerRecord, manager)); + obtainMessage( + UserHandler::notifyDiscoveryPreferenceChangedToManager, + routerRecord.mUserRecord.mHandler, + routerRecord, + manager)); } userRecord.mHandler.sendMessage( @@ -1381,9 +1383,10 @@ class MediaRouter2ServiceImpl { // End of locked methods that are used by both MediaRouter2 and MediaRouter2Manager. private void onDeviceConfigChange(@NonNull DeviceConfig.Properties properties) { - sPackageImportanceForScanning = properties.getInt( - /* name */ KEY_SCANNING_PACKAGE_MINIMUM_IMPORTANCE, - /* defaultValue */ IMPORTANCE_FOREGROUND_SERVICE); + sPackageImportanceForScanning = + properties.getInt( + /* name */ FEATURE_SCANNING_MINIMUM_PACKAGE_IMPORTANCE, + /* defaultValue */ IMPORTANCE_FOREGROUND_SERVICE); } static long toUniqueRequestId(int requesterId, int originalRequestId) { @@ -1734,10 +1737,10 @@ class MediaRouter2ServiceImpl { } boolean isUidRelevant; synchronized (service.mLock) { - isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch( - router -> router.mUid == uid) - | mUserRecord.mManagerRecords.stream().anyMatch( - manager -> manager.mUid == uid); + isUidRelevant = + mUserRecord.mRouterRecords.stream().anyMatch(router -> router.mUid == uid) + | mUserRecord.mManagerRecords.stream() + .anyMatch(manager -> manager.mUid == uid); } if (isUidRelevant) { sendMessage(PooledLambda.obtainMessage( @@ -2400,7 +2403,7 @@ class MediaRouter2ServiceImpl { private static void notifyRoutesUpdatedToRouterRecords( @NonNull List routerRecords, @NonNull List routes) { - for (RouterRecord routerRecord: routerRecords) { + for (RouterRecord routerRecord : routerRecords) { List filteredRoutes = getFilteredRoutesForPackageName(routes, routerRecord.mPackageName); try { @@ -2412,15 +2415,15 @@ class MediaRouter2ServiceImpl { } /** - * Filters list of routes to return only public routes or routes provided by - * the same package name or routes containing this package name in its allow list. + * Filters list of routes to return only public routes or routes provided by the same + * package name or routes containing this package name in its allow list. + * * @param routes initial list of routes to be filtered. * @param packageName router's package name to filter routes for it. * @return only the routes that this package name is allowed to see. */ private static List getFilteredRoutesForPackageName( - @NonNull List routes, - @NonNull String packageName) { + @NonNull List routes, @NonNull String packageName) { List filteredRoutes = new ArrayList<>(); for (MediaRoute2Info route : routes) { if (route.isVisibleTo(packageName)) { @@ -2609,11 +2612,15 @@ class MediaRouter2ServiceImpl { .map(record -> record.mDiscoveryPreference) .collect(Collectors.toList()); } else { - discoveryPreferences = routerRecords.stream().filter(record -> - service.mActivityManager.getPackageImportance(record.mPackageName) - <= sPackageImportanceForScanning) - .map(record -> record.mDiscoveryPreference) - .collect(Collectors.toList()); + discoveryPreferences = + routerRecords.stream() + .filter( + record -> + service.mActivityManager.getPackageImportance( + record.mPackageName) + <= sPackageImportanceForScanning) + .map(record -> record.mDiscoveryPreference) + .collect(Collectors.toList()); } } @@ -2658,6 +2665,7 @@ class MediaRouter2ServiceImpl { return null; } } + static final class SessionCreationRequest { public final RouterRecord mRouterRecord; public final long mUniqueRequestId;