diff --git a/packages/SystemUI/res/drawable/dream_aqi_badge_bg.xml b/packages/SystemUI/res/drawable/dream_aqi_badge_bg.xml new file mode 100644 index 0000000000000..1992c7733bd3d --- /dev/null +++ b/packages/SystemUI/res/drawable/dream_aqi_badge_bg.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_aqi.xml b/packages/SystemUI/res/layout/dream_overlay_complication_aqi.xml new file mode 100644 index 0000000000000..fcebb8d3f6c6e --- /dev/null +++ b/packages/SystemUI/res/layout/dream_overlay_complication_aqi.xml @@ -0,0 +1,26 @@ + + + \ No newline at end of file diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 02ba271ee9a46..ccf18d2a0bb1d 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -233,4 +233,13 @@ #41493D #FCBE03 + + + #689F38 + #FBC02D + #F57C00 + #C53929 + #AD1457 + #880E4F + #BDC1C6 diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index ce5f22dea0132..eff4e00fd07bf 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -727,4 +727,25 @@ com.android.keyguard com.android.systemui + + + + -1 + 50 + 100 + 150 + 200 + 300 + + + + + @color/dream_overlay_aqi_good + @color/dream_overlay_aqi_moderate + @color/dream_overlay_aqi_unhealthy_sensitive + @color/dream_overlay_aqi_unhealthy + @color/dream_overlay_aqi_very_unhealthy + @color/dream_overlay_aqi_hazardous + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 6a098f5d473da..4d365412828ed 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1503,6 +1503,10 @@ 80dp + 28dp + 6dp + 16dp + 0dp diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/AirQualityColorPicker.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/AirQualityColorPicker.java new file mode 100644 index 0000000000000..328753ff15393 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/AirQualityColorPicker.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2022 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.dreams.complication; + +import static com.android.systemui.dreams.complication.dagger.DreamAirQualityComplicationComponent.DreamAirQualityComplicationModule.DREAM_AQI_COLOR_DEFAULT; +import static com.android.systemui.dreams.complication.dagger.DreamAirQualityComplicationComponent.DreamAirQualityComplicationModule.DREAM_AQI_COLOR_THRESHOLDS; +import static com.android.systemui.dreams.complication.dagger.DreamAirQualityComplicationComponent.DreamAirQualityComplicationModule.DREAM_AQI_COLOR_VALUES; + +import android.util.Log; + +import androidx.annotation.ColorInt; + +import javax.inject.Inject; +import javax.inject.Named; + +final class AirQualityColorPicker { + private static final String TAG = "AirQualityColorPicker"; + private final int[] mThresholds; + private final int[] mColorValues; + private final int mDefaultColor; + + @Inject + AirQualityColorPicker(@Named(DREAM_AQI_COLOR_THRESHOLDS) int[] thresholds, + @Named(DREAM_AQI_COLOR_VALUES) int[] colorValues, + @Named(DREAM_AQI_COLOR_DEFAULT) @ColorInt int defaultColor) { + mThresholds = thresholds; + mColorValues = colorValues; + mDefaultColor = defaultColor; + } + + @ColorInt + int getColorForValue(String aqiString) { + int size = mThresholds.length; + if (mThresholds.length != mColorValues.length) { + size = Math.min(mThresholds.length, mColorValues.length); + Log.e(TAG, + "Threshold size (" + + mThresholds.length + ") does not match color value size (" + + mColorValues.length + + "). Taking the minimum, some values may be ignored."); + + } + try { + final int value = Integer.parseInt(aqiString.replaceAll("[^0-9]", "")); + for (int i = size - 1; i >= 0; i--) { + if (value > mThresholds[i]) { + return mColorValues[i]; + } + } + Log.e(TAG, "No matching AQI color for value: " + value); + } catch (NumberFormatException e) { + Log.e(TAG, "Could not read AQI value from:" + aqiString); + } + return mDefaultColor; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamAirQualityComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamAirQualityComplication.java new file mode 100644 index 0000000000000..ba63303d1f2c7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamAirQualityComplication.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2022 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.dreams.complication; + +import static com.android.systemui.dreams.complication.dagger.DreamAirQualityComplicationComponent.DreamAirQualityComplicationModule.DREAM_AQI_COMPLICATION_LAYOUT_PARAMS; +import static com.android.systemui.dreams.complication.dagger.DreamAirQualityComplicationComponent.DreamAirQualityComplicationModule.DREAM_AQI_COMPLICATION_VIEW; +import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT; + +import android.app.smartspace.SmartspaceAction; +import android.app.smartspace.SmartspaceTarget; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.android.systemui.CoreStartable; +import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.dreams.complication.dagger.DreamAirQualityComplicationComponent; +import com.android.systemui.dreams.smartspace.DreamSmartspaceController; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener; +import com.android.systemui.util.ViewController; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * Air quality complication which produces view holder responsible for showing AQI over dreams. + */ +public class DreamAirQualityComplication implements Complication { + // TODO(b/236024839): Move to SmartspaceTarget + public static final int FEATURE_AIR_QUALITY = 46; + + private final DreamAirQualityComplicationComponent.Factory mComponentFactory; + + @Inject + public DreamAirQualityComplication( + DreamAirQualityComplicationComponent.Factory componentFactory) { + mComponentFactory = componentFactory; + } + + @Override + public int getRequiredTypeAvailability() { + return COMPLICATION_TYPE_AIR_QUALITY; + } + + @Override + public ViewHolder createView(ComplicationViewModel model) { + return mComponentFactory.create().getViewHolder(); + } + + /** + * {@link CoreStartable} for registering {@link DreamAirQualityComplication} with SystemUI. + */ + public static class Registrant extends CoreStartable { + private final DreamOverlayStateController mDreamOverlayStateController; + private final DreamAirQualityComplication mComplication; + + /** + * Default constructor to register {@link DreamAirQualityComplication}. + */ + @Inject + public Registrant(Context context, + DreamOverlayStateController dreamOverlayStateController, + DreamAirQualityComplication complication) { + super(context); + mDreamOverlayStateController = dreamOverlayStateController; + mComplication = complication; + } + + @Override + public void start() { + // TODO(b/221500478): Only add complication once we have data to show. + mDreamOverlayStateController.addComplication(mComplication); + } + } + + /** + * ViewHolder to contain value/logic associated with the AQI complication view. + */ + public static class DreamAirQualityViewHolder implements ViewHolder { + private final TextView mView; + private final DreamAirQualityViewController mController; + private final ComplicationLayoutParams mLayoutParams; + + @Inject + DreamAirQualityViewHolder(@Named(DREAM_AQI_COMPLICATION_VIEW) TextView view, + DreamAirQualityViewController controller, + @Named(DREAM_AQI_COMPLICATION_LAYOUT_PARAMS) + ComplicationLayoutParams layoutParams) { + mView = view; + mLayoutParams = layoutParams; + mController = controller; + mController.init(); + } + + @Override + public View getView() { + return mView; + } + + @Override + public ComplicationLayoutParams getLayoutParams() { + return mLayoutParams; + } + } + + static class DreamAirQualityViewController extends ViewController { + private final DreamSmartspaceController mSmartspaceController; + private final String mSmartspaceTrampolineComponent; + private final ActivityStarter mActivityStarter; + private final AirQualityColorPicker mAirQualityColorPicker; + + private final SmartspaceTargetListener mSmartspaceTargetListener = targets -> { + final SmartspaceTarget target = targets.stream() + .filter(t -> t instanceof SmartspaceTarget) + .map(t -> (SmartspaceTarget) t) + .filter(t -> t.getFeatureType() == FEATURE_AIR_QUALITY) + .findFirst() + .orElse(null); + updateView(target); + }; + + @Inject + DreamAirQualityViewController(@Named(DREAM_AQI_COMPLICATION_VIEW) TextView view, + DreamSmartspaceController smartspaceController, + @Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT) + String smartspaceTrampolineComponent, + ActivityStarter activityStarter, + AirQualityColorPicker airQualityColorPicker) { + super(view); + mSmartspaceController = smartspaceController; + mSmartspaceTrampolineComponent = smartspaceTrampolineComponent; + mActivityStarter = activityStarter; + mAirQualityColorPicker = airQualityColorPicker; + } + + @Override + protected void onViewAttached() { + mSmartspaceController.addUnfilteredListener(mSmartspaceTargetListener); + } + + @Override + protected void onViewDetached() { + mSmartspaceController.removeUnfilteredListener(mSmartspaceTargetListener); + } + + private void updateView(@Nullable SmartspaceTarget target) { + final SmartspaceAction headerAction = target == null ? null : target.getHeaderAction(); + if (headerAction == null || TextUtils.isEmpty(headerAction.getTitle())) { + mView.setVisibility(View.GONE); + return; + } + mView.setVisibility(View.VISIBLE); + + final String airQuality = headerAction.getTitle().toString(); + mView.setText(airQuality); + + final Drawable background = mView.getBackground().mutate(); + final int color = mAirQualityColorPicker.getColorForValue(airQuality); + + if (background instanceof ShapeDrawable) { + ((ShapeDrawable) background).getPaint().setColor(color); + } else if (background instanceof GradientDrawable) { + ((GradientDrawable) background).setColor(color); + } + mView.setBackground(background); + + final Intent intent = headerAction.getIntent(); + if (intent != null && intent.getComponent() != null + && intent.getComponent().getClassName().equals( + mSmartspaceTrampolineComponent)) { + mView.setOnClickListener(v -> { + mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0); + }); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java index aceafb54914a8..4eae3b928c64a 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java @@ -18,7 +18,7 @@ package com.android.systemui.dreams.complication; import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS; import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.DREAM_WEATHER_COMPLICATION_VIEW; -import static com.android.systemui.dreams.complication.dagger.DreamWeatherComplicationComponent.DreamWeatherComplicationModule.SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT; +import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT; import android.app.smartspace.SmartspaceAction; import android.app.smartspace.SmartspaceTarget; diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamAirQualityComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamAirQualityComplicationComponent.java new file mode 100644 index 0000000000000..112a1cea98a21 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamAirQualityComplicationComponent.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2022 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.dreams.complication.dagger; + +import android.content.Context; +import android.content.res.Resources; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.ColorInt; + +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.dreams.complication.ComplicationLayoutParams; +import com.android.systemui.dreams.complication.DreamAirQualityComplication; +import com.android.systemui.dreams.complication.DreamAirQualityComplication.DreamAirQualityViewHolder; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +import javax.inject.Named; +import javax.inject.Scope; + +import dagger.Module; +import dagger.Provides; +import dagger.Subcomponent; + +/** + * Component responsible for generating dependencies for the {@link DreamAirQualityComplication}, + * such as the layout details. + */ +@Subcomponent(modules = { + DreamAirQualityComplicationComponent.DreamAirQualityComplicationModule.class, +}) +@DreamAirQualityComplicationComponent.DreamAirQualityComplicationScope +public interface DreamAirQualityComplicationComponent { + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Scope + @interface DreamAirQualityComplicationScope { + } + + /** + * Generates {@link DreamAirQualityComplicationComponent}. + */ + @Subcomponent.Factory + interface Factory { + DreamAirQualityComplicationComponent create(); + } + + /** + * Creates {@link DreamAirQualityViewHolder}. + */ + DreamAirQualityViewHolder getViewHolder(); + + /** + * Scoped values for {@link DreamAirQualityComplicationComponent}. + */ + @Module + interface DreamAirQualityComplicationModule { + String DREAM_AQI_COMPLICATION_VIEW = "aqi_complication_view"; + String DREAM_AQI_COMPLICATION_LAYOUT_PARAMS = "aqi_complication_layout_params"; + String DREAM_AQI_COLOR_THRESHOLDS = "aqi_color_thresholds"; + String DREAM_AQI_COLOR_VALUES = "aqi_color_values"; + String DREAM_AQI_COLOR_DEFAULT = "aqi_color_default"; + // Order weight of insert into parent container + int INSERT_ORDER_WEIGHT = 1; + + /** + * Provides the complication view. + */ + @Provides + @DreamAirQualityComplicationScope + @Named(DREAM_AQI_COMPLICATION_VIEW) + static TextView provideComplicationView(LayoutInflater layoutInflater) { + return Objects.requireNonNull((TextView) + layoutInflater.inflate(R.layout.dream_overlay_complication_aqi, + null, false), + "R.layout.dream_overlay_complication_aqi did not properly inflated"); + } + + /** + * Provides the layout parameters for the complication view. + */ + @Provides + @DreamAirQualityComplicationScope + @Named(DREAM_AQI_COMPLICATION_LAYOUT_PARAMS) + static ComplicationLayoutParams provideLayoutParams() { + return new ComplicationLayoutParams(0, + ViewGroup.LayoutParams.WRAP_CONTENT, + ComplicationLayoutParams.POSITION_BOTTOM + | ComplicationLayoutParams.POSITION_START, + ComplicationLayoutParams.DIRECTION_END, + INSERT_ORDER_WEIGHT, /* snapToGuide= */ true); + } + + @Provides + @DreamAirQualityComplicationScope + @Named(DREAM_AQI_COLOR_THRESHOLDS) + static int[] provideAqiColorThresholds(@Main Resources resources) { + return resources.getIntArray(R.array.config_dreamAqiThresholds); + } + + @Provides + @DreamAirQualityComplicationScope + @Named(DREAM_AQI_COLOR_VALUES) + static int[] provideAqiColorValues(@Main Resources resources) { + return resources.getIntArray(R.array.config_dreamAqiColorValues); + } + + @Provides + @DreamAirQualityComplicationScope + @Named(DREAM_AQI_COLOR_DEFAULT) + @ColorInt + static int provideDefaultAqiColor(Context context) { + return context.getColor(R.color.dream_overlay_aqi_unknown); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java index eb2fc5d1a93e4..3ab26ceeb076b 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java @@ -41,7 +41,7 @@ public interface DreamClockDateComplicationModule { "clock_date_complication_layout_params"; // Order weight of insert into parent container //TODO(b/217199227): move to a single location. - int INSERT_ORDER_WEIGHT = 2; + int INSERT_ORDER_WEIGHT = 3; /** * Provides the complication view. @@ -66,6 +66,6 @@ public interface DreamClockDateComplicationModule { ComplicationLayoutParams.POSITION_BOTTOM | ComplicationLayoutParams.POSITION_START, ComplicationLayoutParams.DIRECTION_END, - INSERT_ORDER_WEIGHT); + INSERT_ORDER_WEIGHT, /* snapToGuide= */ true); } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java index a1660f2b43f26..7ab3ad1a621a6 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java @@ -19,7 +19,6 @@ package com.android.systemui.dreams.complication.dagger; import static java.lang.annotation.RetentionPolicy.RUNTIME; -import android.content.Context; import android.view.LayoutInflater; import android.view.ViewGroup; import android.widget.TextView; @@ -77,9 +76,8 @@ public interface DreamWeatherComplicationComponent { String DREAM_WEATHER_COMPLICATION_VIEW = "weather_complication_view"; String DREAM_WEATHER_COMPLICATION_LAYOUT_PARAMS = "weather_complication_layout_params"; - String SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT = "smartspace_trampoline_activity"; // Order weight of insert into parent container - int INSERT_ORDER_WEIGHT = 1; + int INSERT_ORDER_WEIGHT = 2; /** * Provides the complication view. @@ -106,17 +104,7 @@ public interface DreamWeatherComplicationComponent { ComplicationLayoutParams.POSITION_BOTTOM | ComplicationLayoutParams.POSITION_START, ComplicationLayoutParams.DIRECTION_END, - INSERT_ORDER_WEIGHT); - } - - /** - * Provides the smartspace trampoline activity component. - */ - @Provides - @DreamWeatherComplicationScope - @Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT) - static String provideSmartspaceTrampolineActivityComponent(Context context) { - return context.getString(R.string.config_smartspaceTrampolineActivityComponent); + INSERT_ORDER_WEIGHT, /* snapToGuide= */ true); } } } diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java index 62a4140c6745d..98344aa7aae63 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java @@ -16,9 +16,15 @@ package com.android.systemui.dreams.complication.dagger; +import android.content.Context; + +import com.android.systemui.R; import com.android.systemui.dagger.SystemUIBinder; +import javax.inject.Named; + import dagger.Module; +import dagger.Provides; /** * Module for all components with corresponding dream layer complications registered in @@ -30,6 +36,17 @@ import dagger.Module; }, subcomponents = { DreamWeatherComplicationComponent.class, + DreamAirQualityComplicationComponent.class, }) public interface RegisteredComplicationsModule { + String SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT = "smartspace_trampoline_activity"; + + /** + * Provides the smartspace trampoline activity component. + */ + @Provides + @Named(SMARTSPACE_TRAMPOLINE_ACTIVITY_COMPONENT) + static String provideSmartspaceTrampolineActivityComponent(Context context) { + return context.getString(R.string.config_smartspaceTrampolineActivityComponent); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/AirQualityColorPickerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/AirQualityColorPickerTest.java new file mode 100644 index 0000000000000..33be5dcfe0a02 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/AirQualityColorPickerTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2022 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.dreams.complication; + +import static com.google.common.truth.Truth.assertThat; + +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class AirQualityColorPickerTest extends SysuiTestCase { + private static final int DEFAULT_COLOR = 0; + private static final int MOCK_COLOR_1 = 1; + private static final int MOCK_COLOR_2 = 2; + private static final int MOCK_COLOR_3 = 3; + private static final int MOCK_COLOR_4 = 4; + private static final int MOCK_COLOR_5 = 5; + + private static final int[] MOCK_THRESHOLDS = {-1, 100, 200, 201, 500}; + private static final int[] MOCK_COLORS = + {MOCK_COLOR_1, MOCK_COLOR_2, MOCK_COLOR_3, MOCK_COLOR_4, MOCK_COLOR_5}; + private static final int[] EMPTY_ARRAY = {}; + + @Test + public void testEmptyThresholds() { + final AirQualityColorPicker colorPicker = new AirQualityColorPicker( + EMPTY_ARRAY, + MOCK_COLORS, + DEFAULT_COLOR); + assertThat(colorPicker.getColorForValue("110 AQI")).isEqualTo(DEFAULT_COLOR); + } + + @Test + public void testEmptyColors() { + final AirQualityColorPicker colorPicker = new AirQualityColorPicker( + MOCK_THRESHOLDS, + EMPTY_ARRAY, + DEFAULT_COLOR); + assertThat(colorPicker.getColorForValue("110 AQI")).isEqualTo(DEFAULT_COLOR); + } + + @Test + public void testEmptyAqiString() { + final AirQualityColorPicker colorPicker = new AirQualityColorPicker( + MOCK_THRESHOLDS, + MOCK_COLORS, + DEFAULT_COLOR); + assertThat(colorPicker.getColorForValue("")).isEqualTo(DEFAULT_COLOR); + } + + @Test + public void testInvalidAqiString() { + final AirQualityColorPicker colorPicker = new AirQualityColorPicker( + MOCK_THRESHOLDS, + MOCK_COLORS, + DEFAULT_COLOR); + assertThat(colorPicker.getColorForValue("invalid")).isEqualTo(DEFAULT_COLOR); + } + + @Test + public void testZeroAirQuality() { + final AirQualityColorPicker colorPicker = new AirQualityColorPicker( + MOCK_THRESHOLDS, + MOCK_COLORS, + DEFAULT_COLOR); + assertThat(colorPicker.getColorForValue("0 AQI")).isEqualTo(MOCK_COLOR_1); + } + + @Test + public void testVeryLargeAirQuality() { + final AirQualityColorPicker colorPicker = new AirQualityColorPicker( + MOCK_THRESHOLDS, + MOCK_COLORS, + DEFAULT_COLOR); + assertThat(colorPicker.getColorForValue("100000 AQI")).isEqualTo(MOCK_COLOR_5); + } + + @Test + public void testAirQuality200() { + final AirQualityColorPicker colorPicker = new AirQualityColorPicker( + MOCK_THRESHOLDS, + MOCK_COLORS, + DEFAULT_COLOR); + assertThat(colorPicker.getColorForValue("200 AQI")).isEqualTo(MOCK_COLOR_2); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamAirQualityComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamAirQualityComplicationTest.java new file mode 100644 index 0000000000000..b8a7059e4bb76 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamAirQualityComplicationTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2022 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.dreams.complication; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import android.testing.AndroidTestingRunner; +import android.widget.TextView; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.dreams.DreamOverlayStateController; +import com.android.systemui.dreams.complication.DreamAirQualityComplication.DreamAirQualityViewController; +import com.android.systemui.dreams.smartspace.DreamSmartspaceController; +import com.android.systemui.plugins.ActivityStarter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +public class DreamAirQualityComplicationTest extends SysuiTestCase { + private static final String TRAMPOLINE_COMPONENT = "TestComponent"; + + @Mock + private DreamSmartspaceController mDreamSmartspaceController; + + @Mock + private DreamOverlayStateController mDreamOverlayStateController; + + @Mock + private DreamAirQualityComplication mComplication; + + @Mock + private AirQualityColorPicker mColorPicker; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + /** + * Ensures {@link DreamAirQualityComplication} is registered. + */ + @Test + public void testComplicationRegistered() { + final DreamAirQualityComplication.Registrant registrant = + new DreamAirQualityComplication.Registrant( + mContext, + mDreamOverlayStateController, + mComplication); + registrant.start(); + verify(mDreamOverlayStateController).addComplication(eq(mComplication)); + } + + @Test + public void testGetUnfilteredTargets() { + final DreamAirQualityViewController controller = + new DreamAirQualityViewController( + mock(TextView.class), + mDreamSmartspaceController, + TRAMPOLINE_COMPONENT, + mock(ActivityStarter.class), + mColorPicker); + controller.onViewAttached(); + verify(mDreamSmartspaceController).addUnfilteredListener(any()); + controller.onViewDetached(); + verify(mDreamSmartspaceController).removeUnfilteredListener(any()); + } +}