1 package com.android.contacts; 2 3 import static com.android.contacts.util.PermissionsUtil.hasPermission; 4 5 import static org.junit.Assume.assumeTrue; 6 7 import android.Manifest; 8 import android.content.Context; 9 import android.content.Intent; 10 import android.content.pm.PackageManager; 11 12 import androidx.test.InstrumentationRegistry; 13 import androidx.test.filters.MediumTest; 14 import androidx.test.filters.Suppress; 15 import androidx.test.runner.AndroidJUnit4; 16 import androidx.test.uiautomator.By; 17 import androidx.test.uiautomator.UiDevice; 18 import androidx.test.uiautomator.UiObject2; 19 import androidx.test.uiautomator.Until; 20 21 import org.junit.Before; 22 import org.junit.Test; 23 import org.junit.runner.RunWith; 24 25 /** 26 * Make sure the app doesn't crash when it is started without permissions. Note: this won't 27 * run in most environments because permissions will already have been granted. 28 * 29 * To exercise this run: 30 * 31 * $ adb shell pm revoke com.android.contacts android.permission.READ_CONTACTS 32 * $ adb shell pm revoke com.android.contacts android.permission.WRITE_CONTACTS 33 * $ adb shell pm revoke com.android.contacts android.permission.GET_ACCOUNTS 34 * $ adb shell pm revoke com.android.contacts android.permission.READ_PHONE_STATE 35 * $ adb shell pm revoke com.android.contacts android.permission.CALL_PHONE 36 * $ adb shell am instrument -w \ 37 * com.google.android.contacts.tests/androidx.test.runner.AndroidJUnitRunner \ 38 * -e class com.android.contacts.NoPermissionsLaunchSmokeTest 39 */ 40 @MediumTest 41 // suppressed because failed assumptions are reported as test failures by the build server 42 @Suppress 43 @RunWith(AndroidJUnit4.class) 44 public class NoPermissionsLaunchSmokeTest { 45 private static final long TIMEOUT = 5000; 46 47 private Context mTargetContext; 48 49 @Before setUp()50 public void setUp() throws Exception { 51 mTargetContext = InstrumentationRegistry.getTargetContext(); 52 assumeTrue(!hasPermission(mTargetContext, Manifest.permission.READ_CONTACTS)); 53 assumeTrue(!hasPermission(mTargetContext, Manifest.permission.WRITE_CONTACTS)); 54 assumeTrue(!hasPermission(mTargetContext, Manifest.permission.GET_ACCOUNTS)); 55 assumeTrue(!hasPermission(mTargetContext, Manifest.permission.READ_PHONE_STATE)); 56 assumeTrue(!hasPermission(mTargetContext, Manifest.permission.CALL_PHONE)); 57 assumeTrue(!hasPermission(mTargetContext, Manifest.permission.READ_CALL_LOG)); 58 59 // remove state that might exist outside of the app 60 // (e.g. launcher shortcuts and scheduled jobs) 61 DynamicShortcuts.reset(mTargetContext); 62 } 63 64 @Test launchingMainActivityDoesntCrash()65 public void launchingMainActivityDoesntCrash() throws Exception { 66 final UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 67 68 // Launch the main activity 69 InstrumentationRegistry.getContext().startActivity( 70 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_DEFAULT) 71 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) 72 .setPackage(InstrumentationRegistry.getTargetContext().getPackageName())); 73 74 device.waitForIdle(); 75 76 final PackageManager packageManager = mTargetContext.getPackageManager(); 77 if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 78 device.wait(Until.hasObject(By.textEndsWith("your phone call logs?")), TIMEOUT); 79 final UiObject2 grantCallLogPermissionButton = device.findObject(By.text("ALLOW")); 80 grantCallLogPermissionButton.click(); 81 } 82 83 device.wait(Until.hasObject(By.textEndsWith("access your contacts?")), TIMEOUT); 84 final UiObject2 grantContactsPermissionButton = device.findObject(By.text("ALLOW")); 85 86 grantContactsPermissionButton.click(); 87 88 device.wait(Until.hasObject(By.textEndsWith("make and manage phone calls?")), TIMEOUT); 89 90 if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 91 device.waitForIdle(); 92 return; 93 } 94 95 final UiObject2 grantPhonePermissionButton = device.findObject(By.text("ALLOW")); 96 97 grantPhonePermissionButton.clickAndWait(Until.newWindow(), TIMEOUT); 98 99 // Not sure if this actually waits for the load to complete or not. 100 device.waitForIdle(); 101 } 102 103 // TODO: it would be good to have similar tests for other entry points that might be reached 104 // without required permissions. 105 } 106