Add new preference class MasterSwitchPreference.

- Add a new preference type that has Title and optional summary on the
  left, and a toggle switch on the right. Clicking the left part of the
  preference will open a settings screen.
- Update Connected devices->Bluetooth to use this new preference.
- Refactor BluetoothSettings and BluetoothEnabler to share code between
  the new bluetooth preference controller and the bluetooth setting.

Bug: 34280769
Test: make RunSettingsRoboTests
Change-Id: I109ecdba640ecdd4748a6e5b2b4f4c47cbf653fd
This commit is contained in:
Doris Ling
2017-01-18 13:59:36 -08:00
parent 8f969665e3
commit 1432cb8529
16 changed files with 1107 additions and 233 deletions

View File

@@ -3312,17 +3312,6 @@
android:value="com.android.settings.applications.ProcessStatsSummary" />
</activity-alias>
<activity-alias android:name="BluetoothDashboardAlias"
android:targetActivity="Settings$BluetoothSettingsActivity">
<intent-filter android:priority="7">
<action android:name="com.android.settings.action.SETTINGS"/>
</intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.bluetooth.BluetoothSettings" />
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.device" />
</activity-alias>
<activity-alias android:name="CastDashboardAlias"
android:targetActivity="Settings$WifiDisplaySettingsActivity">
<intent-filter android:priority="6">

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<View
android:layout_width="1dip"
android:layout_height="match_parent"
android:background="?android:attr/colorSecondary"/>
</LinearLayout>
<Switch android:id="@+id/switchWidget"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical" />
</LinearLayout>

View File

@@ -18,6 +18,13 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/connected_devices_dashboard_title">
<com.android.settings.widget.MasterSwitchPreference
android:fragment="com.android.settings.bluetooth.BluetoothSettings"
android:key="toggle_bluetooth"
android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth"
android:order="-7"/>
<SwitchPreference
android:key="toggle_nfc"
android:title="@string/nfc_quick_toggle_title"

View File

