Home | History | Annotate | Download | only in testing
      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 android.content.ContentProviderClient;
     18 import android.content.Context;
     19 import android.os.Bundle;
     20 import android.os.RemoteException;
     21 import android.os.UserHandle;
     22 import android.provider.Settings;
     23 import android.test.mock.MockContentProvider;
     24 import android.util.Log;
     25 
     26 import java.util.HashMap;
     27 
     28 import 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  */
     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 
     47     private TestableSettingsProvider(ContentProviderClient settings) {
     48         mSettings = settings;
     49     }
     50 
     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 
     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, 0);
     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 
    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      */
    125     static TestableSettingsProvider getFakeSettingsProvider(ContentProviderClient settings) {
    126         if (sInstance == null) {
    127             sInstance = new TestableSettingsProvider(settings);
    128         }
    129         return sInstance;
    130     }
    131 }
    132