From 77d81dc6ac28e09e416d7eb0a0fabe0e971780b7 Mon Sep 17 00:00:00 2001 From: kwaky Date: Thu, 12 Dec 2019 16:23:59 -0800 Subject: [PATCH 1/2] Merge CarFacetButton and CarNavigationButton into a single class and add test coverage Test: Manual - Manually verified that navigation button functionalities are working as expected. Unit Tests Bug: 145827784 Bug: 145604656 Change-Id: Ib8f837ba34afbb8d66092a8b851b93c50fa20b26 --- .../res/layout/car_facet_button.xml | 51 ---- .../res/layout/car_navigation_bar.xml | 22 +- .../car_navigation_bar_unprovisioned.xml | 5 +- .../res/layout/car_navigation_button.xml | 34 ++- .../navigationbar/car/AssitantButton.java | 6 +- ...va => ButtonSelectionStateController.java} | 211 +++++++------- ...java => ButtonSelectionStateListener.java} | 17 +- .../navigationbar/car/CarFacetButton.java | 226 --------------- .../navigationbar/car/CarNavigationBar.java | 18 +- .../car/CarNavigationBarController.java | 8 +- .../car/CarNavigationButton.java | 271 +++++++++++++----- ...button_selection_state_controller_test.xml | 55 ++++ .../res/layout/car_navigation_button_test.xml | 115 ++++++++ .../ButtonSelectionStateControllerTest.java | 136 +++++++++ .../car/CarNavigationBarControllerTest.java | 56 ++-- .../car/CarNavigationButtonTest.java | 222 ++++++++++++++ packages/SystemUI/res/values/attrs_car.xml | 36 +-- 17 files changed, 936 insertions(+), 553 deletions(-) delete mode 100644 packages/CarSystemUI/res/layout/car_facet_button.xml rename packages/CarSystemUI/src/com/android/systemui/navigationbar/car/{CarFacetButtonController.java => ButtonSelectionStateController.java} (51%) rename packages/CarSystemUI/src/com/android/systemui/navigationbar/car/{FacetButtonTaskStackListener.java => ButtonSelectionStateListener.java} (75%) delete mode 100644 packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java create mode 100644 packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml create mode 100644 packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml create mode 100644 packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/ButtonSelectionStateControllerTest.java create mode 100644 packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationButtonTest.java diff --git a/packages/CarSystemUI/res/layout/car_facet_button.xml b/packages/CarSystemUI/res/layout/car_facet_button.xml deleted file mode 100644 index 8e7ebad7d7ecc..0000000000000 --- a/packages/CarSystemUI/res/layout/car_facet_button.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml index 6c7a04f2b698c..27ad4fc16532f 100644 --- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml +++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml @@ -33,14 +33,14 @@ android:paddingEnd="20dp" android:gravity="center"> - - - - - diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml b/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml index 0f964fd562856..1c5d37ffd60f8 100644 --- a/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml +++ b/packages/CarSystemUI/res/layout/car_navigation_bar_unprovisioned.xml @@ -31,7 +31,7 @@ android:paddingStart="@*android:dimen/car_padding_5" android:paddingEnd="@*android:dimen/car_padding_5"> - + systemui:highlightWhenSelected="true" + /> diff --git a/packages/CarSystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml index 6d8cca990fa12..bafbb6408f77d 100644 --- a/packages/CarSystemUI/res/layout/car_navigation_button.xml +++ b/packages/CarSystemUI/res/layout/car_navigation_button.xml @@ -18,12 +18,34 @@ --> - - + android:orientation="vertical"> + + + + + + + + diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/AssitantButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/AssitantButton.java index c50de22fb2d87..98cc00e376ccb 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/AssitantButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/AssitantButton.java @@ -30,9 +30,9 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback; /** * AssitantButton is a ui component that will trigger the Voice Interaction Service. */ -public class AssitantButton extends CarFacetButton { +public class AssitantButton extends CarNavigationButton { - private static final String TAG = "CarFacetButton"; + private static final String TAG = "AssistantButton"; private final AssistUtils mAssistUtils; private IVoiceInteractionSessionShowCallback mShowCallback = new IVoiceInteractionSessionShowCallback.Stub() { @@ -62,7 +62,7 @@ public class AssitantButton extends CarFacetButton { } @Override - protected void setupIntents(TypedArray typedArray) { + protected void setUpIntents(TypedArray typedArray) { // left blank because for the assistant button Intent will not be passed from the layout. } } diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/ButtonSelectionStateController.java similarity index 51% rename from packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java rename to packages/CarSystemUI/src/com/android/systemui/navigationbar/car/ButtonSelectionStateController.java index f66e8280197e9..c36aaa092b064 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/ButtonSelectionStateController.java @@ -28,7 +28,6 @@ import android.view.ViewGroup; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -36,151 +35,169 @@ import javax.inject.Inject; import javax.inject.Singleton; /** - * 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. + * CarNavigationButtons can optionally have selection state that toggles certain visual indications + * based on whether the active application on screen is associated with it. This is basically a + * similar concept to a radio button group. + * + * This class controls the selection state of CarNavigationButtons that have opted in to have such + * selection state-dependent visual indications. */ @Singleton -public class CarFacetButtonController { +public class ButtonSelectionStateController { - private final Set mRegisteredViews = new HashSet<>(); + private final Set mRegisteredViews = new HashSet<>(); protected ButtonMap mButtonsByCategory = new ButtonMap(); protected ButtonMap mButtonsByPackage = new ButtonMap(); protected ButtonMap mButtonsByComponentName = new ButtonMap(); - protected HashSet mSelectedFacetButtons; + protected HashSet mSelectedButtons; protected Context mContext; @Inject - public CarFacetButtonController(Context context) { + public ButtonSelectionStateController(Context context) { mContext = context; - mSelectedFacetButtons = new HashSet<>(); + mSelectedButtons = new HashSet<>(); } /** - * 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. - */ - private void addFacetButton(CarFacetButton facetButton) { - if (mRegisteredViews.contains(facetButton)) { - return; - } - - String[] categories = facetButton.getCategories(); - for (int i = 0; i < categories.length; i++) { - mButtonsByCategory.add(categories[i], facetButton); - } - - String[] facetPackages = facetButton.getFacetPackages(); - for (int i = 0; i < facetPackages.length; i++) { - mButtonsByPackage.add(facetPackages[i], facetButton); - } - String[] componentNames = facetButton.getComponentName(); - for (int i = 0; i < componentNames.length; i++) { - mButtonsByComponentName.add(componentNames[i], facetButton); - } - - mRegisteredViews.add(facetButton); - } - - /** Removes all buttons from the button maps. */ - public void removeAll() { - mButtonsByCategory.clear(); - mButtonsByPackage.clear(); - mButtonsByComponentName.clear(); - mSelectedFacetButtons.clear(); - mRegisteredViews.clear(); - } - - /** - * Iterate through a view looking for CarFacetButtons and adding them to the controller if found + * Iterate through a view looking for CarNavigationButton and add it to the controller if it + * opted in to be highlighted when the active application is associated with it. * * @param v the View that may contain CarFacetButtons */ - public void addAllFacetButtons(View v) { - if (v instanceof CarFacetButton) { - addFacetButton((CarFacetButton) v); + protected void addAllButtonsWithSelectionState(View v) { + if (v instanceof CarNavigationButton) { + if (((CarNavigationButton) v).hasSelectionState()) { + addButtonWithSelectionState((CarNavigationButton) v); + } } else if (v instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) v; for (int i = 0; i < viewGroup.getChildCount(); i++) { - addAllFacetButtons(viewGroup.getChildAt(i)); + addAllButtonsWithSelectionState(viewGroup.getChildAt(i)); } } } + /** Removes all buttons from the button maps. */ + protected void removeAll() { + mButtonsByCategory.clear(); + mButtonsByPackage.clear(); + mButtonsByComponentName.clear(); + mSelectedButtons.clear(); + mRegisteredViews.clear(); + } + /** - * 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. + * This will unselect the currently selected CarNavigationButton and determine which one should + * be selected next. It does this by reading the properties on the CarNavigationButton 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. + * for consideration if it has the same displayId as the CarNavigationButton. * * @param stackInfoList of the currently running application + * @param validDisplay index of the valid display */ - public void taskChanged(List stackInfoList) { + + protected void taskChanged(List stackInfoList, int validDisplay) { ActivityManager.StackInfo validStackInfo = null; for (ActivityManager.StackInfo stackInfo : stackInfoList) { // Find the first stack info with a topActivity in the primary display. // TODO: We assume that CarFacetButton will launch an app only in the primary display. - // We need to extend the functionality to handle the mutliple display properly. - if (stackInfo.topActivity != null && stackInfo.displayId == Display.DEFAULT_DISPLAY) { + // We need to extend the functionality to handle the multiple display properly. + if (stackInfo.topActivity != null && stackInfo.displayId == validDisplay) { validStackInfo = stackInfo; break; } } if (validStackInfo == null) { - // No stack was found that was on the same display as the facet buttons thus return + // No stack was found that was on the same display as the buttons thus return return; } + int displayId = validStackInfo.displayId; - if (mSelectedFacetButtons != null) { - Iterator iterator = mSelectedFacetButtons.iterator(); - while (iterator.hasNext()) { - CarFacetButton carFacetButton = iterator.next(); - if (carFacetButton.getDisplayId() == validStackInfo.displayId) { - carFacetButton.setSelected(false); - iterator.remove(); + mSelectedButtons.forEach(carNavigationButton -> { + if (carNavigationButton.getDisplayId() == displayId) { + carNavigationButton.setSelected(false); + } + }); + mSelectedButtons.clear(); + + HashSet selectedButtons = findSelectedButtons(validStackInfo); + + if (selectedButtons != null) { + selectedButtons.forEach(carNavigationButton -> { + if (carNavigationButton.getDisplayId() == displayId) { + carNavigationButton.setSelected(true); + mSelectedButtons.add(carNavigationButton); } - } + }); } - - String packageName = validStackInfo.topActivity.getPackageName(); - HashSet facetButton = - findFacetButtonByComponentName(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) { - for (CarFacetButton carFacetButton : facetButton) { - if (carFacetButton.getDisplayId() == validStackInfo.displayId) { - carFacetButton.setSelected(true); - mSelectedFacetButtons.add(carFacetButton); - } - } - } - } - private HashSet findFacetButtonByComponentName(ComponentName componentName) { - HashSet buttons = + /** + * Defaults to Display.DEFAULT_DISPLAY when no parameter is provided for the validDisplay. + * + * @param stackInfoList + */ + protected void taskChanged(List stackInfoList) { + taskChanged(stackInfoList, Display.DEFAULT_DISPLAY); + } + + /** + * Add navigation button to this controller if it uses selection state. + */ + private void addButtonWithSelectionState(CarNavigationButton carNavigationButton) { + if (mRegisteredViews.contains(carNavigationButton)) { + return; + } + String[] categories = carNavigationButton.getCategories(); + for (int i = 0; i < categories.length; i++) { + mButtonsByCategory.add(categories[i], carNavigationButton); + } + + String[] packages = carNavigationButton.getPackages(); + for (int i = 0; i < packages.length; i++) { + mButtonsByPackage.add(packages[i], carNavigationButton); + } + String[] componentNames = carNavigationButton.getComponentName(); + for (int i = 0; i < componentNames.length; i++) { + mButtonsByComponentName.add(componentNames[i], carNavigationButton); + } + + mRegisteredViews.add(carNavigationButton); + } + + private HashSet findSelectedButtons( + ActivityManager.StackInfo validStackInfo) { + String packageName = validStackInfo.topActivity.getPackageName(); + + HashSet selectedButtons = + findButtonsByComponentName(validStackInfo.topActivity); + if (selectedButtons == null) { + selectedButtons = mButtonsByPackage.get(packageName); + } + if (selectedButtons == null) { + String category = getPackageCategory(packageName); + if (category != null) { + selectedButtons = mButtonsByCategory.get(category); + } + } + + return selectedButtons; + } + + private HashSet findButtonsByComponentName( + ComponentName componentName) { + HashSet buttons = mButtonsByComponentName.get(componentName.flattenToShortString()); return (buttons != null) ? buttons : mButtonsByComponentName.get(componentName.flattenToString()); } - protected String getPackageCategory(String packageName) { + private String getPackageCategory(String packageName) { PackageManager pm = mContext.getPackageManager(); Set supportedCategories = mButtonsByCategory.keySet(); for (String category : supportedCategories) { @@ -190,7 +207,7 @@ public class CarFacetButtonController { 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 + // Cache this package name into ButtonsByPackage map, so we won't have to query // all categories next time this package name shows up. mButtonsByPackage.put(packageName, mButtonsByCategory.get(category)); return category; @@ -200,13 +217,13 @@ public class CarFacetButtonController { } // simple multi-map - private static class ButtonMap extends HashMap> { + private static class ButtonMap extends HashMap> { - public boolean add(String key, CarFacetButton value) { + public boolean add(String key, CarNavigationButton value) { if (containsKey(key)) { return get(key).add(value); } - HashSet set = new HashSet<>(); + HashSet set = new HashSet<>(); set.add(value); put(key, set); return true; diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/FacetButtonTaskStackListener.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/ButtonSelectionStateListener.java similarity index 75% rename from packages/CarSystemUI/src/com/android/systemui/navigationbar/car/FacetButtonTaskStackListener.java rename to packages/CarSystemUI/src/com/android/systemui/navigationbar/car/ButtonSelectionStateListener.java index 4925220d9cad7..9da412111f071 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/FacetButtonTaskStackListener.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/ButtonSelectionStateListener.java @@ -24,28 +24,25 @@ import com.android.systemui.shared.system.TaskStackChangeListener; import javax.inject.Inject; import javax.inject.Singleton; -import dagger.Lazy; - /** * An implementation of TaskStackChangeListener, that listens for changes in the system * task stack and notifies the navigation bar. */ @Singleton -class FacetButtonTaskStackListener extends TaskStackChangeListener { - private static final String TAG = FacetButtonTaskStackListener.class.getSimpleName(); +class ButtonSelectionStateListener extends TaskStackChangeListener { + private static final String TAG = ButtonSelectionStateListener.class.getSimpleName(); - private final Lazy mFacetButtonControllerLazy; + private final ButtonSelectionStateController mButtonSelectionStateController; @Inject - FacetButtonTaskStackListener( - Lazy carFacetButtonControllerLazy) { - mFacetButtonControllerLazy = carFacetButtonControllerLazy; + ButtonSelectionStateListener(ButtonSelectionStateController carNavigationButtonController) { + mButtonSelectionStateController = carNavigationButtonController; } @Override public void onTaskStackChanged() { try { - mFacetButtonControllerLazy.get().taskChanged( + mButtonSelectionStateController.taskChanged( ActivityTaskManager.getService().getAllStackInfos()); } catch (Exception e) { Log.e(TAG, "Getting StackInfo from activity manager failed", e); @@ -55,7 +52,7 @@ class FacetButtonTaskStackListener extends TaskStackChangeListener { @Override public void onTaskDisplayChanged(int taskId, int newDisplayId) { try { - mFacetButtonControllerLazy.get().taskChanged( + mButtonSelectionStateController.taskChanged( ActivityTaskManager.getService().getAllStackInfos()); } catch (Exception e) { Log.e(TAG, "Getting StackInfo from activity manager failed", e); diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java deleted file mode 100644 index 0b8999263c73e..0000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.navigationbar.car; - -import android.app.ActivityOptions; -import android.content.Context; -import android.content.Intent; -import android.content.res.TypedArray; -import android.os.Build; -import android.os.UserHandle; -import android.util.AttributeSet; -import android.view.Display; -import android.view.View; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import com.android.keyguard.AlphaOptimizedImageButton; -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 implying 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. - * - * New activity will be launched on the same display as the button is on. - * 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 static final String TAG = "CarFacetButton"; - - 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); - } - - /** - * Reads the custom attributes to setup click handlers for this component. - */ - protected 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 -> { - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchDisplayId(mContext.getDisplayId()); - intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, mSelected); - mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT); - mContext.sendBroadcastAsUser( - new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT); - }); - - if (longPressIntentString != null && (Build.IS_ENG || Build.IS_USERDEBUG)) { - final Intent longPressIntent = Intent.parseUri(longPressIntentString, - Intent.URI_INTENT_SCHEME); - setOnLongClickListener(v -> { - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchDisplayId(mContext.getDisplayId()); - mContext.startActivityAsUser(longPressIntent, options.toBundle(), - UserHandle.CURRENT); - mContext.sendBroadcastAsUser( - new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), 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; - } - - /** - * @return The list of component names. - */ - 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); - } - } - - /** - * @return The id of the display the button is on or Display.INVALID_DISPLAY if it's not yet on - * a display. - */ - public int getDisplayId() { - Display display = getDisplay(); - if (display == null) { - return Display.INVALID_DISPLAY; - } - return display.getDisplayId(); - } -} diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java index 59a084e337ad9..d8c9d17e71798 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java @@ -57,12 +57,12 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private final WindowManager mWindowManager; private final CarDeviceProvisionedController mCarDeviceProvisionedController; private final CommandQueue mCommandQueue; - private final Lazy mFacetButtonTaskStackListenerLazy; + private final ButtonSelectionStateListener mButtonSelectionStateListener; private final Handler mMainHandler; private final Lazy mKeyguardStateControllerLazy; private final Lazy mNavigationBarControllerLazy; private final SuperStatusBarViewFactory mSuperStatusBarViewFactory; - private final Lazy mCarFacetButtonControllerLazy; + private final ButtonSelectionStateController mButtonSelectionStateController; private IStatusBarService mBarService; private ActivityManagerWrapper mActivityManagerWrapper; @@ -92,24 +92,24 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks WindowManager windowManager, DeviceProvisionedController deviceProvisionedController, CommandQueue commandQueue, - Lazy facetButtonTaskStackListenerLazy, + ButtonSelectionStateListener buttonSelectionStateListener, @Main Handler mainHandler, Lazy keyguardStateControllerLazy, Lazy navigationBarControllerLazy, SuperStatusBarViewFactory superStatusBarViewFactory, - Lazy carFacetButtonControllerLazy) { + ButtonSelectionStateController buttonSelectionStateController) { super(context); mCarNavigationBarController = carNavigationBarController; mWindowManager = windowManager; mCarDeviceProvisionedController = (CarDeviceProvisionedController) deviceProvisionedController; mCommandQueue = commandQueue; - mFacetButtonTaskStackListenerLazy = facetButtonTaskStackListenerLazy; + mButtonSelectionStateListener = buttonSelectionStateListener; mMainHandler = mainHandler; mKeyguardStateControllerLazy = keyguardStateControllerLazy; mNavigationBarControllerLazy = navigationBarControllerLazy; mSuperStatusBarViewFactory = superStatusBarViewFactory; - mCarFacetButtonControllerLazy = carFacetButtonControllerLazy; + mButtonSelectionStateController = buttonSelectionStateController; } @Override @@ -156,7 +156,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks createNavigationBar(result); mActivityManagerWrapper = ActivityManagerWrapper.getInstance(); - mActivityManagerWrapper.registerTaskStackListener(mFacetButtonTaskStackListenerLazy.get()); + mActivityManagerWrapper.registerTaskStackListener(mButtonSelectionStateListener); mCarNavigationBarController.connectToHvac(); } @@ -181,7 +181,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks // remove and reattach all hvac components such that we don't keep a reference to unused // ui elements mCarNavigationBarController.removeAllFromHvac(); - mCarFacetButtonControllerLazy.get().removeAll(); + mButtonSelectionStateController.removeAll(); if (mTopNavigationBarWindow != null) { mTopNavigationBarWindow.removeAllViews(); @@ -343,7 +343,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.print(" mTaskStackListener="); - pw.println(mFacetButtonTaskStackListenerLazy.get()); + pw.println(mButtonSelectionStateListener); pw.print(" mBottomNavigationBarView="); pw.println(mBottomNavigationBarView); } diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java index 6f288439ddeb5..a56c4eda44da6 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java @@ -37,7 +37,7 @@ public class CarNavigationBarController { private final Context mContext; private final NavigationBarViewFactory mNavigationBarViewFactory; - private final Lazy mCarFacetButtonControllerLazy; + private final ButtonSelectionStateController mButtonSelectionStateController; private final Lazy mHvacControllerLazy; private boolean mShowBottom; @@ -58,11 +58,11 @@ public class CarNavigationBarController { @Inject public CarNavigationBarController(Context context, NavigationBarViewFactory navigationBarViewFactory, - Lazy carFacetButtonControllerLazy, + ButtonSelectionStateController buttonSelectionStateController, Lazy hvacControllerLazy) { mContext = context; mNavigationBarViewFactory = navigationBarViewFactory; - mCarFacetButtonControllerLazy = carFacetButtonControllerLazy; + mButtonSelectionStateController = buttonSelectionStateController; mHvacControllerLazy = hvacControllerLazy; // Read configuration. @@ -175,7 +175,7 @@ public class CarNavigationBarController { NotificationsShadeController notifShadeController) { view.setStatusBarWindowTouchListener(statusBarTouchListener); view.setNotificationsPanelController(notifShadeController); - mCarFacetButtonControllerLazy.get().addAllFacetButtons(view); + mButtonSelectionStateController.addAllButtonsWithSelectionState(view); mHvacControllerLazy.get().addTemperatureViewToController(view); } diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java index 922bfffcfa22e..15a2633a86021 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java @@ -24,8 +24,12 @@ import android.os.Build; import android.os.UserHandle; import android.util.AttributeSet; import android.util.Log; +import android.view.Display; +import android.view.View; import android.widget.ImageView; +import android.widget.LinearLayout; +import com.android.keyguard.AlphaOptimizedImageButton; import com.android.systemui.R; import java.net.URISyntaxException; @@ -35,110 +39,66 @@ import java.net.URISyntaxException; * xml file level. This allows for more control via overlays instead of having to update * code. */ -public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImageButton { - private static final String TAG = "CarNavigationButton"; +public class CarNavigationButton extends LinearLayout { + protected static final float DEFAULT_SELECTED_ALPHA = 1f; + protected static final float DEFAULT_UNSELECTED_ALPHA = 0.75f; + + private static final String TAG = "CarNavigationButton"; + private static final String BUTTON_FILTER_DELIMITER = ";"; + private static final String EXTRA_BUTTON_CATEGORIES = "categories"; + private static final String EXTRA_BUTTON_PACKAGES = "packages"; private static final int UNSEEN_ICON_RESOURCE_ID = R.drawable.car_ic_notification_unseen; private static final int UNSEEN_SELECTED_ICON_RESOURCE_ID = R.drawable.car_ic_notification_selected_unseen; private Context mContext; + private AlphaOptimizedImageButton mIcon; + private AlphaOptimizedImageButton mMoreIcon; private String mIntent; private String mLongIntent; private boolean mBroadcastIntent; private boolean mHasUnseen = false; private boolean mSelected = false; - private float mSelectedAlpha = 1f; - private float mUnselectedAlpha = 1f; + private float mSelectedAlpha; + private float mUnselectedAlpha; private int mSelectedIconResourceId; private int mIconResourceId; - + private String[] mComponentNames; + /** App categories that are to be used with this widget */ + private String[] mButtonCategories; + /** App packages that are allowed to be used with this widget */ + private String[] mButtonPackages; + /** Whether to display more icon beneath the primary icon when the button is selected */ + private boolean mShowMoreWhenSelected = false; + /** Whether to highlight the button if the active application is associated with it */ + private boolean mHighlightWhenSelected = false; public CarNavigationButton(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; - + View.inflate(mContext, R.layout.car_navigation_button, /* root= */ this); // CarNavigationButton attrs - TypedArray typedArray = context.obtainStyledAttributes( - attrs, R.styleable.CarNavigationButton); - mIntent = typedArray.getString(R.styleable.CarNavigationButton_intent); - mLongIntent = typedArray.getString(R.styleable.CarNavigationButton_longIntent); - mBroadcastIntent = typedArray.getBoolean(R.styleable.CarNavigationButton_broadcast, false); - mSelectedAlpha = typedArray.getFloat( - R.styleable.CarNavigationButton_selectedAlpha, mSelectedAlpha); - mUnselectedAlpha = typedArray.getFloat( - R.styleable.CarNavigationButton_unselectedAlpha, mUnselectedAlpha); - mSelectedIconResourceId = typedArray.getResourceId( - R.styleable.CarNavigationButton_selectedIcon, mIconResourceId); - mIconResourceId = typedArray.getResourceId( - R.styleable.CarNavigationButton_icon, 0); + TypedArray typedArray = context.obtainStyledAttributes(attrs, + R.styleable.CarNavigationButton); + + setUpIntents(typedArray); + setUpIcons(typedArray); typedArray.recycle(); } - - /** - * After the standard inflate this then adds the xml defined intents to click and long click - * actions if defined. - */ - @Override - public void onFinishInflate() { - super.onFinishInflate(); - setScaleType(ImageView.ScaleType.CENTER); - setAlpha(mUnselectedAlpha); - setImageResource(mIconResourceId); - try { - if (mIntent != null) { - final Intent intent = Intent.parseUri(mIntent, Intent.URI_INTENT_SCHEME); - setOnClickListener(v -> { - try { - if (mBroadcastIntent) { - mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); - mContext.sendBroadcastAsUser( - new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), - UserHandle.CURRENT); - return; - } - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchDisplayId(mContext.getDisplayId()); - mContext.startActivityAsUser(intent, options.toBundle(), - UserHandle.CURRENT); - } catch (Exception e) { - Log.e(TAG, "Failed to launch intent", e); - } - }); - } - } catch (URISyntaxException e) { - throw new RuntimeException("Failed to attach intent", e); - } - - try { - if (mLongIntent != null && (Build.IS_ENG || Build.IS_USERDEBUG)) { - final Intent intent = Intent.parseUri(mLongIntent, Intent.URI_INTENT_SCHEME); - setOnLongClickListener(v -> { - try { - ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchDisplayId(mContext.getDisplayId()); - mContext.startActivityAsUser(intent, options.toBundle(), - UserHandle.CURRENT); - } catch (Exception e) { - Log.e(TAG, "Failed to launch intent", e); - } - // consume event either way - return true; - }); - } - } catch (URISyntaxException e) { - throw new RuntimeException("Failed to attach long press intent", e); - } - } - /** * @param selected true if should indicate if this is a selected state, false otherwise */ public void setSelected(boolean selected) { super.setSelected(selected); mSelected = selected; - setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha); + if (mHighlightWhenSelected) { + setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha); + } + if (mShowMoreWhenSelected && mMoreIcon != null) { + mMoreIcon.setVisibility(selected ? VISIBLE : GONE); + } updateImage(); } @@ -155,12 +115,165 @@ public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImag return mHasUnseen; } + /** + * @return The app categories the component represents + */ + public String[] getCategories() { + if (mButtonCategories == null) { + return new String[0]; + } + return mButtonCategories; + } + + /** + * @return The valid packages that should be considered. + */ + public String[] getPackages() { + if (mButtonPackages == null) { + return new String[0]; + } + return mButtonPackages; + } + + /** + * @return The list of component names. + */ + public String[] getComponentName() { + if (mComponentNames == null) { + return new String[0]; + } + return mComponentNames; + } + + /** + * @return The id of the display the button is on or Display.INVALID_DISPLAY if it's not yet on + * a display. + */ + protected int getDisplayId() { + Display display = getDisplay(); + if (display == null) { + return Display.INVALID_DISPLAY; + } + return display.getDisplayId(); + } + + protected boolean hasSelectionState() { + return mHighlightWhenSelected || mShowMoreWhenSelected; + } + + /** + * Sets up intents for click, long touch, and broadcast. + */ + protected void setUpIntents(TypedArray typedArray) { + mIntent = typedArray.getString(R.styleable.CarNavigationButton_intent); + mLongIntent = typedArray.getString(R.styleable.CarNavigationButton_longIntent); + mBroadcastIntent = typedArray.getBoolean(R.styleable.CarNavigationButton_broadcast, false); + + String categoryString = typedArray.getString(R.styleable.CarNavigationButton_categories); + String packageString = typedArray.getString(R.styleable.CarNavigationButton_packages); + String componentNameString = + typedArray.getString(R.styleable.CarNavigationButton_componentNames); + + try { + if (mIntent != null) { + final Intent intent = Intent.parseUri(mIntent, Intent.URI_INTENT_SCHEME); + setOnClickListener(v -> { + try { + if (mBroadcastIntent) { + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); + mContext.sendBroadcastAsUser( + new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), + UserHandle.CURRENT); + return; + } + ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(mContext.getDisplayId()); + mContext.startActivityAsUser(intent, options.toBundle(), + UserHandle.CURRENT); + mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), + UserHandle.CURRENT); + } catch (Exception e) { + Log.e(TAG, "Failed to launch intent", e); + } + }); + if (packageString != null) { + mButtonPackages = packageString.split(BUTTON_FILTER_DELIMITER); + intent.putExtra(EXTRA_BUTTON_PACKAGES, mButtonPackages); + } + if (categoryString != null) { + mButtonCategories = categoryString.split(BUTTON_FILTER_DELIMITER); + intent.putExtra(EXTRA_BUTTON_CATEGORIES, mButtonCategories); + } + if (componentNameString != null) { + mComponentNames = componentNameString.split(BUTTON_FILTER_DELIMITER); + } + } + } catch (URISyntaxException e) { + throw new RuntimeException("Failed to attach intent", e); + } + + try { + if (mLongIntent != null && (Build.IS_ENG || Build.IS_USERDEBUG)) { + final Intent intent = Intent.parseUri(mLongIntent, Intent.URI_INTENT_SCHEME); + setOnLongClickListener(v -> { + try { + ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchDisplayId(mContext.getDisplayId()); + mContext.startActivityAsUser(intent, options.toBundle(), + UserHandle.CURRENT); + mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), + UserHandle.CURRENT); + } catch (Exception e) { + Log.e(TAG, "Failed to launch intent", e); + } + // consume event either way + return true; + }); + } + } catch (URISyntaxException e) { + throw new RuntimeException("Failed to attach long press intent", e); + } + } + + /** + * Initializes view-related aspects of the button. + */ + private void setUpIcons(TypedArray typedArray) { + mSelectedAlpha = typedArray.getFloat( + R.styleable.CarNavigationButton_selectedAlpha, DEFAULT_SELECTED_ALPHA); + mUnselectedAlpha = typedArray.getFloat( + R.styleable.CarNavigationButton_unselectedAlpha, DEFAULT_UNSELECTED_ALPHA); + mHighlightWhenSelected = typedArray.getBoolean( + R.styleable.CarNavigationButton_highlightWhenSelected, + mHighlightWhenSelected); + mShowMoreWhenSelected = typedArray.getBoolean( + R.styleable.CarNavigationButton_showMoreWhenSelected, + mShowMoreWhenSelected); + + mSelectedIconResourceId = typedArray.getResourceId( + R.styleable.CarNavigationButton_selectedIcon, mIconResourceId); + mIconResourceId = typedArray.getResourceId( + R.styleable.CarNavigationButton_icon, 0); + + mIcon = findViewById(R.id.car_nav_button_icon_image); + mIcon.setScaleType(ImageView.ScaleType.CENTER); + mIcon.setClickable(false); + // Always apply selected alpha if the button does not toggle alpha based on selection state. + mIcon.setAlpha(mHighlightWhenSelected ? mUnselectedAlpha : mSelectedAlpha); + mIcon.setImageResource(mIconResourceId); + + mMoreIcon = findViewById(R.id.car_nav_button_more_icon); + mMoreIcon.setClickable(false); + mMoreIcon.setAlpha(mSelectedAlpha); + mMoreIcon.setVisibility(GONE); + } + private void updateImage() { if (mHasUnseen) { - setImageResource(mSelected ? UNSEEN_SELECTED_ICON_RESOURCE_ID + mIcon.setImageResource(mSelected ? UNSEEN_SELECTED_ICON_RESOURCE_ID : UNSEEN_ICON_RESOURCE_ID); } else { - setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId); + mIcon.setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId); } } } diff --git a/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml b/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml new file mode 100644 index 0000000000000..f0e02164a24bb --- /dev/null +++ b/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml b/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml new file mode 100644 index 0000000000000..576928cda0891 --- /dev/null +++ b/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/ButtonSelectionStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/ButtonSelectionStateControllerTest.java new file mode 100644 index 0000000000000..f94dd82dbd98a --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/ButtonSelectionStateControllerTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.navigationbar.car; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.ActivityManager; +import android.content.ComponentName; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.LayoutInflater; +import android.widget.LinearLayout; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.tests.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class ButtonSelectionStateControllerTest extends SysuiTestCase { + + private static final String TEST_COMPONENT_NAME_PACKAGE = "com.android.car.carlauncher"; + private static final String TEST_COMPONENT_NAME_CLASS = ".CarLauncher"; + private static final String TEST_CATEGORY = "com.google.android.apps.maps"; + private static final String TEST_CATEGORY_CLASS = ".APP_MAPS"; + private static final String TEST_PACKAGE = "com.android.car.dialer"; + private static final String TEST_PACKAGE_CLASS = ".Dialer"; + + // LinearLayout with CarNavigationButtons with different configurations. + private LinearLayout mTestView; + private ButtonSelectionStateController mButtonSelectionStateController; + private ComponentName mComponentName; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mTestView = (LinearLayout) LayoutInflater.from(mContext).inflate( + R.layout.car_button_selection_state_controller_test, /* root= */ null); + mButtonSelectionStateController = new ButtonSelectionStateController(mContext); + mButtonSelectionStateController.addAllButtonsWithSelectionState(mTestView); + } + + @Test + public void onTaskChanged_buttonDetectableByComponentName_selectsAssociatedButton() { + CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_component_name); + mComponentName = new ComponentName(TEST_COMPONENT_NAME_PACKAGE, TEST_COMPONENT_NAME_CLASS); + List testStack = createTestStack(mComponentName); + testButton.setSelected(false); + mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1); + + assertbuttonSelected(testButton); + } + + @Test + public void onTaskChanged_buttonDetectableByCategory_selectsAssociatedButton() { + CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_category); + mComponentName = new ComponentName(TEST_CATEGORY, TEST_CATEGORY_CLASS); + List testStack = createTestStack(mComponentName); + testButton.setSelected(false); + mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1); + + assertbuttonSelected(testButton); + } + + @Test + public void onTaskChanged_buttonDetectableByPackage_selectsAssociatedButton() { + CarNavigationButton testButton = mTestView.findViewById(R.id.detectable_by_package); + mComponentName = new ComponentName(TEST_PACKAGE, TEST_PACKAGE_CLASS); + List testStack = createTestStack(mComponentName); + testButton.setSelected(false); + mButtonSelectionStateController.taskChanged(testStack, /* validDisplay= */ -1); + + assertbuttonSelected(testButton); + } + + @Test + public void onTaskChanged_deselectsPreviouslySelectedButton() { + CarNavigationButton oldButton = mTestView.findViewById(R.id.detectable_by_component_name); + mComponentName = new ComponentName(TEST_COMPONENT_NAME_PACKAGE, TEST_COMPONENT_NAME_CLASS); + List oldStack = createTestStack(mComponentName); + oldButton.setSelected(false); + mButtonSelectionStateController.taskChanged(oldStack, /* validDisplay= */ -1); + + mComponentName = new ComponentName(TEST_PACKAGE, TEST_PACKAGE_CLASS); + List newStack = createTestStack(mComponentName); + mButtonSelectionStateController.taskChanged(newStack, /* validDisplay= */ -1); + + assertButtonUnselected(oldButton); + } + + // Comparing alpha is a valid way to verify button selection state because all test buttons use + // highlightWhenSelected = true. + private void assertbuttonSelected(CarNavigationButton button) { + assertThat(button.getAlpha()).isEqualTo(CarNavigationButton.DEFAULT_SELECTED_ALPHA); + } + + private void assertButtonUnselected(CarNavigationButton button) { + assertThat(button.getAlpha()).isEqualTo(CarNavigationButton.DEFAULT_UNSELECTED_ALPHA); + } + + private List createTestStack(ComponentName componentName) { + ActivityManager.StackInfo validStackInfo = new ActivityManager.StackInfo(); + validStackInfo.displayId = -1; // No display is assigned to this test view + validStackInfo.topActivity = componentName; + + List testStack = new ArrayList<>(); + testStack.add(validStackInfo); + + return testStack; + } +} diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java index 642b1145cb941..e0c13ed536b6d 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java @@ -51,7 +51,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { private TestableResources mTestableResources; @Mock - private CarFacetButtonController mCarFacetButtonController; + private ButtonSelectionStateController mButtonSelectionStateController; @Mock private HvacController mHvacController; @@ -69,7 +69,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testConnectToHvac_callsConnect() { mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); mCarNavigationBar.connectToHvac(); @@ -79,7 +79,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testRemoveAllFromHvac_callsRemoveAll() { mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); mCarNavigationBar.removeAllFromHvac(); @@ -90,7 +90,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetBottomWindow_bottomDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); @@ -101,7 +101,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetBottomWindow_bottomEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); @@ -112,7 +112,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window1 = mCarNavigationBar.getBottomWindow(); ViewGroup window2 = mCarNavigationBar.getBottomWindow(); @@ -124,7 +124,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetLeftWindow_leftDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); assertThat(window).isNull(); } @@ -133,7 +133,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetLeftWindow_leftEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); @@ -144,7 +144,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window1 = mCarNavigationBar.getLeftWindow(); ViewGroup window2 = mCarNavigationBar.getLeftWindow(); @@ -156,7 +156,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetRightWindow_rightDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); @@ -167,7 +167,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetRightWindow_rightEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); @@ -178,7 +178,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window1 = mCarNavigationBar.getRightWindow(); ViewGroup window2 = mCarNavigationBar.getRightWindow(); @@ -190,7 +190,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetBottomWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE); @@ -202,7 +202,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetBottomWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getBottomWindow(); mCarNavigationBar.setBottomWindowVisibility(View.GONE); @@ -214,7 +214,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetLeftWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE); @@ -226,7 +226,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetLeftWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getLeftWindow(); mCarNavigationBar.setLeftWindowVisibility(View.GONE); @@ -238,7 +238,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetRightWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); mCarNavigationBar.setRightWindowVisibility(View.VISIBLE); @@ -250,7 +250,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testSetRightWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); ViewGroup window = mCarNavigationBar.getRightWindow(); mCarNavigationBar.setRightWindowVisibility(View.GONE); @@ -262,7 +262,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener(); @@ -277,7 +277,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class)); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); @@ -290,7 +290,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterNotificationController_createViewFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationBarController.NotificationsShadeController controller = @@ -307,7 +307,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testRegisterNotificationController_registerFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); mCarNavigationBar.registerNotificationController( mock(CarNavigationBarController.NotificationsShadeController.class)); @@ -322,7 +322,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); @@ -335,7 +335,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); @@ -348,7 +348,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); @@ -363,7 +363,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); @@ -378,7 +378,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); @@ -393,7 +393,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - () -> mCarFacetButtonController, () -> mHvacController); + mButtonSelectionStateController, () -> mHvacController); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationButtonTest.java new file mode 100644 index 0000000000000..e1ee6162ddcca --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationButtonTest.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.navigationbar.car; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.test.filters.SmallTest; + +import com.android.keyguard.AlphaOptimizedImageButton; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.tests.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class CarNavigationButtonTest extends SysuiTestCase { + + private static final String DEFAULT_BUTTON_ACTIVITY_NAME = + "com.android.car.carlauncher/.CarLauncher"; + private static final String APP_GRID_BUTTON_ACTIVITY_NAME = + "com.android.car.carlauncher/.AppGridActivity"; + private static final String BROADCAST_ACTION_NAME = + "android.car.intent.action.TOGGLE_HVAC_CONTROLS"; + + private ActivityManager mActivityManager; + // LinearLayout with CarNavigationButtons with different configurations. + private LinearLayout mTestView; + // Does not have any selection state which is the default configuration. + private CarNavigationButton mDefaultButton; + + @Before + public void setUp() { + mContext = spy(mContext); + mTestView = (LinearLayout) LayoutInflater.from(mContext).inflate( + R.layout.car_navigation_button_test, /* root= */ null); + mDefaultButton = mTestView.findViewById(R.id.default_no_selection_state); + mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + } + + @Test + public void onCreate_iconIsVisible() { + AlphaOptimizedImageButton icon = mDefaultButton.findViewById( + R.id.car_nav_button_icon_image); + + assertThat(icon.getDrawable()).isNotNull(); + } + + @Test + public void onSelected_selectedIconDefined_togglesIcon() { + mDefaultButton.setSelected(true); + Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById( + R.id.car_nav_button_icon_image)).getDrawable(); + + + mDefaultButton.setSelected(false); + Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById( + R.id.car_nav_button_icon_image)).getDrawable(); + + assertThat(selectedIconDrawable).isNotEqualTo(unselectedIconDrawable); + } + + @Test + public void onSelected_selectedIconUndefined_displaysSameIcon() { + CarNavigationButton selectedIconUndefinedButton = mTestView.findViewById( + R.id.selected_icon_undefined); + + selectedIconUndefinedButton.setSelected(true); + Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById( + R.id.car_nav_button_icon_image)).getDrawable(); + + + selectedIconUndefinedButton.setSelected(false); + Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById( + R.id.car_nav_button_icon_image)).getDrawable(); + + assertThat(selectedIconDrawable).isEqualTo(unselectedIconDrawable); + } + + @Test + public void onUnselected_doesNotHighlightWhenSelected_applySelectedAlpha() { + mDefaultButton.setSelected(false); + + assertThat(mDefaultButton.getAlpha()).isEqualTo( + CarNavigationButton.DEFAULT_SELECTED_ALPHA); + } + + @Test + public void onSelected_doesNotHighlightWhenSelected_applySelectedAlpha() { + mDefaultButton.setSelected(true); + + assertThat(mDefaultButton.getAlpha()).isEqualTo( + CarNavigationButton.DEFAULT_SELECTED_ALPHA); + } + + @Test + public void onUnselected_highlightWhenSelected_applyDefaultUnselectedAlpha() { + CarNavigationButton highlightWhenSelectedButton = mTestView.findViewById( + R.id.highlightable_no_more_button); + highlightWhenSelectedButton.setSelected(false); + + assertThat(highlightWhenSelectedButton.getAlpha()).isEqualTo( + CarNavigationButton.DEFAULT_UNSELECTED_ALPHA); + } + + @Test + public void onSelected_highlightWhenSelected_applyDefaultSelectedAlpha() { + CarNavigationButton highlightWhenSelectedButton = mTestView.findViewById( + R.id.highlightable_no_more_button); + highlightWhenSelectedButton.setSelected(true); + + assertThat(highlightWhenSelectedButton.getAlpha()).isEqualTo( + CarNavigationButton.DEFAULT_SELECTED_ALPHA); + } + + @Test + public void onSelected_doesNotShowMoreWhenSelected_doesNotShowMoreIcon() { + mDefaultButton.setSelected(true); + AlphaOptimizedImageButton moreIcon = mDefaultButton.findViewById( + R.id.car_nav_button_more_icon); + + assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void onSelected_showMoreWhenSelected_showsMoreIcon() { + CarNavigationButton showMoreWhenSelected = mTestView.findViewById( + R.id.not_highlightable_more_button); + showMoreWhenSelected.setSelected(true); + AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById( + R.id.car_nav_button_more_icon); + + assertThat(moreIcon.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void onUnselected_showMoreWhenSelected_doesNotShowMoreIcon() { + CarNavigationButton showMoreWhenSelected = mTestView.findViewById( + R.id.highlightable_no_more_button); + showMoreWhenSelected.setSelected(true); + showMoreWhenSelected.setSelected(false); + AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById( + R.id.car_nav_button_more_icon); + + assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void onClick_launchesIntentActivity() { + mDefaultButton.performClick(); + + assertThat(getCurrentActivityName()).isEqualTo(DEFAULT_BUTTON_ACTIVITY_NAME); + + CarNavigationButton appGridButton = mTestView.findViewById(R.id.app_grid_activity); + appGridButton.performClick(); + + assertThat(getCurrentActivityName()).isEqualTo(APP_GRID_BUTTON_ACTIVITY_NAME); + } + + @Test + public void onLongClick_longIntentDefined_launchesLongIntentActivity() { + mDefaultButton.performClick(); + + assertThat(getCurrentActivityName()).isEqualTo(DEFAULT_BUTTON_ACTIVITY_NAME); + + CarNavigationButton appGridButton = mTestView.findViewById( + R.id.long_click_app_grid_activity); + appGridButton.performLongClick(); + + assertThat(getCurrentActivityName()).isEqualTo(APP_GRID_BUTTON_ACTIVITY_NAME); + } + + @Test + public void onClick_useBroadcast_broadcastsIntent() { + CarNavigationButton appGridButton = mTestView.findViewById(R.id.broadcast); + appGridButton.performClick(); + + verify(mContext).sendBroadcastAsUser(argThat(new ArgumentMatcher() { + @Override + public boolean matches(Intent argument) { + return argument.getAction().equals(BROADCAST_ACTION_NAME); + } + }), any()); + } + + private String getCurrentActivityName() { + return mActivityManager.getRunningTasks(1).get(0).topActivity.flattenToShortString(); + } +} diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml index 49b87f31d3aba..125076f9c69af 100644 --- a/packages/SystemUI/res/values/attrs_car.xml +++ b/packages/SystemUI/res/values/attrs_car.xml @@ -22,32 +22,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -64,6 +38,16 @@ + + + + + + + + + + From 54bef9dd111a4bd56f624f37298e9469be1a720c Mon Sep 17 00:00:00 2001 From: kwaky Date: Fri, 20 Dec 2019 11:25:37 -0800 Subject: [PATCH 2/2] Move attrs_car from SysUI to attrs in CarSystemUI Bug: 146513202 Test: Build, Manual, and Unit Tests still passing Change-Id: Idd6e58e27e6de909ba20481513112b9abd689571 --- packages/CarSystemUI/res/values/attrs.xml | 69 +++++++++++++++++ packages/SystemUI/res/values/attrs_car.xml | 87 ---------------------- 2 files changed, 69 insertions(+), 87 deletions(-) delete mode 100644 packages/SystemUI/res/values/attrs_car.xml diff --git a/packages/CarSystemUI/res/values/attrs.xml b/packages/CarSystemUI/res/values/attrs.xml index 6178738652893..54026af4bff6d 100644 --- a/packages/CarSystemUI/res/values/attrs.xml +++ b/packages/CarSystemUI/res/values/attrs.xml @@ -16,6 +16,12 @@ --> + + + + + + @@ -32,4 +38,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml deleted file mode 100644 index 125076f9c69af..0000000000000 --- a/packages/SystemUI/res/values/attrs_car.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -