Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00b503d4 authored by Menghan Li's avatar Menghan Li Committed by Android (Google) Code Review
Browse files

Merge "fix(QSTile): Avoid implicit intent hijacking" into main

parents 43b05634 e5d59b7c
Loading
Loading
Loading
Loading
+120 −0
Original line number Diff line number Diff line
/*
 * 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"
    }
}
+9 −1
Original line number Diff line number Diff line
@@ -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);
    }
}
+11 −3
Original line number Diff line number Diff line
@@ -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
+22 −12
Original line number Diff line number Diff line
@@ -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"
    }
}
+26 −5
Original line number Diff line number Diff line
@@ -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"
    }
}
Loading