1 /*
2  * Copyright (C) 2024 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.communal.smartspace
18 
19 import android.app.PendingIntent
20 import android.content.Intent
21 import android.view.View
22 import android.widget.FrameLayout
23 import android.widget.RemoteViews.RemoteResponse
24 import androidx.core.util.component1
25 import androidx.core.util.component2
26 import androidx.test.ext.junit.runners.AndroidJUnit4
27 import androidx.test.filters.SmallTest
28 import com.android.systemui.SysuiTestCase
29 import com.android.systemui.communal.domain.interactor.communalSceneInteractor
30 import com.android.systemui.communal.widgets.CommunalTransitionAnimatorController
31 import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView
32 import com.android.systemui.coroutines.collectLastValue
33 import com.android.systemui.kosmos.testScope
34 import com.android.systemui.log.logcatLogBuffer
35 import com.android.systemui.plugins.ActivityStarter
36 import com.android.systemui.testKosmos
37 import kotlinx.coroutines.test.runTest
38 import org.junit.Assert.assertFalse
39 import org.junit.Assert.assertTrue
40 import org.junit.Before
41 import org.junit.Test
42 import org.junit.runner.RunWith
43 import org.mockito.kotlin.any
44 import org.mockito.kotlin.eq
45 import org.mockito.kotlin.isNull
46 import org.mockito.kotlin.mock
47 import org.mockito.kotlin.refEq
48 import org.mockito.kotlin.verify
49 
50 @SmallTest
51 @RunWith(AndroidJUnit4::class)
52 class SmartspaceInteractionHandlerTest : SysuiTestCase() {
53     private val activityStarter = mock<ActivityStarter>()
54     private val kosmos = testKosmos()
55 
56     private val testIntent =
57         PendingIntent.getActivity(
58             context,
59             /* requestCode= */ 0,
60             Intent("action"),
61             PendingIntent.FLAG_IMMUTABLE
62         )
63     private val testResponse = RemoteResponse.fromPendingIntent(testIntent)
64 
65     private lateinit var underTest: SmartspaceInteractionHandler
66 
67     @Before
setUpnull68     fun setUp() {
69         with(kosmos) {
70             underTest =
71                 SmartspaceInteractionHandler(
72                     activityStarter = activityStarter,
73                     communalSceneInteractor = communalSceneInteractor,
74                     logBuffer = logcatLogBuffer(),
75                 )
76         }
77     }
78 
79     @Test
launchAnimatorIsUsedForSmartspaceViewnull80     fun launchAnimatorIsUsedForSmartspaceView() {
81         with(kosmos) {
82             testScope.runTest {
83                 val launching by collectLastValue(communalSceneInteractor.isLaunchingWidget)
84                 assertFalse(launching!!)
85 
86                 val parent = FrameLayout(context)
87                 val view = SmartspaceAppWidgetHostView(context)
88                 parent.addView(view)
89                 val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)
90 
91                 underTest.onInteraction(view, testIntent, testResponse)
92 
93                 // Verify that we set the state correctly
94                 assertTrue(launching!!)
95                 // Verify that we pass in a non-null Communal animation controller
96                 verify(activityStarter)
97                     .startPendingIntentWithoutDismissing(
98                         /* intent = */ eq(testIntent),
99                         /* dismissShade = */ eq(false),
100                         /* intentSentUiThreadCallback = */ isNull(),
101                         /* animationController = */ any<CommunalTransitionAnimatorController>(),
102                         /* fillInIntent = */ refEq(fillInIntent),
103                         /* extraOptions = */ refEq(activityOptions.toBundle()),
104                     )
105             }
106         }
107     }
108 
109     @Test
launchAnimatorIsNotUsedForRegularViewnull110     fun launchAnimatorIsNotUsedForRegularView() {
111         val parent = FrameLayout(context)
112         val view = View(context)
113         parent.addView(view)
114         val (fillInIntent, activityOptions) = testResponse.getLaunchOptions(view)
115 
116         underTest.onInteraction(view, testIntent, testResponse)
117 
118         // Verify null is used as the animation controller
119         verify(activityStarter)
120             .startPendingIntentWithoutDismissing(
121                 /* intent = */ eq(testIntent),
122                 /* dismissShade = */ eq(false),
123                 /* intentSentUiThreadCallback = */ isNull(),
124                 /* animationController = */ isNull(),
125                 /* fillInIntent = */ refEq(fillInIntent),
126                 /* extraOptions = */ refEq(activityOptions.toBundle()),
127             )
128     }
129 }
130