1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.qs.tiles.base.actions 18 19 import android.app.PendingIntent 20 import android.content.ComponentName 21 import android.content.Intent 22 import android.content.pm.ActivityInfo 23 import android.content.pm.PackageManager 24 import android.content.pm.PackageManager.ResolveInfoFlags 25 import android.content.pm.ResolveInfo 26 import android.os.UserHandle 27 import android.platform.test.annotations.EnabledOnRavenwood 28 import androidx.test.ext.junit.runners.AndroidJUnit4 29 import androidx.test.filters.SmallTest 30 import com.android.systemui.SysuiTestCase 31 import com.android.systemui.plugins.ActivityStarter 32 import com.android.systemui.util.mockito.argThat 33 import com.android.systemui.util.mockito.mock 34 import com.android.systemui.util.mockito.whenever 35 import org.junit.Before 36 import org.junit.Test 37 import org.junit.runner.RunWith 38 import org.mockito.ArgumentMatcher 39 import org.mockito.Mock 40 import org.mockito.Mockito.any 41 import org.mockito.Mockito.eq 42 import org.mockito.Mockito.never 43 import org.mockito.Mockito.verify 44 import org.mockito.Mockito.`when` 45 import org.mockito.MockitoAnnotations 46 47 @SmallTest 48 @EnabledOnRavenwood 49 @RunWith(AndroidJUnit4::class) 50 class QSTileIntentUserInputHandlerTest : SysuiTestCase() { 51 @Mock private lateinit var packageManager: PackageManager 52 @Mock private lateinit var activityStarter: ActivityStarter 53 54 lateinit var underTest: QSTileIntentUserInputHandler 55 56 @Before setupnull57 fun setup() { 58 MockitoAnnotations.initMocks(this) 59 underTest = QSTileIntentUserInputHandlerImpl(activityStarter, packageManager, user) 60 } 61 62 @Test testPassesIntentToStarternull63 fun testPassesIntentToStarter() { 64 val intent = Intent("test.ACTION") 65 66 underTest.handle(null, intent) 67 68 verify(activityStarter).postStartActivityDismissingKeyguard(eq(intent), eq(0), any()) 69 } 70 71 @Test testPassesIntentToStarter_dismissShadeAndShowOverLockScreenWhenLockednull72 fun testPassesIntentToStarter_dismissShadeAndShowOverLockScreenWhenLocked() { 73 val intent = Intent("test.ACTION") 74 75 underTest.handle(null, intent, true) 76 77 verify(activityStarter).startActivity(eq(intent), eq(true), any(), eq(true)) 78 } 79 80 @Test testPassesActivityPendingIntentToStarterAsPendingIntentnull81 fun testPassesActivityPendingIntentToStarterAsPendingIntent() { 82 val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } 83 84 underTest.handle(null, pendingIntent, true) 85 86 verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) 87 } 88 89 @Test testPassesActivityPendingIntentToStarterAsPendingIntentWhenNotRequestingActivityStartnull90 fun testPassesActivityPendingIntentToStarterAsPendingIntentWhenNotRequestingActivityStart() { 91 val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) } 92 93 underTest.handle(null, pendingIntent, false) 94 95 verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any()) 96 } 97 98 @Test testPassNonActivityPendingIntentAndRequestStartingActivity_findsIntentAndStartsnull99 fun testPassNonActivityPendingIntentAndRequestStartingActivity_findsIntentAndStarts() { 100 val pendingIntent = 101 mock<PendingIntent> { 102 whenever(isActivity).thenReturn(false) 103 whenever(creatorPackage).thenReturn(ORIGINAL_PACKAGE) 104 } 105 setUpQueryResult(listOf(createActivityInfo(testResolvedComponent, exported = true))) 106 107 underTest.handle(null, pendingIntent, true) 108 109 val expectedIntent = 110 Intent(Intent.ACTION_MAIN) 111 .addCategory(Intent.CATEGORY_LAUNCHER) 112 .setPackage(null) 113 .addFlags( 114 Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 115 ) 116 .setComponent(testResolvedComponent) 117 118 verify(activityStarter) 119 .postStartActivityDismissingKeyguard( 120 argThat(IntentMatcher(expectedIntent)), 121 eq(0), 122 any() 123 ) 124 } 125 126 @Test testPassNonActivityPendingIntentAndDoNotRequestStartingActivity_doesNotStartActivitynull127 fun testPassNonActivityPendingIntentAndDoNotRequestStartingActivity_doesNotStartActivity() { 128 val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) } 129 130 underTest.handle(null, pendingIntent, false) 131 132 verify(activityStarter, never()) 133 .postStartActivityDismissingKeyguard(any(Intent::class.java), eq(0), any()) 134 } 135 createActivityInfonull136 private fun createActivityInfo( 137 componentName: ComponentName, 138 exported: Boolean = false, 139 ): ActivityInfo { 140 return ActivityInfo().apply { 141 packageName = componentName.packageName 142 name = componentName.className 143 this.exported = exported 144 } 145 } 146 setUpQueryResultnull147 private fun setUpQueryResult(infos: List<ActivityInfo>) { 148 `when`( 149 packageManager.queryIntentActivitiesAsUser( 150 any(Intent::class.java), 151 any(ResolveInfoFlags::class.java), 152 eq(user.identifier) 153 ) 154 ) 155 .thenReturn(infos.map { ResolveInfo().apply { activityInfo = it } }) 156 } 157 158 private class IntentMatcher(intent: Intent) : ArgumentMatcher<Intent> { 159 private val expectedIntent = intent matchesnull160 override fun matches(argument: Intent?): Boolean { 161 return argument?.action.equals(expectedIntent.action) && 162 argument?.`package`.equals(expectedIntent.`package`) && 163 argument?.component?.equals(expectedIntent.component)!! && 164 argument?.categories?.equals(expectedIntent.categories)!! && 165 argument?.flags?.equals(expectedIntent.flags)!! 166 } 167 } 168 169 companion object { 170 private const val ORIGINAL_PACKAGE = "original_pkg" 171 private const val TEST_PACKAGE = "test_pkg" 172 private const val TEST_COMPONENT_CLASS_NAME = "test_component_class_name" 173 private val testResolvedComponent = ComponentName(TEST_PACKAGE, TEST_COMPONENT_CLASS_NAME) 174 private val user = UserHandle.of(0) 175 } 176 } 177