1 /* 2 * Copyright (C) 2022 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 android.photopicker.cts.util; 18 19 import static android.provider.MediaStore.ACTION_PICK_IMAGES; 20 21 import android.Manifest; 22 import android.app.Instrumentation; 23 import android.content.ComponentName; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.content.pm.ResolveInfo; 27 28 import androidx.annotation.NonNull; 29 import androidx.test.InstrumentationRegistry; 30 31 import java.util.concurrent.TimeUnit; 32 import java.util.concurrent.TimeoutException; 33 import java.util.function.Supplier; 34 35 public class GetContentActivityAliasUtils { 36 37 private static final long POLLING_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5); 38 private static final long POLLING_SLEEP_MILLIS = 100; 39 40 private static ComponentName sComponentName = new ComponentName( 41 getPhotoPickerPackageName(), 42 "com.android.providers.media.photopicker.PhotoPickerGetContentActivity"); 43 enableAndGetOldState()44 public static int enableAndGetOldState() throws Exception { 45 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 46 final PackageManager packageManager = inst.getContext().getPackageManager(); 47 if (isComponentEnabledSetAsExpected(packageManager, 48 PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) { 49 return PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 50 } 51 52 final int currentState = packageManager.getComponentEnabledSetting(sComponentName); 53 54 updateComponentEnabledSetting(packageManager, 55 PackageManager.COMPONENT_ENABLED_STATE_ENABLED); 56 57 return currentState; 58 } 59 restoreState(int oldState)60 public static void restoreState(int oldState) throws Exception { 61 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 62 updateComponentEnabledSetting(inst.getContext().getPackageManager(), oldState); 63 } 64 65 /** 66 * Clears the package data. 67 */ clearPackageData(String packageName)68 public static void clearPackageData(String packageName) throws Exception { 69 InstrumentationRegistry.getInstrumentation().getUiAutomation() 70 .executeShellCommand("pm clear " + packageName); 71 72 // We should ideally be listening to an effective measure to know if package data was 73 // cleared, like listening to a broadcasts or checking a value. But that information is 74 // very package private and not available. 75 Thread.sleep(500); 76 } 77 getDocumentsUiPackageName()78 public static String getDocumentsUiPackageName() { 79 final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); 80 intent.setType("*/*"); 81 return getActivityPackageNameFromIntent(intent); 82 } 83 updateComponentEnabledSetting(PackageManager packageManager, int state)84 private static void updateComponentEnabledSetting(PackageManager packageManager, 85 int state) throws Exception { 86 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 87 inst.getUiAutomation().adoptShellPermissionIdentity( 88 Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); 89 try { 90 packageManager.setComponentEnabledSetting(sComponentName, state, 91 PackageManager.DONT_KILL_APP); 92 } finally { 93 inst.getUiAutomation().dropShellPermissionIdentity(); 94 } 95 waitForComponentToBeInExpectedState(packageManager, state); 96 } 97 waitForComponentToBeInExpectedState(PackageManager packageManager, int state)98 private static void waitForComponentToBeInExpectedState(PackageManager packageManager, 99 int state) throws Exception { 100 pollForCondition(() -> isComponentEnabledSetAsExpected(packageManager, state), 101 "Timed out while waiting for component to be enabled"); 102 } 103 pollForCondition(Supplier<Boolean> condition, String errorMessage)104 private static void pollForCondition(Supplier<Boolean> condition, String errorMessage) 105 throws Exception { 106 for (int i = 0; i < POLLING_TIMEOUT_MILLIS / POLLING_SLEEP_MILLIS; i++) { 107 if (condition.get()) { 108 return; 109 } 110 Thread.sleep(POLLING_SLEEP_MILLIS); 111 } 112 throw new TimeoutException(errorMessage); 113 } 114 isComponentEnabledSetAsExpected(PackageManager packageManager, int state)115 private static boolean isComponentEnabledSetAsExpected(PackageManager packageManager, 116 int state) { 117 return packageManager.getComponentEnabledSetting(sComponentName) == state; 118 } 119 120 @NonNull getPhotoPickerPackageName()121 private static String getPhotoPickerPackageName() { 122 return getActivityPackageNameFromIntent(new Intent(ACTION_PICK_IMAGES)); 123 } 124 125 @NonNull getActivityPackageNameFromIntent(@onNull Intent intent)126 private static String getActivityPackageNameFromIntent(@NonNull Intent intent) { 127 final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); 128 final ResolveInfo ri = inst.getContext().getPackageManager().resolveActivity(intent, 0); 129 return ri.activityInfo.packageName; 130 } 131 } 132