1 /* 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 15 package android.testing; 16 17 import static org.junit.Assert.assertEquals; 18 19 import android.content.ContentProviderClient; 20 import android.content.Context; 21 import android.os.Bundle; 22 import android.os.RemoteException; 23 import android.os.UserHandle; 24 import android.provider.Settings; 25 import android.test.mock.MockContentProvider; 26 import android.util.Log; 27 28 import java.util.HashMap; 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 */ 36 public class TestableSettingsProvider extends MockContentProvider { 37 38 private static final String TAG = "TestableSettingsProvider"; 39 private static final boolean DEBUG = false; 40 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 TestableSettingsProvider(ContentProviderClient settings)47 private TestableSettingsProvider(ContentProviderClient settings) { 48 mSettings = settings; 49 } 50 clearValuesAndCheck(Context context)51 void clearValuesAndCheck(Context context) { 52 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); 56 57 Settings.Global.clearProviderForTest(); 58 Settings.Secure.clearProviderForTest(); 59 Settings.System.clearProviderForTest(); 60 // 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 call(String method, String arg, Bundle extras)72 public Bundle call(String method, String arg, Bundle extras) { 73 // Methods are "GET_system", "GET_global", "PUT_secure", etc. 74 final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, UserHandle.myUserId()); 75 final String[] commands = method.split("_", 2); 76 final String op = commands[0]; 77 final String table = commands[1]; 78 79 String k = key(table, arg, userId); 80 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 key(String table, String key, int userId)112 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 119 } 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 */ getFakeSettingsProvider(ContentProviderClient settings)125 static TestableSettingsProvider getFakeSettingsProvider(ContentProviderClient settings) { 126 if (sInstance == null) { 127 sInstance = new TestableSettingsProvider(settings); 128 } 129 return sInstance; 130 } 131 } 132