From 1ca9e0024b3bd13181b56785fd8e7989a8e08b09 Mon Sep 17 00:00:00 2001 From: bachinger Date: Thu, 11 May 2023 16:30:57 +0100 Subject: [PATCH] Remove static MediaSessionImpl.serviceComponentName An app must only have a single service in the manifest that is either exposing `MediaLibraryService.SERVICE_INTERFACE` or `MediaSessionService.SERVICE_INTERFACE`. Hence the component name found by querying the package manager for a service never returns a different result when queried again. The static `MediaSessionImpl.serviceComponentName` can hence be removed and the package manager queried again when a second session instance is created. #minor-release PiperOrigin-RevId: 531210456 --- .../media3/session/MediaSessionImpl.java | 44 +------------------ .../session/MediaSessionLegacyStub.java | 31 ++++++++++--- 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index dcd9ddcb6b..e82f64fc47 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -24,11 +24,8 @@ import static androidx.media3.session.SessionResult.RESULT_INFO_SKIPPED; import static java.lang.Math.min; import android.app.PendingIntent; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Bundle; import android.os.DeadObjectException; @@ -89,24 +86,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /* package */ class MediaSessionImpl { - // Create a static lock for synchronize methods below. - // We'd better not use MediaSessionImplBase.class for synchronized(), which indirectly exposes - // lock object to the outside of the class. - private static final Object STATIC_LOCK = new Object(); - private static final String WRONG_THREAD_ERROR_MESSAGE = "Player callback method is called from a wrong thread. " + "See javadoc of MediaSession for details."; private static final long DEFAULT_SESSION_POSITION_UPDATE_DELAY_MS = 3_000; - @GuardedBy("STATIC_LOCK") - private static boolean componentNamesInitialized = false; - - @GuardedBy("STATIC_LOCK") - @Nullable - private static ComponentName serviceComponentName; - public static final String TAG = "MSImplBase"; private static final SessionResult RESULT_WHEN_CLOSED = new SessionResult(RESULT_INFO_SKIPPED); @@ -198,21 +183,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; sessionStub, tokenExtras); - synchronized (STATIC_LOCK) { - if (!componentNamesInitialized) { - MediaSessionImpl.serviceComponentName = - getServiceComponentByAction(context, MediaLibraryService.SERVICE_INTERFACE); - if (MediaSessionImpl.serviceComponentName == null) { - MediaSessionImpl.serviceComponentName = - getServiceComponentByAction(context, MediaSessionService.SERVICE_INTERFACE); - } - componentNamesInitialized = true; - } - } - sessionLegacyStub = - new MediaSessionLegacyStub( - /* session= */ thisRef, sessionUri, serviceComponentName, applicationHandler); + new MediaSessionLegacyStub(/* session= */ thisRef, sessionUri, applicationHandler); PlayerWrapper playerWrapper = new PlayerWrapper(player); this.playerWrapper = playerWrapper; @@ -818,20 +790,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; sessionStub.getConnectedControllersManager().removeController(controller); } - @Nullable - @SuppressWarnings("QueryPermissionsNeeded") // Needs to be provided in the app manifest. - private static ComponentName getServiceComponentByAction(Context context, String action) { - PackageManager pm = context.getPackageManager(); - Intent queryIntent = new Intent(action); - queryIntent.setPackage(context.getPackageName()); - List resolveInfos = pm.queryIntentServices(queryIntent, /* flags= */ 0); - if (resolveInfos == null || resolveInfos.isEmpty()) { - return null; - } - ResolveInfo resolveInfo = resolveInfos.get(0); - return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); - } - private void verifyApplicationThread() { if (Looper.myLooper() != applicationHandler.getLooper()) { throw new IllegalStateException(WRONG_THREAD_ERROR_MESSAGE); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java index 210ba1abde..4c9dbf4353 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java @@ -136,11 +136,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; private int sessionFlags; @SuppressWarnings("PendingIntentMutability") // We can't use SaferPendingIntent - public MediaSessionLegacyStub( - MediaSessionImpl session, - Uri sessionUri, - @Nullable ComponentName serviceComponentName, - Handler handler) { + public MediaSessionLegacyStub(MediaSessionImpl session, Uri sessionUri, Handler handler) { sessionImpl = session; Context context = sessionImpl.getContext(); appPackageName = context.getPackageName(); @@ -159,8 +155,15 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; // Assume an app that intentionally puts a `MediaButtonReceiver` into the manifest has // implemented some kind of resumption of the last recently played media item. canResumePlaybackOnStart = receiverComponentName != null; + boolean isReceiverComponentAService = false; if (receiverComponentName == null) { - receiverComponentName = serviceComponentName; + receiverComponentName = + getServiceComponentByAction(context, MediaLibraryService.SERVICE_INTERFACE); + if (receiverComponentName == null) { + receiverComponentName = + getServiceComponentByAction(context, MediaSessionService.SERVICE_INTERFACE); + } + isReceiverComponentAService = receiverComponentName != null; } Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, sessionUri); PendingIntent mediaButtonIntent; @@ -181,7 +184,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } else { intent.setComponent(receiverComponentName); mediaButtonIntent = - Objects.equals(serviceComponentName, receiverComponentName) + isReceiverComponentAService ? (Util.SDK_INT >= 26 ? PendingIntent.getForegroundService( context, /* requestCode= */ 0, intent, PENDING_INTENT_FLAG_MUTABLE) @@ -1434,6 +1437,20 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; return "Failed to load bitmap: " + throwable.getMessage(); } + @Nullable + @SuppressWarnings("QueryPermissionsNeeded") // Needs to be provided in the app manifest. + private static ComponentName getServiceComponentByAction(Context context, String action) { + PackageManager pm = context.getPackageManager(); + Intent queryIntent = new Intent(action); + queryIntent.setPackage(context.getPackageName()); + List resolveInfos = pm.queryIntentServices(queryIntent, /* flags= */ 0); + if (resolveInfos == null || resolveInfos.isEmpty()) { + return null; + } + ResolveInfo resolveInfo = resolveInfos.get(0); + return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name); + } + // TODO(b/193193462): Replace this with androidx.media.session.MediaButtonReceiver private final class MediaButtonReceiver extends BroadcastReceiver {