@@ -24,14 +24,13 @@ import android.content.IntentFilter;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.widget.Switch;
import android.widget.Toast;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.search.Index;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.SwitchWidgetController;
import com.android.settingslib.WirelessUtils;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -41,9 +40,8 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
* preference. It turns on/off Bluetooth and ensures the summary of the
* preference reflects the current state.
*/
public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener {
private final Switch mSwitch;
private final SwitchBar mSwitchBar;
public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchChangeListener {
private final SwitchWidgetController mSwitchWidget;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private Context mContext;
private boolean mValidListener;
@@ -76,19 +74,18 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener
}
};
public BluetoothEnabler(Context context, SwitchBar switchBar,
MetricsFeatureProvider metricsFeatureProvider) {
public BluetoothEnabler(Context context, SwitchWidgetController switchWidget,
MetricsFeatureProvider metricsFeatureProvider, LocalBluetoothManager manager) {
mContext = context;
mMetricsFeatureProvider = metricsFeatureProvider;
mSwitchBar = switchBar;
mSwitch = switchBar.getSwitch();
mSwitchWidget = switchWidget;
mSwitchWidget.setListener(this);
mValidListener = false;
LocalBluetoothManager manager = Utils.getLocalBtManager(context);
if (manager == null) {
// Bluetooth is not supported
mLocalAdapter = null;
mSwitch.setEnabled(false);
mSwitchWidget.setEnabled(false);
} else {
mLocalAdapter = manager.getBluetoothAdapter();
}
@@ -96,16 +93,16 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener
}
public void setupSwitchBar() {
mSwitchBar.show();
mSwitchWidget.setupView();
}
public void teardownSwitchBar() {
mSwitchBar.hide();
mSwitchWidget.teardownView();
}
public void resume(Context context) {
if (mLocalAdapter == null) {
mSwitch.setEnabled(false);
mSwitchWidget.setEnabled(false);
return;
}
@@ -116,7 +113,7 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener
// Bluetooth state is not sticky, so set it manually
handleStateChanged(mLocalAdapter.getBluetoothState());
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchWidget.startListening();
mContext.registerReceiver(mReceiver, mIntentFilter);
mValidListener = true;
}
@@ -125,47 +122,48 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener
if (mLocalAdapter == null) {
return;
}
mSwitchBar.removeOnSwitchChangeListener(this);
if (mValidListener) {
mSwitchWidget.stopListening();
mContext.unregisterReceiver(mReceiver);
mValidListener = false;
}
}
void handleStateChanged(int state) {
switch (state) {
case BluetoothAdapter.STATE_TURNING_ON:
mSwitch.setEnabled(false);
mSwitchWidget.setEnabled(false);
break;
case BluetoothAdapter.STATE_ON:
setChecked(true);
mSwitch.setEnabled(true);
mSwitchWidget.setEnabled(true);
updateSearchIndex(true);
break;
case BluetoothAdapter.STATE_TURNING_OFF:
mSwitch.setEnabled(false);
mSwitchWidget.setEnabled(false);
break;
case BluetoothAdapter.STATE_OFF:
setChecked(false);
mSwitch.setEnabled(true);
mSwitchWidget.setEnabled(true);
updateSearchIndex(false);
break;
default:
setChecked(false);
mSwitch.setEnabled(true);
mSwitchWidget.setEnabled(true);
updateSearchIndex(false);
}
}
private void setChecked(boolean isChecked) {
if (isChecked != mSwitch.isChecked()) {
if (isChecked != mSwitchWidget.isChecked()) {
// set listener to null, so onCheckedChanged won't be called
// if the checked status on Switch isn't changed by user click
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
mSwitchWidget.stopListening();
}
mSwitch.setChecked(isChecked);
mSwitchWidget.setChecked(isChecked);
if (mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchWidget.startListening();
}
}
}
@@ -180,13 +178,14 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
public boolean onSwitchToggled(boolean isChecked) {
// Show toast message if Bluetooth is not allowed in airplane mode
if (isChecked &&
!WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_BLUETOOTH)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off
switchView.setChecked(false);
mSwitchWidget.setChecked(false);
return false;
}
mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_BLUETOOTH_TOGGLE, isChecked);
@@ -197,12 +196,13 @@ public final class BluetoothEnabler implements SwitchBar.OnSwitchChangeListener
// a) The switch should be OFF but it should still be togglable (enabled = True)
// b) The switch bar should have OFF text.
if (isChecked && !status) {
switchView.setChecked(false);
mSwitch.setEnabled(true);
mSwitchBar.setTextViewLabel(false);
return;
mSwitchWidget.setChecked(false);
mSwitchWidget.setEnabled(true);
mSwitchWidget.updateTitle(false);
return false;
}
}
mSwitch.setEnabled(false);
mSwitchWidget.setEnabled(false);
return true;
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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.settings.bluetooth;
import android.content.Context;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.LifecycleObserver;
import com.android.settings.core.lifecycle.events.OnPause;
import com.android.settings.core.lifecycle.events.OnResume;
import com.android.settings.core.lifecycle.events.OnStart;
import com.android.settings.core.lifecycle.events.OnStop;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settings.widget.MasterSwitchController;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
public class BluetoothMasterSwitchPreferenceController extends PreferenceController
implements BluetoothSummaryHelper.OnSummaryChangeListener,
LifecycleObserver, OnResume, OnPause, OnStart, OnStop {
private static final String KEY_TOGGLE_BLUETOOTH = "toggle_bluetooth";
private LocalBluetoothManager mBluetoothManager;
private MasterSwitchPreference mBtPreference;
private BluetoothEnabler mBluetoothEnabler;
private BluetoothSummaryHelper mSummaryHelper;
public BluetoothMasterSwitchPreferenceController(Context context,
LocalBluetoothManager bluetoothManager) {
super(context);
mBluetoothManager = bluetoothManager;
mSummaryHelper = new BluetoothSummaryHelper(mContext, mBluetoothManager);
mSummaryHelper.setOnSummaryChangeListener(this);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mBtPreference = (MasterSwitchPreference) screen.findPreference(KEY_TOGGLE_BLUETOOTH);
mBluetoothEnabler = new BluetoothEnabler(mContext,
new MasterSwitchController(mBtPreference),
FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(), mBluetoothManager);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY_TOGGLE_BLUETOOTH;
}
public void onResume() {
mSummaryHelper.setListening(true);
}
@Override
public void onPause() {
mSummaryHelper.setListening(false);
}
@Override
public void onStart() {
if (mBluetoothEnabler != null) {
mBluetoothEnabler.resume(mContext);
}
}
@Override
public void onStop() {
if (mBluetoothEnabler != null) {
mBluetoothEnabler.pause();
}
}
@Override
public void onSummaryChanged(String summary) {
if (mBtPreference != null) {
mBtPreference.setSummary(summary);
}
}
}

