| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| package com.android.dialer.configprovider; |
| |
| import android.app.IntentService; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.content.SharedPreferences.Editor; |
| import android.support.annotation.Nullable; |
| import com.android.dialer.common.Assert; |
| import com.android.dialer.common.LogUtil; |
| import com.android.dialer.storage.StorageComponent; |
| import com.android.dialer.storage.Unencrypted; |
| import com.android.dialer.strictmode.StrictModeUtils; |
| import javax.inject.Inject; |
| |
| /** |
| * {@link ConfigProvider} which uses a shared preferences file. |
| * |
| * <p>Config flags can be written using adb (with root access), for example: |
| * |
| * <pre> |
| * adb root |
| * adb shell am startservice -n \ |
| * 'com.android.dialer/.configprovider.SharedPrefConfigProvider\$Service' \ |
| * --ez boolean_flag_name flag_value |
| * </pre> |
| * |
| * <p>(For longs use --el and for strings use --es.) |
| * |
| * <p>Flags can be viewed with: |
| * |
| * <pre> |
| * adb shell cat \ |
| * /data/user_de/0/com.android.dialer/shared_prefs/com.android.dialer_preferences.xml |
| * </pre> |
| */ |
| public class SharedPrefConfigProvider implements ConfigProvider { |
| private static final String PREF_PREFIX = "config_provider_prefs_"; |
| |
| private final SharedPreferences sharedPreferences; |
| |
| @Inject |
| SharedPrefConfigProvider(@Unencrypted SharedPreferences sharedPreferences) { |
| this.sharedPreferences = sharedPreferences; |
| } |
| |
| /** Service to write values into {@link SharedPrefConfigProvider} using adb. */ |
| public static class Service extends IntentService { |
| |
| public Service() { |
| super("SharedPrefConfigProvider.Service"); |
| } |
| |
| @Override |
| protected void onHandleIntent(@Nullable Intent intent) { |
| if (intent == null || intent.getExtras() == null || intent.getExtras().size() != 1) { |
| LogUtil.w("SharedPrefConfigProvider.Service.onHandleIntent", "must set exactly one extra"); |
| return; |
| } |
| String key = intent.getExtras().keySet().iterator().next(); |
| Object value = intent.getExtras().get(key); |
| put(key, value); |
| } |
| |
| private void put(String key, Object value) { |
| Editor editor = getSharedPrefs(getApplicationContext()).edit(); |
| String prefixedKey = PREF_PREFIX + key; |
| if (value instanceof Boolean) { |
| editor.putBoolean(prefixedKey, (Boolean) value); |
| } else if (value instanceof Long) { |
| editor.putLong(prefixedKey, (Long) value); |
| } else if (value instanceof String) { |
| editor.putString(prefixedKey, (String) value); |
| } else { |
| throw Assert.createAssertionFailException("unsupported extra type: " + value.getClass()); |
| } |
| editor.apply(); |
| } |
| } |
| |
| /** Set a boolean config value. */ |
| public void putBoolean(String key, boolean value) { |
| sharedPreferences.edit().putBoolean(PREF_PREFIX + key, value).apply(); |
| } |
| |
| public void putLong(String key, long value) { |
| sharedPreferences.edit().putLong(PREF_PREFIX + key, value).apply(); |
| } |
| |
| public void putString(String key, String value) { |
| sharedPreferences.edit().putString(PREF_PREFIX + key, value).apply(); |
| } |
| |
| @Override |
| public String getString(String key, String defaultValue) { |
| // Reading shared prefs on the main thread is generally safe since a single instance is cached. |
| return StrictModeUtils.bypass( |
| () -> sharedPreferences.getString(PREF_PREFIX + key, defaultValue)); |
| } |
| |
| @Override |
| public long getLong(String key, long defaultValue) { |
| // Reading shared prefs on the main thread is generally safe since a single instance is cached. |
| return StrictModeUtils.bypass(() -> sharedPreferences.getLong(PREF_PREFIX + key, defaultValue)); |
| } |
| |
| @Override |
| public boolean getBoolean(String key, boolean defaultValue) { |
| // Reading shared prefs on the main thread is generally safe since a single instance is cached. |
| return StrictModeUtils.bypass( |
| () -> sharedPreferences.getBoolean(PREF_PREFIX + key, defaultValue)); |
| } |
| |
| private static SharedPreferences getSharedPrefs(Context appContext) { |
| return StorageComponent.get(appContext).unencryptedSharedPrefs(); |
| } |
| } |