1 /* 2 * Copyright (C) 2016 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.cts.content; 18 19 import android.accounts.Account; 20 import android.accounts.AccountManager; 21 import android.app.Activity; 22 import android.content.ContentProviderClient; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.SyncRequest; 27 import android.content.SyncResult; 28 import android.content.cts.FlakyTestRule; 29 import android.content.pm.PackageManager; 30 import android.net.ConnectivityManager; 31 import android.net.NetworkInfo; 32 import android.os.Bundle; 33 import android.os.Process; 34 import android.os.SystemClock; 35 import android.support.test.InstrumentationRegistry; 36 import android.support.test.runner.AndroidJUnit4; 37 import android.support.test.uiautomator.By; 38 import android.support.test.uiautomator.UiDevice; 39 import android.support.test.uiautomator.Until; 40 import org.junit.After; 41 import org.junit.Before; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.rules.TestRule; 45 import org.junit.runner.RunWith; 46 47 import java.io.IOException; 48 import java.util.concurrent.CountDownLatch; 49 import java.util.concurrent.TimeUnit; 50 51 import static junit.framework.Assert.assertFalse; 52 import static junit.framework.Assert.assertTrue; 53 54 import com.android.compatibility.common.util.SystemUtil; 55 56 /** 57 * Tests whether a sync adapter can access accounts. 58 */ 59 @RunWith(AndroidJUnit4.class) 60 public class CtsSyncAccountAccessOtherCertTestCases { 61 private static final long SYNC_TIMEOUT_MILLIS = 20000; // 20 sec 62 private static final long UI_TIMEOUT_MILLIS = 5000; // 5 sec 63 64 public static final String TOKEN_TYPE_REMOVE_ACCOUNTS = "TOKEN_TYPE_REMOVE_ACCOUNTS"; 65 66 @Rule 67 public final TestRule mFlakyTestRule = new FlakyTestRule(3); 68 69 @Before setUp()70 public void setUp() throws Exception { 71 allowSyncAdapterRunInBackgroundAndDataInBackground(); 72 } 73 74 @After tearDown()75 public void tearDown() throws Exception { 76 disallowSyncAdapterRunInBackgroundAndDataInBackground(); 77 } 78 79 @Test testAccountAccess_otherCertAsAuthenticatorCanNotSeeAccount()80 public void testAccountAccess_otherCertAsAuthenticatorCanNotSeeAccount() throws Exception { 81 if (!hasDataConnection() || !hasNotificationSupport()) { 82 return; 83 } 84 85 Intent intent = new Intent(getContext(), StubActivity.class); 86 Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent); 87 88 AccountManager accountManager = getContext().getSystemService(AccountManager.class); 89 Bundle result = accountManager.addAccount("com.stub", null, null, null, activity, 90 null, null).getResult(); 91 92 Account addedAccount = new Account( 93 result.getString(AccountManager.KEY_ACCOUNT_NAME), 94 result.getString(AccountManager.KEY_ACCOUNT_TYPE)); 95 96 waitForSyncManagerAccountChangeUpdate(); 97 98 try { 99 CountDownLatch latch = new CountDownLatch(1); 100 101 SyncAdapter.setOnPerformSyncDelegate((Account account, Bundle extras, 102 String authority, ContentProviderClient provider, SyncResult syncResult) 103 -> latch.countDown()); 104 105 Bundle extras = new Bundle(); 106 extras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); 107 extras.putBoolean(ContentResolver.SYNC_EXTRAS_PRIORITY, true); 108 extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true); 109 SyncRequest request = new SyncRequest.Builder() 110 .setSyncAdapter(null, "com.android.cts.stub.provider") 111 .syncOnce() 112 .setExtras(extras) 113 .setExpedited(true) 114 .setManual(true) 115 .build(); 116 ContentResolver.requestSync(request); 117 118 assertFalse(latch.await(SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); 119 120 UiDevice uiDevice = getUiDevice(); 121 122 uiDevice.openNotification(); 123 uiDevice.wait(Until.hasObject(By.text("Permission requested")), 124 UI_TIMEOUT_MILLIS); 125 126 uiDevice.findObject(By.text("Permission requested")).click(); 127 uiDevice.wait(Until.hasObject(By.text("ALLOW")), 128 UI_TIMEOUT_MILLIS); 129 130 uiDevice.findObject(By.text("ALLOW")).click(); 131 132 ContentResolver.requestSync(request); 133 134 assertTrue(latch.await(SYNC_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); 135 } finally { 136 // Ask the differently signed authenticator to drop all accounts 137 accountManager.getAuthToken(addedAccount, TOKEN_TYPE_REMOVE_ACCOUNTS, 138 null, false, null, null); 139 } 140 } 141 getContext()142 private Context getContext() { 143 return InstrumentationRegistry.getInstrumentation().getContext(); 144 } 145 getUiDevice()146 private UiDevice getUiDevice() { 147 return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 148 } 149 waitForSyncManagerAccountChangeUpdate()150 private void waitForSyncManagerAccountChangeUpdate() { 151 // Wait for the sync manager to be notified for the new account. 152 // Unfortunately, there is no way to detect this event, sigh... 153 SystemClock.sleep(SYNC_TIMEOUT_MILLIS); 154 } 155 hasDataConnection()156 private boolean hasDataConnection() { 157 ConnectivityManager connectivityManager = getContext().getSystemService( 158 ConnectivityManager.class); 159 NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo(); 160 return activeNetwork != null && activeNetwork.isConnectedOrConnecting(); 161 } 162 hasNotificationSupport()163 private boolean hasNotificationSupport() { 164 return !getContext().getPackageManager() 165 .hasSystemFeature(PackageManager.FEATURE_LEANBACK); 166 } 167 allowSyncAdapterRunInBackgroundAndDataInBackground()168 private void allowSyncAdapterRunInBackgroundAndDataInBackground() throws IOException { 169 // Allow us to run in the background 170 SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), 171 "cmd deviceidle whitelist +" + getContext().getPackageName()); 172 // Allow us to use data in the background 173 SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), 174 "cmd netpolicy add restrict-background-whitelist " + Process.myUid()); 175 } 176 disallowSyncAdapterRunInBackgroundAndDataInBackground()177 private void disallowSyncAdapterRunInBackgroundAndDataInBackground() throws IOException { 178 // Allow us to run in the background 179 SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), 180 "cmd deviceidle whitelist -" + getContext().getPackageName()); 181 // Allow us to use data in the background 182 SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), 183 "cmd netpolicy remove restrict-background-whitelist " + Process.myUid()); 184 } 185 } 186