summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lucas Silva <lusilva@google.com> 2022-06-15 17:39:26 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-06-15 17:39:26 +0000
commit513cc27dc7ac59fa20fc0d1fbcd3dccc1ec4584e (patch)
tree068712f2be5f0f9037db7ff05083eb5c38237d05
parentd6579ac1b7b3a43a59b4bda4fb35b80959e67d05 (diff)
parentee76de8f4aa465244985d73829590b84eba347a3 (diff)
Merge "Implement air quality dream complication" into tm-qpr-dev
-rw-r--r--packages/SystemUI/res/drawable/dream_aqi_badge_bg.xml20
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_complication_aqi.xml26
-rw-r--r--packages/SystemUI/res/values/colors.xml9
-rw-r--r--packages/SystemUI/res/values/config.xml21
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/AirQualityColorPicker.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamAirQualityComplication.java199
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamAirQualityComplicationComponent.java137
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockDateComplicationModule.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamWeatherComplicationComponent.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/AirQualityColorPickerTest.java107
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamAirQualityComplicationTest.java91
14 files changed, 706 insertions, 17 deletions
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 000000000000..1992c7733bd3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/dream_aqi_badge_bg.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@color/dream_overlay_aqi_unknown" />
+ <corners android:radius="@dimen/dream_aqi_badge_corner_radius" />
+</shape> \ 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 000000000000..fcebb8d3f6c6
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_aqi.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/aqi_view"
+ style="@style/clock_subtitle"
+ android:visibility="gone"
+ android:background="@drawable/dream_aqi_badge_bg"
+ android:paddingHorizontal="@dimen/dream_aqi_badge_padding_horizontal"
+ android:paddingVertical="@dimen/dream_aqi_badge_padding_vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 02ba271ee9a4..ccf18d2a0bb1 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -233,4 +233,13 @@
<color name="connected_network_secondary_color">#41493D</color>
<color name="dream_overlay_camera_mic_off_dot_color">#FCBE03</color>
+
+ <!-- Air Quality -->
+ <color name="dream_overlay_aqi_good">#689F38</color>
+ <color name="dream_overlay_aqi_moderate">#FBC02D</color>
+ <color name="dream_overlay_aqi_unhealthy_sensitive">#F57C00</color>
+ <color name="dream_overlay_aqi_unhealthy">#C53929</color>
+ <color name="dream_overlay_aqi_very_unhealthy">#AD1457</color>
+ <color name="dream_overlay_aqi_hazardous">#880E4F</color>
+ <color name="dream_overlay_aqi_unknown">#BDC1C6</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ce5f22dea013..eff4e00fd07b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -727,4 +727,25 @@
<item>com.android.keyguard</item>
<item>com.android.systemui</item>
</string-array>
+
+ <!-- The thresholds which determine the color used by the AQI dream overlay.
+ NOTE: This must always be kept sorted from low to high -->
+ <integer-array name="config_dreamAqiThresholds">
+ <item>-1</item>
+ <item>50</item>
+ <item>100</item>
+ <item>150</item>
+ <item>200</item>
+ <item>300</item>
+ </integer-array>
+
+ <!-- The color values which correspond to the thresholds above -->
+ <integer-array name="config_dreamAqiColorValues">
+ <item>@color/dream_overlay_aqi_good</item>
+ <item>@color/dream_overlay_aqi_moderate</item>
+ <item>@color/dream_overlay_aqi_unhealthy_sensitive</item>
+ <item>@color/dream_overlay_aqi_unhealthy</item>
+ <item>@color/dream_overlay_aqi_very_unhealthy</item>
+ <item>@color/dream_overlay_aqi_hazardous</item>
+ </integer-array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6a098f5d473d..4d365412828e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1503,6 +1503,10 @@
<dimen name="dream_overlay_y_offset">80dp</dimen>
+ <dimen name="dream_aqi_badge_corner_radius">28dp</dimen>
+ <dimen name="dream_aqi_badge_padding_vertical">6dp</dimen>
+ <dimen name="dream_aqi_badge_padding_horizontal">16dp</dimen>
+
<dimen name="status_view_margin_horizontal">0dp</dimen>
<!-- Media output broadcast dialog QR code picture size -->
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 000000000000..328753ff1539
--- /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 000000000000..ba63303d1f2c
--- /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<TextView> {
+ 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 aceafb54914a..4eae3b928c64 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 000000000000..112a1cea98a2
--- /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 eb2fc5d1a93e..3ab26ceeb076 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 a1660f2b43f2..7ab3ad1a621a 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 62a4140c6745..98344aa7aae6 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 000000000000..33be5dcfe0a0
--- /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 000000000000..b8a7059e4bb7
--- /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());
+ }
+}