1 /*
2  * Copyright (C) 2017 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.settings.testutils.shadow;
18 
19 import static android.provider.Settings.DEFAULT_OVERRIDEABLE_BY_RESTORE;
20 
21 import android.content.ContentResolver;
22 import android.provider.Settings;
23 
24 import com.google.common.collect.HashBasedTable;
25 import com.google.common.collect.Table;
26 
27 import org.robolectric.annotation.Implementation;
28 import org.robolectric.annotation.Implements;
29 import org.robolectric.shadows.ShadowSettings;
30 
31 import java.util.Map;
32 import java.util.WeakHashMap;
33 
34 @Implements(Settings.Secure.class)
35 public class ShadowSecureSettings extends ShadowSettings.ShadowSecure {
36 
37     private static final Map<ContentResolver, Table<Integer, String, Object>> sUserDataMap =
38         new WeakHashMap<>();
39 
40     @Implementation
putStringForUser(ContentResolver resolver, String name, String value, String tag, boolean makeDefault, int userHandle, boolean overrideableByRestore)41     public static boolean putStringForUser(ContentResolver resolver, String name, String value,
42         String tag, boolean makeDefault, int userHandle, boolean overrideableByRestore) {
43         final Table<Integer, String, Object> userTable = getUserTable(resolver);
44         synchronized (userTable) {
45             if (value != null) {
46                 userTable.put(userHandle, name, value);
47             } else {
48                 userTable.remove(userHandle, name);
49             }
50             return true;
51         }
52     }
53 
54     /**
55      * Same implementation as Settings.Secure because robolectric.ShadowSettings.ShadowSecure
56      * overrides this API.
57      */
58     @Implementation
putString(ContentResolver resolver, String name, String value)59     public static boolean putString(ContentResolver resolver, String name, String value) {
60         return putStringForUser(resolver, name, value, null, false,
61                 resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE);
62     }
63 
64     @Implementation
getStringForUser(ContentResolver resolver, String name, int userHandle)65     public static String getStringForUser(ContentResolver resolver, String name, int userHandle) {
66         final Table<Integer, String, Object> userTable = getUserTable(resolver);
67         synchronized (userTable) {
68             return (String) userTable.get(userHandle, name);
69         }
70     }
71 
72     /**
73      * Same implementation as Settings.Secure because robolectric.ShadowSettings.ShadowSecure
74      * overrides this API.
75      */
76     @Implementation
putInt(ContentResolver resolver, String name, int value)77     public static boolean putInt(ContentResolver resolver, String name, int value) {
78         return putIntForUser(resolver, name, value, resolver.getUserId());
79     }
80 
81     @Implementation
putIntForUser(ContentResolver resolver, String name, int value, int userHandle)82     public static boolean putIntForUser(ContentResolver resolver, String name, int value,
83         int userHandle) {
84         final Table<Integer, String, Object> userTable = getUserTable(resolver);
85         synchronized (userTable) {
86             userTable.put(userHandle, name, value);
87             return true;
88         }
89     }
90 
91     /**
92      * Same implementation as Settings.Secure because robolectric.ShadowSettings.ShadowSecure
93      * overrides this API.
94      */
95     @Implementation
getInt(ContentResolver resolver, String name, int def)96     public static int getInt(ContentResolver resolver, String name, int def) {
97         return getIntForUser(resolver, name, def, resolver.getUserId());
98     }
99 
100     @Implementation
getIntForUser(ContentResolver resolver, String name, int def, int userHandle)101     public static int getIntForUser(ContentResolver resolver, String name, int def,
102         int userHandle) {
103         final Table<Integer, String, Object> userTable = getUserTable(resolver);
104         synchronized (userTable) {
105             final Object object = userTable.get(userHandle, name);
106             return object instanceof Integer ? (Integer) object : def;
107         }
108     }
109 
110     @Implementation
putLongForUser(ContentResolver resolver, String name, long value, int userHandle)111     public static boolean putLongForUser(ContentResolver resolver, String name, long value,
112         int userHandle) {
113         final Table<Integer, String, Object> userTable = getUserTable(resolver);
114         synchronized (userTable) {
115             userTable.put(userHandle, name, value);
116             return true;
117         }
118     }
119 
120     @Implementation
getLongForUser(ContentResolver resolver, String name, long def, int userHandle)121     public static long getLongForUser(ContentResolver resolver, String name, long def,
122         int userHandle) {
123         final Table<Integer, String, Object> userTable = getUserTable(resolver);
124         synchronized (userTable) {
125             final Object object = userTable.get(userHandle, name);
126             return object instanceof Long ? (Long) object : def;
127         }
128     }
129 
130     @Implementation
putFloatForUser( ContentResolver resolver, String name, float value, int userHandle)131     public static boolean putFloatForUser(
132             ContentResolver resolver, String name, float value, int userHandle) {
133         final Table<Integer, String, Object> userTable = getUserTable(resolver);
134         synchronized (userTable) {
135             userTable.put(userHandle, name, value);
136             return true;
137         }
138     }
139 
140     @Implementation
getFloatForUser( ContentResolver resolver, String name, float def, int userHandle)141     public static float getFloatForUser(
142             ContentResolver resolver, String name, float def, int userHandle) {
143         final Table<Integer, String, Object> userTable = getUserTable(resolver);
144         synchronized (userTable) {
145             final Object object = userTable.get(userHandle, name);
146             return object instanceof Float ? (Float) object : def;
147         }
148     }
149 
clear()150     public static void clear() {
151         synchronized (sUserDataMap) {
152             sUserDataMap.clear();
153         }
154     }
155 
getUserTable(ContentResolver contentResolver)156     private static Table<Integer, String, Object> getUserTable(ContentResolver contentResolver) {
157         synchronized (sUserDataMap) {
158             Table<Integer, String, Object> table = sUserDataMap.get(contentResolver);
159             if (table == null) {
160                 table = HashBasedTable.create();
161                 sUserDataMap.put(contentResolver, table);
162             }
163             return table;
164         }
165     }
166 }
167