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.intentresolver.util
18 
19 import android.app.PendingIntent
20 import android.content.IIntentReceiver
21 import android.content.IIntentSender
22 import android.content.Intent
23 import android.graphics.Bitmap
24 import android.graphics.drawable.Icon
25 import android.net.Uri
26 import android.os.Binder
27 import android.os.Bundle
28 import android.os.IBinder
29 import android.os.UserHandle
30 import android.service.chooser.ChooserAction
31 import androidx.test.ext.junit.runners.AndroidJUnit4
32 import org.junit.Assert.assertFalse
33 import org.junit.Assert.assertTrue
34 import org.junit.Test
35 import org.junit.runner.RunWith
36 
37 @RunWith(AndroidJUnit4::class)
38 class UriFiltersTest {
39 
40     @Test
uri_ownedByCurrentUser_noUserIdnull41     fun uri_ownedByCurrentUser_noUserId() {
42         val uri = Uri.parse("content://media/images/12345")
43         assertTrue("Uri without userId should always return true", uri.ownedByCurrentUser)
44     }
45 
46     @Test
uri_ownedByCurrentUser_selfUserIdnull47     fun uri_ownedByCurrentUser_selfUserId() {
48         val uri = Uri.parse("content://${UserHandle.myUserId()}@media/images/12345")
49         assertTrue("Uri with own userId should return true", uri.ownedByCurrentUser)
50     }
51 
52     @Test
uri_ownedByCurrentUser_otherUserIdnull53     fun uri_ownedByCurrentUser_otherUserId() {
54         val otherUserId = UserHandle.myUserId() + 10
55         val uri = Uri.parse("content://${otherUserId}@media/images/12345")
56         assertFalse("Uri with other userId should return false", uri.ownedByCurrentUser)
57     }
58 
59     @Test
chooserAction_hasValidIcon_bitmapnull60     fun chooserAction_hasValidIcon_bitmap() =
61         smallBitmap().use {
62             val icon = Icon.createWithBitmap(it)
63             val action = actionWithIcon(icon)
64             assertTrue("No uri, assumed valid", hasValidIcon(action))
65         }
66 
67     @Test
chooserAction_hasValidIcon_urinull68     fun chooserAction_hasValidIcon_uri() {
69         val icon = Icon.createWithContentUri("content://provider/content/12345")
70         assertTrue("No userId in uri, uri is valid", hasValidIcon(actionWithIcon(icon)))
71     }
72     @Test
chooserAction_hasValidIcon_uri_unownednull73     fun chooserAction_hasValidIcon_uri_unowned() {
74         val userId = UserHandle.myUserId() + 10
75         val icon = Icon.createWithContentUri("content://${userId}@provider/content/12345")
76         assertFalse("uri userId references a different user", hasValidIcon(actionWithIcon(icon)))
77     }
78 
smallBitmapnull79     private fun smallBitmap() = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
80 
81     private fun mockAction(): PendingIntent {
82         return PendingIntent(
83             object : IIntentSender {
84                 override fun asBinder(): IBinder = Binder()
85                 override fun send(
86                     code: Int,
87                     intent: Intent?,
88                     resolvedType: String?,
89                     whitelistToken: IBinder?,
90                     finishedReceiver: IIntentReceiver?,
91                     requiredPermission: String?,
92                     options: Bundle?
93                 ) {
94                     /* empty */
95                 }
96             }
97         )
98     }
99 
actionWithIconnull100     private fun actionWithIcon(icon: Icon): ChooserAction {
101         return ChooserAction.Builder(icon, "", mockAction()).build()
102     }
103 
104     /** Unconditionally recycles the [Bitmap] after running the given block */
Bitmapnull105     private fun Bitmap.use(block: (Bitmap) -> Unit) =
106         try {
107             block(this)
108         } finally {
109             recycle()
110         }
111 }
112