Home | History | Annotate | Download | only in car
      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