From d0cfab0964b669c22b5ba379c70e04cbd47a1c92 Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Wed, 23 Oct 2019 16:52:31 -0700 Subject: [PATCH 1/2] Setup on device testing for sys ui This borrows on the testing infrastructure set up by the phone sys ui team and provides an examples via test for CarNavigationBarController. Bug: 143227120 Test: atest CarNavigationBarControllerTest Change-Id: I10fd4e2e51f2faf75ade5b40e47441a9e948f075 --- packages/CarSystemUI/Android.bp | 58 ++++ .../car/CarNavigationBarView.java | 19 +- packages/CarSystemUI/tests/Android.mk | 88 +++++ .../CarSystemUI/tests/AndroidManifest.xml | 40 +++ packages/CarSystemUI/tests/AndroidTest.xml | 30 ++ .../CarSystemUI/tests/res/values/config.xml | 23 ++ ...VerifySysuiRequiredTestPropertiesTest.java | 214 ++++++++++++ .../car/CarNavigationBarControllerTest.java | 316 ++++++++++++++++++ 8 files changed, 784 insertions(+), 4 deletions(-) create mode 100644 packages/CarSystemUI/tests/Android.mk create mode 100644 packages/CarSystemUI/tests/AndroidManifest.xml create mode 100644 packages/CarSystemUI/tests/AndroidTest.xml create mode 100644 packages/CarSystemUI/tests/res/values/config.xml create mode 100644 packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java create mode 100644 packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index 672879ae6e9d4..b2451c91057c9 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -63,6 +63,64 @@ android_library { } +android_library { + name: "CarSystemUI-tests", + manifest: "tests/AndroidManifest.xml", + resource_dirs: [ + "tests/res", + "res-keyguard", + "res", + ], + srcs: [ + "tests/src/**/*.java", + "src/**/*.java", + "src/**/I*.aidl", + ], + static_libs: [ + "SystemUI-tests", + "CarNotificationLib", + "SystemUIPluginLib", + "SystemUISharedLib", + "SettingsLib", + "android.car.userlib", + "androidx.legacy_legacy-support-v4", + "androidx.recyclerview_recyclerview", + "androidx.preference_preference", + "androidx.appcompat_appcompat", + "androidx.mediarouter_mediarouter", + "androidx.palette_palette", + "androidx.legacy_legacy-preference-v14", + "androidx.leanback_leanback", + "androidx.slice_slice-core", + "androidx.slice_slice-view", + "androidx.slice_slice-builders", + "androidx.arch.core_core-runtime", + "androidx.lifecycle_lifecycle-extensions", + "SystemUI-tags", + "SystemUI-proto", + "metrics-helper-lib", + "androidx.test.rules", "hamcrest-library", + "mockito-target-inline-minus-junit4", + "testables", + "truth-prebuilt", + "dagger2-2.19", + "//external/kotlinc:kotlin-annotations", + ], + libs: [ + "android.test.runner", + "telephony-common", + "android.test.base", + "android.car", + ], + + aaptflags: [ + "--extra-packages", + "com.android.systemui", + ], + + plugins: ["dagger2-compiler-2.19"], +} + android_app { name: "CarSystemUI", diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java index 24f8b74eed617..c2455088a52bd 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarView.java @@ -24,6 +24,7 @@ import android.widget.LinearLayout; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.navigationbar.car.CarNavigationBarController.NotificationsShadeController; import com.android.systemui.statusbar.phone.StatusBarIconController; /** @@ -35,7 +36,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; public class CarNavigationBarView extends LinearLayout { private View mNavButtons; private CarNavigationButton mNotificationsButton; - private CarNavigationBarController.NotificationsShadeController mNotificationsShadeController; + private NotificationsShadeController mNotificationsShadeController; private Context mContext; private View mLockScreenButtons; // used to wire in open/close gestures for notifications @@ -81,13 +82,18 @@ public class CarNavigationBarView extends LinearLayout { return super.onInterceptTouchEvent(ev); } - public void setNotificationsPanelController( - CarNavigationBarController.NotificationsShadeController controller) { + /** Sets the notifications panel controller. */ + public void setNotificationsPanelController(NotificationsShadeController controller) { mNotificationsShadeController = controller; } + /** Gets the notifications panel controller. */ + public NotificationsShadeController getNotificationsPanelController() { + return mNotificationsShadeController; + } + /** - * Set a touch listener that will be called from onInterceptTouchEvent and onTouchEvent + * Sets a touch listener that will be called from onInterceptTouchEvent and onTouchEvent * * @param statusBarWindowTouchListener The listener to call from touch and intercept touch */ @@ -95,6 +101,11 @@ public class CarNavigationBarView extends LinearLayout { mStatusBarWindowTouchListener = statusBarWindowTouchListener; } + /** Gets the touch listener that will be called from onInterceptTouchEvent and onTouchEvent. */ + public OnTouchListener getStatusBarWindowTouchListener() { + return mStatusBarWindowTouchListener; + } + @Override public boolean onTouchEvent(MotionEvent event) { if (mStatusBarWindowTouchListener != null) { diff --git a/packages/CarSystemUI/tests/Android.mk b/packages/CarSystemUI/tests/Android.mk new file mode 100644 index 0000000000000..1366568c3a661 --- /dev/null +++ b/packages/CarSystemUI/tests/Android.mk @@ -0,0 +1,88 @@ +# 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. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_USE_AAPT2 := true +LOCAL_MODULE_TAGS := tests + +LOCAL_JACK_FLAGS := --multi-dex native +LOCAL_DX_FLAGS := --multi-dex + +LOCAL_PACKAGE_NAME := CarSystemUITests +LOCAL_PRIVATE_PLATFORM_APIS := true +LOCAL_COMPATIBILITY_SUITE := device-tests + +LOCAL_STATIC_ANDROID_LIBRARIES := \ + CarSystemUI-tests + +LOCAL_MULTILIB := both + +LOCAL_JNI_SHARED_LIBRARIES := \ + libdexmakerjvmtiagent \ + libmultiplejvmtiagentsinterferenceagent + +LOCAL_JAVA_LIBRARIES := \ + android.test.runner \ + telephony-common \ + android.test.base \ + +LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui + +# sign this with platform cert, so this test is allowed to inject key events into +# UI it doesn't own. This is necessary to allow screenshots to be taken +LOCAL_CERTIFICATE := platform + +# Provide jack a list of classes to exclude from code coverage. +# This is needed because the CarSystemUITests compile CarSystemUI source directly, rather than using +# LOCAL_INSTRUMENTATION_FOR := CarSystemUI. +# +# We want to exclude the test classes from code coverage measurements, but they share the same +# package as the rest of SystemUI so they can't be easily filtered by package name. +# +# Generate a comma separated list of patterns based on the test source files under src/ +# SystemUI classes are in ../src/ so they won't be excluded. +# Example: +# Input files: src/com/android/systemui/Test.java src/com/android/systemui/AnotherTest.java +# Generated exclude list: com.android.systemui.Test*,com.android.systemui.AnotherTest* + +# Filter all src files under src/ to just java files +local_java_files := $(filter %.java,$(call all-java-files-under, src)) + +# Transform java file names into full class names. +# This only works if the class name matches the file name and the directory structure +# matches the package. +local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files))) +local_comma := , +local_empty := +local_space := $(local_empty) $(local_empty) + +# Convert class name list to jacoco exclude list +# This appends a * to all classes and replace the space separators with commas. +jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes))) + +LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*,com.android.keyguard.* +LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) + +ifeq ($(EXCLUDE_SYSTEMUI_TESTS),) + include $(BUILD_PACKAGE) +endif + +# Reset variables +local_java_files := +local_classes := +local_comma := +local_space := +jacoco_exclude := diff --git a/packages/CarSystemUI/tests/AndroidManifest.xml b/packages/CarSystemUI/tests/AndroidManifest.xml new file mode 100644 index 0000000000000..a74bb56d8d75a --- /dev/null +++ b/packages/CarSystemUI/tests/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + diff --git a/packages/CarSystemUI/tests/AndroidTest.xml b/packages/CarSystemUI/tests/AndroidTest.xml new file mode 100644 index 0000000000000..8685632f2b631 --- /dev/null +++ b/packages/CarSystemUI/tests/AndroidTest.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/packages/CarSystemUI/tests/res/values/config.xml b/packages/CarSystemUI/tests/res/values/config.xml new file mode 100644 index 0000000000000..0d08ac26d962d --- /dev/null +++ b/packages/CarSystemUI/tests/res/values/config.xml @@ -0,0 +1,23 @@ + + + + + false + false + false + diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java new file mode 100644 index 0000000000000..fe59cbf20a13c --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java @@ -0,0 +1,214 @@ +/* + * 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; + +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import android.testing.AndroidTestingRunner; +import android.text.TextUtils; +import android.util.Log; + +import androidx.test.filters.LargeTest; +import androidx.test.filters.MediumTest; +import androidx.test.filters.SmallTest; +import androidx.test.internal.runner.ClassPathScanner; +import androidx.test.internal.runner.ClassPathScanner.ChainedClassNameFilter; +import androidx.test.internal.runner.ClassPathScanner.ExternalClassNameFilter; + +import com.android.systemui.SysuiBaseFragmentTest; +import com.android.systemui.SysuiTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +/** + * This is named AAAPlusPlusVerifySysuiRequiredTestPropertiesTest for two reasons. + * a) Its so awesome it deserves an AAA++ + * b) It should run first to draw attention to itself. + * + * For trues though: this test verifies that all the sysui tests extend the right classes. + * This matters because including tests with different context implementations in the same + * test suite causes errors, such as the incorrect settings provider being cached. + * For an example, see {@link com.android.systemui.DependencyTest}. + */ +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestCase { + + private static final String TAG = "AAA++VerifyTest"; + + private static final Class[] BASE_CLS_WHITELIST = { + SysuiTestCase.class, + SysuiBaseFragmentTest.class, + }; + + private static final Class[] SUPPORTED_SIZES = { + SmallTest.class, + MediumTest.class, + LargeTest.class, + android.test.suitebuilder.annotation.SmallTest.class, + android.test.suitebuilder.annotation.MediumTest.class, + android.test.suitebuilder.annotation.LargeTest.class, + }; + + @Test + public void testAllClassInheritance() throws Throwable { + ArrayList fails = new ArrayList<>(); + for (String className : getClassNamesFromClassPath()) { + Class cls = Class.forName(className, false, this.getClass().getClassLoader()); + if (!isTestClass(cls)) continue; + + boolean hasParent = false; + for (Class parent : BASE_CLS_WHITELIST) { + if (parent.isAssignableFrom(cls)) { + hasParent = true; + break; + } + } + boolean hasSize = hasSize(cls); + if (!hasSize) { + fails.add(cls.getName() + " does not have size annotation, such as @SmallTest"); + } + if (!hasParent) { + fails.add(cls.getName() + " does not extend any of " + getClsStr()); + } + } + + assertThat("All sysui test classes must have size and extend one of " + getClsStr(), + fails, is(empty())); + } + + private boolean hasSize(Class cls) { + for (int i = 0; i < SUPPORTED_SIZES.length; i++) { + if (cls.getDeclaredAnnotation(SUPPORTED_SIZES[i]) != null) return true; + } + return false; + } + + private Collection getClassNamesFromClassPath() { + ClassPathScanner scanner = new ClassPathScanner(mContext.getPackageCodePath()); + + ChainedClassNameFilter filter = new ChainedClassNameFilter(); + + filter.add(new ExternalClassNameFilter()); + filter.add(s -> s.startsWith("com.android.systemui") + || s.startsWith("com.android.keyguard")); + + try { + return scanner.getClassPathEntries(filter); + } catch (IOException e) { + Log.e(TAG, "Failed to scan classes", e); + } + return Collections.emptyList(); + } + + private String getClsStr() { + return TextUtils.join(",", Arrays.asList(BASE_CLS_WHITELIST) + .stream().map(cls -> cls.getSimpleName()).toArray()); + } + + /** + * Determines if given class is a valid test class. + * + * @return true if loadedClass is a test + */ + private boolean isTestClass(Class loadedClass) { + try { + if (Modifier.isAbstract(loadedClass.getModifiers())) { + logDebug(String.format("Skipping abstract class %s: not a test", + loadedClass.getName())); + return false; + } + // TODO: try to find upstream junit calls to replace these checks + if (junit.framework.Test.class.isAssignableFrom(loadedClass)) { + // ensure that if a TestCase, it has at least one test method otherwise + // TestSuite will throw error + if (junit.framework.TestCase.class.isAssignableFrom(loadedClass)) { + return hasJUnit3TestMethod(loadedClass); + } + return true; + } + // TODO: look for a 'suite' method? + if (loadedClass.isAnnotationPresent(RunWith.class)) { + return true; + } + for (Method testMethod : loadedClass.getMethods()) { + if (testMethod.isAnnotationPresent(Test.class)) { + return true; + } + } + logDebug(String.format("Skipping class %s: not a test", loadedClass.getName())); + return false; + } catch (Exception e) { + // Defensively catch exceptions - Will throw runtime exception if it cannot load + // methods. + // For earlier versions of Android (Pre-ICS), Dalvik might try to initialize a class + // during getMethods(), fail to do so, hide the error and throw a NoSuchMethodException. + // Since the java.lang.Class.getMethods does not declare such an exception, resort to a + // generic catch all. + // For ICS+, Dalvik will throw a NoClassDefFoundException. + Log.w(TAG, String.format("%s in isTestClass for %s", e.toString(), + loadedClass.getName())); + return false; + } catch (Error e) { + // defensively catch Errors too + Log.w(TAG, String.format("%s in isTestClass for %s", e.toString(), + loadedClass.getName())); + return false; + } + } + + private boolean hasJUnit3TestMethod(Class loadedClass) { + for (Method testMethod : loadedClass.getMethods()) { + if (isPublicTestMethod(testMethod)) { + return true; + } + } + return false; + } + + // copied from junit.framework.TestSuite + private boolean isPublicTestMethod(Method m) { + return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); + } + + // copied from junit.framework.TestSuite + private boolean isTestMethod(Method m) { + return m.getParameterTypes().length == 0 && m.getName().startsWith("test") + && m.getReturnType().equals(Void.TYPE); + } + + /** + * Utility method for logging debug messages. Only actually logs a message if TAG is marked + * as loggable to limit log spam during normal use. + */ + private void logDebug(String msg) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, msg); + } + } +} 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 new file mode 100644 index 0000000000000..20ace44cfa198 --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/CarNavigationBarControllerTest.java @@ -0,0 +1,316 @@ +/* + * 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.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.testing.TestableResources; +import android.view.View; +import android.view.ViewGroup; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.car.hvac.HvacController; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import dagger.Lazy; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class CarNavigationBarControllerTest extends SysuiTestCase { + + private CarNavigationBarController mCarNavigationBar; + private NavigationBarViewFactory mNavigationBarViewFactory; + private Lazy mHvacControllerLazy; + private TestableResources mTestableResources; + + @Mock + private HvacController mHvacController; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mNavigationBarViewFactory = new NavigationBarViewFactory(mContext); + mHvacControllerLazy = () -> mHvacController; + mTestableResources = mContext.getOrCreateTestableResources(); + } + + @Test + public void testConnectToHvac_callsConnect() { + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + mCarNavigationBar.connectToHvac(); + + verify(mHvacController).connectToCarService(); + } + + @Test + public void testRemoveAllFromHvac_callsRemoveAll() { + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + mCarNavigationBar.removeAllFromHvac(); + + verify(mHvacController).removeAllComponents(); + } + + @Test + public void testGetBottomWindow_bottomDisabled_returnsNull() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getBottomWindow(); + + assertThat(window).isNull(); + } + + @Test + public void testGetBottomWindow_bottomEnabled_returnsWindow() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getBottomWindow(); + + assertThat(window).isNotNull(); + } + + @Test + public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window1 = mCarNavigationBar.getBottomWindow(); + ViewGroup window2 = mCarNavigationBar.getBottomWindow(); + + assertThat(window1).isEqualTo(window2); + } + + @Test + public void testGetLeftWindow_leftDisabled_returnsNull() { + mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + ViewGroup window = mCarNavigationBar.getLeftWindow(); + assertThat(window).isNull(); + } + + @Test + public void testGetLeftWindow_leftEnabled_returnsWindow() { + mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getLeftWindow(); + + assertThat(window).isNotNull(); + } + + @Test + public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() { + mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window1 = mCarNavigationBar.getLeftWindow(); + ViewGroup window2 = mCarNavigationBar.getLeftWindow(); + + assertThat(window1).isEqualTo(window2); + } + + @Test + public void testGetRightWindow_rightDisabled_returnsNull() { + mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getRightWindow(); + + assertThat(window).isNull(); + } + + @Test + public void testGetRightWindow_rightEnabled_returnsWindow() { + mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getRightWindow(); + + assertThat(window).isNotNull(); + } + + @Test + public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() { + mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window1 = mCarNavigationBar.getRightWindow(); + ViewGroup window2 = mCarNavigationBar.getRightWindow(); + + assertThat(window1).isEqualTo(window2); + } + + @Test + public void testSetBottomWindowVisibility_setTrue_isVisible() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getBottomWindow(); + mCarNavigationBar.setBottomWindowVisibility(true); + + assertThat(window.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testSetBottomWindowVisibility_setFalse_isGone() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getBottomWindow(); + mCarNavigationBar.setBottomWindowVisibility(false); + + assertThat(window.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void testSetLeftWindowVisibility_setTrue_isVisible() { + mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getLeftWindow(); + mCarNavigationBar.setLeftWindowVisibility(true); + + assertThat(window.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testSetLeftWindowVisibility_setFalse_isGone() { + mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getLeftWindow(); + mCarNavigationBar.setLeftWindowVisibility(false); + + assertThat(window.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void testSetRightWindowVisibility_setTrue_isVisible() { + mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getRightWindow(); + mCarNavigationBar.setRightWindowVisibility(true); + + assertThat(window.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testSetRightWindowVisibility_setFalse_isGone() { + mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + ViewGroup window = mCarNavigationBar.getRightWindow(); + mCarNavigationBar.setRightWindowVisibility(false); + + assertThat(window.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener(); + assertThat(controller).isNull(); + mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class)); + controller = bottomBar.getStatusBarWindowTouchListener(); + + assertThat(controller).isNotNull(); + } + + @Test + public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class)); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener(); + + assertThat(controller).isNotNull(); + } + + @Test + public void testRegisterNotificationController_createViewFirst_registrationSuccessful() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + CarNavigationBarController.NotificationsShadeController controller = + bottomBar.getNotificationsPanelController(); + assertThat(controller).isNull(); + mCarNavigationBar.registerNotificationController( + mock(CarNavigationBarController.NotificationsShadeController.class)); + controller = bottomBar.getNotificationsPanelController(); + + assertThat(controller).isNotNull(); + } + + @Test + public void testRegisterNotificationController_registerFirst_registrationSuccessful() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + + mCarNavigationBar.registerNotificationController( + mock(CarNavigationBarController.NotificationsShadeController.class)); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + CarNavigationBarController.NotificationsShadeController controller = + bottomBar.getNotificationsPanelController(); + + assertThat(controller).isNotNull(); + } +} From 8d6ec6a7eccc834726188fcbfe8ce6ee35c8b250 Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Fri, 25 Oct 2019 14:34:11 -0700 Subject: [PATCH 2/2] Remove references to nav bar views in StatusBar All relevant logic is in the CarNavigationBarController which means we don't need to account for the views in two different parts of SystemUI. Bug: 143143539 Test: atest CarNavigationBarControllerTest Change-Id: I0a54ddf3966a8e373909062df78ec2665f4a9c9d --- .../navigationbar/car/CarNavigationBar.java | 4 +- .../car/CarNavigationBarController.java | 83 ++++++++++++-- .../car/CarNavigationButton.java | 5 + .../systemui/statusbar/car/CarStatusBar.java | 100 +++-------------- .../car/CarNavigationBarControllerTest.java | 104 +++++++++++++++++- 5 files changed, 197 insertions(+), 99 deletions(-) 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 63bc66afddf8d..98b91ebd80386 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBar.java @@ -25,6 +25,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.view.Display; import android.view.Gravity; +import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; @@ -291,7 +292,8 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks } boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0; - mCarNavigationBarController.setBottomWindowVisibility(!isKeyboardVisible); + mCarNavigationBarController.setBottomWindowVisibility( + isKeyboardVisible ? View.GONE : View.VISIBLE); } private void updateNavBarForKeyguardContent() { 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 f59f886d487b6..6bed69bdee880 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationBarController.java @@ -98,31 +98,30 @@ public class CarNavigationBarController { } /** Toggles the bottom nav bar visibility. */ - public boolean setBottomWindowVisibility(boolean isVisible) { - return setWindowVisibility(getBottomWindow(), isVisible); + public boolean setBottomWindowVisibility(@View.Visibility int visibility) { + return setWindowVisibility(getBottomWindow(), visibility); } /** Toggles the left nav bar visibility. */ - public boolean setLeftWindowVisibility(boolean isVisible) { - return setWindowVisibility(getLeftWindow(), isVisible); + public boolean setLeftWindowVisibility(@View.Visibility int visibility) { + return setWindowVisibility(getLeftWindow(), visibility); } /** Toggles the right nav bar visibility. */ - public boolean setRightWindowVisibility(boolean isVisible) { - return setWindowVisibility(getRightWindow(), isVisible); + public boolean setRightWindowVisibility(@View.Visibility int visibility) { + return setWindowVisibility(getRightWindow(), visibility); } - private boolean setWindowVisibility(ViewGroup window, boolean isVisible) { + private boolean setWindowVisibility(ViewGroup window, @View.Visibility int visibility) { if (window == null) { return false; } - int newVisibility = isVisible ? View.VISIBLE : View.GONE; - if (window.getVisibility() == newVisibility) { + if (window.getVisibility() == visibility) { return false; } - window.setVisibility(newVisibility); + window.setVisibility(visibility); return true; } @@ -228,6 +227,63 @@ public class CarNavigationBarController { } } + /** + * Shows all of the keyguard specific buttons on the valid instances of + * {@link CarNavigationBarView}. + */ + public void showAllKeyguardButtons(boolean isSetUp) { + checkAllBars(isSetUp); + if (mTopView != null) { + mTopView.showKeyguardButtons(); + } + if (mBottomView != null) { + mBottomView.showKeyguardButtons(); + } + if (mLeftView != null) { + mLeftView.showKeyguardButtons(); + } + if (mRightView != null) { + mRightView.showKeyguardButtons(); + } + } + + /** + * Hides all of the keyguard specific buttons on the valid instances of + * {@link CarNavigationBarView}. + */ + public void hideAllKeyguardButtons(boolean isSetUp) { + checkAllBars(isSetUp); + if (mTopView != null) { + mTopView.hideKeyguardButtons(); + } + if (mBottomView != null) { + mBottomView.hideKeyguardButtons(); + } + if (mLeftView != null) { + mLeftView.hideKeyguardButtons(); + } + if (mRightView != null) { + mRightView.hideKeyguardButtons(); + } + } + + /** Toggles whether the notifications icon has an unseen indicator or not. */ + public void toggleAllNotificationsUnseenIndicator(boolean isSetUp, boolean hasUnseen) { + checkAllBars(isSetUp); + if (mTopView != null) { + mTopView.toggleNotificationUnseenIndicator(hasUnseen); + } + if (mBottomView != null) { + mBottomView.toggleNotificationUnseenIndicator(hasUnseen); + } + if (mLeftView != null) { + mLeftView.toggleNotificationUnseenIndicator(hasUnseen); + } + if (mRightView != null) { + mRightView.toggleNotificationUnseenIndicator(hasUnseen); + } + } + /** Interface for controlling the notifications shade. */ public interface NotificationsShadeController { /** Toggles the visibility of the notifications shade. */ @@ -244,4 +300,11 @@ public class CarNavigationBarController { } } } + + private void checkAllBars(boolean isSetUp) { + mTopView = getTopBar(isSetUp); + mBottomView = getBottomBar(isSetUp); + mLeftView = getLeftBar(isSetUp); + mRightView = getRightBar(isSetUp); + } } 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 40823abaaead4..922bfffcfa22e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarNavigationButton.java @@ -150,6 +150,11 @@ public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImag updateImage(); } + /** Gets whether the icon is in an unseen state. */ + public boolean getUnseen() { + return mHasUnseen; + } + private void updateImage() { if (mHasUnseen) { setImageResource(mSelected ? UNSEEN_SELECTED_ICON_RESOURCE_ID diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 601bc40302267..ce763b900b9a8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -168,13 +168,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt private Drawable mNotificationPanelBackground; private ViewGroup mTopNavigationBarContainer; - private ViewGroup mNavigationBarWindow; - private ViewGroup mLeftNavigationBarWindow; - private ViewGroup mRightNavigationBarWindow; private CarNavigationBarView mTopNavigationBarView; - private CarNavigationBarView mNavigationBarView; - private CarNavigationBarView mLeftNavigationBarView; - private CarNavigationBarView mRightNavigationBarView; private final Object mQueueLock = new Object(); private final CarNavigationBarController mCarNavigationBarController; @@ -425,12 +419,12 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt new DeviceProvisionedController.DeviceProvisionedListener() { @Override public void onUserSetupChanged() { - mHandler.post(() -> restartNavBarsIfNecessary()); + mHandler.post(() -> resetSystemBarsIfNecessary()); } @Override public void onUserSwitched() { - mHandler.post(() -> restartNavBarsIfNecessary()); + mHandler.post(() -> resetSystemBarsIfNecessary()); } }); @@ -444,11 +438,11 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mSwitchToGuestTimer = new SwitchToGuestTimer(mContext); } - private void restartNavBarsIfNecessary() { + private void resetSystemBarsIfNecessary() { boolean currentUserSetup = mDeviceProvisionedController.isCurrentUserSetup(); if (mDeviceIsSetUpForUser != currentUserSetup) { mDeviceIsSetUpForUser = currentUserSetup; - restartNavBars(); + resetSystemBars(); } } @@ -456,19 +450,9 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt * Remove all content from navbars and rebuild them. Used to allow for different nav bars * before and after the device is provisioned. . Also for change of density and font size. */ - private void restartNavBars() { + private void resetSystemBars() { mCarFacetButtonController.removeAll(); - if (mNavigationBarWindow != null) { - mNavigationBarView = null; - } - if (mLeftNavigationBarWindow != null) { - mLeftNavigationBarView = null; - } - if (mRightNavigationBarWindow != null) { - mRightNavigationBarView = null; - } - buildNavBarContent(); // CarFacetButtonController was reset therefore we need to re-add the status bar elements // to the controller. @@ -480,51 +464,22 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt * the full screen user selector is shown. */ void setNavBarVisibility(@View.Visibility int visibility) { - if (mNavigationBarWindow != null) { - mNavigationBarWindow.setVisibility(visibility); - } - if (mLeftNavigationBarWindow != null) { - mLeftNavigationBarWindow.setVisibility(visibility); - } - if (mRightNavigationBarWindow != null) { - mRightNavigationBarWindow.setVisibility(visibility); - } + mCarNavigationBarController.setBottomWindowVisibility(visibility); + mCarNavigationBarController.setLeftWindowVisibility(visibility); + mCarNavigationBarController.setRightWindowVisibility(visibility); } @Override public boolean hideKeyguard() { boolean result = super.hideKeyguard(); - if (mNavigationBarView != null) { - mNavigationBarView.hideKeyguardButtons(); - } - if (mLeftNavigationBarView != null) { - mLeftNavigationBarView.hideKeyguardButtons(); - } - if (mRightNavigationBarView != null) { - mRightNavigationBarView.hideKeyguardButtons(); - } + mCarNavigationBarController.hideAllKeyguardButtons(mDeviceIsSetUpForUser); return result; } @Override public void showKeyguard() { super.showKeyguard(); - updateNavBarForKeyguardContent(); - } - - /** - * Switch to the keyguard applicable content contained in the nav bars - */ - private void updateNavBarForKeyguardContent() { - if (mNavigationBarView != null) { - mNavigationBarView.showKeyguardButtons(); - } - if (mLeftNavigationBarView != null) { - mLeftNavigationBarView.showKeyguardButtons(); - } - if (mRightNavigationBarView != null) { - mRightNavigationBarView.showKeyguardButtons(); - } + mCarNavigationBarController.showAllKeyguardButtons(mDeviceIsSetUpForUser); } @Override @@ -628,20 +583,11 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mNotificationDataManager = new NotificationDataManager(); mNotificationDataManager.setOnUnseenCountUpdateListener( () -> { - if (mNavigationBarView != null && mNotificationDataManager != null) { - Boolean hasUnseen = + if (mNotificationDataManager != null) { + boolean hasUnseen = mNotificationDataManager.getUnseenNotificationCount() > 0; - if (mNavigationBarView != null) { - mNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen); - } - - if (mLeftNavigationBarView != null) { - mLeftNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen); - } - - if (mRightNavigationBarView != null) { - mRightNavigationBarView.toggleNotificationUnseenIndicator(hasUnseen); - } + mCarNavigationBarController.toggleAllNotificationsUnseenIndicator( + mDeviceIsSetUpForUser, hasUnseen); } }); @@ -895,37 +841,27 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override protected void createNavigationBar(@Nullable RegisterStatusBarResult result) { - buildNavBarWindows(); + mTopNavigationBarContainer = mStatusBarWindow + .findViewById(R.id.car_top_navigation_bar_container); + buildNavBarContent(); } private void buildNavBarContent() { buildTopBar(); - mNavigationBarView = mCarNavigationBarController.getBottomBar(mDeviceIsSetUpForUser); mCarNavigationBarController.registerBottomBarTouchListener( mNavBarNotificationTouchListener); - mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser); mCarNavigationBarController.registerLeftBarTouchListener( mNavBarNotificationTouchListener); - mRightNavigationBarView = mCarNavigationBarController.getLeftBar(mDeviceIsSetUpForUser); mCarNavigationBarController.registerRightBarTouchListener( mNavBarNotificationTouchListener); mCarNavigationBarController.registerNotificationController(() -> togglePanel()); } - private void buildNavBarWindows() { - mTopNavigationBarContainer = mStatusBarWindow - .findViewById(R.id.car_top_navigation_bar_container); - - mNavigationBarWindow = mCarNavigationBarController.getBottomWindow(); - mLeftNavigationBarWindow = mCarNavigationBarController.getLeftWindow(); - mRightNavigationBarWindow = mCarNavigationBarController.getRightWindow(); - } - private void buildTopBar() { mTopNavigationBarContainer.removeAllViews(); mTopNavigationBarView = mCarNavigationBarController.getTopBar(mDeviceIsSetUpForUser); @@ -1099,7 +1035,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt @Override public void onDensityOrFontScaleChanged() { super.onDensityOrFontScaleChanged(); - restartNavBars(); + resetSystemBars(); // Need to update the background on density changed in case the change was due to night // mode. mNotificationPanelBackground = getDefaultWallpaper(); 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 20ace44cfa198..901d2006eb124 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 @@ -31,7 +31,9 @@ import androidx.test.filters.SmallTest; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; +import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.statusbar.car.hvac.HvacController; +import com.android.systemui.statusbar.phone.StatusBarIconController; import org.junit.Before; import org.junit.Test; @@ -60,6 +62,10 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mNavigationBarViewFactory = new NavigationBarViewFactory(mContext); mHvacControllerLazy = () -> mHvacController; mTestableResources = mContext.getOrCreateTestableResources(); + + // Needed to inflate top navigation bar. + mDependency.injectMockDependency(DarkIconDispatcher.class); + mDependency.injectMockDependency(StatusBarIconController.class); } @Test @@ -189,7 +195,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mHvacControllerLazy); ViewGroup window = mCarNavigationBar.getBottomWindow(); - mCarNavigationBar.setBottomWindowVisibility(true); + mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE); assertThat(window.getVisibility()).isEqualTo(View.VISIBLE); } @@ -201,7 +207,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mHvacControllerLazy); ViewGroup window = mCarNavigationBar.getBottomWindow(); - mCarNavigationBar.setBottomWindowVisibility(false); + mCarNavigationBar.setBottomWindowVisibility(View.GONE); assertThat(window.getVisibility()).isEqualTo(View.GONE); } @@ -213,7 +219,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mHvacControllerLazy); ViewGroup window = mCarNavigationBar.getLeftWindow(); - mCarNavigationBar.setLeftWindowVisibility(true); + mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE); assertThat(window.getVisibility()).isEqualTo(View.VISIBLE); } @@ -225,7 +231,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mHvacControllerLazy); ViewGroup window = mCarNavigationBar.getLeftWindow(); - mCarNavigationBar.setLeftWindowVisibility(false); + mCarNavigationBar.setLeftWindowVisibility(View.GONE); assertThat(window.getVisibility()).isEqualTo(View.GONE); } @@ -237,7 +243,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mHvacControllerLazy); ViewGroup window = mCarNavigationBar.getRightWindow(); - mCarNavigationBar.setRightWindowVisibility(true); + mCarNavigationBar.setRightWindowVisibility(View.VISIBLE); assertThat(window.getVisibility()).isEqualTo(View.VISIBLE); } @@ -249,7 +255,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mHvacControllerLazy); ViewGroup window = mCarNavigationBar.getRightWindow(); - mCarNavigationBar.setRightWindowVisibility(false); + mCarNavigationBar.setRightWindowVisibility(View.GONE); assertThat(window.getVisibility()).isEqualTo(View.GONE); } @@ -313,4 +319,90 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { assertThat(controller).isNotNull(); } + + @Test + public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); + + mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true); + + assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); + + mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true); + + assertThat(bottomButtons.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); + + mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true); + assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.VISIBLE); + mCarNavigationBar.hideAllKeyguardButtons(/* isSetUp= */ true); + + assertThat(bottomKeyguardButtons.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); + + mCarNavigationBar.showAllKeyguardButtons(/* isSetUp= */ true); + assertThat(bottomButtons.getVisibility()).isEqualTo(View.GONE); + mCarNavigationBar.hideAllKeyguardButtons(/* isSetUp= */ true); + + assertThat(bottomButtons.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); + + boolean hasUnseen = true; + mCarNavigationBar.toggleAllNotificationsUnseenIndicator(/* isSetUp= */ true, + hasUnseen); + + assertThat(notifications.getUnseen()).isTrue(); + } + + @Test + public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() { + mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); + mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mHvacControllerLazy); + CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); + CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); + + boolean hasUnseen = false; + mCarNavigationBar.toggleAllNotificationsUnseenIndicator(/* isSetUp= */ true, + hasUnseen); + + assertThat(notifications.getUnseen()).isFalse(); + } }