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