package com.android.systemui.statusbar.car; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.view.Display; import android.view.View; import java.util.HashMap; import java.util.List; import java.util.Set; /** * CarFacetButtons placed on the nav bar are designed to have visual indication that the active * application on screen is associated with it. This is basically a similar concept to a radio * button group. */ public class CarFacetButtonController { protected HashMap mButtonsByCategory = new HashMap<>(); protected HashMap mButtonsByPackage = new HashMap<>(); protected HashMap mButtonsByComponentName = new HashMap<>(); protected CarFacetButton mSelectedFacetButton; protected Context mContext; public CarFacetButtonController(Context context) { mContext = context; } /** * Add facet button to this controller. The expected use is for the facet button * to get a reference to this controller via {@link com.android.systemui.Dependency} * and self add. * @param facetButton */ public void addFacetButton(CarFacetButton facetButton) { String[] categories = facetButton.getCategories(); for (int i = 0; i < categories.length; i++) { mButtonsByCategory.put(categories[i], facetButton); } String[] facetPackages = facetButton.getFacetPackages(); for (int i = 0; i < facetPackages.length; i++) { mButtonsByPackage.put(facetPackages[i], facetButton); } String[] componentNames = facetButton.getComponentName(); for (int i = 0; i < componentNames.length; i++) { mButtonsByComponentName.put(componentNames[i], facetButton); } // Using the following as a default button for display id info it's not // attached to a screen at this point so it can't be extracted here. mSelectedFacetButton = facetButton; } public void removeAll() { mButtonsByCategory.clear(); mButtonsByPackage.clear(); mButtonsByComponentName.clear(); mSelectedFacetButton = null; } /** * This will unselect the currently selected CarFacetButton and determine which one should be * selected next. It does this by reading the properties on the CarFacetButton and seeing if * they are a match with the supplied StackInfo list. * The order of selection detection is ComponentName, PackageName then Category * They will then be compared with the supplied StackInfo list. * The StackInfo is expected to be supplied in order of recency and StackInfo will only be used * for consideration if it has the same displayId as the CarFacetButtons. * @param taskInfo of the currently running application */ public void taskChanged(List stackInfoList) { int displayId = getDisplayId(); ActivityManager.StackInfo validStackInfo = null; for (ActivityManager.StackInfo stackInfo :stackInfoList) { // If the display id is unknown or it matches the stack, it's valid for use if ((displayId == -1 || displayId == stackInfo.displayId) && stackInfo.topActivity != null) { validStackInfo = stackInfo; break; } } if (validStackInfo == null) { // No stack was found that was on the same display as the facet buttons thus return return; } if (mSelectedFacetButton != null) { mSelectedFacetButton.setSelected(false); } String packageName = validStackInfo.topActivity.getPackageName(); CarFacetButton facetButton = findFacetButtongByComponentName(validStackInfo.topActivity); if (facetButton == null) { facetButton = mButtonsByPackage.get(packageName); } if (facetButton == null) { String category = getPackageCategory(packageName); if (category != null) { facetButton = mButtonsByCategory.get(category); } } if (facetButton != null && facetButton.getVisibility() == View.VISIBLE) { facetButton.setSelected(true); mSelectedFacetButton = facetButton; } } private int getDisplayId() { if (mSelectedFacetButton != null) { Display display = mSelectedFacetButton.getDisplay(); if (display != null) { return display.getDisplayId(); } } return -1; } private CarFacetButton findFacetButtongByComponentName(ComponentName componentName) { CarFacetButton button = mButtonsByComponentName.get(componentName.flattenToShortString()); return (button != null) ? button : mButtonsByComponentName.get(componentName.flattenToString()); } protected String getPackageCategory(String packageName) { PackageManager pm = mContext.getPackageManager(); Set supportedCategories = mButtonsByCategory.keySet(); for (String category : supportedCategories) { Intent intent = new Intent(); intent.setPackage(packageName); intent.setAction(Intent.ACTION_MAIN); intent.addCategory(category); List list = pm.queryIntentActivities(intent, 0); if (list.size() > 0) { // Cache this package name into facetPackageMap, so we won't have to query // all categories next time this package name shows up. mButtonsByPackage.put(packageName, mButtonsByCategory.get(category)); return category; } } return null; } }