blob: ded6ee5ade3a1be786bd51bfe048bec13b19797d [file] [log] [blame]
package com.android.clockwork.common;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Exposes a Secure Settings hook to "Disable" a device based on a user actively selecting
* "Disconnect [Watchname]" from the Companion app.
*
* <p>The expectation is that some process on the phone will relay this intent to disable the device
* to some process on the watch, which will in turn write to the secure setting.
*
* <p>Can be simulated locally on the watch by adb:
* <li>adb root</li>
* <li>adb shell settings put secure cw_device_enabled 0</li>
*
* <p>By default it is assumed that a device is enabled unless the setting is explicitly written.
*/
public class DeviceEnableSetting {
private static final String TAG = "DeviceEnableSetting";
// This is the "API" of exposed by Framework via Settings, via this class.
public static final String DEVICE_ENABLED_SECURE_SETTINGS_KEY =
"cw_device_enabled";
// Make these public so the Mediators can initialize with correct defaults.
public static final int STATE_DISABLED = 0;
public static final int STATE_ENABLED = 1;
public static final int DEVICE_ENABLED_SETTING_DEFAULT = STATE_ENABLED;
public interface Listener {
void onDeviceEnableChanged();
}
private enum Radio {
CELLULAR,
WIFI
}
private final ContentResolver mContentResolver;
private final SettingsObserver mSettingsObserver;
private final Set<Radio> mAffectedRadios = new HashSet<>();
private HashSet<Listener> mListeners = new HashSet<>();
private final AtomicBoolean mDeviceEnabled = new AtomicBoolean(true);
public DeviceEnableSetting(Context context, ContentResolver contentResolver) {
mContentResolver = contentResolver;
mSettingsObserver = new SettingsObserver(new Handler(Looper.getMainLooper()));
for (Uri uri : getObservedUris()) {
mContentResolver.registerContentObserver(uri, false, mSettingsObserver);
}
Resources wearableResources = WearResourceUtil.getWearableResources(context);
if (wearableResources != null) {
populateAffectedRadios(wearableResources.getStringArray(
com.android.wearable.resources.R.array.config_wearDeviceEnableRadios));
}
}
public boolean affectsWifi() {
return mAffectedRadios.contains(Radio.WIFI);
}
public boolean affectsCellular() {
return mAffectedRadios.contains(Radio.CELLULAR);
}
@VisibleForTesting
void populateAffectedRadios(String radios[]) {
if (radios == null) {
return;
}
for (String radio : radios) {
if ("wifi".equalsIgnoreCase(radio)) {
mAffectedRadios.add(Radio.WIFI);
} else if ("cellular".equalsIgnoreCase(radio)) {
mAffectedRadios.add(Radio.CELLULAR);
}
}
}
@VisibleForTesting
SettingsObserver getSettingsObserver() {
return mSettingsObserver;
}
private List<Uri> getObservedUris() {
ArrayList<Uri> uris = new ArrayList<>();
uris.add(Settings.Secure.getUriFor(DEVICE_ENABLED_SECURE_SETTINGS_KEY));
return uris;
}
public void addListener(Listener listener) {
mListeners.add(listener);
}
public boolean isDeviceEnabled() {
return Settings.Secure.getInt(
mContentResolver,
DEVICE_ENABLED_SECURE_SETTINGS_KEY,
DEVICE_ENABLED_SETTING_DEFAULT) == STATE_ENABLED;
}
/** Returns true if the setting was changed. */
private boolean updateDeviceEnabledFromSettings() {
boolean prev = mDeviceEnabled.get();
boolean newSetting = Settings.Secure.getInt(
mContentResolver,
DEVICE_ENABLED_SECURE_SETTINGS_KEY,
DEVICE_ENABLED_SETTING_DEFAULT) == STATE_ENABLED;
if (prev == newSetting) {
return false;
}
mDeviceEnabled.set(newSetting);
return true;
}
final class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (uri.equals(Settings.Secure.getUriFor(DEVICE_ENABLED_SECURE_SETTINGS_KEY))) {
if (updateDeviceEnabledFromSettings()) {
for (Listener listener : mListeners) {
listener.onDeviceEnableChanged();
}
}
}
}
}
}