• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.appenumeration.cts;
18 
19 import static android.appenumeration.cts.Constants.ACCOUNT_NAME;
20 import static android.appenumeration.cts.Constants.ACCOUNT_TYPE;
21 import static android.appenumeration.cts.Constants.ACCOUNT_TYPE_SHARED_USER;
22 import static android.appenumeration.cts.Constants.ACTION_GET_IS_SYNCABLE;
23 import static android.appenumeration.cts.Constants.ACTION_GET_PERIODIC_SYNCS;
24 import static android.appenumeration.cts.Constants.ACTION_GET_SYNCADAPTER_CONTROL_PANEL;
25 import static android.appenumeration.cts.Constants.ACTION_GET_SYNCADAPTER_PACKAGES_FOR_AUTHORITY;
26 import static android.appenumeration.cts.Constants.ACTION_GET_SYNCADAPTER_TYPES;
27 import static android.appenumeration.cts.Constants.ACTION_GET_SYNC_AUTOMATICALLY;
28 import static android.appenumeration.cts.Constants.ACTION_REQUEST_PERIODIC_SYNC;
29 import static android.appenumeration.cts.Constants.ACTION_REQUEST_SYNC_AND_AWAIT_STATUS;
30 import static android.appenumeration.cts.Constants.ACTION_SET_SYNC_AUTOMATICALLY;
31 import static android.appenumeration.cts.Constants.AUTHORITY_SUFFIX;
32 import static android.appenumeration.cts.Constants.EXTRA_ACCOUNT;
33 import static android.appenumeration.cts.Constants.EXTRA_AUTHORITY;
34 import static android.appenumeration.cts.Constants.QUERIES_NOTHING;
35 import static android.appenumeration.cts.Constants.QUERIES_NOTHING_SHARED_USER;
36 import static android.appenumeration.cts.Constants.QUERIES_PACKAGE;
37 import static android.appenumeration.cts.Constants.SERVICE_CLASS_SYNC_ADAPTER;
38 import static android.appenumeration.cts.Constants.TARGET_SYNCADAPTER;
39 import static android.appenumeration.cts.Constants.TARGET_SYNCADAPTER_AUTHORITY;
40 import static android.appenumeration.cts.Constants.TARGET_SYNCADAPTER_SHARED_USER;
41 import static android.appenumeration.cts.Utils.allowTestApiAccess;
42 import static android.appenumeration.cts.Utils.resetTestApiAccess;
43 import static android.content.Intent.EXTRA_COMPONENT_NAME;
44 
45 import static org.hamcrest.MatcherAssert.assertThat;
46 import static org.hamcrest.Matchers.hasItemInArray;
47 import static org.hamcrest.Matchers.not;
48 import static org.hamcrest.Matchers.notNullValue;
49 import static org.hamcrest.Matchers.nullValue;
50 import static org.hamcrest.core.Is.is;
51 import static org.junit.Assert.assertThrows;
52 
53 import android.accounts.Account;
54 import android.accounts.AccountManager;
55 import android.app.PendingIntent;
56 import android.content.ComponentName;
57 import android.content.Intent;
58 import android.content.PeriodicSync;
59 import android.content.SyncAdapterType;
60 import android.os.Bundle;
61 import android.os.Process;
62 
63 import androidx.test.ext.junit.runners.AndroidJUnit4;
64 
65 import org.junit.AfterClass;
66 import org.junit.BeforeClass;
67 import org.junit.Test;
68 import org.junit.runner.RunWith;
69 
70 import java.util.List;
71 
72 @RunWith(AndroidJUnit4.class)
73 public class SyncAdapterEnumerationTests extends AppEnumerationTestsBase {
74 
75     private static AccountManager sAccountManager;
76 
77     private static final Account ACCOUNT_SYNCADAPTER = new Account(ACCOUNT_NAME, ACCOUNT_TYPE);
78     private static final Account ACCOUNT_SYNCADAPTER_SHARED_USER = new Account(ACCOUNT_NAME,
79             ACCOUNT_TYPE_SHARED_USER);
80 
81     @BeforeClass
setUpAccounts()82     public static void setUpAccounts() {
83         sAccountManager = AccountManager.get(sContext);
84         assertThat(sAccountManager.addAccountExplicitly(ACCOUNT_SYNCADAPTER,
85                 null /* password */, null /* userdata */), is(true));
86         assertThat(sAccountManager.addAccountExplicitly(ACCOUNT_SYNCADAPTER_SHARED_USER,
87                 null /* password */, null /* userdata */), is(true));
88     }
89 
90     @AfterClass
tearDownAccounts()91     public static void tearDownAccounts() {
92         assertThat(sAccountManager.removeAccountExplicitly(ACCOUNT_SYNCADAPTER),
93                 is(true));
94         assertThat(sAccountManager.removeAccountExplicitly(ACCOUNT_SYNCADAPTER_SHARED_USER),
95                 is(true));
96     }
97 
98     @Test
queriesPackage_getSyncAdapterTypes_canSeeSyncAdapterTarget()99     public void queriesPackage_getSyncAdapterTypes_canSeeSyncAdapterTarget() throws Exception {
100         assertVisible(QUERIES_PACKAGE, TARGET_SYNCADAPTER, this::getSyncAdapterTypes);
101     }
102 
103     @Test
queriesNothing_getSyncAdapterTypes_cannotSeeSyncAdapterTarget()104     public void queriesNothing_getSyncAdapterTypes_cannotSeeSyncAdapterTarget() throws Exception {
105         assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER, this::getSyncAdapterTypes);
106         assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER_SHARED_USER,
107                 this::getSyncAdapterTypes);
108     }
109 
110     @Test
queriesNothingSharedUser_getSyncAdapterTypes_canSeeSyncAdapterSharedUserTarget()111     public void queriesNothingSharedUser_getSyncAdapterTypes_canSeeSyncAdapterSharedUserTarget()
112             throws Exception {
113         assertVisible(QUERIES_NOTHING_SHARED_USER, TARGET_SYNCADAPTER_SHARED_USER,
114                 this::getSyncAdapterTypes);
115     }
116 
117     @Test
queriesPackage_getSyncAdapterPackages_canSeeSyncAdapterTarget()118     public void queriesPackage_getSyncAdapterPackages_canSeeSyncAdapterTarget() throws Exception {
119         try {
120             allowTestApiAccess(QUERIES_PACKAGE);
121 
122             assertVisible(QUERIES_PACKAGE, TARGET_SYNCADAPTER,
123                     this::getSyncAdapterPackagesForAuthorityAsUser);
124         } finally {
125             resetTestApiAccess(QUERIES_PACKAGE);
126         }
127     }
128 
129     @Test
queriesNothing_getSyncAdapterPackages_cannotSeeSyncAdapterTarget()130     public void queriesNothing_getSyncAdapterPackages_cannotSeeSyncAdapterTarget()
131             throws Exception {
132         try {
133             allowTestApiAccess(QUERIES_NOTHING);
134 
135             assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER,
136                     this::getSyncAdapterPackagesForAuthorityAsUser);
137             assertNotVisible(QUERIES_NOTHING, TARGET_SYNCADAPTER_SHARED_USER,
138                     this::getSyncAdapterPackagesForAuthorityAsUser);
139         } finally {
140             resetTestApiAccess(QUERIES_NOTHING);
141         }
142     }
143 
144     @Test
queriesNothingSharedUser_getSyncAdapterPackages_canSeeSyncAdapterSharedUserTarget()145     public void queriesNothingSharedUser_getSyncAdapterPackages_canSeeSyncAdapterSharedUserTarget()
146             throws Exception {
147         try {
148             allowTestApiAccess(QUERIES_NOTHING_SHARED_USER);
149 
150             assertVisible(QUERIES_NOTHING_SHARED_USER, TARGET_SYNCADAPTER_SHARED_USER,
151                     this::getSyncAdapterPackagesForAuthorityAsUser);
152         } finally {
153             resetTestApiAccess(QUERIES_NOTHING_SHARED_USER);
154         }
155     }
156 
157     @Test
queriesPackage_requestSync_canSeeSyncAdapterTarget()158     public void queriesPackage_requestSync_canSeeSyncAdapterTarget() throws Exception {
159         assertThat(
160                 requestSyncAndAwaitStatus(QUERIES_PACKAGE, ACCOUNT_SYNCADAPTER, TARGET_SYNCADAPTER),
161                 is(true));
162     }
163 
164     @Test
queriesNothingSharedUser_requestSync_canSeeSyncAdapterSharedUserTarget()165     public void queriesNothingSharedUser_requestSync_canSeeSyncAdapterSharedUserTarget()
166             throws Exception {
167         assertThat(requestSyncAndAwaitStatus(QUERIES_NOTHING_SHARED_USER,
168                 ACCOUNT_SYNCADAPTER_SHARED_USER, TARGET_SYNCADAPTER_SHARED_USER), is(true));
169     }
170 
171     @Test
queriesNothing_requestSync_cannotSeeSyncAdapterTarget()172     public void queriesNothing_requestSync_cannotSeeSyncAdapterTarget() {
173         assertThrows(MissingCallbackException.class,
174                 () -> requestSyncAndAwaitStatus(QUERIES_NOTHING, ACCOUNT_SYNCADAPTER,
175                         TARGET_SYNCADAPTER));
176         assertThrows(MissingCallbackException.class,
177                 () -> requestSyncAndAwaitStatus(QUERIES_NOTHING, ACCOUNT_SYNCADAPTER_SHARED_USER,
178                         TARGET_SYNCADAPTER_SHARED_USER));
179     }
180 
181     @Test
queriesPackage_getRunningServiceControlPanel_canSeeSyncAdapterTarget()182     public void queriesPackage_getRunningServiceControlPanel_canSeeSyncAdapterTarget()
183             throws Exception {
184         assertThat(getSyncAdapterControlPanel(QUERIES_PACKAGE, ACCOUNT_SYNCADAPTER,
185                 TARGET_SYNCADAPTER), notNullValue());
186     }
187 
188     @Test
queriesNothing_getRunningServiceControlPanel_cannotSeeSyncAdapterTarget()189     public void queriesNothing_getRunningServiceControlPanel_cannotSeeSyncAdapterTarget()
190             throws Exception {
191         assertThat(getSyncAdapterControlPanel(QUERIES_NOTHING, ACCOUNT_SYNCADAPTER,
192                 TARGET_SYNCADAPTER), nullValue());
193     }
194 
195     @Test
queriesNothing_getIsSyncable_cannotSeeSyncAdapterTarget()196     public void queriesNothing_getIsSyncable_cannotSeeSyncAdapterTarget() throws Exception {
197         assertThat(getIsSyncable(QUERIES_NOTHING, ACCOUNT_SYNCADAPTER, TARGET_SYNCADAPTER),
198                 is(0));
199     }
200 
201     @Test
queriesPackage_getIsSyncable_canSeeSyncAdapterTarget()202     public void queriesPackage_getIsSyncable_canSeeSyncAdapterTarget() throws Exception {
203         assertThat(getIsSyncable(QUERIES_PACKAGE, ACCOUNT_SYNCADAPTER, TARGET_SYNCADAPTER),
204                 not(is(0)));
205     }
206 
207     @Test
queriesNothing_getSyncAutomatically_cannotSeeSyncAdapterTarget()208     public void queriesNothing_getSyncAutomatically_cannotSeeSyncAdapterTarget() throws Exception {
209         setSyncAutomatically(TARGET_SYNCADAPTER, ACCOUNT_SYNCADAPTER);
210         assertThat(getSyncAutomatically(QUERIES_NOTHING, TARGET_SYNCADAPTER), is(false));
211     }
212 
213     @Test
queriesPackage_getSyncAutomatically_canSeeSyncAdapterTarget()214     public void queriesPackage_getSyncAutomatically_canSeeSyncAdapterTarget() throws Exception {
215         setSyncAutomatically(TARGET_SYNCADAPTER, ACCOUNT_SYNCADAPTER);
216         assertThat(getSyncAutomatically(QUERIES_PACKAGE, TARGET_SYNCADAPTER), is(true));
217     }
218 
219     @Test
queriesNothing_getPeriodicSyncs_cannotSeeSyncAdapterTarget()220     public void queriesNothing_getPeriodicSyncs_cannotSeeSyncAdapterTarget() throws Exception {
221         assertThat(requestPeriodicSync(TARGET_SYNCADAPTER, ACCOUNT_SYNCADAPTER), is(true));
222         assertThat(getPeriodicSyncs(QUERIES_NOTHING, ACCOUNT_SYNCADAPTER, TARGET_SYNCADAPTER),
223                 not(hasItemInArray(TARGET_SYNCADAPTER_AUTHORITY)));
224     }
225 
226     @Test
queriesPackage_getPeriodicSyncs_canSeeSyncAdapterTarget()227     public void queriesPackage_getPeriodicSyncs_canSeeSyncAdapterTarget() throws Exception {
228         assertThat(requestPeriodicSync(TARGET_SYNCADAPTER, ACCOUNT_SYNCADAPTER), is(true));
229         assertThat(getPeriodicSyncs(QUERIES_PACKAGE, ACCOUNT_SYNCADAPTER, TARGET_SYNCADAPTER),
230                 hasItemInArray(TARGET_SYNCADAPTER_AUTHORITY));
231     }
232 
233 
getSyncAdapterTypes(String sourcePackageName)234     private String[] getSyncAdapterTypes(String sourcePackageName) throws Exception {
235         final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
236                 /* intentExtra */ null, ACTION_GET_SYNCADAPTER_TYPES);
237         final List<SyncAdapterType> types = response.getParcelableArrayList(
238                 Intent.EXTRA_RETURN_RESULT, SyncAdapterType.class);
239         return types.stream()
240                 .map(type -> type.getPackageName())
241                 .distinct()
242                 .toArray(String[]::new);
243     }
244 
getSyncAdapterPackagesForAuthorityAsUser(String sourcePackageName, String targetPackageName)245     private String[] getSyncAdapterPackagesForAuthorityAsUser(String sourcePackageName,
246             String targetPackageName) throws Exception {
247         final Bundle extraData = new Bundle();
248         extraData.putString(EXTRA_AUTHORITY, targetPackageName + AUTHORITY_SUFFIX);
249         extraData.putInt(Intent.EXTRA_USER, Process.myUserHandle().getIdentifier());
250         final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
251                 extraData, ACTION_GET_SYNCADAPTER_PACKAGES_FOR_AUTHORITY);
252         return response.getStringArray(Intent.EXTRA_PACKAGES);
253     }
254 
requestSyncAndAwaitStatus(String sourcePackageName, Account account, String targetPackageName)255     private boolean requestSyncAndAwaitStatus(String sourcePackageName, Account account,
256             String targetPackageName) throws Exception {
257         final Bundle extraData = new Bundle();
258         extraData.putParcelable(EXTRA_ACCOUNT, account);
259         extraData.putString(EXTRA_AUTHORITY, targetPackageName + AUTHORITY_SUFFIX);
260         final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
261                 extraData, ACTION_REQUEST_SYNC_AND_AWAIT_STATUS);
262         return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
263     }
264 
getSyncAdapterControlPanel(String sourcePackageName, Account account, String targetPackageName)265     private PendingIntent getSyncAdapterControlPanel(String sourcePackageName, Account account,
266             String targetPackageName) throws Exception {
267         final ComponentName componentName = new ComponentName(
268                 targetPackageName, SERVICE_CLASS_SYNC_ADAPTER);
269         final Bundle extraData = new Bundle();
270         extraData.putParcelable(EXTRA_ACCOUNT, account);
271         extraData.putString(EXTRA_AUTHORITY, targetPackageName + AUTHORITY_SUFFIX);
272         extraData.putParcelable(EXTRA_COMPONENT_NAME, componentName);
273         final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
274                 extraData, ACTION_GET_SYNCADAPTER_CONTROL_PANEL);
275         return response.getParcelable(Intent.EXTRA_RETURN_RESULT, PendingIntent.class);
276     }
277 
requestPeriodicSync(String providerPackageName, Account account)278     private boolean requestPeriodicSync(String providerPackageName, Account account)
279             throws Exception {
280         final String authority = providerPackageName + AUTHORITY_SUFFIX;
281         final Bundle extraData = new Bundle();
282         extraData.putParcelable(EXTRA_ACCOUNT, account);
283         extraData.putString(EXTRA_AUTHORITY, authority);
284         final Bundle response = sendCommandBlocking(providerPackageName,
285                 null /* targetPackageName */, extraData, ACTION_REQUEST_PERIODIC_SYNC);
286         return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
287     }
288 
setSyncAutomatically(String providerPackageName, Account account)289     private void setSyncAutomatically(String providerPackageName, Account account)
290             throws Exception {
291         final String authority = providerPackageName + AUTHORITY_SUFFIX;
292         final Bundle extraData = new Bundle();
293         extraData.putParcelable(EXTRA_ACCOUNT, account);
294         extraData.putString(EXTRA_AUTHORITY, authority);
295         sendCommandBlocking(providerPackageName, null /* targetPackageName */, extraData,
296                 ACTION_SET_SYNC_AUTOMATICALLY);
297     }
298 
getSyncAutomatically(String sourcePackageName, String targetPackageName)299     private boolean getSyncAutomatically(String sourcePackageName, String targetPackageName)
300             throws Exception {
301         final String authority = targetPackageName + AUTHORITY_SUFFIX;
302         final Bundle extraData = new Bundle();
303         extraData.putString(EXTRA_AUTHORITY, authority);
304         final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
305                 extraData, ACTION_GET_SYNC_AUTOMATICALLY);
306         return response.getBoolean(Intent.EXTRA_RETURN_RESULT);
307     }
308 
getIsSyncable(String sourcePackageName, Account account, String targetPackageName)309     private int getIsSyncable(String sourcePackageName, Account account, String targetPackageName)
310             throws Exception {
311         final String authority = targetPackageName + AUTHORITY_SUFFIX;
312         final Bundle extraData = new Bundle();
313         extraData.putParcelable(EXTRA_ACCOUNT, account);
314         extraData.putString(EXTRA_AUTHORITY, authority);
315         final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
316                 extraData, ACTION_GET_IS_SYNCABLE);
317         return response.getInt(Intent.EXTRA_RETURN_RESULT);
318     }
319 
getPeriodicSyncs(String sourcePackageName, Account account, String targetPackageName)320     private String[] getPeriodicSyncs(String sourcePackageName, Account account,
321             String targetPackageName) throws Exception {
322         final String authority = targetPackageName + AUTHORITY_SUFFIX;
323         final Bundle extraData = new Bundle();
324         extraData.putParcelable(EXTRA_ACCOUNT, account);
325         extraData.putString(EXTRA_AUTHORITY, authority);
326         final Bundle response = sendCommandBlocking(sourcePackageName, null /* targetPackageName */,
327                 extraData, ACTION_GET_PERIODIC_SYNCS);
328         final List<PeriodicSync> list = response.getParcelableArrayList(Intent.EXTRA_RETURN_RESULT,
329                 PeriodicSync.class);
330         return list.stream()
331                 .map(sync -> sync.authority)
332                 .distinct()
333                 .toArray(String[]::new);
334     }
335 }
336