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 package android.bluetooth.test_utils 17 18 import android.app.UiAutomation 19 import android.util.Log 20 import androidx.test.platform.app.InstrumentationRegistry 21 import org.junit.Assert.assertThrows 22 23 private const val TAG: String = "Permissions" 24 25 object Permissions { 26 private val uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation() 27 28 public interface PermissionContext : AutoCloseable { 29 // Override AutoCloseable method to silent the requirement on Exception closenull30 override fun close() 31 } 32 33 /** 34 * Set permissions to be used as long as the resource is open. Restore initial permissions after 35 * closing resource. 36 * 37 * @param newPermissions Permissions to hold when using resource. You need to specify at least 1 38 */ 39 @JvmStatic 40 fun withPermissions(vararg newPermissions: String): PermissionContext { 41 val savedPermissions = replacePermissionsWith(*newPermissions) 42 return object : PermissionContext { 43 override fun close() { 44 restorePermissions(savedPermissions) 45 } 46 } 47 } 48 49 @JvmStatic enforceEachPermissionsnull50 fun enforceEachPermissions(action: () -> Any, newPermissions: List<String>) { 51 if (newPermissions.size < 2) { 52 throw IllegalArgumentException("Not supported for less than 2 permissions") 53 } 54 newPermissions.forEach { 55 val permissionsSet = newPermissions.toMutableSet() 56 permissionsSet.remove(it) 57 58 withPermissions(*arrayOf(*permissionsSet.toTypedArray())).use { 59 assertThrows(SecurityException::class.java, { action() }) 60 } 61 } 62 } 63 restorePermissionsnull64 private fun restorePermissions(permissions: Set<String>) { 65 if (UiAutomation.ALL_PERMISSIONS.equals(permissions)) { 66 uiAutomation.adoptShellPermissionIdentity() 67 } else { 68 uiAutomation.adoptShellPermissionIdentity(*permissions.map { it }.toTypedArray()) 69 } 70 Log.d(TAG, "Restored ${permissions}") 71 } 72 replacePermissionsWithnull73 private fun replacePermissionsWith(vararg newPermissions: String): Set<String> { 74 val currentPermissions = uiAutomation.getAdoptedShellPermissions() 75 if (newPermissions.size == 0) { 76 // Throw even if the code support it as we are not expecting this by design 77 throw IllegalArgumentException("Invalid permissions replacement with no permissions.") 78 } 79 uiAutomation.adoptShellPermissionIdentity(*newPermissions) 80 Log.d(TAG, "Replaced ${currentPermissions} with ${newPermissions.toSet()}") 81 return currentPermissions 82 } 83 } 84