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