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
This commit is contained in:
bachinger 2023-05-11 16:30:57 +01:00 committed by Ian Baker
parent 674885cfa5
commit 1ca9e0024b
2 changed files with 25 additions and 50 deletions

View File

@ -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<ResolveInfo> 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);

View File

@ -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<ResolveInfo> 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 {