Use component name instead of package name to get media service
Bug: 134776956
Test: manual
Change-Id: I92e95c3f7e63ab5f826353578cda7ca4abb7ab53
(cherry picked from commit 496bbf057bbb55c05e459dac3083f34b083d31ff)
diff --git a/src/com/android/car/carlauncher/AppGridActivity.java b/src/com/android/car/carlauncher/AppGridActivity.java
index a4a8bed..b0cb0d4 100644
--- a/src/com/android/car/carlauncher/AppGridActivity.java
+++ b/src/com/android/car/carlauncher/AppGridActivity.java
@@ -41,8 +41,8 @@
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup;
-
import androidx.recyclerview.widget.RecyclerView;
+
import com.android.car.carlauncher.AppLauncherUtils.LauncherAppsInfo;
import java.util.ArrayList;
@@ -155,7 +155,7 @@
Set<String> blackList = mShowAllApps ? Collections.emptySet() : mHiddenApps;
LauncherAppsInfo appsInfo = AppLauncherUtils.getAllLauncherApps(blackList,
getSystemService(LauncherApps.class), mCarPackageManager, mPackageManager);
- mGridAdapter.setAllApps(appsInfo.getApplicationsList());
+ mGridAdapter.setAllApps(appsInfo.getLaunchableComponentsList());
mGridAdapter.setMostRecentApps(getMostRecentApps(appsInfo));
}
@@ -238,8 +238,12 @@
continue;
}
+ // TODO(b/136222320): UsageStats is obtained per package, but a package may contain
+ // multiple media services. We need to find a way to get the usage stats per service.
+ ComponentName componentName = AppLauncherUtils.getMediaSource(mPackageManager,
+ packageName);
// Exempt media services from background and launcher checks
- if (!appsInfo.isMediaService(packageName)) {
+ if (!appsInfo.isMediaService(componentName)) {
// do not include apps that only ran in the background
if (usageStats.getTotalTimeInForeground() == 0) {
continue;
@@ -252,7 +256,7 @@
}
}
- AppMetaData app = appsInfo.getAppMetaData(packageName);
+ AppMetaData app = appsInfo.getAppMetaData(componentName);
// Prevent duplicated entries
// e.g. app is used at 2017/12/31 23:59, and 2018/01/01 00:00
if (app != null && !apps.contains(app)) {
diff --git a/src/com/android/car/carlauncher/AppLauncherUtils.java b/src/com/android/car/carlauncher/AppLauncherUtils.java
index dbeff4d..398bb3e 100644
--- a/src/com/android/car/carlauncher/AppLauncherUtils.java
+++ b/src/com/android/car/carlauncher/AppLauncherUtils.java
@@ -21,6 +21,7 @@
import android.car.Car;
import android.car.CarNotConnectedException;
import android.car.content.pm.CarPackageManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
@@ -29,6 +30,7 @@
import android.content.pm.ResolveInfo;
import android.os.Process;
import android.service.media.MediaBrowserService;
+import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -37,6 +39,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -45,7 +48,6 @@
* Util class that contains helper method used by app launcher classes.
*/
class AppLauncherUtils {
-
private static final String TAG = "AppLauncherUtils";
private AppLauncherUtils() {
@@ -71,49 +73,77 @@
/** Bundles application and services info. */
static class LauncherAppsInfo {
- /** Map of all apps' metadata keyed by package name. */
- private final Map<String, AppMetaData> mApplications;
+ /*
+ * Map of all car launcher components' (including launcher activities and media services)
+ * metadata keyed by ComponentName.
+ */
+ private final Map<ComponentName, AppMetaData> mLaunchables;
- /** Map of all the media services keyed by package name. */
- private final Map<String, ResolveInfo> mMediaServices;
+ /** Map of all the media services keyed by ComponentName. */
+ private final Map<ComponentName, ResolveInfo> mMediaServices;
- LauncherAppsInfo(@NonNull Map<String, AppMetaData> apps,
- @NonNull Map<String, ResolveInfo> mediaServices) {
- mApplications = apps;
+ LauncherAppsInfo(@NonNull Map<ComponentName, AppMetaData> components,
+ @NonNull Map<ComponentName, ResolveInfo> mediaServices) {
+ mLaunchables = components;
mMediaServices = mediaServices;
}
/** Returns true if all maps are empty. */
boolean isEmpty() {
- return mApplications.isEmpty() && mMediaServices.isEmpty();
+ return mLaunchables.isEmpty() && mMediaServices.isEmpty();
}
- /** Returns whether the given package name is a media service. */
- boolean isMediaService(String packageName) {
- return mMediaServices.containsKey(packageName);
+ /**
+ * Returns whether the given componentName is a media service.
+ */
+ boolean isMediaService(ComponentName componentName) {
+ return mMediaServices.containsKey(componentName);
}
- /** Returns the {@link AppMetaData} for the given package name. */
+ /** Returns the {@link AppMetaData} for the given componentName. */
@Nullable
- AppMetaData getAppMetaData(String packageName) {
- return mApplications.get(packageName);
+ AppMetaData getAppMetaData(ComponentName componentName) {
+ return mLaunchables.get(componentName);
}
- /** Returns a new list of the applications' {@link AppMetaData}. */
+ /** Returns a new list of all launchable components' {@link AppMetaData}. */
@NonNull
- List<AppMetaData> getApplicationsList() {
- return new ArrayList<>(mApplications.values());
+ List<AppMetaData> getLaunchableComponentsList() {
+ return new ArrayList<>(mLaunchables.values());
}
}
private final static LauncherAppsInfo EMPTY_APPS_INFO = new LauncherAppsInfo(
Collections.emptyMap(), Collections.emptyMap());
+ /*
+ * Gets the media source in a given package. If there are multiple sources in the package,
+ * returns the first one.
+ */
+ static ComponentName getMediaSource(@NonNull PackageManager packageManager,
+ @NonNull String packageName) {
+ Intent mediaIntent = new Intent();
+ mediaIntent.setPackage(packageName);
+ mediaIntent.setAction(MediaBrowserService.SERVICE_INTERFACE);
+
+ List<ResolveInfo> mediaServices = packageManager.queryIntentServices(mediaIntent,
+ PackageManager.GET_RESOLVED_FILTER);
+
+ if (mediaServices == null || mediaServices.isEmpty()) {
+ return null;
+ }
+ String defaultService = mediaServices.get(0).serviceInfo.name;
+ if (!TextUtils.isEmpty(defaultService)) {
+ return new ComponentName(packageName, defaultService);
+ }
+ return null;
+ }
+
/**
- * Gets all the apps that we want to see in the launcher in unsorted order. Includes media
- * services without launcher activities.
+ * Gets all the components that we want to see in the launcher in unsorted order, including
+ * launcher activities and media services.
*
- * @param blackList A (possibly empty) list of apps to hide
+ * @param blackList A (possibly empty) list of apps (package names) to hide
* @param launcherApps The {@link LauncherApps} system service
* @param carPackageManager The {@link CarPackageManager} system service
* @param packageManager The {@link PackageManager} system service
@@ -136,56 +166,68 @@
List<LauncherActivityInfo> availableActivities =
launcherApps.getActivityList(null, Process.myUserHandle());
- Map<String, AppMetaData> apps = new HashMap<>(
+ Map<ComponentName, AppMetaData> components = new HashMap<>(
mediaServices.size() + availableActivities.size());
- Map<String, ResolveInfo> mediaServicesMap = new HashMap<>(mediaServices.size());
+ Map<ComponentName, ResolveInfo> mediaServicesMap = new HashMap<>(mediaServices.size());
+ Set<String> mediaPackages = new HashSet<>();
// Process media services
for (ResolveInfo info : mediaServices) {
String packageName = info.serviceInfo.packageName;
- mediaServicesMap.put(packageName, info);
- if (shouldAdd(packageName, apps, blackList)) {
+ String className = info.serviceInfo.name;
+ ComponentName componentName = new ComponentName(packageName, className);
+ mediaServicesMap.put(componentName, info);
+ if (shouldAdd(componentName, components, blackList)) {
+ mediaPackages.add(packageName);
final boolean isDistractionOptimized = true;
Intent intent = new Intent(Car.CAR_INTENT_ACTION_MEDIA_TEMPLATE);
- intent.putExtra(Car.CAR_EXTRA_MEDIA_PACKAGE, packageName);
+ intent.putExtra(Car.CAR_EXTRA_MEDIA_COMPONENT, componentName.flattenToString());
AppMetaData appMetaData = new AppMetaData(
info.serviceInfo.loadLabel(packageManager),
- packageName,
+ componentName,
info.serviceInfo.loadIcon(packageManager),
isDistractionOptimized,
intent,
packageManager.getLaunchIntentForPackage(packageName));
- apps.put(packageName, appMetaData);
+ components.put(componentName, appMetaData);
}
}
// Process activities
for (LauncherActivityInfo info : availableActivities) {
- String packageName = info.getComponentName().getPackageName();
- if (shouldAdd(packageName, apps, blackList)) {
+ ComponentName componentName = info.getComponentName();
+ String packageName = componentName.getPackageName();
+ // If a media service has been added to the map, don't add the activity belonging to the
+ // same package.
+ if (mediaPackages.contains(packageName)) {
+ continue;
+ }
+ if (shouldAdd(componentName, components, blackList)) {
boolean isDistractionOptimized =
isActivityDistractionOptimized(carPackageManager, packageName,
info.getName());
AppMetaData appMetaData = new AppMetaData(
info.getLabel(),
- packageName,
+ componentName,
info.getBadgedIcon(0),
isDistractionOptimized,
packageManager.getLaunchIntentForPackage(packageName),
null);
- apps.put(packageName, appMetaData);
+ components.put(componentName, appMetaData);
}
}
- return new LauncherAppsInfo(apps, mediaServicesMap);
+ return new LauncherAppsInfo(components, mediaServicesMap);
}
- private static boolean shouldAdd(String packageName, Map<String, AppMetaData> apps,
+ private static boolean shouldAdd(ComponentName componentName,
+ Map<ComponentName, AppMetaData> components,
@NonNull Set<String> blackList) {
- return !apps.containsKey(packageName) && !blackList.contains(packageName);
+ return !components.containsKey(componentName) && !blackList.contains(
+ componentName.getPackageName());
}
/**
diff --git a/src/com/android/car/carlauncher/AppMetaData.java b/src/com/android/car/carlauncher/AppMetaData.java
index affc472..14c6a9f 100644
--- a/src/com/android/car/carlauncher/AppMetaData.java
+++ b/src/com/android/car/carlauncher/AppMetaData.java
@@ -17,11 +17,12 @@
package com.android.car.carlauncher;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Intent;
import android.graphics.drawable.Drawable;
/**
- * Meta data of an app including the display name, the full package name, the icon drawable, and an
+ * Meta data of an app including the display name, the component name, the icon drawable, and an
* intent to either open the app or the media center (for media services).
*/
@@ -29,8 +30,8 @@
// The display name of the app
@Nullable
private final String mDisplayName;
- // The package name of the app
- private final String mPackageName;
+ // The component name of the app
+ private final ComponentName mComponentName;
private final Drawable mIcon;
private final boolean mIsDistractionOptimized;
private final Intent mMainLaunchIntent;
@@ -38,23 +39,25 @@
/**
* AppMetaData
- * @param displayName the name to display in the launcher
- * @param packageName the application's package
- * @param icon the application's icon
+ *
+ * @param displayName the name to display in the launcher
+ * @param componentName the component name
+ * @param icon the application's icon
* @param isDistractionOptimized whether mainLaunchIntent is safe for driving
- * @param mainLaunchIntent what to open by default (goes to the media center for media apps)
- * @param alternateLaunchIntent temporary allowance for media apps that still need to show UI
- * beyond sign in and settings
+ * @param mainLaunchIntent what to open by default (goes to the media center for media
+ * apps)
+ * @param alternateLaunchIntent temporary allowance for media apps that still need to show UI
+ * beyond sign in and settings
*/
AppMetaData(
CharSequence displayName,
- String packageName,
+ ComponentName componentName,
Drawable icon,
boolean isDistractionOptimized,
Intent mainLaunchIntent,
@Nullable Intent alternateLaunchIntent) {
mDisplayName = displayName == null ? "" : displayName.toString();
- mPackageName = packageName == null ? "" : packageName;
+ mComponentName = componentName;
mIcon = icon;
mIsDistractionOptimized = isDistractionOptimized;
mMainLaunchIntent = mainLaunchIntent;
@@ -66,7 +69,11 @@
}
public String getPackageName() {
- return mPackageName;
+ return getComponentName().getPackageName();
+ }
+
+ public ComponentName getComponentName() {
+ return mComponentName;
}
Intent getMainLaunchIntent() {
@@ -86,22 +93,22 @@
}
/**
- * The equality of two AppMetaData is determined by whether the package names are the same.
+ * The equality of two AppMetaData is determined by whether the component names are the same.
*
* @param o Object that this AppMetaData object is compared against
- * @return {@code true} when two AppMetaData have the same package name
+ * @return {@code true} when two AppMetaData have the same component name
*/
@Override
public boolean equals(Object o) {
if (!(o instanceof AppMetaData)) {
return false;
} else {
- return ((AppMetaData) o).getPackageName().equals(mPackageName);
+ return ((AppMetaData) o).getComponentName().equals(mComponentName);
}
}
@Override
public int hashCode() {
- return mPackageName.hashCode();
+ return mComponentName.hashCode();
}
}
diff --git a/src/com/android/car/carlauncher/AppSearchActivity.java b/src/com/android/car/carlauncher/AppSearchActivity.java
index 59315db..2947906 100644
--- a/src/com/android/car/carlauncher/AppSearchActivity.java
+++ b/src/com/android/car/carlauncher/AppSearchActivity.java
@@ -170,7 +170,7 @@
AppLauncherUtils.LauncherAppsInfo appsInfo = AppLauncherUtils.getAllLauncherApps(
Collections.emptySet(), getSystemService(LauncherApps.class), mCarPackageManager,
mPackageManager);
- return appsInfo.getApplicationsList();
+ return appsInfo.getLaunchableComponentsList();
}
public void hideKeyboard() {