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         // Verify that if any test is using TestableContext, they all have the correct settings
     58         // provider.
     59         assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY,
     60                 Settings.Global.getString(context.getContentResolver(), MY_UNIQUE_KEY));
     61         assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY,
     62                 Settings.Secure.getString(context.getContentResolver(), MY_UNIQUE_KEY));
     63         assertEquals("Incorrect settings provider, test using incorrect Context?", MY_UNIQUE_KEY,
     64                 Settings.System.getString(context.getContentResolver(), MY_UNIQUE_KEY));
     65 
     66         mValues.clear();
     67     }
     68 
     69     public Bundle call(String method, String arg, Bundle extras) {
     70         // Methods are "GET_system", "GET_global", "PUT_secure", etc.
     71         final int userId = extras.getInt(Settings.CALL_METHOD_USER_KEY, 0);
     72         final String[] commands = method.split("_", 2);
     73         final String op = commands[0];
     74         final String table = commands[1];
     75 
     76             String k = key(table, arg, userId);
     77             String value;
     78             Bundle out = new Bundle();
     79             switch (op) {
     80                 case "GET":
     81                     if (mValues.containsKey(k)) {
     82                         value = mValues.get(k);
     83                         if (value != null) {
     84                             out.putString(Settings.NameValueTable.VALUE, value);
     85                         }
     86                     } else {
     87                         // Fall through to real settings.
     88                         try {
     89                             if (DEBUG) Log.d(TAG, "Falling through to real settings " + method);
     90                             // TODO: Add our own version of caching to handle this.
     91                             Bundle call = mSettings.call(method, arg, extras);
     92                             call.remove(Settings.CALL_METHOD_TRACK_GENERATION_KEY);
     93                             return call;
     94                         } catch (RemoteException e) {
     95                             throw new RuntimeException(e);
     96                         }
     97                     }
     98                     break;
     99                 case "PUT":
    100                     value = extras.getString(Settings.NameValueTable.VALUE, null);
    101                     mValues.put(k, value);
    102                     break;
    103                 default:
    104                     throw new UnsupportedOperationException("Unknown command " + method);
    105             }
    106             return out;
    107     }
    108 
    109     private static String key(String table, String key, int userId) {
    110         if ("global".equals(table)) {
    111             return table + "_" + key;
    112         } else {
    113             return table + "_" + userId + "_" + key;
    114         }
    115 
    116     }
    117 
    118     /**
    119      * Since the settings provider is cached inside android.provider.Settings, this must
    120      * be gotten statically to ensure there is only one instance referenced.
    121      */
    122     static TestableSettingsProvider getFakeSettingsProvider(ContentProviderClient settings) {
    123         if (sInstance == null) {
    124             sInstance = new TestableSettingsProvider(settings);
    125         }
    126         return sInstance;
    127     }
    128 }
    129