View File

@@ -45,6 +45,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.LinkifyUtils;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.bluetooth.BluetoothSummaryHelper.OnSummaryChangeListener;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.location.ScanningSettings;
import com.android.settings.search.BaseSearchIndexProvider;
@@ -52,13 +53,12 @@ import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.widget.FooterPreference;
import com.android.settings.widget.SwitchBar;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settings.widget.SwitchBarController;
import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Set;
@@ -148,7 +148,8 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitchBar = activity.getSwitchBar();
mBluetoothEnabler = new BluetoothEnabler(activity, mSwitchBar, mMetricsFeatureProvider);
mBluetoothEnabler = new BluetoothEnabler(activity, new SwitchBarController(mSwitchBar),
mMetricsFeatureProvider, Utils.getLocalBtManager(activity));
mBluetoothEnabler.setupSwitchBar();
}
@@ -508,112 +509,34 @@ public final class BluetoothSettings extends DeviceListPreferenceFragment implem
}
@VisibleForTesting
static class SummaryProvider
implements SummaryLoader.SummaryProvider, BluetoothCallback {
static class SummaryProvider implements SummaryLoader.SummaryProvider, OnSummaryChangeListener {
private final LocalBluetoothManager mBluetoothManager;
private final Context mContext;
private final SummaryLoader mSummaryLoader;
private boolean mEnabled;
private int mConnectionState;
@VisibleForTesting
BluetoothSummaryHelper mSummaryHelper;
public SummaryProvider(Context context, SummaryLoader summaryLoader,
LocalBluetoothManager bluetoothManager) {
mBluetoothManager = bluetoothManager;
mContext = context;
mSummaryLoader = summaryLoader;
mSummaryHelper = new BluetoothSummaryHelper(mContext, mBluetoothManager);
mSummaryHelper.setOnSummaryChangeListener(this);
}
@Override
public void setListening(boolean listening) {
BluetoothAdapter defaultAdapter = BluetoothAdapter.getDefaultAdapter();
if (defaultAdapter == null) return;
if (listening) {
mEnabled = defaultAdapter.isEnabled();
mConnectionState = defaultAdapter.getConnectionState();
mSummaryLoader.setSummary(this, getSummary());
mBluetoothManager.getEventManager().registerCallback(this);
} else {
mBluetoothManager.getEventManager().unregisterCallback(this);
}
}
private CharSequence getSummary() {
if (!mEnabled) {
return mContext.getString(R.string.bluetooth_disabled);
} else if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
return mContext.getString(R.string.bluetooth_connected);
} else {
return mContext.getString(R.string.bluetooth_disconnected);
}
mSummaryHelper.setListening(listening);
}
@Override
public void onBluetoothStateChanged(int bluetoothState) {
mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
|| bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
mSummaryLoader.setSummary(this, getSummary());
public void onSummaryChanged(String summary) {
if (mSummaryLoader != null) {
mSummaryLoader.setSummary(this, summary);
}
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
mConnectionState = state;
updateConnected();
mSummaryLoader.setSummary(this, getSummary());
}
@Override
public void onScanningStateChanged(boolean started) {
}
@Override
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
}
@Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
}
private void updateConnected() {
// Make sure our connection state is up to date.
int state = mBluetoothManager.getBluetoothAdapter().getConnectionState();
if (state != mConnectionState) {
mConnectionState = state;
return;
}
final Collection<CachedBluetoothDevice> devices = getDevices();
if (devices == null) {
mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
return;
}
if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
CachedBluetoothDevice connectedDevice = null;
for (CachedBluetoothDevice device : devices) {
if (device.isConnected()) {
connectedDevice = device;
}
}
if (connectedDevice == null) {
// If somehow we think we are connected, but have no connected devices, we
// aren't connected.
mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
}
}
}
private Collection<CachedBluetoothDevice> getDevices() {
return mBluetoothManager != null
? mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
: null;
}
}

View File

