diff options
| author | 2024-12-29 18:51:09 -0800 | |
|---|---|---|
| committer | 2024-12-29 18:51:09 -0800 | |
| commit | 00b503d431d583e1b7283fac57a213d5bd635e5d (patch) | |
| tree | b4ccfe566fe2c1b6fa448686262c8f8affd09423 | |
| parent | 43b05634f5da0334d3fb78c422e8a78200a8a1f4 (diff) | |
| parent | e5d59b7c51045560e0296d137f1cc465980e0ae0 (diff) | |
Merge "fix(QSTile): Avoid implicit intent hijacking" into main
15 files changed, 367 insertions, 66 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/shared/QSSettingsPackageRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/shared/QSSettingsPackageRepositoryTest.kt new file mode 100644 index 000000000000..765c02afbb41 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/shared/QSSettingsPackageRepositoryTest.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2024 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.qs.shared + +import android.content.Context +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.testScope +import com.android.systemui.testKosmos +import com.android.systemui.user.data.repository.fakeUserRepository +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.mockito.kotlin.whenever + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class QSSettingsPackageRepositoryTest : SysuiTestCase() { + + @get:Rule val mockito: MockitoRule = MockitoJUnit.rule() + + @Mock private lateinit var context: Context + @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var resolveInfo: ResolveInfo + @Mock private lateinit var activityInfo: ActivityInfo + + private val kosmos = testKosmos() + private val scope = kosmos.testScope + private val userRepository = kosmos.fakeUserRepository + + private lateinit var underTest: QSSettingsPackageRepository + + @Before + fun setUp() { + whenever(context.createContextAsUser(any(), anyInt())).thenReturn(context) + whenever(context.packageManager).thenReturn(packageManager) + whenever(packageManager.queryIntentActivities(any(Intent::class.java), anyInt())) + .thenReturn(listOf(resolveInfo)) + resolveInfo.activityInfo = activityInfo + + underTest = QSSettingsPackageRepository(context, scope, userRepository) + } + + @Test + fun getSettingsPackageName_noInit_returnsDefaultPackageName() { + assertThat(underTest.getSettingsPackageName()).isEqualTo(DEFAULT_SETTINGS_PACKAGE_NAME) + } + + @Test + fun getSettingsPackageName_repositoryWithCustomPackage_returnsCustomPackageName() { + scope.runTest { + activityInfo.packageName = CUSTOM_SETTINGS_PACKAGE_NAME + + underTest.init() + runCurrent() + + assertThat(underTest.getSettingsPackageName()).isEqualTo(CUSTOM_SETTINGS_PACKAGE_NAME) + } + } + + @Test + fun getSettingsPackageName_noMatchingActivity_returnsDefaultPackageName() { + scope.runTest { + whenever(packageManager.queryIntentActivities(any(Intent::class.java), anyInt())) + .thenReturn(emptyList()) + + underTest.init() + runCurrent() + + assertThat(underTest.getSettingsPackageName()).isEqualTo(DEFAULT_SETTINGS_PACKAGE_NAME) + } + } + + @Test + fun getSettingsPackageName_nullActivityInfo_returnsDefaultPackageName() { + scope.runTest { + resolveInfo.activityInfo = null + + underTest.init() + runCurrent() + + assertThat(underTest.getSettingsPackageName()).isEqualTo(DEFAULT_SETTINGS_PACKAGE_NAME) + } + } + + companion object { + private const val DEFAULT_SETTINGS_PACKAGE_NAME = "com.android.settings" + private const val CUSTOM_SETTINGS_PACKAGE_NAME = "com.android.test.settings" + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java index 028beb599644..e5e8d4a6ed32 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorCorrectionTileTest.java @@ -39,6 +39,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.shared.QSSettingsPackageRepository; import com.android.systemui.settings.UserTracker; import com.android.systemui.util.settings.FakeSettings; import com.android.systemui.util.settings.SecureSettings; @@ -55,6 +56,7 @@ import org.mockito.MockitoAnnotations; @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class ColorCorrectionTileTest extends SysuiTestCase { + private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; @Mock private QSHost mHost; @@ -70,6 +72,8 @@ public class ColorCorrectionTileTest extends SysuiTestCase { private QsEventLogger mUiEventLogger; @Mock private UserTracker mUserTracker; + @Mock + private QSSettingsPackageRepository mQSSettingsPackageRepository; private TestableLooper mTestableLooper; private SecureSettings mSecureSettings; @@ -83,6 +87,8 @@ public class ColorCorrectionTileTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); when(mHost.getContext()).thenReturn(mContext); + when(mQSSettingsPackageRepository.getSettingsPackageName()) + .thenReturn(SETTINGS_PACKAGE_NAME); mTile = new ColorCorrectionTile( mHost, @@ -95,7 +101,8 @@ public class ColorCorrectionTileTest extends SysuiTestCase { mActivityStarter, mQSLogger, mUserTracker, - mSecureSettings + mSecureSettings, + mQSSettingsPackageRepository ); mTile.initialize(); @@ -119,5 +126,6 @@ public class ColorCorrectionTileTest extends SysuiTestCase { anyInt(), any()); assertThat(IntentCaptor.getValue().getAction()).isEqualTo( Settings.ACTION_COLOR_CORRECTION_SETTINGS); + assertThat(IntentCaptor.getValue().getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME); } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java index a58dd6301e07..cbde99847770 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ColorInversionTileTest.java @@ -45,6 +45,7 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.flags.QsInCompose; import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.shared.QSSettingsPackageRepository; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; @@ -59,15 +60,16 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.List; - import platform.test.runner.parameterized.ParameterizedAndroidJunit4; import platform.test.runner.parameterized.Parameters; +import java.util.List; + @RunWith(ParameterizedAndroidJunit4.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest public class ColorInversionTileTest extends SysuiTestCase { + private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; private static final Integer COLOR_INVERSION_DISABLED = 0; private static final Integer COLOR_INVERSION_ENABLED = 1; @@ -90,6 +92,8 @@ public class ColorInversionTileTest extends SysuiTestCase { private QsEventLogger mUiEventLogger; @Mock private UserTracker mUserTracker; + @Mock + private QSSettingsPackageRepository mQSSettingsPackageRepository; private TestableLooper mTestableLooper; private SecureSettings mSecureSettings; @@ -108,6 +112,8 @@ public class ColorInversionTileTest extends SysuiTestCase { mTestableLooper = TestableLooper.get(this); when(mHost.getContext()).thenReturn(mContext); + when(mQSSettingsPackageRepository.getSettingsPackageName()) + .thenReturn(SETTINGS_PACKAGE_NAME); mTile = new ColorInversionTile( mHost, @@ -120,7 +126,8 @@ public class ColorInversionTileTest extends SysuiTestCase { mActivityStarter, mQSLogger, mUserTracker, - mSecureSettings + mSecureSettings, + mQSSettingsPackageRepository ); mTile.initialize(); @@ -144,6 +151,7 @@ public class ColorInversionTileTest extends SysuiTestCase { anyInt(), any()); assertThat(IntentCaptor.getValue().getAction()).isEqualTo( Settings.ACTION_COLOR_INVERSION_SETTINGS); + assertThat(IntentCaptor.getValue().getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt index c854920cbf1f..ae4da9de5e48 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt @@ -32,11 +32,10 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.eq import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import org.junit.After @@ -49,8 +48,10 @@ import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -68,21 +69,24 @@ class FontScalingTileTest : SysuiTestCase() { @Mock private lateinit var dialog: SystemUIDialog @Mock private lateinit var expandable: Expandable @Mock private lateinit var controller: DialogTransitionAnimator.Controller + @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository + + @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable> private lateinit var testableLooper: TestableLooper private lateinit var systemClock: FakeSystemClock private lateinit var backgroundDelayableExecutor: FakeExecutor private lateinit var fontScalingTile: FontScalingTile - @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable> - @Before fun setUp() { MockitoAnnotations.initMocks(this) testableLooper = TestableLooper.get(this) - `when`(qsHost.getContext()).thenReturn(mContext) - `when`(fontScalingDialogDelegate.createDialog()).thenReturn(dialog) - `when`(expandable.dialogTransitionController(any())).thenReturn(controller) + whenever(qsHost.getContext()).thenReturn(mContext) + whenever(fontScalingDialogDelegate.createDialog()).thenReturn(dialog) + whenever(expandable.dialogTransitionController(any())).thenReturn(controller) + whenever(settingsPackageRepository.getSettingsPackageName()) + .thenReturn(SETTINGS_PACKAGE_NAME) systemClock = FakeSystemClock() backgroundDelayableExecutor = FakeExecutor(systemClock) @@ -100,6 +104,7 @@ class FontScalingTileTest : SysuiTestCase() { keyguardStateController, mDialogTransitionAnimator, { fontScalingDialogDelegate }, + settingsPackageRepository, ) fontScalingTile.initialize() testableLooper.processAllMessages() @@ -120,7 +125,7 @@ class FontScalingTileTest : SysuiTestCase() { @Test fun clickTile_screenUnlocked_showDialogAnimationFromView() { - `when`(keyguardStateController.isShowing).thenReturn(false) + whenever(keyguardStateController.isShowing).thenReturn(false) fontScalingTile.click(expandable) testableLooper.processAllMessages() @@ -130,7 +135,7 @@ class FontScalingTileTest : SysuiTestCase() { eq(null), eq(true), eq(true), - eq(false) + eq(false), ) argumentCaptor.value.run() verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean()) @@ -138,7 +143,7 @@ class FontScalingTileTest : SysuiTestCase() { @Test fun clickTile_onLockScreen_neverShowDialogAnimationFromView() { - `when`(keyguardStateController.isShowing).thenReturn(true) + whenever(keyguardStateController.isShowing).thenReturn(true) fontScalingTile.click(expandable) testableLooper.processAllMessages() @@ -148,7 +153,7 @@ class FontScalingTileTest : SysuiTestCase() { eq(null), eq(true), eq(true), - eq(false) + eq(false), ) argumentCaptor.value.run() verify(mDialogTransitionAnimator, never()).show(any(), any(), anyBoolean()) @@ -159,5 +164,10 @@ class FontScalingTileTest : SysuiTestCase() { val intent: Intent? = fontScalingTile.getLongClickIntent() assertThat(intent!!.action).isEqualTo(Settings.ACTION_TEXT_READING_SETTINGS) + assertThat(intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME) + } + + companion object { + private const val SETTINGS_PACKAGE_NAME = "com.android.settings" } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt index 3bc53b273e89..0cf3734dd92b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt @@ -23,29 +23,45 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.accessibility.data.repository.FakeColorCorrectionRepository +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.mockito.kotlin.whenever @SmallTest @EnabledOnRavenwood @RunWith(AndroidJUnit4::class) class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() { + @get:Rule val mockito: MockitoRule = MockitoJUnit.rule() + + @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository + private val testUser = UserHandle.CURRENT private val repository = FakeColorCorrectionRepository() private val inputHandler = FakeQSTileIntentUserInputHandler() - private val underTest = - ColorCorrectionUserActionInteractor( - repository, - inputHandler, - ) + private lateinit var underTest: ColorCorrectionUserActionInteractor + + @Before + fun setUp() { + whenever(settingsPackageRepository.getSettingsPackageName()) + .thenReturn(SETTINGS_PACKAGE_NAME) + + underTest = + ColorCorrectionUserActionInteractor(repository, inputHandler, settingsPackageRepository) + } @Test fun handleClickWhenEnabled() = runTest { @@ -86,6 +102,11 @@ class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() { QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_CORRECTION_SETTINGS) + assertThat(it.intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME) } } + + companion object { + private const val SETTINGS_PACKAGE_NAME = "com.android.settings" + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt index d3095542e90f..9bd4895ac21c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingUserActionInteractorTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.animation.LaunchableView import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.intentInputs import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx @@ -36,11 +37,7 @@ import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click import com.android.systemui.qs.tiles.impl.fontscaling.domain.model.FontScalingTileModel import com.android.systemui.statusbar.phone.FakeKeyguardStateController import com.android.systemui.statusbar.phone.SystemUIDialog -import com.android.systemui.util.mockito.any -import com.android.systemui.util.mockito.eq -import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever -import com.google.common.truth.Truth +import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test @@ -51,15 +48,14 @@ import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever @SmallTest @RunWith(AndroidJUnit4::class) class FontScalingUserActionInteractorTest : SysuiTestCase() { - private val kosmos = Kosmos() - private val qsTileIntentUserActionHandler = FakeQSTileIntentUserInputHandler() - private val keyguardStateController = FakeKeyguardStateController() - - private lateinit var underTest: FontScalingTileUserActionInteractor @Mock private lateinit var fontScalingDialogDelegate: FontScalingDialogDelegate @Mock private lateinit var mDialogTransitionAnimator: DialogTransitionAnimator @@ -67,35 +63,47 @@ class FontScalingUserActionInteractorTest : SysuiTestCase() { @Mock private lateinit var activityStarter: ActivityStarter @Mock private lateinit var expandable: Expandable @Mock private lateinit var controller: DialogTransitionAnimator.Controller + @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository @Captor private lateinit var argumentCaptor: ArgumentCaptor<Runnable> + private val kosmos = Kosmos() + private val scope = kosmos.testScope + private val qsTileIntentUserActionHandler = FakeQSTileIntentUserInputHandler() + private val keyguardStateController = FakeKeyguardStateController() + + private lateinit var underTest: FontScalingTileUserActionInteractor + @Before fun setup() { activityStarter = mock<ActivityStarter>() mDialogTransitionAnimator = mock<DialogTransitionAnimator>() dialog = mock<SystemUIDialog>() - fontScalingDialogDelegate = - mock<FontScalingDialogDelegate> { whenever(createDialog()).thenReturn(dialog) } + fontScalingDialogDelegate = mock<FontScalingDialogDelegate>() + whenever(fontScalingDialogDelegate.createDialog()).thenReturn(dialog) controller = mock<DialogTransitionAnimator.Controller>() - expandable = - mock<Expandable> { whenever(dialogTransitionController(any())).thenReturn(controller) } + expandable = mock<Expandable>() + whenever(expandable.dialogTransitionController(any())).thenReturn(controller) + settingsPackageRepository = mock<QSSettingsPackageRepository>() + whenever(settingsPackageRepository.getSettingsPackageName()) + .thenReturn(SETTINGS_PACKAGE_NAME) argumentCaptor = ArgumentCaptor.forClass(Runnable::class.java) underTest = FontScalingTileUserActionInteractor( - kosmos.testScope.coroutineContext, + scope.coroutineContext, qsTileIntentUserActionHandler, { fontScalingDialogDelegate }, keyguardStateController, mDialogTransitionAnimator, - activityStarter + activityStarter, + settingsPackageRepository, ) } @Test fun clickTile_screenUnlocked_showDialogAnimationFromView() = - kosmos.testScope.runTest { + scope.runTest { keyguardStateController.isShowing = false underTest.handleInput(click(FontScalingTileModel, expandable = expandable)) @@ -106,7 +114,7 @@ class FontScalingUserActionInteractorTest : SysuiTestCase() { eq(null), eq(true), eq(true), - eq(false) + eq(false), ) argumentCaptor.value.run() verify(mDialogTransitionAnimator).show(any(), any(), anyBoolean()) @@ -114,7 +122,7 @@ class FontScalingUserActionInteractorTest : SysuiTestCase() { @Test fun clickTile_onLockScreen_neverShowDialogAnimationFromView_butShowsDialog() = - kosmos.testScope.runTest { + scope.runTest { keyguardStateController.isShowing = true underTest.handleInput(click(FontScalingTileModel, expandable = expandable)) @@ -125,7 +133,7 @@ class FontScalingUserActionInteractorTest : SysuiTestCase() { eq(null), eq(true), eq(true), - eq(false) + eq(false), ) argumentCaptor.value.run() verify(mDialogTransitionAnimator, never()).show(any(), any(), anyBoolean()) @@ -134,17 +142,20 @@ class FontScalingUserActionInteractorTest : SysuiTestCase() { @Test fun handleLongClick() = - kosmos.testScope.runTest { + scope.runTest { underTest.handleInput(QSTileInputTestKtx.longClick(FontScalingTileModel)) - Truth.assertThat(qsTileIntentUserActionHandler.handledInputs).hasSize(1) - val intentInput = qsTileIntentUserActionHandler.intentInputs.last() - val actualIntentAction = intentInput.intent.action - val expectedIntentAction = Settings.ACTION_TEXT_READING_SETTINGS - Truth.assertThat(actualIntentAction).isEqualTo(expectedIntentAction) + assertThat(qsTileIntentUserActionHandler.handledInputs).hasSize(1) + val it = qsTileIntentUserActionHandler.intentInputs.last() + assertThat(it.intent.action).isEqualTo(Settings.ACTION_TEXT_READING_SETTINGS) + assertThat(it.intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME) } private class FontScalingTileTestView(context: Context) : View(context), LaunchableView { override fun setShouldBlockVisibilityChanges(block: Boolean) {} } + + companion object { + private const val SETTINGS_PACKAGE_NAME = "com.android.settings" + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt index f574f793fbf2..3f77b86971e1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt @@ -23,29 +23,45 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.accessibility.data.repository.FakeColorInversionRepository +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.mockito.kotlin.whenever @SmallTest @EnabledOnRavenwood @RunWith(AndroidJUnit4::class) class ColorInversionUserActionInteractorTest : SysuiTestCase() { + @get:Rule val mockito: MockitoRule = MockitoJUnit.rule() + + @Mock private lateinit var settingsPackageRepository: QSSettingsPackageRepository + private val testUser = UserHandle.CURRENT private val repository = FakeColorInversionRepository() private val inputHandler = FakeQSTileIntentUserInputHandler() - private val underTest = - ColorInversionUserActionInteractor( - repository, - inputHandler, - ) + private lateinit var underTest: ColorInversionUserActionInteractor + + @Before + fun setUp() { + whenever(settingsPackageRepository.getSettingsPackageName()) + .thenReturn(SETTINGS_PACKAGE_NAME) + + underTest = + ColorInversionUserActionInteractor(repository, inputHandler, settingsPackageRepository) + } @Test fun handleClickWhenEnabled() = runTest { @@ -86,6 +102,11 @@ class ColorInversionUserActionInteractorTest : SysuiTestCase() { QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput { assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_INVERSION_SETTINGS) + assertThat(it.intent.getPackage()).isEqualTo(SETTINGS_PACKAGE_NAME) } } + + companion object { + private const val SETTINGS_PACKAGE_NAME = "com.android.settings" + } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt index 9677d47b38e8..3b3fb9b10052 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt @@ -23,6 +23,7 @@ import com.android.systemui.qs.pipeline.domain.interactor.AutoAddInteractor import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor import com.android.systemui.qs.pipeline.domain.interactor.RestoreReconciliationInteractor import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository +import com.android.systemui.qs.shared.QSSettingsPackageRepository import javax.inject.Inject @SysUISingleton @@ -33,12 +34,14 @@ constructor( private val accessibilityTilesInteractor: AccessibilityTilesInteractor, private val autoAddInteractor: AutoAddInteractor, private val featureFlags: QSPipelineFlagsRepository, + private val settingsPackageRepository: QSSettingsPackageRepository, private val restoreReconciliationInteractor: RestoreReconciliationInteractor, ) : CoreStartable { override fun start() { accessibilityTilesInteractor.init(currentTilesInteractor) autoAddInteractor.init(currentTilesInteractor) + settingsPackageRepository.init() restoreReconciliationInteractor.start() } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/shared/QSSettingsPackageRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/shared/QSSettingsPackageRepository.kt new file mode 100644 index 000000000000..592e9dadcb92 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/shared/QSSettingsPackageRepository.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2024 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.qs.shared + +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.os.UserHandle +import android.provider.Settings +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.user.data.repository.UserRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +/** + * Provides the cached package name of the default Settings application. + * + * This repository retrieves and stores the package name to avoid repeated lookups. The package name + * is retrieved in a background thread when the `init()` method is called. + */ +@SysUISingleton +@Suppress("ShadeDisplayAwareContextChecker") +class QSSettingsPackageRepository +@Inject +constructor( + private val context: Context, + @Background private val backgroundScope: CoroutineScope, + private val userRepository: UserRepository, +) { + private var settingsPackageName: String? = null + + /** + * Initializes the repository by determining and caching the package name of the Settings app. + */ + fun init() { + backgroundScope.launch { + val mainUserId = userRepository.mainUserId + val mainUserContext = + context.createContextAsUser(UserHandle.of(mainUserId), /* flags */ 0) + val pm = mainUserContext.packageManager + settingsPackageName = + pm.queryIntentActivities( + Intent(Settings.ACTION_SETTINGS), + PackageManager.MATCH_SYSTEM_ONLY or PackageManager.MATCH_DEFAULT_ONLY, + ) + .firstOrNull() + ?.activityInfo + ?.packageName ?: DEFAULT_SETTINGS_PACKAGE_NAME + } + } + + /** + * Returns the cached package name of the Settings app. + * + * If the package name has not been initialized yet, this method will return the default + * Settings package name. + * + * @return The package name of the Settings app. + */ + fun getSettingsPackageName(): String { + return settingsPackageName ?: DEFAULT_SETTINGS_PACKAGE_NAME + } + + companion object { + private const val DEFAULT_SETTINGS_PACKAGE_NAME = "com.android.settings" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java index c2e609ddfc3a..1f936810da28 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java @@ -38,6 +38,7 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.UserSettingObserver; import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.shared.QSSettingsPackageRepository; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; @@ -53,6 +54,7 @@ public class ColorCorrectionTile extends QSTileImpl<BooleanState> { @Nullable private Icon mIcon = null; private final UserSettingObserver mSetting; + private final QSSettingsPackageRepository mQSSettingsPackageRepository; @Inject public ColorCorrectionTile( @@ -66,11 +68,13 @@ public class ColorCorrectionTile extends QSTileImpl<BooleanState> { ActivityStarter activityStarter, QSLogger qsLogger, UserTracker userTracker, - SecureSettings secureSettings + SecureSettings secureSettings, + QSSettingsPackageRepository qsSettingsPackageRepository ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); + mQSSettingsPackageRepository = qsSettingsPackageRepository; mSetting = new UserSettingObserver(secureSettings, mHandler, Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, userTracker.getUserId()) { @Override @@ -106,7 +110,8 @@ public class ColorCorrectionTile extends QSTileImpl<BooleanState> { @Override public Intent getLongClickIntent() { - return new Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS); + return new Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS) + .setPackage(mQSSettingsPackageRepository.getSettingsPackageName()); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index ce80133e67a2..38e9a205e9ed 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -39,6 +39,7 @@ import com.android.systemui.qs.QSHost; import com.android.systemui.qs.QsEventLogger; import com.android.systemui.qs.UserSettingObserver; import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.shared.QSSettingsPackageRepository; import com.android.systemui.qs.tileimpl.QSTileImpl; import com.android.systemui.res.R; import com.android.systemui.settings.UserTracker; @@ -51,6 +52,7 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { public static final String TILE_SPEC = "inversion"; private final UserSettingObserver mSetting; + private final QSSettingsPackageRepository mQSSettingsPackageRepository; @Inject public ColorInversionTile( @@ -64,11 +66,13 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { ActivityStarter activityStarter, QSLogger qsLogger, UserTracker userTracker, - SecureSettings secureSettings + SecureSettings secureSettings, + QSSettingsPackageRepository qsSettingsPackageRepository ) { super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger, statusBarStateController, activityStarter, qsLogger); + mQSSettingsPackageRepository = qsSettingsPackageRepository; mSetting = new UserSettingObserver(secureSettings, mHandler, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, userTracker.getUserId()) { @Override @@ -104,7 +108,8 @@ public class ColorInversionTile extends QSTileImpl<BooleanState> { @Override public Intent getLongClickIntent() { - return new Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS); + return new Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS) + .setPackage(mQSSettingsPackageRepository.getSettingsPackageName()); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt index 43e84a0ee2b4..4050f2a1cb4e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt @@ -34,6 +34,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.res.R import com.android.systemui.statusbar.phone.SystemUIDialog @@ -56,6 +57,7 @@ constructor( private val keyguardStateController: KeyguardStateController, private val dialogTransitionAnimator: DialogTransitionAnimator, private val fontScalingDialogDelegateProvider: Provider<FontScalingDialogDelegate>, + private val settingsPackageRepository: QSSettingsPackageRepository, ) : QSTileImpl<QSTile.State?>( host, @@ -118,6 +120,7 @@ constructor( override fun getLongClickIntent(): Intent? { return Intent(Settings.ACTION_TEXT_READING_SETTINGS) + .setPackage(settingsPackageRepository.getSettingsPackageName()) } override fun getTileLabel(): CharSequence { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt index dfdec3b458a9..b774643eb21d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionUserActionInteractor.kt @@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor import android.content.Intent import android.provider.Settings import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor @@ -32,21 +33,20 @@ class ColorCorrectionUserActionInteractor constructor( private val colorCorrectionRepository: ColorCorrectionRepository, private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler, + private val settingsPackageRepository: QSSettingsPackageRepository, ) : QSTileUserActionInteractor<ColorCorrectionTileModel> { override suspend fun handleInput(input: QSTileInput<ColorCorrectionTileModel>): Unit = with(input) { when (action) { is QSTileUserAction.Click -> { - colorCorrectionRepository.setIsEnabled( - !data.isEnabled, - user, - ) + colorCorrectionRepository.setIsEnabled(!data.isEnabled, user) } is QSTileUserAction.LongClick -> { qsTileIntentUserActionHandler.handle( action.expandable, Intent(Settings.ACTION_COLOR_CORRECTION_SETTINGS) + .setPackage(settingsPackageRepository.getSettingsPackageName()), ) } is QSTileUserAction.ToggleClick -> {} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt index 6ab5796dceaa..0ebb51e722af 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/fontscaling/domain/interactor/FontScalingTileUserActionInteractor.kt @@ -24,6 +24,7 @@ import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor @@ -46,6 +47,7 @@ constructor( private val keyguardStateController: KeyguardStateController, private val dialogTransitionAnimator: DialogTransitionAnimator, private val activityStarter: ActivityStarter, + private val settingsPackageRepository: QSSettingsPackageRepository, ) : QSTileUserActionInteractor<FontScalingTileModel> { override suspend fun handleInput(input: QSTileInput<FontScalingTileModel>): Unit = @@ -63,7 +65,7 @@ constructor( ?.dialogTransitionController( DialogCuj( InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, - INTERACTION_JANK_TAG + INTERACTION_JANK_TAG, ) ) ?.let { dialogTransitionAnimator.show(dialog, it) } ?: dialog.show() @@ -78,7 +80,7 @@ constructor( /* cancelAction= */ null, /* dismissShade= */ true, /* afterKeyguardGone= */ true, - /* deferred= */ false + /* deferred= */ false, ) } } @@ -86,6 +88,7 @@ constructor( qsTileIntentUserActionHandler.handle( action.expandable, Intent(Settings.ACTION_TEXT_READING_SETTINGS) + .setPackage(settingsPackageRepository.getSettingsPackageName()), ) } is QSTileUserAction.ToggleClick -> {} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt index aa8387732160..f78349718697 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt @@ -19,6 +19,7 @@ package com.android.systemui.qs.tiles.impl.inversion.domain.interactor import android.content.Intent import android.provider.Settings import com.android.systemui.accessibility.data.repository.ColorInversionRepository +import com.android.systemui.qs.shared.QSSettingsPackageRepository import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.interactor.QSTileInput import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor @@ -32,21 +33,20 @@ class ColorInversionUserActionInteractor constructor( private val colorInversionRepository: ColorInversionRepository, private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler, + private val settingsPackageRepository: QSSettingsPackageRepository, ) : QSTileUserActionInteractor<ColorInversionTileModel> { override suspend fun handleInput(input: QSTileInput<ColorInversionTileModel>): Unit = with(input) { when (action) { is QSTileUserAction.Click -> { - colorInversionRepository.setIsEnabled( - !data.isEnabled, - user, - ) + colorInversionRepository.setIsEnabled(!data.isEnabled, user) } is QSTileUserAction.LongClick -> { qsTileIntentUserActionHandler.handle( action.expandable, Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS) + .setPackage(settingsPackageRepository.getSettingsPackageName()), ) } is QSTileUserAction.ToggleClick -> {} |