blob: b158476bd438ccefd26f61e86279b2fc88e6067d [file] [log] [blame]
Jason Monkf06a3172017-04-25 16:30:53 -04001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package android.testing;
16
17import android.content.ContentProviderClient;
18import android.content.Context;
19import android.os.Bundle;
20import android.os.RemoteException;
Chris Wren629c20c2017-05-10 15:08:36 -040021import android.os.UserHandle;
Jason Monkf06a3172017-04-25 16:30:53 -040022import android.provider.Settings;
23import android.test.mock.MockContentProvider;
24import android.util.Log;
25
26import java.util.HashMap;
27
28import static org.junit.Assert.*;
29
30/**
31 * Allows calls to android.provider.Settings to be tested easier.
32 *
33 * This provides a simple copy-on-write implementation of settings that gets cleared
34 * at the end of each test.
35 */
36public class TestableSettingsProvider extends MockContentProvider {
37
38 private static final String TAG = "TestableSettingsProvider";
Jason Monk1fc931a2017-12-14 13:22:58 -050039 private static final boolean DEBUG = false;
Jason Monkf06a3172017-04-25 16:30:53 -040040 private static final String MY_UNIQUE_KEY = "Key_" + TestableSettingsProvider.class.getName();
41 private static TestableSettingsProvider sInstance;
42
43 private final ContentProviderClient mSettings;
44
45 private final HashMap<String, String> mValues = new HashMap<>();
46
47 private TestableSettingsProvider(ContentProviderClient settings) {
48 mSettings = settings;
49 }
50
51 void clearValuesAndCheck(Context context) {
Chris Wren629c20c2017-05-10 15:08:36 -040052 int userId = UserHandle.myUserId();
53 mValues.put(key("global", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
54 mValues.put(key("secure", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
55 mValues.put(key("system", MY_UNIQUE_KEY, userId), MY_UNIQUE_KEY);
Jason Monkf06a3172017-04-25 16:30:53 -040056
Jason Monk1fc931a2017-12-14 13:22:58 -050057 Settings.Global.clearProviderForTest();
58 Settings.Secure.clearProviderForTest();
59 Settings.System.clearProviderForTest();
Jason Monkf06a3172017-04-25 16:30:53 -040060 // Verify that if any test is using TestableContext, they all have the correct settings
61 // provider.
62 assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY,
63 Settings.Global.getString(context.getContentResolver(), MY_UNIQUE_KEY));
64 assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY,
65 Settings.Secure.getString(context.getContentResolver(), MY_UNIQUE_KEY));
66 assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY,
67 Settings.System.getString(context.getContentResolver(), MY_UNIQUE_KEY));
68
69 mValues.clear();
70 }
71
72 public Bundle call(String method, String arg, Bundle extras) {
73 // Methods are "GET_system", "GET_global", "PUT_secure", etc.
Chris Wren629c20c2017-05-10 15:08:36 -040074 final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, 0);
Jason Monkf06a3172017-04-25 16:30:53 -040075 final String[] commands = method.split("_", 2);
76 final String op = commands[0];
77 final String table = commands[1];
78
Chris Wren629c20c2017-05-10 15:08:36 -040079 String k = key(table, arg, userId);
Jason Monkf06a3172017-04-25 16:30:53 -040080 String value;
81 Bundle out = new Bundle();
82 switch (op) {
83 case "GET":
84 if (mValues.containsKey(k)) {
85 value = mValues.get(k);
86 if (value != null) {
87 out.putString(Settings.NameValueTable.VALUE, value);
88 }
89 } else {
90 // Fall through to real settings.
91 try {
92 if (DEBUG) Log.d(TAG, "Falling through to real settings " + method);
93 // TODO: Add our own version of caching to handle this.
94 Bundle call = mSettings.call(method, arg, extras);
95 call.remove(Settings.CALL_METHOD_TRACK_GENERATION_KEY);
96 return call;
97 } catch (RemoteException e) {
98 throw new RuntimeException(e);
99 }
100 }
101 break;
102 case "PUT":
103 value = extras.getString(Settings.NameValueTable.VALUE, null);
104 mValues.put(k, value);
105 break;
106 default:
107 throw new UnsupportedOperationException("Unknown command " + method);
108 }
109 return out;
110 }
111
Chris Wren629c20c2017-05-10 15:08:36 -0400112 private static String key(String table, String key, int userId) {
113 if ("global".equals(table)) {
114 return table + "_" + key;
115 } else {
116 return table + "_" + userId + "_" + key;
117 }
118
Jason Monkf06a3172017-04-25 16:30:53 -0400119 }
120
121 /**
122 * Since the settings provider is cached inside android.provider.Settings, this must
123 * be gotten statically to ensure there is only one instance referenced.
124 */
125 static TestableSettingsProvider getFakeSettingsProvider(ContentProviderClient settings) {
126 if (sInstance == null) {
127 sInstance = new TestableSettingsProvider(settings);
128 }
129 return sInstance;
130 }
131}