@@ -0,0 +1,172 @@
/*
* 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.settings.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import java.util.Collection;
/**
* Helper class that listeners to bluetooth callback and notify client when there is update in
* bluetooth summary info.
*/
public final class BluetoothSummaryHelper implements BluetoothCallback {
private OnSummaryChangeListener mListener;
private final LocalBluetoothManager mBluetoothManager;
private final LocalBluetoothAdapter mBluetoothAdapter;
private final Context mContext;
private boolean mEnabled;
private int mConnectionState;
private String mSummary;
public interface OnSummaryChangeListener {
/**
* Called when bluetooth summary has changed.
*
* @param summary The new bluetooth summary .
*/
void onSummaryChanged(String summary);
}
public BluetoothSummaryHelper(Context context, LocalBluetoothManager bluetoothManager) {
mContext = context;
mBluetoothManager = bluetoothManager;
mBluetoothAdapter = mBluetoothManager != null
? mBluetoothManager.getBluetoothAdapter() : null;
}
@Override
public void onBluetoothStateChanged(int bluetoothState) {
mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
|| bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
notifyChangeIfNeeded();
}
@Override
public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
mConnectionState = state;
updateConnected();
notifyChangeIfNeeded();
}
@Override
public void onScanningStateChanged(boolean started) {
}
@Override
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
}
@Override
public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
}
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
}
public void setOnSummaryChangeListener(OnSummaryChangeListener listener) {
mListener = listener;
}
public void setListening(boolean listening) {
if (mBluetoothAdapter == null) {
return;
}
if (listening) {
mEnabled = mBluetoothAdapter.isEnabled();
mConnectionState = mBluetoothAdapter.getConnectionState();
notifyChangeIfNeeded();
mBluetoothManager.getEventManager().registerCallback(this);
} else {
mBluetoothManager.getEventManager().unregisterCallback(this);
}
}
private void notifyChangeIfNeeded() {
String summary = getSummary();
if (!TextUtils.equals(mSummary, summary)) {
mSummary = summary;
if (mListener != null) {
mListener.onSummaryChanged(summary);
}
}
}
private String getSummary() {
if (!mEnabled) {
return mContext.getString(R.string.bluetooth_disabled);
}
switch (mConnectionState) {
case BluetoothAdapter.STATE_CONNECTED:
return mContext.getString(R.string.bluetooth_connected);
case BluetoothAdapter.STATE_CONNECTING:
return mContext.getString(R.string.bluetooth_connecting);
case BluetoothAdapter.STATE_DISCONNECTING:
return mContext.getString(R.string.bluetooth_disconnecting);
default:
return mContext.getString(R.string.bluetooth_disconnected);
}
}
private void updateConnected() {
if (mBluetoothAdapter == null) {
return;
}
// Make sure our connection state is up to date.
int state = mBluetoothAdapter.getConnectionState();
if (state != mConnectionState) {
mConnectionState = state;
return;
}
final Collection<CachedBluetoothDevice> devices = getDevices();
if (devices == null) {
mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
return;
}
if (mConnectionState == BluetoothAdapter.STATE_CONNECTED) {
CachedBluetoothDevice connectedDevice = null;
for (CachedBluetoothDevice device : devices) {
if (device.isConnected()) {
connectedDevice = device;
break;
}
}
if (connectedDevice == null) {
// If somehow we think we are connected, but have no connected devices, we
// aren't connected.
mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
}
}
}
private Collection<CachedBluetoothDevice> getDevices() {
return mBluetoothManager != null
? mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
: null;
}
}

View File

