diff options
| author | 2022-06-15 17:39:26 +0000 | |
|---|---|---|
| committer | 2022-06-15 17:39:26 +0000 | |
| commit | 513cc27dc7ac59fa20fc0d1fbcd3dccc1ec4584e (patch) | |
| tree | 068712f2be5f0f9037db7ff05083eb5c38237d05 | |
| parent | d6579ac1b7b3a43a59b4bda4fb35b80959e67d05 (diff) | |
| parent | ee76de8f4aa465244985d73829590b84eba347a3 (diff) | |
Merge "Implement air quality dream complication" into tm-qpr-dev
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()); + } +} |