blob: 5aaf7f680d5cd145b132d4838177b4a07631a4e8 [file] [log] [blame]
/*
* Copyright (C) 2020 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.systemui.util.settings;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.provider.Settings;
/**
* Used to interact with Settings.Secure, Settings.Global, and Settings.System.
*
* This interface can be implemented to give instance method (instead of static method) versions
* of Settings.Secure, Settings.Global, and Settings.System. It can be injected into class
* constructors and then faked or mocked as needed in tests.
*
* You can ask for {@link SecureSettings}, {@link GlobalSettings}, or {@link SystemSettings} to be
* injected as needed.
*
* This class also provides {@link #registerContentObserver(String, ContentObserver)} methods,
* normally found on {@link ContentResolver} instances, unifying setting related actions in one
* place.
*/
public interface SettingsProxy {
/**
* Returns the {@link ContentResolver} this instance was constructed with.
*/
ContentResolver getContentResolver();
/**
* Returns the user id for the associated {@link ContentResolver}.
*/
default int getUserId() {
return getContentResolver().getUserId();
}
/**
* Construct the content URI for a particular name/value pair,
* useful for monitoring changes with a ContentObserver.
* @param name to look up in the table
* @return the corresponding content URI, or null if not present
*/
Uri getUriFor(String name);
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
*
* Implicitly calls {@link #getUriFor(String)} on the passed in name.
*/
default void registerContentObserver(String name, ContentObserver settingsObserver) {
registerContentObserver(getUriFor(name), settingsObserver);
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
*/
default void registerContentObserver(Uri uri, ContentObserver settingsObserver) {
registerContentObserverForUser(uri, settingsObserver, getUserId());
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
*
* Implicitly calls {@link #getUriFor(String)} on the passed in name.
*/
default void registerContentObserver(String name, boolean notifyForDescendents,
ContentObserver settingsObserver) {
registerContentObserver(getUriFor(name), notifyForDescendents, settingsObserver);
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver)}.'
*/
default void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver settingsObserver) {
registerContentObserverForUser(uri, notifyForDescendents, settingsObserver, getUserId());
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
*
* Implicitly calls {@link #getUriFor(String)} on the passed in name.
*/
default void registerContentObserverForUser(
String name, ContentObserver settingsObserver, int userHandle) {
registerContentObserverForUser(
getUriFor(name), settingsObserver, userHandle);
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
*/
default void registerContentObserverForUser(
Uri uri, ContentObserver settingsObserver, int userHandle) {
registerContentObserverForUser(
uri, false, settingsObserver, userHandle);
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
*
* Implicitly calls {@link #getUriFor(String)} on the passed in name.
*/
default void registerContentObserverForUser(
String name, boolean notifyForDescendents, ContentObserver settingsObserver,
int userHandle) {
registerContentObserverForUser(
getUriFor(name), notifyForDescendents, settingsObserver, userHandle);
}
/**
* Convenience wrapper around
* {@link ContentResolver#registerContentObserver(Uri, boolean, ContentObserver, int)}
*/
default void registerContentObserverForUser(
Uri uri, boolean notifyForDescendents, ContentObserver settingsObserver,
int userHandle) {
getContentResolver().registerContentObserver(
uri, notifyForDescendents, settingsObserver, userHandle);
}
/** See {@link ContentResolver#unregisterContentObserver(ContentObserver)}. */
default void unregisterContentObserver(ContentObserver settingsObserver) {
getContentResolver().unregisterContentObserver(settingsObserver);
}
/**
* Look up a name in the database.
* @param name to look up in the table
* @return the corresponding value, or null if not present
*/
default String getString(String name) {
return getStringForUser(name, getUserId());
}
/**See {@link #getString(String)}. */
String getStringForUser(String name, int userHandle);
/**
* Store a name/value pair into the database. Values written by this method will be
* overridden if a restore happens in the future.
*
* @param name to store
* @param value to associate with the name
* @return true if the value was set, false on database errors
*/
boolean putString(String name, String value, boolean overrideableByRestore);
/**
* Store a name/value pair into the database.
* @param name to store
* @param value to associate with the name
* @return true if the value was set, false on database errors
*/
default boolean putString(String name, String value) {
return putStringForUser(name, value, getUserId());
}
/** See {@link #putString(String, String)}. */
boolean putStringForUser(String name, String value, int userHandle);
/** See {@link #putString(String, String)}. */
boolean putStringForUser(@NonNull String name, @Nullable String value, @Nullable String tag,
boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore);
/**
* Store a name/value pair into the database.
* <p>
* The method takes an optional tag to associate with the setting
* which can be used to clear only settings made by your package and
* associated with this tag by passing the tag to {@link
* #resetToDefaults(String)}. Anyone can override
* the current tag. Also if another package changes the setting
* then the tag will be set to the one specified in the set call
* which can be null. Also any of the settings setters that do not
* take a tag as an argument effectively clears the tag.
* </p><p>
* For example, if you set settings A and B with tags T1 and T2 and
* another app changes setting A (potentially to the same value), it
* can assign to it a tag T3 (note that now the package that changed
* the setting is not yours). Now if you reset your changes for T1 and
* T2 only setting B will be reset and A not (as it was changed by
* another package) but since A did not change you are in the desired
* initial state. Now if the other app changes the value of A (assuming
* you registered an observer in the beginning) you would detect that
* the setting was changed by another app and handle this appropriately
* (ignore, set back to some value, etc).
* </p><p>
* Also the method takes an argument whether to make the value the
* default for this setting. If the system already specified a default
* value, then the one passed in here will <strong>not</strong>
* be set as the default.
* </p>
*
* @param name to store.
* @param value to associate with the name.
* @param tag to associate with the setting.
* @param makeDefault whether to make the value the default one.
* @return true if the value was set, false on database errors.
*
* @see #resetToDefaults(String)
*
*/
boolean putString(@NonNull String name, @Nullable String value, @Nullable String tag,
boolean makeDefault);
/**
* Convenience function for retrieving a single secure settings value
* as an integer. Note that internally setting values are always
* stored as strings; this function converts the string to an integer
* for you. The default value will be returned if the setting is
* not defined or not an integer.
*
* @param name The name of the setting to retrieve.
* @param def Value to return if the setting is not defined.
*
* @return The setting's current value, or 'def' if it is not defined
* or not a valid integer.
*/
default int getInt(String name, int def) {
return getIntForUser(name, def, getUserId());
}
/** See {@link #getInt(String, int)}. */
default int getIntForUser(String name, int def, int userHandle) {
String v = getStringForUser(name, userHandle);
try {
return v != null ? Integer.parseInt(v) : def;
} catch (NumberFormatException e) {
return def;
}
}
/**
* Convenience function for retrieving a single secure settings value
* as an integer. Note that internally setting values are always
* stored as strings; this function converts the string to an integer
* for you.
* <p>
* This version does not take a default value. If the setting has not
* been set, or the string value is not a number,
* it throws {@link Settings.SettingNotFoundException}.
*
* @param name The name of the setting to retrieve.
*
* @throws Settings.SettingNotFoundException Thrown if a setting by the given
* name can't be found or the setting value is not an integer.
*
* @return The setting's current value.
*/
default int getInt(String name) throws Settings.SettingNotFoundException {
return getIntForUser(name, getUserId());
}
/** See {@link #getInt(String)}. */
default int getIntForUser(String name, int userHandle)
throws Settings.SettingNotFoundException {
String v = getStringForUser(name, userHandle);
try {
return Integer.parseInt(v);
} catch (NumberFormatException e) {
throw new Settings.SettingNotFoundException(name);
}
}
/**
* Convenience function for updating a single settings value as an
* integer. This will either create a new entry in the table if the
* given name does not exist, or modify the value of the existing row
* with that name. Note that internally setting values are always
* stored as strings, so this function converts the given value to a
* string before storing it.
*
* @param name The name of the setting to modify.
* @param value The new value for the setting.
* @return true if the value was set, false on database errors
*/
default boolean putInt(String name, int value) {
return putIntForUser(name, value, getUserId());
}
/** See {@link #putInt(String, int)}. */
default boolean putIntForUser(String name, int value, int userHandle) {
return putStringForUser(name, Integer.toString(value), userHandle);
}
/**
* Convenience function for retrieving a single secure settings value
* as a {@code long}. Note that internally setting values are always
* stored as strings; this function converts the string to a {@code long}
* for you. The default value will be returned if the setting is
* not defined or not a {@code long}.
*
* @param name The name of the setting to retrieve.
* @param def Value to return if the setting is not defined.
*
* @return The setting's current value, or 'def' if it is not defined
* or not a valid {@code long}.
*/
default long getLong(String name, long def) {
return getLongForUser(name, def, getUserId());
}
/** See {@link #getLong(String, long)}. */
default long getLongForUser(String name, long def, int userHandle) {
String valString = getStringForUser(name, userHandle);
long value;
try {
value = valString != null ? Long.parseLong(valString) : def;
} catch (NumberFormatException e) {
value = def;
}
return value;
}
/**
* Convenience function for retrieving a single secure settings value
* as a {@code long}. Note that internally setting values are always
* stored as strings; this function converts the string to a {@code long}
* for you.
* <p>
* This version does not take a default value. If the setting has not
* been set, or the string value is not a number,
* it throws {@link Settings.SettingNotFoundException}.
*
* @param name The name of the setting to retrieve.
*
* @return The setting's current value.
* @throws Settings.SettingNotFoundException Thrown if a setting by the given
* name can't be found or the setting value is not an integer.
*/
default long getLong(String name) throws Settings.SettingNotFoundException {
return getLongForUser(name, getUserId());
}
/** See {@link #getLong(String)}. */
default long getLongForUser(String name, int userHandle)
throws Settings.SettingNotFoundException {
String valString = getStringForUser(name, userHandle);
try {
return Long.parseLong(valString);
} catch (NumberFormatException e) {
throw new Settings.SettingNotFoundException(name);
}
}
/**
* Convenience function for updating a secure settings value as a long
* integer. This will either create a new entry in the table if the
* given name does not exist, or modify the value of the existing row
* with that name. Note that internally setting values are always
* stored as strings, so this function converts the given value to a
* string before storing it.
*
* @param name The name of the setting to modify.
* @param value The new value for the setting.
* @return true if the value was set, false on database errors
*/
default boolean putLong(String name, long value) {
return putLongForUser(name, value, getUserId());
}
/** See {@link #putLong(String, long)}. */
default boolean putLongForUser(String name, long value, int userHandle) {
return putStringForUser(name, Long.toString(value), userHandle);
}
/**
* Convenience function for retrieving a single secure settings value
* as a floating point number. Note that internally setting values are
* always stored as strings; this function converts the string to an
* float for you. The default value will be returned if the setting
* is not defined or not a valid float.
*
* @param name The name of the setting to retrieve.
* @param def Value to return if the setting is not defined.
*
* @return The setting's current value, or 'def' if it is not defined
* or not a valid float.
*/
default float getFloat(String name, float def) {
return getFloatForUser(name, def, getUserId());
}
/** See {@link #getFloat(String)}. */
default float getFloatForUser(String name, float def, int userHandle) {
String v = getStringForUser(name, userHandle);
try {
return v != null ? Float.parseFloat(v) : def;
} catch (NumberFormatException e) {
return def;
}
}
/**
* Convenience function for retrieving a single secure settings value
* as a float. Note that internally setting values are always
* stored as strings; this function converts the string to a float
* for you.
* <p>
* This version does not take a default value. If the setting has not
* been set, or the string value is not a number,
* it throws {@link Settings.SettingNotFoundException}.
*
* @param name The name of the setting to retrieve.
*
* @throws Settings.SettingNotFoundException Thrown if a setting by the given
* name can't be found or the setting value is not a float.
*
* @return The setting's current value.
*/
default float getFloat(String name) throws Settings.SettingNotFoundException {
return getFloatForUser(name, getUserId());
}
/** See {@link #getFloat(String, float)}. */
default float getFloatForUser(String name, int userHandle)
throws Settings.SettingNotFoundException {
String v = getStringForUser(name, userHandle);
if (v == null) {
throw new Settings.SettingNotFoundException(name);
}
try {
return Float.parseFloat(v);
} catch (NumberFormatException e) {
throw new Settings.SettingNotFoundException(name);
}
}
/**
* Convenience function for updating a single settings value as a
* floating point number. This will either create a new entry in the
* table if the given name does not exist, or modify the value of the
* existing row with that name. Note that internally setting values
* are always stored as strings, so this function converts the given
* value to a string before storing it.
*
* @param name The name of the setting to modify.
* @param value The new value for the setting.
* @return true if the value was set, false on database errors
*/
default boolean putFloat(String name, float value) {
return putFloatForUser(name, value, getUserId());
}
/** See {@link #putFloat(String, float)} */
default boolean putFloatForUser(String name, float value, int userHandle) {
return putStringForUser(name, Float.toString(value), userHandle);
}
}