Add support for SELF_SCAN_ONLY providers
Bug: 278249714 Test: atest CtsMediaBetterTogetherTestCases Change-Id: If24d505e889f933a9b4512b3aa5be0a2c91dc1ee Merged-In: If24d505e889f933a9b4512b3aa5be0a2c91dc1ee
This commit is contained in:
@@ -80,6 +80,18 @@ public abstract class MediaRoute2ProviderService extends Service {
|
||||
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
|
||||
public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService";
|
||||
|
||||
/**
|
||||
* A category indicating that the associated provider is only intended for use within the app
|
||||
* that hosts the provider.
|
||||
*
|
||||
* <p>Declaring this category helps the system save resources by avoiding the launch of services
|
||||
* whose routes are known to be private to the app that provides them.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String CATEGORY_SELF_SCAN_ONLY =
|
||||
"android.media.MediaRoute2ProviderService.SELF_SCAN_ONLY";
|
||||
|
||||
/**
|
||||
* The request ID to pass {@link #notifySessionCreated(long, RoutingSessionInfo)}
|
||||
* when {@link MediaRoute2ProviderService} created a session although there was no creation
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
abstract class MediaRoute2Provider {
|
||||
final ComponentName mComponentName;
|
||||
@@ -56,7 +57,9 @@ abstract class MediaRoute2Provider {
|
||||
public abstract void requestCreateSession(long requestId, String packageName, String routeId,
|
||||
@Nullable Bundle sessionHints);
|
||||
public abstract void releaseSession(long requestId, String sessionId);
|
||||
public abstract void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference);
|
||||
|
||||
public abstract void updateDiscoveryPreference(
|
||||
Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference);
|
||||
|
||||
public abstract void selectRoute(long requestId, String sessionId, String routeId);
|
||||
public abstract void deselectRoute(long requestId, String sessionId, String routeId);
|
||||
|
||||
@@ -49,6 +49,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Maintains a connection to a particular {@link MediaRoute2ProviderService}.
|
||||
@@ -61,6 +62,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
private final Context mContext;
|
||||
private final int mUserId;
|
||||
private final Handler mHandler;
|
||||
private final boolean mIsSelfScanOnlyProvider;
|
||||
|
||||
// Connection state
|
||||
private boolean mRunning;
|
||||
@@ -70,14 +72,19 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
|
||||
private boolean mIsManagerScanning;
|
||||
private RouteDiscoveryPreference mLastDiscoveryPreference = null;
|
||||
private boolean mLastDiscoveryPreferenceIncludesThisPackage = false;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
final List<RoutingSessionInfo> mReleasingSessions = new ArrayList<>();
|
||||
|
||||
MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
|
||||
MediaRoute2ProviderServiceProxy(
|
||||
@NonNull Context context,
|
||||
@NonNull ComponentName componentName,
|
||||
boolean isSelfScanOnlyProvider,
|
||||
int userId) {
|
||||
super(componentName);
|
||||
mContext = Objects.requireNonNull(context, "Context must not be null.");
|
||||
mIsSelfScanOnlyProvider = isSelfScanOnlyProvider;
|
||||
mUserId = userId;
|
||||
mHandler = new Handler(Looper.myLooper());
|
||||
}
|
||||
@@ -107,8 +114,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
|
||||
public void updateDiscoveryPreference(
|
||||
Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference) {
|
||||
mLastDiscoveryPreference = discoveryPreference;
|
||||
mLastDiscoveryPreferenceIncludesThisPackage =
|
||||
activelyScanningPackages.contains(mComponentName.getPackageName());
|
||||
if (mConnectionReady) {
|
||||
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
|
||||
}
|
||||
@@ -209,11 +219,15 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
|
||||
private boolean shouldBind() {
|
||||
if (mRunning) {
|
||||
// Bind when there is a discovery preference or an active route session.
|
||||
return (mLastDiscoveryPreference != null
|
||||
&& !mLastDiscoveryPreference.getPreferredFeatures().isEmpty())
|
||||
|| !getSessionInfos().isEmpty()
|
||||
|| mIsManagerScanning;
|
||||
boolean shouldBind =
|
||||
mLastDiscoveryPreference != null
|
||||
&& !mLastDiscoveryPreference.getPreferredFeatures().isEmpty();
|
||||
if (mIsSelfScanOnlyProvider) {
|
||||
shouldBind &= mLastDiscoveryPreferenceIncludesThisPackage;
|
||||
}
|
||||
shouldBind |= mIsManagerScanning;
|
||||
shouldBind |= !getSessionInfos().isEmpty();
|
||||
return shouldBind;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -301,7 +315,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
|
||||
if (mActiveConnection == connection) {
|
||||
mConnectionReady = true;
|
||||
if (mLastDiscoveryPreference != null) {
|
||||
updateDiscoveryPreference(mLastDiscoveryPreference);
|
||||
updateDiscoveryPreference(
|
||||
mLastDiscoveryPreferenceIncludesThisPackage
|
||||
? Set.of(mComponentName.getPackageName())
|
||||
: Set.of(),
|
||||
mLastDiscoveryPreference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.media;
|
||||
|
||||
import static android.content.pm.PackageManager.GET_RESOLVED_FILTER;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
@@ -34,6 +36,7 @@ import android.util.Slog;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Watches changes of packages, or scan them for finding media route providers.
|
||||
@@ -41,8 +44,8 @@ import java.util.Collections;
|
||||
final class MediaRoute2ProviderWatcher {
|
||||
private static final String TAG = "MR2ProviderWatcher";
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final PackageManager.ResolveInfoFlags RESOLVE_INFO_FLAGS_NONE =
|
||||
PackageManager.ResolveInfoFlags.of(0);
|
||||
private static final PackageManager.ResolveInfoFlags RESOLVE_INFO_FLAGS =
|
||||
PackageManager.ResolveInfoFlags.of(GET_RESOLVED_FILTER);
|
||||
|
||||
private final Context mContext;
|
||||
private final Callback mCallback;
|
||||
@@ -118,16 +121,26 @@ final class MediaRoute2ProviderWatcher {
|
||||
int targetIndex = 0;
|
||||
Intent intent = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE);
|
||||
for (ResolveInfo resolveInfo :
|
||||
mPackageManager.queryIntentServicesAsUser(
|
||||
intent, RESOLVE_INFO_FLAGS_NONE, mUserId)) {
|
||||
mPackageManager.queryIntentServicesAsUser(intent, RESOLVE_INFO_FLAGS, mUserId)) {
|
||||
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
|
||||
if (serviceInfo != null) {
|
||||
boolean isSelfScanOnlyProvider = false;
|
||||
Iterator<String> categoriesIterator = resolveInfo.filter.categoriesIterator();
|
||||
if (categoriesIterator != null) {
|
||||
while (categoriesIterator.hasNext()) {
|
||||
isSelfScanOnlyProvider |=
|
||||
MediaRoute2ProviderService.CATEGORY_SELF_SCAN_ONLY.equals(
|
||||
categoriesIterator.next());
|
||||
}
|
||||
}
|
||||
int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
|
||||
if (sourceIndex < 0) {
|
||||
MediaRoute2ProviderServiceProxy proxy =
|
||||
new MediaRoute2ProviderServiceProxy(mContext,
|
||||
new ComponentName(serviceInfo.packageName, serviceInfo.name),
|
||||
mUserId);
|
||||
new MediaRoute2ProviderServiceProxy(
|
||||
mContext,
|
||||
new ComponentName(serviceInfo.packageName, serviceInfo.name),
|
||||
isSelfScanOnlyProvider,
|
||||
mUserId);
|
||||
proxy.start();
|
||||
mProxies.add(targetIndex++, proxy);
|
||||
mCallback.onAddProviderService(proxy);
|
||||
|
||||
@@ -1478,6 +1478,7 @@ class MediaRouter2ServiceImpl {
|
||||
final ArrayList<RouterRecord> mRouterRecords = new ArrayList<>();
|
||||
final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
|
||||
RouteDiscoveryPreference mCompositeDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
|
||||
Set<String> mActivelyScanningPackages = Set.of();
|
||||
final UserHandler mHandler;
|
||||
|
||||
UserRecord(int userId) {
|
||||
@@ -1525,7 +1526,12 @@ class MediaRouter2ServiceImpl {
|
||||
pw.println(indent + "<no manager records>");
|
||||
}
|
||||
|
||||
mCompositeDiscoveryPreference.dump(pw, indent);
|
||||
pw.println(indent + "Composite discovery preference:");
|
||||
mCompositeDiscoveryPreference.dump(pw, indent + " ");
|
||||
pw.println(
|
||||
indent
|
||||
+ "Packages actively scanning: "
|
||||
+ String.join(", ", mActivelyScanningPackages));
|
||||
|
||||
if (!mHandler.runWithScissors(() -> mHandler.dump(pw, indent), 1000)) {
|
||||
pw.println(indent + "<could not dump handler state>");
|
||||
@@ -1834,7 +1840,9 @@ class MediaRouter2ServiceImpl {
|
||||
public void onAddProviderService(@NonNull MediaRoute2ProviderServiceProxy proxy) {
|
||||
proxy.setCallback(this);
|
||||
mRouteProviders.add(proxy);
|
||||
proxy.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
|
||||
proxy.updateDiscoveryPreference(
|
||||
mUserRecord.mActivelyScanningPackages,
|
||||
mUserRecord.mCompositeDiscoveryPreference);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2341,8 +2349,8 @@ class MediaRouter2ServiceImpl {
|
||||
return;
|
||||
}
|
||||
notifySessionInfoChangedToRouters(getRouterRecords(true), sessionInfo);
|
||||
notifySessionInfoChangedToRouters(getRouterRecords(false),
|
||||
mSystemProvider.getDefaultSessionInfo());
|
||||
notifySessionInfoChangedToRouters(
|
||||
getRouterRecords(false), mSystemProvider.getDefaultSessionInfo());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2711,8 +2719,8 @@ class MediaRouter2ServiceImpl {
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
List<RouteDiscoveryPreference> discoveryPreferences = Collections.emptyList();
|
||||
List<RouterRecord> routerRecords = getRouterRecords();
|
||||
List<RouterRecord> activeRouterRecords = Collections.emptyList();
|
||||
List<RouterRecord> allRouterRecords = getRouterRecords();
|
||||
List<ManagerRecord> managerRecords = getManagerRecords();
|
||||
|
||||
boolean isManagerScanning = false;
|
||||
@@ -2723,15 +2731,16 @@ class MediaRouter2ServiceImpl {
|
||||
<= sPackageImportanceForScanning);
|
||||
|
||||
if (isManagerScanning) {
|
||||
discoveryPreferences = routerRecords.stream()
|
||||
.map(record -> record.mDiscoveryPreference)
|
||||
.collect(Collectors.toList());
|
||||
activeRouterRecords = allRouterRecords;
|
||||
} else {
|
||||
discoveryPreferences = routerRecords.stream().filter(record ->
|
||||
service.mActivityManager.getPackageImportance(record.mPackageName)
|
||||
<= sPackageImportanceForScanning)
|
||||
.map(record -> record.mDiscoveryPreference)
|
||||
.collect(Collectors.toList());
|
||||
activeRouterRecords =
|
||||
allRouterRecords.stream()
|
||||
.filter(
|
||||
record ->
|
||||
service.mActivityManager.getPackageImportance(
|
||||
record.mPackageName)
|
||||
<= sPackageImportanceForScanning)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2748,22 +2757,30 @@ class MediaRouter2ServiceImpl {
|
||||
// to query route providers once to obtain all of the routes of interest, which
|
||||
// can be subsequently filtered for the individual discovery preferences.
|
||||
Set<String> preferredFeatures = new HashSet<>();
|
||||
Set<String> activelyScanningPackages = new HashSet<>();
|
||||
boolean activeScan = false;
|
||||
for (RouteDiscoveryPreference preference : discoveryPreferences) {
|
||||
for (RouterRecord activeRouterRecord : activeRouterRecords) {
|
||||
RouteDiscoveryPreference preference = activeRouterRecord.mDiscoveryPreference;
|
||||
preferredFeatures.addAll(preference.getPreferredFeatures());
|
||||
activeScan |= preference.shouldPerformActiveScan();
|
||||
if (preference.shouldPerformActiveScan()) {
|
||||
activeScan = true;
|
||||
activelyScanningPackages.add(activeRouterRecord.mPackageName);
|
||||
}
|
||||
}
|
||||
RouteDiscoveryPreference newPreference = new RouteDiscoveryPreference.Builder(
|
||||
List.copyOf(preferredFeatures), activeScan || isManagerScanning).build();
|
||||
|
||||
synchronized (service.mLock) {
|
||||
if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) {
|
||||
if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)
|
||||
&& activelyScanningPackages.equals(mUserRecord.mActivelyScanningPackages)) {
|
||||
return;
|
||||
}
|
||||
mUserRecord.mCompositeDiscoveryPreference = newPreference;
|
||||
mUserRecord.mActivelyScanningPackages = activelyScanningPackages;
|
||||
}
|
||||
for (MediaRoute2Provider provider : mRouteProviders) {
|
||||
provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference);
|
||||
provider.updateDiscoveryPreference(
|
||||
activelyScanningPackages, mUserRecord.mCompositeDiscoveryPreference);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides routes for local playbacks such as phone speaker, wired headset, or Bluetooth speakers.
|
||||
@@ -196,7 +197,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
|
||||
public void updateDiscoveryPreference(
|
||||
Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user