• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.intentresolver
18 
19 import android.app.Activity
20 import android.app.PendingIntent
21 import android.content.BroadcastReceiver
22 import android.content.Context
23 import android.content.Context.RECEIVER_EXPORTED
24 import android.content.Intent
25 import android.content.IntentFilter
26 import android.content.res.Resources
27 import android.graphics.drawable.Icon
28 import android.service.chooser.ChooserAction
29 import androidx.test.ext.junit.runners.AndroidJUnit4
30 import androidx.test.platform.app.InstrumentationRegistry
31 import com.android.intentresolver.logging.EventLog
32 import com.android.intentresolver.ui.ShareResultSender
33 import com.android.intentresolver.ui.model.ShareAction
34 import com.google.common.truth.Truth.assertThat
35 import java.util.Optional
36 import java.util.concurrent.CountDownLatch
37 import java.util.concurrent.TimeUnit
38 import java.util.function.Consumer
39 import org.junit.After
40 import org.junit.Assert.assertEquals
41 import org.junit.Assert.assertTrue
42 import org.junit.Before
43 import org.junit.Test
44 import org.junit.runner.RunWith
45 import org.mockito.kotlin.eq
46 import org.mockito.kotlin.mock
47 import org.mockito.kotlin.verify
48 
49 @RunWith(AndroidJUnit4::class)
50 class ChooserActionFactoryTest {
51     private val context = InstrumentationRegistry.getInstrumentation().context
52 
53     private val logger = mock<EventLog>()
54     private val actionLabel = "Action label"
55     private val testAction = "com.android.intentresolver.testaction"
56     private val countdown = CountDownLatch(1)
57     private val testReceiver: BroadcastReceiver =
58         object : BroadcastReceiver() {
onReceivenull59             override fun onReceive(context: Context, intent: Intent) {
60                 // Just doing at most a single countdown per test.
61                 countdown.countDown()
62             }
63         }
64     private val resultConsumer =
65         object : Consumer<Int> {
66             var latestReturn = Integer.MIN_VALUE
67 
acceptnull68             override fun accept(resultCode: Int) {
69                 latestReturn = resultCode
70             }
71         }
72 
73     @Before
setupnull74     fun setup() {
75         context.registerReceiver(testReceiver, IntentFilter(testAction), RECEIVER_EXPORTED)
76     }
77 
78     @After
teardownnull79     fun teardown() {
80         context.unregisterReceiver(testReceiver)
81     }
82 
83     @Test
testCreateCustomActionsnull84     fun testCreateCustomActions() {
85         val factory = createFactory()
86 
87         val customActions = factory.createCustomActions()
88 
89         assertThat(customActions.size).isEqualTo(1)
90         assertThat(customActions[0].label).isEqualTo(actionLabel)
91 
92         // click it
93         customActions[0].onClicked.run()
94 
95         verify(logger).logCustomActionSelected(eq(0))
96         assertEquals(Activity.RESULT_OK, resultConsumer.latestReturn)
97         // Verify the pending intent has been called
98         assertTrue("Timed out waiting for broadcast", countdown.await(2500, TimeUnit.MILLISECONDS))
99     }
100 
101     @Test
nonSendAction_noCopyRunnablenull102     fun nonSendAction_noCopyRunnable() {
103         val targetIntent =
104             Intent(Intent.ACTION_SEND_MULTIPLE).apply {
105                 putExtra(Intent.EXTRA_TEXT, "Text to show")
106             }
107 
108         val testSubject =
109             ChooserActionFactory(
110                 /* context = */ context,
111                 /* targetIntent = */ targetIntent,
112                 /* referrerPackageName = */ null,
113                 /* chooserActions = */ emptyList(),
114                 /* imageEditor = */ Optional.empty(),
115                 /* log = */ logger,
116                 /* onUpdateSharedTextIsExcluded = */ {},
117                 /* firstVisibleImageQuery = */ { null },
118                 /* activityStarter = */ mock(),
119                 /* shareResultSender = */ null,
120                 /* finishCallback = */ {},
121                 /* clipboardManager = */ mock(),
122             )
123         assertThat(testSubject.copyButtonRunnable).isNull()
124     }
125 
126     @Test
sendActionNoText_noCopyRunnablenull127     fun sendActionNoText_noCopyRunnable() {
128         val targetIntent = Intent(Intent.ACTION_SEND)
129         val testSubject =
130             ChooserActionFactory(
131                 /* context = */ context,
132                 /* targetIntent = */ targetIntent,
133                 /* referrerPackageName = */ "com.example",
134                 /* chooserActions = */ emptyList(),
135                 /* imageEditor = */ Optional.empty(),
136                 /* log = */ logger,
137                 /* onUpdateSharedTextIsExcluded = */ {},
138                 /* firstVisibleImageQuery = */ { null },
139                 /* activityStarter = */ mock(),
140                 /* shareResultSender = */ null,
141                 /* finishCallback = */ {},
142                 /* clipboardManager = */ mock(),
143             )
144         assertThat(testSubject.copyButtonRunnable).isNull()
145     }
146 
147     @Test
sendActionWithTextCopyRunnablenull148     fun sendActionWithTextCopyRunnable() {
149         val targetIntent = Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_TEXT, "Text") }
150         val resultSender = mock<ShareResultSender>()
151         val testSubject =
152             ChooserActionFactory(
153                 /* context = */ context,
154                 /* targetIntent = */ targetIntent,
155                 /* referrerPackageName = */ "com.example",
156                 /* chooserActions = */ emptyList(),
157                 /* imageEditor = */ Optional.empty(),
158                 /* log = */ logger,
159                 /* onUpdateSharedTextIsExcluded = */ {},
160                 /* firstVisibleImageQuery = */ { null },
161                 /* activityStarter = */ mock(),
162                 /* shareResultSender = */ resultSender,
163                 /* finishCallback = */ {},
164                 /* clipboardManager = */ mock(),
165             )
166         assertThat(testSubject.copyButtonRunnable).isNotNull()
167 
168         testSubject.copyButtonRunnable?.run()
169 
170         verify(resultSender) { 1 * { onActionSelected(ShareAction.SYSTEM_COPY) } }
171     }
172 
createFactorynull173     private fun createFactory(): ChooserActionFactory {
174         val testPendingIntent =
175             PendingIntent.getBroadcast(context, 0, Intent(testAction), PendingIntent.FLAG_IMMUTABLE)
176         val targetIntent = Intent()
177         val action =
178             ChooserAction.Builder(
179                     Icon.createWithResource("", Resources.ID_NULL),
180                     actionLabel,
181                     testPendingIntent
182                 )
183                 .build()
184         return ChooserActionFactory(
185             /* context = */ context,
186             /* targetIntent = */ targetIntent,
187             /* referrerPackageName = */ "com.example",
188             /* chooserActions = */ listOf(action),
189             /* imageEditor = */ Optional.empty(),
190             /* log = */ logger,
191             /* onUpdateSharedTextIsExcluded = */ {},
192             /* firstVisibleImageQuery = */ { null },
193             /* activityStarter = */ mock(),
194             /* shareResultSender = */ null,
195             /* finishCallback = */ resultConsumer,
196             /* clipboardManager = */ mock(),
197         )
198     }
199 }
200