@@ -20,7 +20,10 @@ import android.provider.SearchIndexableResource;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
import com.android.settings.bluetooth.Utils;
import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.deviceinfo.UsbBackend;
import com.android.settings.nfc.NfcPreferenceController;
@@ -37,6 +40,7 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
private static final String TAG = "ConnectedDeviceFrag";
private UsbModePreferenceController mUsbPrefController;
private BluetoothMasterSwitchPreferenceController mBluetoothPreferenceController;
@Override
public int getMetricsCategory() {
@@ -61,13 +65,19 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
@Override
protected List<PreferenceController> getPreferenceControllers(Context context) {
final List<PreferenceController> controllers = new ArrayList<>();
final Lifecycle lifecycle = getLifecycle();
final NfcPreferenceController nfcPreferenceController =
new NfcPreferenceController(context);
getLifecycle().addObserver(nfcPreferenceController);
lifecycle.addObserver(nfcPreferenceController);
controllers.add(nfcPreferenceController);
mUsbPrefController = new UsbModePreferenceController(context, new UsbBackend(context));
getLifecycle().addObserver(mUsbPrefController);
lifecycle.addObserver(mUsbPrefController);
controllers.add(mUsbPrefController);
mBluetoothPreferenceController =
new BluetoothMasterSwitchPreferenceController(
context, Utils.getLocalBtManager(context));
lifecycle.addObserver(mBluetoothPreferenceController);
controllers.add(mBluetoothPreferenceController);
return controllers;
}

View File

@@ -0,0 +1,70 @@
/*
* 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.settings.widget;
import android.support.v7.preference.Preference;
/*
* The switch controller that is used to update the switch widget in the MasterSwitchPreference
* layout.
*/
public class MasterSwitchController extends SwitchWidgetController implements
Preference.OnPreferenceChangeListener {
private final MasterSwitchPreference mPreference;
public MasterSwitchController(MasterSwitchPreference preference) {
mPreference = preference;
}
@Override
public void updateTitle(boolean isChecked) {
}
@Override
public void startListening() {
mPreference.setOnPreferenceChangeListener(this);
}
@Override
public void stopListening() {
mPreference.setOnPreferenceChangeListener(null);
}
@Override
public void setChecked(boolean checked) {
mPreference.setChecked(checked);
}
@Override
public boolean isChecked() {
return mPreference.isChecked();
}
@Override
public void setEnabled(boolean enabled) {
mPreference.setSwitchEnabled(enabled);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (mListener != null) {
return mListener.onSwitchToggled((Boolean) newValue);
}
return false;
}
}

View File

@@ -0,0 +1,102 @@
/*
* 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.settings.widget;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.widget.CompoundButton;
import android.widget.Switch;
import com.android.settings.R;
/**
* A custom preference that provides inline switch toggle. It has a mandatory field for title, and
* optional fields for icon and sub-text.
*/
public class MasterSwitchPreference extends Preference {
private Switch mSwitch;
private boolean mChecked;
public MasterSwitchPreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public MasterSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public MasterSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MasterSwitchPreference(Context context) {
super(context);
init();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mSwitch = (Switch) holder.itemView.findViewById(R.id.switchWidget);
if (mSwitch != null) {
mSwitch.setChecked(mChecked);
mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton button, boolean isChecked) {
if (!callChangeListener(isChecked)) {
button.setChecked(!isChecked);
} else {
persistBoolean(isChecked);
mChecked = isChecked;
}
}
});
}
}
public boolean isChecked() {
return isEnabled() && mChecked;
}
public void setChecked(boolean checked) {
mChecked = checked;
if (mSwitch != null) {
mSwitch.setChecked(checked);
}
}
public boolean isSwitchEnabled() {
return isEnabled() && mSwitch != null && mSwitch.isEnabled();
}
public void setSwitchEnabled(boolean enabled) {
if (mSwitch != null) {
mSwitch.setEnabled(enabled);
}
}
private void init() {
setWidgetLayoutResource(R.layout.preference_widget_master_switch);
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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.settings.widget;
import android.widget.Switch;
/*
* The switch controller that is used to update the switch widget in the SwitchBar layout.
*/
public class SwitchBarController extends SwitchWidgetController implements
SwitchBar.OnSwitchChangeListener {
private final SwitchBar mSwitchBar;
private final Switch mSwitch;
public SwitchBarController(SwitchBar switchBar) {
mSwitchBar = switchBar;
mSwitch = switchBar.getSwitch();
}
@Override
public void setupView() {
mSwitchBar.show();
}
@Override
public void teardownView() {
mSwitchBar.hide();
}
@Override
public void updateTitle(boolean isChecked) {
mSwitchBar.setTextViewLabel(isChecked);
}
@Override
public void startListening() {
mSwitchBar.addOnSwitchChangeListener(this);
}
@Override
public void stopListening() {
mSwitchBar.removeOnSwitchChangeListener(this);
}
@Override
public void setChecked(boolean checked) {
mSwitch.setChecked(checked);
}
@Override
public boolean isChecked() {
return mSwitch.isChecked();
}
@Override
public void setEnabled(boolean enabled) {
mSwitch.setEnabled(enabled);
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (mListener != null) {
mListener.onSwitchToggled(isChecked);
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.settings.widget;
/*
* A controller class for general switch widget handling. We have different containers that provide
* different forms of switch layout. Provide a centralized control for updating the switch widget.
*/
public abstract class SwitchWidgetController {
protected OnSwitchChangeListener mListener;
public interface OnSwitchChangeListener {
/**
* Called when the checked state of the Switch has changed.
*
* @param isChecked The new checked state of switchView.
*/
boolean onSwitchToggled(boolean isChecked);
}
public void setupView() {
}
public void teardownView() {
}
public void setListener(OnSwitchChangeListener listener) {
mListener = listener;
}
public abstract void updateTitle(boolean isChecked);
public abstract void startListening();
public abstract void stopListening();
public abstract void setChecked(boolean checked);
public abstract boolean isChecked();
public abstract void setEnabled(boolean enabled);
}

View File

@@ -0,0 +1,114 @@
/*
* 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.settings.bluetooth;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.widget.MasterSwitchPreference;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class BluetoothMasterSwitchPreferenceControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private LocalBluetoothManager mBluetoothManager;
@Mock
private PreferenceScreen mScreen;
@Mock
private MasterSwitchPreference mPreference;
private Context mContext;
private BluetoothMasterSwitchPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application.getApplicationContext();
mController = new BluetoothMasterSwitchPreferenceController(mContext, mBluetoothManager);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
}
@Test
public void isAvailable_shouldAlwaysReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void onResume_shouldRegisterCallback() {
mController.onResume();
verify(mBluetoothManager.getEventManager()).registerCallback(any(BluetoothCallback.class));
}
@Test
public void onPause_shouldUnregisterCallback() {
mController.onPause();
verify(mBluetoothManager.getEventManager()).unregisterCallback(
any(BluetoothCallback.class));
}
@Test
public void onStart_shouldRegisterPreferenceChangeListener() {
mController.displayPreference(mScreen);
mController.onStart();
verify(mPreference).setOnPreferenceChangeListener(any(OnPreferenceChangeListener.class));
}
@Test
public void onStop_shouldRegisterPreferenceChangeListener() {
mController.displayPreference(mScreen);
mController.onStart();
mController.onStop();
verify(mPreference).setOnPreferenceChangeListener(null);
}
@Test
public void onSummaryUpdated_shouldUpdatePreferenceSummary() {
mController.displayPreference(mScreen);
mController.onSummaryChanged("test summary");
verify(mPreference).setSummary("test summary");
}
}

View File

@@ -16,14 +16,11 @@
package com.android.settings.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.dashboard.SummaryLoader;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
@@ -34,15 +31,10 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowBluetoothAdapter;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -67,102 +59,27 @@ public class BluetoothSettingsSummaryProviderTest {
}
@Test
public void setListening_shouldUpdateSummary() {
public void setListening_shouldRegister() {
mSummaryProvider.setListening(true);
verify(mBluetoothManager.getEventManager()).registerCallback(mSummaryProvider);
verify(mSummaryLoader).setSummary(eq(mSummaryProvider), anyString());
verify(mBluetoothManager.getEventManager()).registerCallback(
mSummaryProvider.mSummaryHelper);
}
@Test
public void setNotListening_shouldUnregister() {
mSummaryProvider.setListening(false);
verify(mBluetoothManager.getEventManager()).unregisterCallback(mSummaryProvider);
verify(mBluetoothManager.getEventManager()).unregisterCallback(
mSummaryProvider.mSummaryHelper);
}
@Test
public void updateSummary_btDisabled_shouldShowDisabledMessage() {
ShadowBluetoothAdapter.getDefaultAdapter().disable();
mSummaryProvider.setListening(true);
public void onSummaryChanged_shouldSetSummary() {
final String summary = "Bluetooth summary";
mSummaryProvider.onSummaryChanged(summary);
verify(mSummaryLoader).setSummary(mSummaryProvider,
mContext.getString(R.string.bluetooth_disabled));
}
@Test
public void updateSummary_btEnabled_noDevice_shouldShowDisconnectedMessage() {
ShadowBluetoothAdapter.getDefaultAdapter().enable();
mSummaryProvider.setListening(true);
verify(mSummaryLoader).setSummary(mSummaryProvider,
mContext.getString(R.string.bluetooth_disconnected));
}
@Test
public void updateState_btEnabled_noDevice_shouldShowDisconnectedMessage() {
ShadowBluetoothAdapter.getDefaultAdapter().enable();
mSummaryProvider.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_ON);
verify(mSummaryLoader).setSummary(mSummaryProvider,
mContext.getString(R.string.bluetooth_disconnected));
}
@Test
public void updateState_btDisabled_shouldShowDisabledMessage() {
ShadowBluetoothAdapter.getDefaultAdapter().enable();
mSummaryProvider.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_OFF);
verify(mSummaryLoader).setSummary(mSummaryProvider,
mContext.getString(R.string.bluetooth_disabled));
}
@Test
public void updateConnectionState_disconnected_shouldShowDisconnectedMessage() {
ShadowBluetoothAdapter.getDefaultAdapter().enable();
when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
.thenReturn(BluetoothAdapter.STATE_DISCONNECTED);
mSummaryProvider.setListening(true);
mSummaryProvider.onConnectionStateChanged(null /* device */,
BluetoothAdapter.STATE_DISCONNECTED);
verify(mSummaryLoader, times(2)).setSummary(mSummaryProvider,
mContext.getString(R.string.bluetooth_disconnected));
}
@Test
public void updateConnectionState_connected_shouldShowConnectedMessage() {
ShadowBluetoothAdapter.getDefaultAdapter().enable();
when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
.thenReturn(BluetoothAdapter.STATE_CONNECTED);
final List<CachedBluetoothDevice> devices = new ArrayList<>();
devices.add(mock(CachedBluetoothDevice.class));
when(devices.get(0).isConnected()).thenReturn(true);
when(mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy())
.thenReturn(devices);
mSummaryProvider.setListening(true);
mSummaryProvider.onConnectionStateChanged(null /* device */,
BluetoothAdapter.STATE_CONNECTED);
verify(mSummaryLoader).setSummary(mSummaryProvider,
mContext.getString(R.string.bluetooth_connected));
}
@Test
public void updateConnectionState_inconsistentState_shouldShowDisconnectedMessage() {
ShadowBluetoothAdapter.getDefaultAdapter().enable();
when(mBluetoothManager.getBluetoothAdapter().getConnectionState())
.thenReturn(BluetoothAdapter.STATE_CONNECTED);
mSummaryProvider.setListening(true);
mSummaryProvider.onConnectionStateChanged(null /* device */,
BluetoothAdapter.STATE_CONNECTED);
verify(mSummaryLoader, times(2)).setSummary(mSummaryProvider,
mContext.getString(R.string.bluetooth_disconnected));
verify(mSummaryLoader).setSummary(mSummaryProvider, summary);
}
}

View File

@@ -0,0 +1,168 @@
/*
* 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.settings.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowBluetoothAdapter;
import java.util.ArrayList;
import java.util.List;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class BluetoothSummaryHelperTest {
private Context mContext;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private LocalBluetoothManager mBluetoothManager;
@Mock
private LocalBluetoothAdapter mBtAdapter;
private BluetoothSummaryHelper mHelper;
@Mock
private SummaryListener mListener;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mBluetoothManager.getBluetoothAdapter()).thenReturn(mBtAdapter);
when(mBtAdapter.isEnabled()).thenReturn(true);
when(mBtAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_CONNECTED);
mContext = RuntimeEnvironment.application.getApplicationContext();
mHelper = new BluetoothSummaryHelper(mContext, mBluetoothManager);
mHelper.setOnSummaryChangeListener(mListener);
}
@Test
public void setListening_shouldRegisterListener() {
mHelper.setListening(true);
verify(mBluetoothManager.getEventManager()).registerCallback(mHelper);
}
@Test
public void setNotListening_shouldUnregisterListener() {
mHelper.setListening(false);
verify(mBluetoothManager.getEventManager()).unregisterCallback(mHelper);
}
@Test
public void setListening_shouldSendSummaryChange() {
mHelper.setListening(true);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_connected));
}
@Test
public void onBluetoothStateChanged_btDisabled_shouldSendDisabledSummary() {
mHelper.setListening(true);
mHelper.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_disabled));
}
@Test
public void onBluetoothStateChanged_btEnabled_connected_shouldSendConnectedSummary() {
mHelper.setListening(true);
mHelper.onBluetoothStateChanged(BluetoothAdapter.STATE_ON);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_connected));
}
@Test
public void onBluetoothStateChanged_btEnabled_notConnected_shouldSendDisconnectedMessage() {
when(mBtAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_DISCONNECTED);
mHelper.setListening(true);
mHelper.onBluetoothStateChanged(BluetoothAdapter.STATE_TURNING_ON);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_disconnected));
}
@Test
public void onConnectionStateChanged_connected_shouldSendConnectedMessage() {
final List<CachedBluetoothDevice> devices = new ArrayList<>();
devices.add(mock(CachedBluetoothDevice.class));
when(devices.get(0).isConnected()).thenReturn(true);
when(mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy())
.thenReturn(devices);
when(mBtAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_DISCONNECTED);
mHelper.setListening(true);
when(mBtAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_CONNECTED);
mHelper.onConnectionStateChanged(null /* device */, BluetoothAdapter.STATE_CONNECTED);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_connected));
}
@Test
public void onConnectionStateChanged_inconsistentState_shouldSendDisconnectedMessage() {
mHelper.setListening(true);
mHelper.onConnectionStateChanged(null /* device */, BluetoothAdapter.STATE_CONNECTED);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_disconnected));
}
@Test
public void onConnectionStateChanged_connecting_shouldSendConnectingMessage() {
mHelper.setListening(true);
when(mBtAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_CONNECTING);
mHelper.onConnectionStateChanged(null /* device */, BluetoothAdapter.STATE_CONNECTING);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_connecting));
}
@Test
public void onConnectionStateChanged_disconnecting_shouldSendDisconnectingMessage() {
mHelper.setListening(true);
when(mBtAdapter.getConnectionState()).thenReturn(BluetoothAdapter.STATE_DISCONNECTING);
mHelper.onConnectionStateChanged(null /* device */, BluetoothAdapter.STATE_DISCONNECTING);
verify(mListener).onSummaryChanged(mContext.getString(R.string.bluetooth_disconnecting));
}
private class SummaryListener implements BluetoothSummaryHelper.OnSummaryChangeListener {
String summary;
@Override
public void onSummaryChanged(String summary) {
this.summary = summary;
}
}
}

