16d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti/*
26d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * Copyright (C) 2016 The Android Open Source Project
36d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
46d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License");
56d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * you may not use this file except in compliance with the License.
66d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * You may obtain a copy of the License at
76d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
86d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *      http://www.apache.org/licenses/LICENSE-2.0
96d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
106d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * Unless required by applicable law or agreed to in writing, software
116d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS,
126d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * See the License for the specific language governing permissions and
146d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * limitations under the License.
156d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti */
166d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
176d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittipackage com.android.internal.util;
186d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
196d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittiimport android.net.Uri;
206d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittiimport android.os.Bundle;
216d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittiimport android.provider.Settings;
226d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittiimport android.test.mock.MockContentProvider;
236d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittiimport android.util.Log;
246d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
256d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittiimport java.util.HashMap;
266d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
276d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti/**
286d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * Fake for system settings.
296d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
306d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * To use, ensure that the Context used by the test code returns a ContentResolver that uses this
316d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * provider for the Settings authority:
326d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
336d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *   class MyTestContext extends MockContext {
346d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       ...
356d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       private final MockContentResolver mContentResolver;
366d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       public MyTestContext(...) {
376d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *           ...
386d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *           mContentResolver = new MockContentResolver();
396d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *           mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
406d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       }
416d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       ...
426d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       @Override
436d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       public ContentResolver getContentResolver() {
446d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *           return mContentResolver;
456d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *       }
466d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
476d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * As long as the code under test is using the test Context, the actual code under test does not
486d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * need to be modified, and can access Settings using the normal static methods:
496d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
506d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *   Settings.Global.getInt(cr, "my_setting", 0);  // Returns 0.
516d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *   Settings.Global.putInt(cr, "my_setting", 5);
526d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *   Settings.Global.getInt(cr, "my_setting", 0);  // Returns 5.
536d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
546d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * Note that this class cannot be used in the same process as real settings. This is because it
556d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * works by passing an alternate ContentResolver to Settings operations. Unfortunately, the Settings
566d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * class only fetches the content provider from the passed-in ContentResolver the first time it's
576d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * used, and after that stores it in a per-process static.
586d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
596d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * TODO: evaluate implementing settings change notifications. This would require:
606d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *
616d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * 1. Making ContentResolver#registerContentObserver non-final and overriding it in
626d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti *    MockContentResolver.
636d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * 2. Making FakeSettingsProvider take a ContentResolver argument.
646d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti * 3. Calling ContentResolver#notifyChange(getUriFor(table, arg), ...) on every settings change.
656d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti */
666d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colittipublic class FakeSettingsProvider extends MockContentProvider {
676d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
686d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    private static final String TAG = FakeSettingsProvider.class.getSimpleName();
696d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    private static final boolean DBG = false;
706d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    private static final String[] TABLES = { "system", "secure", "global" };
716d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
726d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    private final HashMap<String, HashMap<String, String>> mTables = new HashMap<>();
736d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
746d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    public FakeSettingsProvider() {
756d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        for (int i = 0; i < TABLES.length; i++) {
766d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            mTables.put(TABLES[i], new HashMap<String, String>());
776d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        }
786d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    }
796d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
806d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    private Uri getUriFor(String table, String key) {
816d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        switch (table) {
826d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            case "system":
836d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                return Settings.System.getUriFor(key);
846d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            case "secure":
856d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                return Settings.Secure.getUriFor(key);
866d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            case "global":
876d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                return Settings.Global.getUriFor(key);
886d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            default:
896d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                throw new UnsupportedOperationException("Unknown settings table " + table);
906d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        }
916d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    }
926d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
936d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    public Bundle call(String method, String arg, Bundle extras) {
946d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        // Methods are "GET_system", "GET_global", "PUT_secure", etc.
956d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        String[] commands = method.split("_", 2);
966d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        String op = commands[0];
976d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        String table = commands[1];
986d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
996d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        Bundle out = new Bundle();
1006d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        String value;
1016d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        switch (op) {
1026d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            case "GET":
1036d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                value = mTables.get(table).get(arg);
1046d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                if (value != null) {
1056d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                    if (DBG) {
1066d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                        Log.d(TAG, String.format("Returning fake setting %s.%s = %s",
1076d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                                table, arg, value));
1086d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                    }
1096d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                    out.putString(Settings.NameValueTable.VALUE, value);
1106d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                }
1116d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                break;
1126d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            case "PUT":
1136d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                value = extras.getString(Settings.NameValueTable.VALUE, null);
1146d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                if (DBG) {
1156d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                    Log.d(TAG, String.format("Inserting fake setting %s.%s = %s",
1166d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                            table, arg, value));
1176d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                }
1186d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                if (value != null) {
1196d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                    mTables.get(table).put(arg, value);
1206d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                } else {
1216d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                    mTables.get(table).remove(arg);
1226d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                }
1236d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                break;
1246d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti            default:
1256d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti                throw new UnsupportedOperationException("Unknown command " + method);
1266d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        }
1276d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti
1286d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti        return out;
1296d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti    }
1306d553f6dfdcc188fa6b17d4abb11d6222009a8fbLorenzo Colitti}
131