package com.android.systemui.statusbar.car; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import com.android.keyguard.AlphaOptimizedImageButton; import com.android.systemui.Dependency; import com.android.systemui.R; /** * CarFacetButton is a ui component designed to be used as a shortcut for an app of a defined * category. It can also render a indicator impling that there are more options of apps to launch * using this component. This is done with a "More icon" currently an arrow as defined in the layout * file. The class is to serve as an example. * Usage example: A button that allows a user to select a music app and indicate that there are * other music apps installed. */ public class CarFacetButton extends LinearLayout { private static final String FACET_FILTER_DELIMITER = ";"; /** * Extra information to be sent to a helper to make the decision of what app to launch when * clicked. */ private static final String EXTRA_FACET_CATEGORIES = "categories"; private static final String EXTRA_FACET_PACKAGES = "packages"; private static final String EXTRA_FACET_ID = "filter_id"; private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker"; private Context mContext; private AlphaOptimizedImageButton mIcon; private AlphaOptimizedImageButton mMoreIcon; private boolean mSelected = false; private String[] mComponentNames; /** App categories that are to be used with this widget */ private String[] mFacetCategories; /** App packages that are allowed to be used with this widget */ private String[] mFacetPackages; private int mIconResourceId; /** * If defined in the xml this will be the icon that's rendered when the button is marked as * selected */ private int mSelectedIconResourceId; private boolean mUseMoreIcon = true; private float mSelectedAlpha = 1f; private float mUnselectedAlpha = 1f; public CarFacetButton(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; View.inflate(context, R.layout.car_facet_button, this); // extract custom attributes TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton); setupIntents(typedArray); setupIcons(typedArray); CarFacetButtonController carFacetButtonController = Dependency.get( CarFacetButtonController.class); carFacetButtonController.addFacetButton(this); } /** * Reads the custom attributes to setup click handlers for this component. */ private void setupIntents(TypedArray typedArray) { String intentString = typedArray.getString(R.styleable.CarFacetButton_intent); String longPressIntentString = typedArray.getString(R.styleable.CarFacetButton_longIntent); String categoryString = typedArray.getString(R.styleable.CarFacetButton_categories); String packageString = typedArray.getString(R.styleable.CarFacetButton_packages); String componentNameString = typedArray.getString(R.styleable.CarFacetButton_componentNames); try { final Intent intent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME); intent.putExtra(EXTRA_FACET_ID, Integer.toString(getId())); if (packageString != null) { mFacetPackages = packageString.split(FACET_FILTER_DELIMITER); intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages); } if (categoryString != null) { mFacetCategories = categoryString.split(FACET_FILTER_DELIMITER); intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories); } if (componentNameString != null) { mComponentNames = componentNameString.split(FACET_FILTER_DELIMITER); } setOnClickListener(v -> { intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, mSelected); mContext.startActivityAsUser(intent, UserHandle.CURRENT); }); if (longPressIntentString != null) { final Intent longPressIntent = Intent.parseUri(longPressIntentString, Intent.URI_INTENT_SCHEME); setOnLongClickListener(v -> { mContext.startActivityAsUser(longPressIntent, UserHandle.CURRENT); return true; }); } } catch (Exception e) { throw new RuntimeException("Failed to attach intent", e); } } private void setupIcons(TypedArray styledAttributes) { mSelectedAlpha = styledAttributes.getFloat( R.styleable.CarFacetButton_selectedAlpha, mSelectedAlpha); mUnselectedAlpha = styledAttributes.getFloat( R.styleable.CarFacetButton_unselectedAlpha, mUnselectedAlpha); mIcon = findViewById(R.id.car_nav_button_icon); mIcon.setScaleType(ImageView.ScaleType.CENTER); mIcon.setClickable(false); mIcon.setAlpha(mUnselectedAlpha); mIconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0); mIcon.setImageResource(mIconResourceId); mSelectedIconResourceId = styledAttributes.getResourceId( R.styleable.CarFacetButton_selectedIcon, mIconResourceId); mMoreIcon = findViewById(R.id.car_nav_button_more_icon); mMoreIcon.setClickable(false); mMoreIcon.setAlpha(mSelectedAlpha); mMoreIcon.setVisibility(GONE); mUseMoreIcon = styledAttributes.getBoolean(R.styleable.CarFacetButton_useMoreIcon, true); } /** * @return The app categories the component represents */ public String[] getCategories() { if (mFacetCategories == null) { return new String[0]; } return mFacetCategories; } /** * @return The valid packages that should be considered. */ public String[] getFacetPackages() { if (mFacetPackages == null) { return new String[0]; } return mFacetPackages; } public String[] getComponentName() { if (mComponentNames == null) { return new String[0]; } return mComponentNames; } /** * Updates the alpha of the icons to "selected" and shows the "More icon" * @param selected true if the view must be selected, false otherwise */ public void setSelected(boolean selected) { super.setSelected(selected); setSelected(selected, selected); } /** * Updates the visual state to let the user know if it's been selected. * @param selected true if should update the alpha of the icon to selected, false otherwise * @param showMoreIcon true if the "more icon" should be shown, false otherwise. Note this * is ignored if the attribute useMoreIcon is set to false */ public void setSelected(boolean selected, boolean showMoreIcon) { mSelected = selected; mIcon.setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha); mIcon.setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId); if (mUseMoreIcon) { mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE); } } }