View File

@@ -0,0 +1,121 @@
/*
* 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.settings.widget;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.view.LayoutInflater;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Switch;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class MasterSwitchPreferenceTest {
private Context mContext;
@Before
public void setUp() {
mContext = ShadowApplication.getInstance().getApplicationContext();
}
@Test
public void createNewPreference_shouldSetLayout() {
final MasterSwitchPreference preference = new MasterSwitchPreference(mContext);
assertThat(preference.getWidgetLayoutResource()).isEqualTo(
R.layout.preference_widget_master_switch);
}
@Test
public void setChecked_shouldUpdateButtonCheckedState() {
final MasterSwitchPreference preference = new MasterSwitchPreference(mContext);
final PreferenceViewHolder holder = new PreferenceViewHolder(LayoutInflater.from(mContext)
.inflate(R.layout.preference_widget_master_switch, null));
final Switch toggle = (Switch) holder.itemView.findViewById(R.id.switchWidget);
preference.onBindViewHolder(holder);
preference.setChecked(true);
assertThat(toggle.isChecked()).isTrue();
preference.setChecked(false);
assertThat(toggle.isChecked()).isFalse();
}
@Test
public void setSwitchEnabled_shouldUpdateButtonEnabledState() {
final MasterSwitchPreference preference = new MasterSwitchPreference(mContext);
final PreferenceViewHolder holder = new PreferenceViewHolder(
LayoutInflater.from(mContext).inflate(R.layout.preference_widget_master_switch, null));
final Switch toggle = (Switch) holder.itemView.findViewById(R.id.switchWidget);
preference.onBindViewHolder(holder);
preference.setSwitchEnabled(true);
assertThat(toggle.isEnabled()).isTrue();
preference.setSwitchEnabled(false);
assertThat(toggle.isEnabled()).isFalse();
}
@Test
public void toggleButtonOn_shouldNotifyChecked() {
final MasterSwitchPreference preference = new MasterSwitchPreference(mContext);
final PreferenceViewHolder holder = new PreferenceViewHolder(
LayoutInflater.from(mContext).inflate(R.layout.preference_widget_master_switch, null));
final Switch toggle = (Switch) holder.itemView.findViewById(R.id.switchWidget);
final OnPreferenceChangeListener listener = mock(OnPreferenceChangeListener.class);
preference.setOnPreferenceChangeListener(listener);
preference.onBindViewHolder(holder);
toggle.setChecked(true);
verify(listener).onPreferenceChange(preference, true);
}
@Test
public void toggleButtonOff_shouldNotifyUnchecked() {
final MasterSwitchPreference preference = new MasterSwitchPreference(mContext);
final PreferenceViewHolder holder = new PreferenceViewHolder(
LayoutInflater.from(mContext).inflate(R.layout.preference_widget_master_switch, null));
final Switch toggle = (Switch) holder.itemView.findViewById(R.id.switchWidget);
final OnPreferenceChangeListener listener = mock(OnPreferenceChangeListener.class);
preference.setChecked(true);
preference.setOnPreferenceChangeListener(listener);
preference.onBindViewHolder(holder);
toggle.setChecked(false);
verify(listener).onPreferenceChange(preference, false);
}
}