From 568d3a22ab1752a0b7c2567af911ccfb64de856d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Pomini?= Date: Fri, 10 Feb 2023 14:37:44 +0000 Subject: [PATCH] Add ContrastDialog class and tests, activity version Creates the SystemUIDialog class for contrast, as well as the intent ACTION_SHOW_CONTRAST_DIALOG and a helper class that listen to the intent to open the dialog. Bug: 266071578 Test: atest ContrastDialogTest Change-Id: I3c5f25ccd99d5b8875a8fa1fdb9f24ef4886c72b --- core/java/android/content/Intent.java | 7 + packages/SystemUI/AndroidManifest.xml | 14 ++ .../contrast_dialog_button_background.xml | 46 +++++++ .../res/drawable/ic_contrast_high.xml | 25 ++++ .../res/drawable/ic_contrast_medium.xml | 23 ++++ .../res/drawable/ic_contrast_standard.xml | 23 ++++ .../SystemUI/res/layout/contrast_dialog.xml | 127 ++++++++++++++++++ packages/SystemUI/res/values/dimens.xml | 9 ++ packages/SystemUI/res/values/strings.xml | 9 ++ packages/SystemUI/res/values/styles.xml | 4 + .../systemui/contrast/ContrastDialog.kt | 106 +++++++++++++++ .../contrast/ContrastDialogActivity.kt | 46 +++++++ .../dagger/DefaultActivityBinder.java | 7 + .../systemui/contrast/ContrastDialogTest.kt | 84 ++++++++++++ 14 files changed, 530 insertions(+) create mode 100644 packages/SystemUI/res/drawable/contrast_dialog_button_background.xml create mode 100644 packages/SystemUI/res/drawable/ic_contrast_high.xml create mode 100644 packages/SystemUI/res/drawable/ic_contrast_medium.xml create mode 100644 packages/SystemUI/res/drawable/ic_contrast_standard.xml create mode 100644 packages/SystemUI/res/layout/contrast_dialog.xml create mode 100644 packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt create mode 100644 packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt create mode 100644 packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 58b0571653f16..154068eb9e092 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4232,6 +4232,13 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_SHOW_BRIGHTNESS_DIALOG = "com.android.intent.action.SHOW_BRIGHTNESS_DIALOG"; + /** + * Activity Action: Shows the contrast setting dialog. + * @hide + */ + public static final String ACTION_SHOW_CONTRAST_DIALOG = + "com.android.intent.action.SHOW_CONTRAST_DIALOG"; + /** * Broadcast Action: A global button was pressed. Includes a single * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index ff570524ca0ee..36a0b5dd72b83 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -872,6 +872,20 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_contrast_high.xml b/packages/SystemUI/res/drawable/ic_contrast_high.xml new file mode 100644 index 0000000000000..aa5b5abc33aa8 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_contrast_high.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_contrast_medium.xml b/packages/SystemUI/res/drawable/ic_contrast_medium.xml new file mode 100644 index 0000000000000..89519b86b9749 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_contrast_medium.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/packages/SystemUI/res/drawable/ic_contrast_standard.xml b/packages/SystemUI/res/drawable/ic_contrast_standard.xml new file mode 100644 index 0000000000000..f914975823dac --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_contrast_standard.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/packages/SystemUI/res/layout/contrast_dialog.xml b/packages/SystemUI/res/layout/contrast_dialog.xml new file mode 100644 index 0000000000000..8e885cf39e2be --- /dev/null +++ b/packages/SystemUI/res/layout/contrast_dialog.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 2663ffb1fed94..714d495af7620 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1735,6 +1735,15 @@ 44dp 16dp + + 90dp + 82dp + 20dp + 4dp + 14sp + 4dp + 16dp + 0dp 0dp diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 1dd12eef4639b..f1777f84cd6d8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -757,6 +757,15 @@ One-handed mode + + Contrast + + Standard + + Medium + + High + Unblock device microphone? diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 8a86fd560655a..064cea112b5a1 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -377,6 +377,10 @@ @android:color/transparent + + diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt new file mode 100644 index 0000000000000..9e15c7e311272 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialog.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2023 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.contrast + +import android.app.UiModeManager +import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_HIGH +import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_MEDIUM +import android.app.UiModeManager.ContrastUtils.CONTRAST_LEVEL_STANDARD +import android.app.UiModeManager.ContrastUtils.fromContrastLevel +import android.app.UiModeManager.ContrastUtils.toContrastLevel +import android.content.Context +import android.os.Bundle +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import android.widget.FrameLayout +import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.R +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.settings.UserTracker +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.util.settings.SecureSettings +import java.util.concurrent.Executor + +/** Dialog to select contrast options */ +class ContrastDialog( + context: Context?, + @Main private val mainExecutor: Executor, + private val uiModeManager: UiModeManager, + private val userTracker: UserTracker, + private val secureSettings: SecureSettings, +) : SystemUIDialog(context), UiModeManager.ContrastChangeListener { + + @VisibleForTesting lateinit var contrastButtons: Map + lateinit var dialogView: View + @VisibleForTesting var initialContrast: Float = fromContrastLevel(CONTRAST_LEVEL_STANDARD) + + public override fun onCreate(savedInstanceState: Bundle?) { + dialogView = LayoutInflater.from(context).inflate(R.layout.contrast_dialog, null) + setView(dialogView) + + setTitle(R.string.quick_settings_contrast_label) + setNeutralButton(R.string.cancel) { _, _ -> + secureSettings.putFloatForUser( + Settings.Secure.CONTRAST_LEVEL, + initialContrast, + userTracker.userId + ) + dismiss() + } + setPositiveButton(R.string.done) { _, _ -> dismiss() } + super.onCreate(savedInstanceState) + + contrastButtons = + mapOf( + CONTRAST_LEVEL_STANDARD to findViewById(R.id.contrast_button_standard), + CONTRAST_LEVEL_MEDIUM to findViewById(R.id.contrast_button_medium), + CONTRAST_LEVEL_HIGH to findViewById(R.id.contrast_button_high) + ) + + contrastButtons.forEach { (contrastLevel, contrastButton) -> + contrastButton.setOnClickListener { + val contrastValue = fromContrastLevel(contrastLevel) + secureSettings.putFloatForUser( + Settings.Secure.CONTRAST_LEVEL, + contrastValue, + userTracker.userId + ) + } + } + + initialContrast = uiModeManager.contrast + highlightContrast(toContrastLevel(initialContrast)) + } + + override fun onStart() { + super.onStart() + uiModeManager.addContrastChangeListener(mainExecutor, this) + } + + override fun onStop() { + super.onStop() + uiModeManager.removeContrastChangeListener(this) + } + + override fun onContrastChanged(contrast: Float) { + highlightContrast(toContrastLevel(contrast)) + } + + private fun highlightContrast(contrast: Int) { + contrastButtons.forEach { (level, button) -> button.isSelected = level == contrast } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt new file mode 100644 index 0000000000000..70d713845f00a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/contrast/ContrastDialogActivity.kt @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2023 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.contrast + +import android.app.Activity +import android.app.UiModeManager +import android.content.Context +import android.os.Bundle +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.settings.UserTracker +import com.android.systemui.util.settings.SecureSettings +import java.util.concurrent.Executor +import javax.inject.Inject + +/** Trampoline activity responsible for creating a [ContrastDialog] */ +class ContrastDialogActivity +@Inject +constructor( + private val context: Context, + @Main private val mainExecutor: Executor, + private val uiModeManager: UiModeManager, + private val userTracker: UserTracker, + private val secureSettings: SecureSettings +) : Activity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val contrastDialog = + ContrastDialog(context, mainExecutor, uiModeManager, userTracker, secureSettings) + contrastDialog.show() + finish() + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java index 3cf26b381d7d3..dba353b0d70e1 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java @@ -19,6 +19,7 @@ package com.android.systemui.dagger; import android.app.Activity; import com.android.systemui.ForegroundServicesDialog; +import com.android.systemui.contrast.ContrastDialogActivity; import com.android.systemui.hdmi.HdmiCecSetMenuLanguageActivity; import com.android.systemui.keyguard.WorkLockActivity; import com.android.systemui.people.PeopleSpaceActivity; @@ -73,6 +74,12 @@ public abstract class DefaultActivityBinder { @ClassKey(BrightnessDialog.class) public abstract Activity bindBrightnessDialog(BrightnessDialog activity); + /** Inject into ContrastDialogActivity. */ + @Binds + @IntoMap + @ClassKey(ContrastDialogActivity.class) + public abstract Activity bindContrastDialogActivity(ContrastDialogActivity activity); + /** Inject into UsbDebuggingActivity. */ @Binds @IntoMap diff --git a/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt new file mode 100644 index 0000000000000..7753197afc9b2 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/contrast/ContrastDialogTest.kt @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 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.contrast + +import android.app.UiModeManager +import android.app.UiModeManager.ContrastUtils.fromContrastLevel +import android.os.Looper +import android.provider.Settings +import android.testing.AndroidTestingRunner +import android.widget.FrameLayout +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.settings.UserTracker +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.settings.SecureSettings +import com.google.common.util.concurrent.MoreExecutors +import java.util.concurrent.Executor +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.eq +import org.mockito.Mockito.verify +import org.mockito.MockitoAnnotations + +/** Test the behaviour of buttons of the [ContrastDialog]. */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +class ContrastDialogTest : SysuiTestCase() { + + private lateinit var mainExecutor: Executor + private lateinit var contrastDialog: ContrastDialog + @Mock private lateinit var mockUiModeManager: UiModeManager + @Mock private lateinit var mockUserTracker: UserTracker + @Mock private lateinit var mockSecureSettings: SecureSettings + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + mainExecutor = MoreExecutors.directExecutor() + whenever(mockUserTracker.userId).thenReturn(context.userId) + } + + @Test + fun testClickButtons_putsContrastInSettings() { + if (Looper.myLooper() == null) Looper.prepare() + contrastDialog = + ContrastDialog( + context, + mainExecutor, + mockUiModeManager, + mockUserTracker, + mockSecureSettings + ) + contrastDialog.show() + try { + contrastDialog.contrastButtons.forEach { + (contrastLevel: Int, clickedButton: FrameLayout) -> + clickedButton.performClick() + verify(mockSecureSettings) + .putFloatForUser( + eq(Settings.Secure.CONTRAST_LEVEL), + eq(fromContrastLevel(contrastLevel)), + eq(context.userId) + ) + } + } finally { + contrastDialog.dismiss() + } + } +}