1 /*
2  * Copyright (C) 2018 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.car.settings.testutils;
18 
19 import android.accounts.Account;
20 import android.annotation.UserIdInt;
21 import android.content.ContentResolver;
22 import android.content.SyncAdapterType;
23 import android.content.SyncInfo;
24 import android.content.SyncStatusInfo;
25 import android.content.SyncStatusObserver;
26 import android.os.Bundle;
27 
28 import org.robolectric.annotation.Implementation;
29 import org.robolectric.annotation.Implements;
30 import org.robolectric.annotation.Resetter;
31 
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 
37 /**
38  * Derived from {@link com.android.settings.testutils.shadow.ShadowContentResolver}
39  *
40  * <p>Needed for many account-related tests because the default ShadowContentResolver does not
41  * include an implementation of getSyncAdapterTypesAsUser, which is used by {@link
42  * com.android.settingslib.accounts.AuthenticatorHelper#buildAccountTypeToAuthoritiesMap}.
43  */
44 @Implements(ContentResolver.class)
45 public class ShadowContentResolver extends org.robolectric.shadows.ShadowContentResolver {
46     private static final int SYNCABLE = 1;
47 
48     private static SyncAdapterType[] sSyncAdapterTypes = new SyncAdapterType[0];
49     private static Map<String, Integer> sSyncable = new HashMap<>();
50     private static Map<String, Boolean> sSyncAutomatically = new HashMap<>();
51     private static Map<Integer, Boolean> sMasterSyncAutomatically = new HashMap<>();
52     private static Map<String, SyncStatusInfo> sSyncStatus = new HashMap<>();
53     private static List<SyncInfo> sSyncs = new ArrayList<>();
54     private static SyncListener sSyncListener;
55     private static SyncStatusObserver sStatusObserver;
56 
57     @Implementation
getSyncAdapterTypesAsUser(int userId)58     protected static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
59         return sSyncAdapterTypes;
60     }
61 
62     @Implementation
getIsSyncableAsUser(Account account, String authority, int userId)63     protected static int getIsSyncableAsUser(Account account, String authority, int userId) {
64         return sSyncable.getOrDefault(authority, SYNCABLE);
65     }
66 
67     @Implementation
getSyncAutomaticallyAsUser(Account account, String authority, int userId)68     protected static boolean getSyncAutomaticallyAsUser(Account account, String authority,
69             int userId) {
70         return sSyncAutomatically.getOrDefault(authority, true);
71     }
72 
73     @Implementation
getMasterSyncAutomaticallyAsUser(int userId)74     protected static boolean getMasterSyncAutomaticallyAsUser(int userId) {
75         return sMasterSyncAutomatically.getOrDefault(userId, true);
76     }
77 
78     @Implementation
getCurrentSyncsAsUser(@serIdInt int userId)79     protected static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
80         return sSyncs;
81     }
82 
83     @Implementation
getSyncStatusAsUser(Account account, String authority, @UserIdInt int userId)84     protected static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
85             @UserIdInt int userId) {
86         return sSyncStatus.get(authority);
87     }
88 
setSyncAdapterTypes(SyncAdapterType[] syncAdapterTypes)89     public static void setSyncAdapterTypes(SyncAdapterType[] syncAdapterTypes) {
90         sSyncAdapterTypes = syncAdapterTypes;
91     }
92 
93     @Implementation
setIsSyncable(Account account, String authority, int syncable)94     public static void setIsSyncable(Account account, String authority, int syncable) {
95         sSyncable.put(authority, syncable);
96     }
97 
98     @Implementation
setSyncAutomaticallyAsUser(Account account, String authority, boolean sync, @UserIdInt int userId)99     protected static void setSyncAutomaticallyAsUser(Account account, String authority,
100             boolean sync, @UserIdInt int userId) {
101         sSyncAutomatically.put(authority, sync);
102     }
103 
104     @Implementation
setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId)105     protected static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
106         sMasterSyncAutomatically.put(userId, sync);
107     }
108 
setCurrentSyncs(List<SyncInfo> syncs)109     public static void setCurrentSyncs(List<SyncInfo> syncs) {
110         sSyncs = syncs;
111     }
112 
setSyncStatus(Account account, String authority, SyncStatusInfo status)113     public static void setSyncStatus(Account account, String authority, SyncStatusInfo status) {
114         sSyncStatus.put(authority, status);
115     }
116 
117     @Implementation
cancelSyncAsUser(Account account, String authority, @UserIdInt int userId)118     public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
119         if (sSyncListener != null) {
120             sSyncListener.onSyncCanceled(account, authority, userId);
121         }
122     }
123 
124     @Implementation
requestSyncAsUser(Account account, String authority, @UserIdInt int userId, Bundle extras)125     public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
126             Bundle extras) {
127         if (sSyncListener != null) {
128             sSyncListener.onSyncRequested(account, authority, userId, extras);
129         }
130     }
131 
setSyncListener(SyncListener syncListener)132     public static void setSyncListener(SyncListener syncListener) {
133         sSyncListener = syncListener;
134     }
135 
136     @Implementation
addStatusChangeListener(int mask, SyncStatusObserver callback)137     protected static Object addStatusChangeListener(int mask, SyncStatusObserver callback) {
138         sStatusObserver = callback;
139         return null;
140     }
141 
142     @Implementation
removeStatusChangeListener(Object handle)143     protected static void removeStatusChangeListener(Object handle) {
144         sStatusObserver = null;
145     }
146 
getStatusChangeListener()147     public static SyncStatusObserver getStatusChangeListener() {
148         return sStatusObserver;
149     }
150 
151     @Resetter
reset()152     public static void reset() {
153         org.robolectric.shadows.ShadowContentResolver.reset();
154         sSyncable.clear();
155         sSyncAutomatically.clear();
156         sMasterSyncAutomatically.clear();
157         sSyncAdapterTypes = new SyncAdapterType[0];
158         sSyncStatus.clear();
159         sSyncs = new ArrayList<>();
160         sSyncListener = null;
161         sStatusObserver = null;
162     }
163 
164     /**
165      * A listener interface that can be used to verify calls to {@link #cancelSyncAsUser} and {@link
166      * #requestSyncAsUser}
167      */
168     public interface SyncListener {
onSyncCanceled(Account account, String authority, @UserIdInt int userId)169         void onSyncCanceled(Account account, String authority, @UserIdInt int userId);
170 
onSyncRequested(Account account, String authority, @UserIdInt int userId, Bundle extras)171         void onSyncRequested(Account account, String authority, @UserIdInt int userId,
172                 Bundle extras);
173     }
174 }
175