diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java index c35303e1e6c97..2bd5fe228f415 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java @@ -19,36 +19,16 @@ package com.android.systemui; import android.content.Context; import com.android.systemui.dagger.SystemUIRootComponent; -import com.android.systemui.navigationbar.car.CarFacetButtonController; - -import javax.inject.Singleton; - -import dagger.Component; /** * Class factory to provide car specific SystemUI components. */ public class CarSystemUIFactory extends SystemUIFactory { - private CarDependencyComponent mCarDependencyComponent; - @Override protected SystemUIRootComponent buildSystemUIRootComponent(Context context) { - mCarDependencyComponent = DaggerCarSystemUIFactory_CarDependencyComponent.builder() - .contextHolder(new ContextHolder(context)) - .build(); return DaggerCarSystemUIRootComponent.builder() .contextHolder(new ContextHolder(context)) .build(); } - - public CarDependencyComponent getCarDependencyComponent() { - return mCarDependencyComponent; - } - - @Singleton - @Component(modules = ContextHolder.class) - public interface CarDependencyComponent { - CarFacetButtonController getCarFacetButtonController(); - } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java index f8bfeec6df2d2..80ee371279655 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java @@ -19,6 +19,8 @@ package com.android.systemui.car; import android.car.Car; import android.content.Context; +import androidx.annotation.VisibleForTesting; + import java.util.ArrayList; import java.util.List; @@ -50,6 +52,12 @@ public class CarServiceProvider { }); } + @VisibleForTesting + public CarServiceProvider(Context context, Car car) { + mContext = context; + mCar = car; + } + /** * Let's other components hook into the connection to the car service. If we're already * connected to the car service, the callback is immediately triggered. diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java index c46e6e7433a3e..0b8999263c73e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java @@ -29,9 +29,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import com.android.keyguard.AlphaOptimizedImageButton; -import com.android.systemui.CarSystemUIFactory; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; /** * CarFacetButton is a ui component designed to be used as a shortcut for an app of a defined @@ -82,10 +80,6 @@ public class CarFacetButton extends LinearLayout { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton); setupIntents(typedArray); setupIcons(typedArray); - CarSystemUIFactory factory = SystemUIFactory.getInstance(); - CarFacetButtonController carFacetButtonController = factory.getCarDependencyComponent() - .getCarFacetButtonController(); - carFacetButtonController.addFacetButton(this); } /** diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java index 30f63f052b9f4..f66e8280197e9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java @@ -43,6 +43,8 @@ import javax.inject.Singleton; @Singleton public class CarFacetButtonController { + private final Set mRegisteredViews = new HashSet<>(); + protected ButtonMap mButtonsByCategory = new ButtonMap(); protected ButtonMap mButtonsByPackage = new ButtonMap(); protected ButtonMap mButtonsByComponentName = new ButtonMap(); @@ -60,7 +62,11 @@ public class CarFacetButtonController { * to get a reference to this controller via {@link com.android.systemui.Dependency} * and self add. */ - public void addFacetButton(CarFacetButton facetButton) { + 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); @@ -74,6 +80,8 @@ public class CarFacetButtonController { for (int i = 0; i < componentNames.length; i++) { mButtonsByComponentName.add(componentNames[i], facetButton); } + + mRegisteredViews.add(facetButton); } /** Removes all buttons from the button maps. */ @@ -82,6 +90,7 @@ public class CarFacetButtonController { mButtonsByPackage.clear(); mButtonsByComponentName.clear(); mSelectedFacetButtons.clear(); + mRegisteredViews.clear(); } /** diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java index af2cb0ab5950a..fd9c488278ba4 100644 --- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java +++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/hvac/HvacController.java @@ -32,10 +32,12 @@ import com.android.systemui.car.CarServiceProvider; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import javax.inject.Inject; import javax.inject.Singleton; @@ -49,6 +51,7 @@ public class HvacController { public static final String TAG = "HvacController"; private final CarServiceProvider mCarServiceProvider; + private final Set mRegisteredViews = new HashSet<>(); private CarHvacManager mHvacManager; private HashMap> mTempComponents = new HashMap<>(); @@ -112,7 +115,10 @@ public class HvacController { /** * Add component to list and initialize it if the connection is up. */ - public void addHvacTextView(TemperatureView temperatureView) { + private void addHvacTextView(TemperatureView temperatureView) { + if (mRegisteredViews.contains(temperatureView)) { + return; + } HvacKey hvacKey = new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId()); if (!mTempComponents.containsKey(hvacKey)) { @@ -120,6 +126,8 @@ public class HvacController { } mTempComponents.get(hvacKey).add(temperatureView); initComponent(temperatureView); + + mRegisteredViews.add(temperatureView); } private void initComponents() { @@ -165,6 +173,7 @@ public class HvacController { */ public void removeAllComponents() { mTempComponents.clear(); + mRegisteredViews.clear(); } /** diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java new file mode 100644 index 0000000000000..a71d1db3ee70b --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java @@ -0,0 +1,135 @@ +/* + * 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.hvac; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.car.Car; +import android.car.hardware.hvac.CarHvacManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarServiceProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class HvacControllerTest extends SysuiTestCase { + + private static final int PROPERTY_ID = 1; + private static final int AREA_ID = 1; + private static final float VALUE = 72.0f; + + private HvacController mHvacController; + private CarServiceProvider mCarServiceProvider; + + @Mock + private Car mCar; + @Mock + private CarHvacManager mCarHvacManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mCar.isConnected()).thenReturn(true); + when(mCar.getCarManager(Car.HVAC_SERVICE)).thenReturn(mCarHvacManager); + + mCarServiceProvider = new CarServiceProvider(mContext, mCar); + mHvacController = new HvacController(mCarServiceProvider); + mHvacController.connectToCarService(); + } + + @Test + public void connectToCarService_registersCallback() { + verify(mCarHvacManager).registerCallback(any()); + } + + @Test + public void addTemperatureViewToController_usingTemperatureView_registersView() { + TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE); + mHvacController.addTemperatureViewToController(v); + + verify(v).setTemp(VALUE); + } + + @Test + public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() { + TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE); + mHvacController.addTemperatureViewToController(v); + verify(v).setTemp(VALUE); + resetTemperatureView(v, PROPERTY_ID, AREA_ID); + + mHvacController.addTemperatureViewToController(v); + verify(v, never()).setTemp(VALUE); + } + + @Test + public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() { + TemperatureTextView v1 = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE); + mHvacController.addTemperatureViewToController(v1); + verify(v1).setTemp(VALUE); + + TemperatureTextView v2 = setupMockTemperatureTextView( + PROPERTY_ID + 1, + AREA_ID + 1, + VALUE + 1); + mHvacController.addTemperatureViewToController(v2); + verify(v2).setTemp(VALUE + 1); + } + + @Test + public void removeAllComponents_ableToRegisterSameView() { + TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE); + mHvacController.addTemperatureViewToController(v); + verify(v).setTemp(VALUE); + + mHvacController.removeAllComponents(); + resetTemperatureView(v, PROPERTY_ID, AREA_ID); + + mHvacController.addTemperatureViewToController(v); + verify(v).setTemp(VALUE); + } + + private TemperatureTextView setupMockTemperatureTextView(int propertyId, int areaId, + float value) { + TemperatureTextView v = mock(TemperatureTextView.class); + resetTemperatureView(v, propertyId, areaId); + when(mCarHvacManager.isPropertyAvailable(propertyId, areaId)).thenReturn(true); + when(mCarHvacManager.getFloatProperty(propertyId, areaId)).thenReturn(value); + return v; + } + + private void resetTemperatureView(TemperatureTextView view, int propertyId, int areaId) { + reset(view); + when(view.getPropertyId()).thenReturn(propertyId); + when(view.getAreaId()).thenReturn(areaId); + } +}