1078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningpackage com.android.systemui.statusbar.car; 2078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 3078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport android.app.ActivityManager; 4d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenningimport android.content.ComponentName; 5078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport android.content.Context; 6078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport android.content.Intent; 7078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport android.content.pm.PackageManager; 8078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport android.content.pm.ResolveInfo; 9a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenningimport android.view.Display; 107e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenningimport android.view.View; 11078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 12078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport java.util.HashMap; 13078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport java.util.List; 14078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningimport java.util.Set; 15078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 16078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning/** 17078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning * CarFacetButtons placed on the nav bar are designed to have visual indication that the active 18078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning * application on screen is associated with it. This is basically a similar concept to a radio 19078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning * button group. 20078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning */ 21078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenningpublic class CarFacetButtonController { 22078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 23078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning protected HashMap<String, CarFacetButton> mButtonsByCategory = new HashMap<>(); 24078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning protected HashMap<String, CarFacetButton> mButtonsByPackage = new HashMap<>(); 25d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning protected HashMap<String, CarFacetButton> mButtonsByComponentName = new HashMap<>(); 26078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning protected CarFacetButton mSelectedFacetButton; 27078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning protected Context mContext; 28078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 29078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning public CarFacetButtonController(Context context) { 30078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning mContext = context; 31078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 32078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 33078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning /** 3438b46f82f718891de608ca31e49034d824a88a12Brad Stenning * Add facet button to this controller. The expected use is for the facet button 3538b46f82f718891de608ca31e49034d824a88a12Brad Stenning * to get a reference to this controller via {@link com.android.systemui.Dependency} 3638b46f82f718891de608ca31e49034d824a88a12Brad Stenning * and self add. 3738b46f82f718891de608ca31e49034d824a88a12Brad Stenning * @param facetButton 38078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning */ 3938b46f82f718891de608ca31e49034d824a88a12Brad Stenning public void addFacetButton(CarFacetButton facetButton) { 4038b46f82f718891de608ca31e49034d824a88a12Brad Stenning String[] categories = facetButton.getCategories(); 41d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning for (int i = 0; i < categories.length; i++) { 42d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning mButtonsByCategory.put(categories[i], facetButton); 4338b46f82f718891de608ca31e49034d824a88a12Brad Stenning } 44078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 4538b46f82f718891de608ca31e49034d824a88a12Brad Stenning String[] facetPackages = facetButton.getFacetPackages(); 46d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning for (int i = 0; i < facetPackages.length; i++) { 47d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning mButtonsByPackage.put(facetPackages[i], facetButton); 48d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning } 49d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning String[] componentNames = facetButton.getComponentName(); 50d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning for (int i = 0; i < componentNames.length; i++) { 51d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning mButtonsByComponentName.put(componentNames[i], facetButton); 52078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 53a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning // Using the following as a default button for display id info it's not 54a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning // attached to a screen at this point so it can't be extracted here. 55a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning mSelectedFacetButton = facetButton; 56078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 57078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 58224b5b39a274623e92e9238e112181eb086379adBrad Stenning public void removeAll() { 59224b5b39a274623e92e9238e112181eb086379adBrad Stenning mButtonsByCategory.clear(); 60224b5b39a274623e92e9238e112181eb086379adBrad Stenning mButtonsByPackage.clear(); 61d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning mButtonsByComponentName.clear(); 62224b5b39a274623e92e9238e112181eb086379adBrad Stenning mSelectedFacetButton = null; 63224b5b39a274623e92e9238e112181eb086379adBrad Stenning } 64224b5b39a274623e92e9238e112181eb086379adBrad Stenning 65078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning /** 66078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning * This will unselect the currently selected CarFacetButton and determine which one should be 67078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning * selected next. It does this by reading the properties on the CarFacetButton and seeing if 68a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning * they are a match with the supplied StackInfo list. 69a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning * The order of selection detection is ComponentName, PackageName then Category 70a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning * They will then be compared with the supplied StackInfo list. 71a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning * The StackInfo is expected to be supplied in order of recency and StackInfo will only be used 72a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning * for consideration if it has the same displayId as the CarFacetButtons. 73078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning * @param taskInfo of the currently running application 74078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning */ 75a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning public void taskChanged(List<ActivityManager.StackInfo> stackInfoList) { 76a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning int displayId = getDisplayId(); 777e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning ActivityManager.StackInfo validStackInfo = null; 78a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning for (ActivityManager.StackInfo stackInfo :stackInfoList) { 797e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning // If the display id is unknown or it matches the stack, it's valid for use 807e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning if ((displayId == -1 || displayId == stackInfo.displayId) && 817e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning stackInfo.topActivity != null) { 827e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning validStackInfo = stackInfo; 837e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning break; 84a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning } 857e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning } 86078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 877e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning if (validStackInfo == null) { 887e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning // No stack was found that was on the same display as the facet buttons thus return 897e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning return; 907e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning } 91a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning 927e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning if (mSelectedFacetButton != null) { 937e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning mSelectedFacetButton.setSelected(false); 947e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning } 95a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning 967e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning String packageName = validStackInfo.topActivity.getPackageName(); 977e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning CarFacetButton facetButton = findFacetButtongByComponentName(validStackInfo.topActivity); 987e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning if (facetButton == null) { 997e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning facetButton = mButtonsByPackage.get(packageName); 1007e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning } 101a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning 1027e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning if (facetButton == null) { 1037e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning String category = getPackageCategory(packageName); 1047e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning if (category != null) { 1057e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning facetButton = mButtonsByCategory.get(category); 106a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning } 107a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning } 1087e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning 1097e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning if (facetButton != null && facetButton.getVisibility() == View.VISIBLE) { 1107e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning facetButton.setSelected(true); 1117e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning mSelectedFacetButton = facetButton; 1127e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning } 1137e4118135a6e2b685a98073e26637d5d89fdec06Brad Stenning 114a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning } 115a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning 116a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning private int getDisplayId() { 117a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning if (mSelectedFacetButton != null) { 118a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning Display display = mSelectedFacetButton.getDisplay(); 119a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning if (display != null) { 120a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning return display.getDisplayId(); 121078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 122078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 123a5e714cafa091cafef1d89af8f41291ca773a058Brad Stenning return -1; 124078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 125078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning 126d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning private CarFacetButton findFacetButtongByComponentName(ComponentName componentName) { 127d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning CarFacetButton button = mButtonsByComponentName.get(componentName.flattenToShortString()); 128d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning return (button != null) ? button : 129d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning mButtonsByComponentName.get(componentName.flattenToString()); 130d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning } 131d450ad6d1b2c2f12c5b1968f6ba1190e6d9c912bBrad Stenning 132078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning protected String getPackageCategory(String packageName) { 133078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning PackageManager pm = mContext.getPackageManager(); 134078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning Set<String> supportedCategories = mButtonsByCategory.keySet(); 135078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning for (String category : supportedCategories) { 136078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning Intent intent = new Intent(); 137078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning intent.setPackage(packageName); 138078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning intent.setAction(Intent.ACTION_MAIN); 139078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning intent.addCategory(category); 140078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); 141078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning if (list.size() > 0) { 142078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning // Cache this package name into facetPackageMap, so we won't have to query 143078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning // all categories next time this package name shows up. 144078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning mButtonsByPackage.put(packageName, mButtonsByCategory.get(category)); 145078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning return category; 146078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 147078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 148078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning return null; 149078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning } 150078235b17d3aadc78196e41c21759fa40c0df5d4Brad Stenning} 151