1 package com.android.systemui.statusbar.car; 2 3 import android.app.ActivityManager; 4 import android.content.ComponentName; 5 import android.content.Context; 6 import android.content.Intent; 7 import android.content.pm.PackageManager; 8 import android.content.pm.ResolveInfo; 9 import android.view.Display; 10 import android.view.View; 11 12 import java.util.HashMap; 13 import java.util.List; 14 import java.util.Set; 15 16 /** 17 * CarFacetButtons placed on the nav bar are designed to have visual indication that the active 18 * application on screen is associated with it. This is basically a similar concept to a radio 19 * button group. 20 */ 21 public class CarFacetButtonController { 22 23 protected HashMap<String, CarFacetButton> mButtonsByCategory = new HashMap<>(); 24 protected HashMap<String, CarFacetButton> mButtonsByPackage = new HashMap<>(); 25 protected HashMap<String, CarFacetButton> mButtonsByComponentName = new HashMap<>(); 26 protected CarFacetButton mSelectedFacetButton; 27 protected Context mContext; 28 29 public CarFacetButtonController(Context context) { 30 mContext = context; 31 } 32 33 /** 34 * Add facet button to this controller. The expected use is for the facet button 35 * to get a reference to this controller via {@link com.android.systemui.Dependency} 36 * and self add. 37 * @param facetButton 38 */ 39 public void addFacetButton(CarFacetButton facetButton) { 40 String[] categories = facetButton.getCategories(); 41 for (int i = 0; i < categories.length; i++) { 42 mButtonsByCategory.put(categories[i], facetButton); 43 } 44 45 String[] facetPackages = facetButton.getFacetPackages(); 46 for (int i = 0; i < facetPackages.length; i++) { 47 mButtonsByPackage.put(facetPackages[i], facetButton); 48 } 49 String[] componentNames = facetButton.getComponentName(); 50 for (int i = 0; i < componentNames.length; i++) { 51 mButtonsByComponentName.put(componentNames[i], facetButton); 52 } 53 // Using the following as a default button for display id info it's not 54 // attached to a screen at this point so it can't be extracted here. 55 mSelectedFacetButton = facetButton; 56 } 57 58 public void removeAll() { 59 mButtonsByCategory.clear(); 60 mButtonsByPackage.clear(); 61 mButtonsByComponentName.clear(); 62 mSelectedFacetButton = null; 63 } 64 65 /** 66 * This will unselect the currently selected CarFacetButton and determine which one should be 67 * selected next. It does this by reading the properties on the CarFacetButton and seeing if 68 * they are a match with the supplied StackInfo list. 69 * The order of selection detection is ComponentName, PackageName then Category 70 * They will then be compared with the supplied StackInfo list. 71 * The StackInfo is expected to be supplied in order of recency and StackInfo will only be used 72 * for consideration if it has the same displayId as the CarFacetButtons. 73 * @param taskInfo of the currently running application 74 */ 75 public void taskChanged(List<ActivityManager.StackInfo> stackInfoList) { 76 int displayId = getDisplayId(); 77 ActivityManager.StackInfo validStackInfo = null; 78 for (ActivityManager.StackInfo stackInfo :stackInfoList) { 79 // If the display id is unknown or it matches the stack, it's valid for use 80 if ((displayId == -1 || displayId == stackInfo.displayId) && 81 stackInfo.topActivity != null) { 82 validStackInfo = stackInfo; 83 break; 84 } 85 } 86 87 if (validStackInfo == null) { 88 // No stack was found that was on the same display as the facet buttons thus return 89 return; 90 } 91 92 if (mSelectedFacetButton != null) { 93 mSelectedFacetButton.setSelected(false); 94 } 95 96 String packageName = validStackInfo.topActivity.getPackageName(); 97 CarFacetButton facetButton = findFacetButtongByComponentName(validStackInfo.topActivity); 98 if (facetButton == null) { 99 facetButton = mButtonsByPackage.get(packageName); 100 } 101 102 if (facetButton == null) { 103 String category = getPackageCategory(packageName); 104 if (category != null) { 105 facetButton = mButtonsByCategory.get(category); 106 } 107 } 108 109 if (facetButton != null && facetButton.getVisibility() == View.VISIBLE) { 110 facetButton.setSelected(true); 111 mSelectedFacetButton = facetButton; 112 } 113 114 } 115 116 private int getDisplayId() { 117 if (mSelectedFacetButton != null) { 118 Display display = mSelectedFacetButton.getDisplay(); 119 if (display != null) { 120 return display.getDisplayId(); 121 } 122 } 123 return -1; 124 } 125 126 private CarFacetButton findFacetButtongByComponentName(ComponentName componentName) { 127 CarFacetButton button = mButtonsByComponentName.get(componentName.flattenToShortString()); 128 return (button != null) ? button : 129 mButtonsByComponentName.get(componentName.flattenToString()); 130 } 131 132 protected String getPackageCategory(String packageName) { 133 PackageManager pm = mContext.getPackageManager(); 134 Set<String> supportedCategories = mButtonsByCategory.keySet(); 135 for (String category : supportedCategories) { 136 Intent intent = new Intent(); 137 intent.setPackage(packageName); 138 intent.setAction(Intent.ACTION_MAIN); 139 intent.addCategory(category); 140 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); 141 if (list.size() > 0) { 142 // Cache this package name into facetPackageMap, so we won't have to query 143 // all categories next time this package name shows up. 144 mButtonsByPackage.put(packageName, mButtonsByCategory.get(category)); 145 return category; 146 } 147 } 148 return null; 149 } 150 } 151