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.screenshot
18 
19 import android.content.Intent
20 import android.net.Uri
21 import android.os.Process
22 import android.os.UserHandle
23 import android.testing.AndroidTestingRunner
24 import androidx.test.filters.SmallTest
25 import com.android.internal.logging.UiEventLogger
26 import com.android.systemui.SysuiTestCase
27 import com.android.systemui.screenshot.ui.viewmodel.PreviewAction
28 import com.google.common.truth.Truth.assertThat
29 import java.util.UUID
30 import kotlin.test.Test
31 import kotlinx.coroutines.test.runTest
32 import org.junit.Before
33 import org.junit.runner.RunWith
34 import org.mockito.Mockito.verifyNoMoreInteractions
35 import org.mockito.kotlin.any
36 import org.mockito.kotlin.argumentCaptor
37 import org.mockito.kotlin.eq
38 import org.mockito.kotlin.mock
39 import org.mockito.kotlin.never
40 import org.mockito.kotlin.times
41 import org.mockito.kotlin.verify
42 
43 @RunWith(AndroidTestingRunner::class)
44 @SmallTest
45 class DefaultScreenshotActionsProviderTest : SysuiTestCase() {
46     private val actionExecutor = mock<ActionExecutor>()
47     private val uiEventLogger = mock<UiEventLogger>()
48     private val actionsCallback = mock<ScreenshotActionsController.ActionsCallback>()
49 
50     private val request = ScreenshotData.forTesting()
51     private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0)
52 
53     private lateinit var actionsProvider: ScreenshotActionsProvider
54 
55     @Before
setUpnull56     fun setUp() {
57         request.userHandle = UserHandle.OWNER
58     }
59 
60     @Test
previewActionAccessed_beforeScreenshotCompleted_doesNothingnull61     fun previewActionAccessed_beforeScreenshotCompleted_doesNothing() {
62         actionsProvider = createActionsProvider()
63 
64         val previewActionCaptor = argumentCaptor<PreviewAction>()
65         verify(actionsCallback).providePreviewAction(previewActionCaptor.capture())
66         previewActionCaptor.firstValue.onClick.invoke()
67         verifyNoMoreInteractions(actionExecutor)
68     }
69 
70     @Test
actionButtonsAccessed_beforeScreenshotCompleted_doesNothingnull71     fun actionButtonsAccessed_beforeScreenshotCompleted_doesNothing() {
72         actionsProvider = createActionsProvider()
73 
74         val actionButtonCaptor = argumentCaptor<() -> Unit>()
75         verify(actionsCallback, times(2))
76             .provideActionButton(any(), any(), actionButtonCaptor.capture())
77         val firstAction = actionButtonCaptor.firstValue
78         val secondAction = actionButtonCaptor.secondValue
79         firstAction.invoke()
80         secondAction.invoke()
81         verifyNoMoreInteractions(actionExecutor)
82     }
83 
84     @Test
<lambda>null85     fun actionAccessed_withResult_launchesIntent() = runTest {
86         actionsProvider = createActionsProvider()
87 
88         actionsProvider.setCompletedScreenshot(validResult)
89 
90         val actionButtonCaptor = argumentCaptor<() -> Unit>()
91         verify(actionsCallback, times(2))
92             .provideActionButton(any(), any(), actionButtonCaptor.capture())
93         actionButtonCaptor.firstValue.invoke()
94 
95         verify(uiEventLogger).log(eq(ScreenshotEvent.SCREENSHOT_SHARE_TAPPED), eq(0), eq(""))
96         val intentCaptor = argumentCaptor<Intent>()
97         verify(actionExecutor)
98             .startSharedTransition(intentCaptor.capture(), eq(Process.myUserHandle()), eq(false))
99         assertThat(intentCaptor.firstValue.action).isEqualTo(Intent.ACTION_CHOOSER)
100     }
101 
102     @Test
<lambda>null103     fun actionAccessed_whilePending_launchesMostRecentAction() = runTest {
104         actionsProvider = createActionsProvider()
105 
106         val previewActionCaptor = argumentCaptor<PreviewAction>()
107         verify(actionsCallback).providePreviewAction(previewActionCaptor.capture())
108         val actionButtonCaptor = argumentCaptor<() -> Unit>()
109         verify(actionsCallback, times(2))
110             .provideActionButton(any(), any(), actionButtonCaptor.capture())
111 
112         actionButtonCaptor.firstValue.invoke()
113         previewActionCaptor.firstValue.onClick.invoke()
114         actionButtonCaptor.secondValue.invoke()
115         actionsProvider.setCompletedScreenshot(validResult)
116 
117         verify(uiEventLogger).log(eq(ScreenshotEvent.SCREENSHOT_EDIT_TAPPED), eq(0), eq(""))
118         val intentCaptor = argumentCaptor<Intent>()
119         verify(actionExecutor)
120             .startSharedTransition(intentCaptor.capture(), eq(Process.myUserHandle()), eq(true))
121         assertThat(intentCaptor.firstValue.action).isEqualTo(Intent.ACTION_EDIT)
122     }
123 
124     @Test
<lambda>null125     fun scrollChipClicked_callsOnClick() = runTest {
126         actionsProvider = createActionsProvider()
127 
128         val onScrollClick = mock<Runnable>()
129         actionsProvider.onScrollChipReady(onScrollClick)
130         val actionButtonCaptor = argumentCaptor<() -> Unit>()
131         // share, edit, scroll
132         verify(actionsCallback, times(3))
133             .provideActionButton(any(), any(), actionButtonCaptor.capture())
134         actionButtonCaptor.thirdValue.invoke()
135 
136         verify(onScrollClick).run()
137     }
138 
139     @Test
<lambda>null140     fun scrollChipClicked_afterInvalidate_doesNothing() = runTest {
141         actionsProvider = createActionsProvider()
142 
143         val onScrollClick = mock<Runnable>()
144         actionsProvider.onScrollChipReady(onScrollClick)
145         val actionButtonCaptor = argumentCaptor<() -> Unit>()
146         actionsProvider.onScrollChipInvalidated()
147         // share, edit, scroll
148         verify(actionsCallback, times(3))
149             .provideActionButton(any(), any(), actionButtonCaptor.capture())
150         actionButtonCaptor.thirdValue.invoke()
151 
152         verify(onScrollClick, never()).run()
153     }
154 
155     @Test
scrollChipClicked_afterUpdate_runsNewActionnull156     fun scrollChipClicked_afterUpdate_runsNewAction() = runTest {
157         actionsProvider = createActionsProvider()
158 
159         val onScrollClick = mock<Runnable>()
160         val onScrollClick2 = mock<Runnable>()
161 
162         actionsProvider.onScrollChipReady(onScrollClick)
163         actionsProvider.onScrollChipInvalidated()
164         actionsProvider.onScrollChipReady(onScrollClick2)
165         val actionButtonCaptor = argumentCaptor<() -> Unit>()
166         // share, edit, scroll
167         verify(actionsCallback, times(3))
168             .provideActionButton(any(), any(), actionButtonCaptor.capture())
169         actionButtonCaptor.thirdValue.invoke()
170 
171         verify(onScrollClick2).run()
172         verify(onScrollClick, never()).run()
173     }
174 
createActionsProvidernull175     private fun createActionsProvider(): ScreenshotActionsProvider {
176         return DefaultScreenshotActionsProvider(
177             context,
178             uiEventLogger,
179             UUID.randomUUID(),
180             request,
181             actionExecutor,
182             actionsCallback,
183         )
184     }
185 }
186