Move BT, NFC out of Conntection pref

Move BT, NFC preference out of Connection Preference,
To Connected devices page.
Because NFC and Android Beam are controlled by the same controller,
Create each controller for those preference and leave the sharing part.

Change-Id: I8bc303a5f487de9c667487119b49e1e4130aa80c
Fixes: 72458929
Test: manually test, make RunSettingsRoboTests
This commit is contained in:
HJ ChangLiao
2018-03-21 16:01:31 +08:00
parent 0a5367c0c4
commit b247311b2a
14 changed files with 718 additions and 262 deletions

View File

@@ -38,9 +38,24 @@
settings:userRestriction="no_config_bluetooth" settings:userRestriction="no_config_bluetooth"
settings:useAdminDisabledSummary="true"/> settings:useAdminDisabledSummary="true"/>
<com.android.settingslib.RestrictedSwitchPreference
android:key="toggle_bluetooth_switch"
android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_pref_summary"
settings:allowDividerAbove="true"
settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"
settings:userRestriction="no_bluetooth"
settings:platform_slice="true"/>
<SwitchPreference
android:key="toggle_nfc"
android:title="@string/nfc_quick_toggle_title"
android:icon="@drawable/ic_nfc"
android:summary="@string/nfc_quick_toggle_summary"/>
<Preference <Preference
android:fragment="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment" android:fragment="com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment"
android:key="connection_preferences" android:key="connection_preferences"
android:title="@string/connected_device_connections_title" android:title="@string/connected_device_connections_title"/>
settings:allowDividerAbove="true"/>
</PreferenceScreen> </PreferenceScreen>

View File

@@ -20,23 +20,6 @@
android:key="connected_devices_advanced_screen" android:key="connected_devices_advanced_screen"
android:title="@string/connected_device_connections_title"> android:title="@string/connected_device_connections_title">
<com.android.settingslib.RestrictedSwitchPreference
android:key="toggle_bluetooth_switch"
android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_pref_summary"
android:order="-7"
settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"
settings:userRestriction="no_bluetooth"
settings:platform_slice="true"/>
<SwitchPreference
android:key="toggle_nfc"
android:title="@string/nfc_quick_toggle_title"
android:icon="@drawable/ic_nfc"
android:summary="@string/nfc_quick_toggle_summary"
android:order="-5"/>
<com.android.settingslib.RestrictedPreference <com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.nfc.AndroidBeam" android:fragment="com.android.settings.nfc.AndroidBeam"
android:key="android_beam_settings" android:key="android_beam_settings"
@@ -63,7 +46,7 @@
<Preference <Preference
android:key="bt_received_files" android:key="bt_received_files"
android:icon="@drawable/ic_folder_vd_theme_24" android:icon="@drawable/ic_folder_vd_theme_24"
android:title="@string/bluetooth_show_received_files" /> android:title="@string/bluetooth_show_received_files"/>
<PreferenceCategory <PreferenceCategory
android:key="dashboard_tile_placeholder" android:key="dashboard_tile_placeholder"

View File

@@ -22,10 +22,8 @@ import android.provider.SearchIndexableResource;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothFilesPreferenceController; import com.android.settings.bluetooth.BluetoothFilesPreferenceController;
import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
import com.android.settings.bluetooth.BluetoothSwitchPreferenceController;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.nfc.NfcPreferenceController; import com.android.settings.nfc.AndroidBeamPreferenceController;
import com.android.settings.print.PrintSettingPreferenceController; import com.android.settings.print.PrintSettingPreferenceController;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
@@ -70,21 +68,19 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
private static List<AbstractPreferenceController> buildControllers(Context context, private static List<AbstractPreferenceController> buildControllers(Context context,
Lifecycle lifecycle) { Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>(); final List<AbstractPreferenceController> controllers = new ArrayList<>();
final NfcPreferenceController nfcPreferenceController =
new NfcPreferenceController(context); final AndroidBeamPreferenceController beamPreferenceController =
controllers.add(nfcPreferenceController); new AndroidBeamPreferenceController(context);
final BluetoothSwitchPreferenceController bluetoothPreferenceController = controllers.add(beamPreferenceController);
new BluetoothSwitchPreferenceController(context);
controllers.add(bluetoothPreferenceController);
controllers.add(new BluetoothFilesPreferenceController(context)); controllers.add(new BluetoothFilesPreferenceController(context));
controllers.add(new BluetoothOnWhileDrivingPreferenceController(context)); controllers.add(new BluetoothOnWhileDrivingPreferenceController(context));
final PrintSettingPreferenceController printerController = final PrintSettingPreferenceController printerController =
new PrintSettingPreferenceController(context); new PrintSettingPreferenceController(context);
if (lifecycle != null) { if (lifecycle != null) {
lifecycle.addObserver(beamPreferenceController);
lifecycle.addObserver(printerController); lifecycle.addObserver(printerController);
lifecycle.addObserver(nfcPreferenceController);
lifecycle.addObserver(bluetoothPreferenceController);
} }
controllers.add(printerController); controllers.add(printerController);
@@ -109,10 +105,8 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
final List<String> keys = super.getNonIndexableKeys(context); final List<String> keys = super.getNonIndexableKeys(context);
PackageManager pm = context.getPackageManager(); PackageManager pm = context.getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
keys.add(NfcPreferenceController.KEY_TOGGLE_NFC); keys.add(AndroidBeamPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
keys.add(NfcPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
} }
keys.add(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH);
return keys; return keys;
} }

View File

@@ -17,11 +17,14 @@ package com.android.settings.connecteddevice;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothSwitchPreferenceController;
import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.SummaryLoader; import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.nfc.NfcPreferenceController; import com.android.settings.nfc.NfcPreferenceController;
@@ -73,6 +76,19 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
controllers.add(new ConnectedDeviceGroupController(context, dashboardFragment, lifecycle)); controllers.add(new ConnectedDeviceGroupController(context, dashboardFragment, lifecycle));
controllers.add(new SavedDeviceGroupController(context, dashboardFragment, lifecycle)); controllers.add(new SavedDeviceGroupController(context, dashboardFragment, lifecycle));
final NfcPreferenceController nfcPreferenceController =
new NfcPreferenceController(context);
controllers.add(nfcPreferenceController);
final BluetoothSwitchPreferenceController bluetoothPreferenceController =
new BluetoothSwitchPreferenceController(context);
controllers.add(bluetoothPreferenceController);
if (lifecycle != null) {
lifecycle.addObserver(nfcPreferenceController);
lifecycle.addObserver(bluetoothPreferenceController);
}
return controllers; return controllers;
} }

View File

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2018 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.nfc;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
/**
* AndroidBeanEnabler is a helper to manage the Android Beam preference. It turns on/off
* Android Beam and ensures the summary of the preference reflects the current state.
*/
public class AndroidBeamEnabler extends BaseNfcEnabler {
private final boolean mBeamDisallowedBySystem;
private final RestrictedPreference mPreference;
public AndroidBeamEnabler(Context context, RestrictedPreference preference) {
super(context);
mPreference = preference;
mBeamDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(context,
UserManager.DISALLOW_OUTGOING_BEAM, UserHandle.myUserId());
if (!isNfcAvailable()) {
// NFC is not supported
mPreference.setEnabled(false);
return;
}
if (mBeamDisallowedBySystem) {
mPreference.setEnabled(false);
}
}
@Override
protected void handleNfcStateChanged(int newState) {
switch (newState) {
case NfcAdapter.STATE_OFF:
mPreference.setEnabled(false);
mPreference.setSummary(R.string.android_beam_disabled_summary);
break;
case NfcAdapter.STATE_ON:
if (mBeamDisallowedBySystem) {
mPreference.setDisabledByAdmin(null);
mPreference.setEnabled(false);
} else {
mPreference.checkRestrictionAndSetDisabled(UserManager.DISALLOW_OUTGOING_BEAM);
}
if (mNfcAdapter.isNdefPushEnabled() && mPreference.isEnabled()) {
mPreference.setSummary(R.string.android_beam_on_summary);
} else {
mPreference.setSummary(R.string.android_beam_off_summary);
}
break;
case NfcAdapter.STATE_TURNING_ON:
mPreference.setEnabled(false);
break;
case NfcAdapter.STATE_TURNING_OFF:
mPreference.setEnabled(false);
break;
}
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2018 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.nfc;
import android.content.Context;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
public class AndroidBeamPreferenceController extends BaseNfcPreferenceController {
public static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings";
public AndroidBeamPreferenceController(Context context) {
super(context);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (!isAvailable()) {
return;
}
mNfcEnabler = new AndroidBeamEnabler(mContext, (RestrictedPreference) mPreference);
}
@Override
public String getPreferenceKey() {
return KEY_ANDROID_BEAM_SETTINGS;
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2018 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.nfc;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.support.v7.preference.Preference;
/**
* BaseNfcEnabler is a abstract helper to manage the Nfc state for Nfc and Android Beam
* preference. It will receive intent and update state to ensure preference show correct state.
*/
public abstract class BaseNfcEnabler {
private final Context mContext;
protected final NfcAdapter mNfcAdapter;
private final IntentFilter mIntentFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_ADAPTER_STATE_CHANGED.equals(action)) {
handleNfcStateChanged(intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
NfcAdapter.STATE_OFF));
}
}
};
public BaseNfcEnabler(Context context) {
mContext = context;
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
if (!isNfcAvailable()) {
// NFC is not supported
mIntentFilter = null;
return;
}
mIntentFilter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
}
public void resume() {
if (!isNfcAvailable()) {
return;
}
handleNfcStateChanged(mNfcAdapter.getAdapterState());
mContext.registerReceiver(mReceiver, mIntentFilter);
}
public void pause() {
if (!isNfcAvailable()) {
return;
}
mContext.unregisterReceiver(mReceiver);
}
public boolean isNfcAvailable() {
return mNfcAdapter != null;
}
protected abstract void handleNfcStateChanged(int newState);
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright (C) 2018 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.nfc;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.nfc.NfcManager;
import android.os.Handler;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import java.util.List;
public abstract class BaseNfcPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause {
protected BaseNfcEnabler mNfcEnabler;
private NfcAdapter mNfcAdapter;
private int mAirplaneMode;
private AirplaneModeObserver mAirplaneModeObserver;
protected Preference mPreference;
public BaseNfcPreferenceController(Context context) {
super(context);
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (!isAvailable()) {
mNfcEnabler = null;
return;
}
mPreference = screen.findPreference(getPreferenceKey());
// Manually set dependencies for NFC when not toggleable.
if (!isToggleableInAirplaneMode(mContext)) {
mAirplaneModeObserver = new AirplaneModeObserver();
updateNfcPreference();
}
}
@Override
public void updateNonIndexableKeys(List<String> keys) {
if (isAvailable()) {
keys.add(getPreferenceKey());
}
}
@Override
public boolean isAvailable() {
return mNfcAdapter != null;
}
public abstract String getPreferenceKey();
@Override
public void onResume() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.register();
}
if (mNfcEnabler != null) {
mNfcEnabler.resume();
}
}
@Override
public void onPause() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.unregister();
}
if (mNfcEnabler != null) {
mNfcEnabler.pause();
}
}
private void updateNfcPreference() {
final int airplaneMode = Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, mAirplaneMode);
if (airplaneMode == mAirplaneMode) {
return;
}
mAirplaneMode = airplaneMode;
boolean toggleable = mAirplaneMode != 1;
if (toggleable) {
mNfcAdapter.enable();
} else {
mNfcAdapter.disable();
}
mPreference.setEnabled(toggleable);
}
public static boolean isToggleableInAirplaneMode(Context context) {
String toggleable = Settings.Global.getString(context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
return toggleable != null && toggleable.contains(Settings.Global.RADIO_NFC);
}
private final class AirplaneModeObserver extends ContentObserver {
private final Uri AIRPLANE_MODE_URI =
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
private AirplaneModeObserver() {
super(new Handler());
}
public void register() {
mContext.getContentResolver().registerContentObserver(AIRPLANE_MODE_URI, false, this);
}
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
updateNfcPreference();
}
}
}

View File

@@ -16,90 +16,44 @@
package com.android.settings.nfc; package com.android.settings.nfc;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter; import android.nfc.NfcAdapter;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen; import android.support.v14.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
/** /**
* NfcEnabler is a helper to manage the Nfc on/off checkbox preference. It is * NfcEnabler is a helper to manage the Nfc on/off checkbox preference. It turns on/off Nfc
* turns on/off Nfc and ensures the summary of the preference reflects the * and ensures the summary of the preference reflects the current state.
* current state.
*/ */
public class NfcEnabler implements Preference.OnPreferenceChangeListener { public class NfcEnabler extends BaseNfcEnabler implements Preference.OnPreferenceChangeListener {
private final Context mContext; private final SwitchPreference mPreference;
private final SwitchPreference mSwitch;
private final RestrictedPreference mAndroidBeam;
private final NfcAdapter mNfcAdapter;
private final IntentFilter mIntentFilter;
private boolean mBeamDisallowedBySystem;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public NfcEnabler(Context context, SwitchPreference preference) {
@Override super(context);
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (NfcAdapter.ACTION_ADAPTER_STATE_CHANGED.equals(action)) {
handleNfcStateChanged(intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
NfcAdapter.STATE_OFF));
}
}
};
public NfcEnabler(Context context, SwitchPreference switchPreference, mPreference = preference;
RestrictedPreference androidBeam) {
mContext = context;
mSwitch = switchPreference;
mAndroidBeam = androidBeam;
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
mBeamDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(context,
UserManager.DISALLOW_OUTGOING_BEAM, UserHandle.myUserId());
if (mNfcAdapter == null) {
// NFC is not supported
mSwitch.setEnabled(false);
mAndroidBeam.setEnabled(false);
mIntentFilter = null;
return;
}
if (mBeamDisallowedBySystem) {
mAndroidBeam.setEnabled(false);
}
mIntentFilter = new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
} }
public void resume() { public void resume() {
if (mNfcAdapter == null) { super.resume();
return; if (isNfcAvailable()) {
mPreference.setOnPreferenceChangeListener(this);
} }
handleNfcStateChanged(mNfcAdapter.getAdapterState());
mContext.registerReceiver(mReceiver, mIntentFilter);
mSwitch.setOnPreferenceChangeListener(this);
} }
public void pause() { public void pause() {
if (mNfcAdapter == null) { super.pause();
return; if (isNfcAvailable()) {
mPreference.setOnPreferenceChangeListener(null);
} }
mContext.unregisterReceiver(mReceiver);
mSwitch.setOnPreferenceChangeListener(null);
} }
public boolean onPreferenceChange(Preference preference, Object value) { public boolean onPreferenceChange(Preference preference, Object value) {
// Turn NFC on/off // Turn NFC on/off
final boolean desiredState = (Boolean) value; final boolean desiredState = (Boolean) value;
mSwitch.setChecked(desiredState); mPreference.setChecked(desiredState);
mSwitch.setEnabled(false); mPreference.setEnabled(false);
if (desiredState) { if (desiredState) {
mNfcAdapter.enable(); mNfcAdapter.enable();
@@ -110,39 +64,25 @@ public class NfcEnabler implements Preference.OnPreferenceChangeListener {
return false; return false;
} }
private void handleNfcStateChanged(int newState) { @Override
protected void handleNfcStateChanged(int newState) {
switch (newState) { switch (newState) {
case NfcAdapter.STATE_OFF: case NfcAdapter.STATE_OFF:
mSwitch.setChecked(false); mPreference.setChecked(false);
mSwitch.setEnabled(true); mPreference.setEnabled(true);
mAndroidBeam.setEnabled(false); break;
mAndroidBeam.setSummary(R.string.android_beam_disabled_summary); case NfcAdapter.STATE_ON:
break; mPreference.setChecked(true);
case NfcAdapter.STATE_ON: mPreference.setEnabled(true);
mSwitch.setChecked(true); break;
mSwitch.setEnabled(true); case NfcAdapter.STATE_TURNING_ON:
if (mBeamDisallowedBySystem) { mPreference.setChecked(true);
mAndroidBeam.setDisabledByAdmin(null); mPreference.setEnabled(false);
mAndroidBeam.setEnabled(false); break;
} else { case NfcAdapter.STATE_TURNING_OFF:
mAndroidBeam.checkRestrictionAndSetDisabled(UserManager.DISALLOW_OUTGOING_BEAM); mPreference.setChecked(false);
} mPreference.setEnabled(false);
if (mNfcAdapter.isNdefPushEnabled() && mAndroidBeam.isEnabled()) { break;
mAndroidBeam.setSummary(R.string.android_beam_on_summary);
} else {
mAndroidBeam.setSummary(R.string.android_beam_off_summary);
}
break;
case NfcAdapter.STATE_TURNING_ON:
mSwitch.setChecked(true);
mSwitch.setEnabled(false);
mAndroidBeam.setEnabled(false);
break;
case NfcAdapter.STATE_TURNING_OFF:
mSwitch.setChecked(false);
mSwitch.setEnabled(false);
mAndroidBeam.setEnabled(false);
break;
} }
} }
} }

View File

@@ -16,146 +16,35 @@
package com.android.settings.nfc; package com.android.settings.nfc;
import android.content.Context; import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.nfc.NfcManager;
import android.os.Handler;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.support.v14.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.core.lifecycle.events.OnResume;
import java.util.List;
public class NfcPreferenceController extends AbstractPreferenceController public class NfcPreferenceController extends BaseNfcPreferenceController {
implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause {
public static final String KEY_TOGGLE_NFC = "toggle_nfc"; public static final String KEY_TOGGLE_NFC = "toggle_nfc";
public static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings";
private NfcEnabler mNfcEnabler;
private NfcAdapter mNfcAdapter;
private int mAirplaneMode;
private AirplaneModeObserver mAirplaneModeObserver;
private SwitchPreference mNfcPreference;
private RestrictedPreference mBeamPreference;
public NfcPreferenceController(Context context) { public NfcPreferenceController(Context context) {
super(context); super(context);
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
} }
@Override @Override
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (!isAvailable()) { if (!isAvailable()) {
setVisible(screen, KEY_TOGGLE_NFC, false /* visible */);
setVisible(screen, KEY_ANDROID_BEAM_SETTINGS, false /* visible */);
mNfcEnabler = null;
return; return;
} }
mNfcPreference = (SwitchPreference) screen.findPreference(KEY_TOGGLE_NFC);
mBeamPreference = (RestrictedPreference) screen.findPreference(
KEY_ANDROID_BEAM_SETTINGS);
mNfcEnabler = new NfcEnabler(mContext, mNfcPreference, mBeamPreference);
// Manually set dependencies for NFC when not toggleable.
if (!isToggleableInAirplaneMode(mContext)) {
mAirplaneModeObserver = new AirplaneModeObserver();
updateNfcPreference();
}
}
@Override mNfcEnabler = new NfcEnabler(mContext, (SwitchPreference) mPreference);
public void updateNonIndexableKeys(List<String> keys) {
final NfcManager manager = (NfcManager) mContext.getSystemService(Context.NFC_SERVICE);
if (manager != null) {
NfcAdapter adapter = manager.getDefaultAdapter();
if (adapter == null) {
keys.add(KEY_TOGGLE_NFC);
keys.add(KEY_ANDROID_BEAM_SETTINGS);
}
}
}
@Override
public boolean isAvailable() {
return mNfcAdapter != null;
} }
@Override @Override
public String getPreferenceKey() { public String getPreferenceKey() {
return null; return KEY_TOGGLE_NFC;
} }
public void onResume() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.register();
}
if (mNfcEnabler != null) {
mNfcEnabler.resume();
}
}
@Override
public void onPause() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.unregister();
}
if (mNfcEnabler != null) {
mNfcEnabler.pause();
}
}
private void updateNfcPreference() {
final int airplaneMode = Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, mAirplaneMode);
if (airplaneMode == mAirplaneMode) {
return;
}
mAirplaneMode = airplaneMode;
boolean toggleable = mAirplaneMode != 1;
if (toggleable) {
mNfcAdapter.enable();
} else {
mNfcAdapter.disable();
}
mNfcPreference.setEnabled(toggleable);
mBeamPreference.setEnabled(toggleable);
}
public static boolean isToggleableInAirplaneMode(Context context) {
String toggleable = Settings.Global.getString(context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
return toggleable != null && toggleable.contains(Settings.Global.RADIO_NFC);
}
private final class AirplaneModeObserver extends ContentObserver {
private final Uri AIRPLANE_MODE_URI =
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
private AirplaneModeObserver() {
super(new Handler());
}
public void register() {
mContext.getContentResolver().registerContentObserver(AIRPLANE_MODE_URI, false, this);
}
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
updateNfcPreference();
}
}
} }

View File

@@ -16,13 +16,10 @@
package com.android.settings.connecteddevice; package com.android.settings.connecteddevice;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
;
import android.content.Context;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowBluetoothPan; import com.android.settings.testutils.shadow.ShadowBluetoothPan;
import com.android.settings.testutils.shadow.ShadowConnectivityManager; import com.android.settings.testutils.shadow.ShadowConnectivityManager;
import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUserManager;
@@ -59,8 +56,8 @@ public class AdvancedConnectedDeviceDashboardFragmentTest {
@Test @Test
public void testSearchIndexProvider_shouldIndexResource() { public void testSearchIndexProvider_shouldIndexResource() {
final List<SearchIndexableResource> indexRes = final List<SearchIndexableResource> indexRes =
AdvancedConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER AdvancedConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getXmlResourcesToIndex(RuntimeEnvironment.application, true /* enabled */); .getXmlResourcesToIndex(RuntimeEnvironment.application, true /* enabled */);
assertThat(indexRes).isNotNull(); assertThat(indexRes).isNotNull();
assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId()); assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
@@ -70,14 +67,4 @@ public class AdvancedConnectedDeviceDashboardFragmentTest {
public void testGetCategoryKey_returnCategoryDevice() { public void testGetCategoryKey_returnCategoryDevice() {
assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_DEVICE); assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_DEVICE);
} }
@Test
public void testNonIndexableKeys_existInXmlLayout() {
final Context context = RuntimeEnvironment.application;
final List<String> niks =
AdvancedConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(context);
assertThat(niks).contains(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH);
}
} }

View File

@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.nfc.NfcPreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowBluetoothPan; import com.android.settings.testutils.shadow.ShadowBluetoothPan;
import com.android.settings.testutils.shadow.ShadowConnectivityManager; import com.android.settings.testutils.shadow.ShadowConnectivityManager;
@@ -77,6 +78,7 @@ public class ConnectedDeviceDashboardFragmentTest {
final List<String> niks = ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER final List<String> niks = ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER
.getNonIndexableKeys(mContext); .getNonIndexableKeys(mContext);
assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_SAVED_DEVICES); assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_SAVED_DEVICES,
NfcPreferenceController.KEY_TOGGLE_NFC);
} }
} }

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2018 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.nfc;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.nfc.NfcManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class AndroidBeamPreferenceControllerTest {
Context mContext;
@Mock
private NfcAdapter mNfcAdapter;
@Mock
NfcManager mManager;
@Mock
private UserManager mUserManager;
@Mock
private PreferenceScreen mScreen;
private RestrictedPreference mAndroidBeamPreference;
private AndroidBeamPreferenceController mAndroidBeamController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getApplicationContext()).thenReturn(mContext);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mContext.getSystemService(Context.NFC_SERVICE)).thenReturn(mManager);
when(RestrictedLockUtils.hasBaseUserRestriction(mContext,
UserManager.DISALLOW_OUTGOING_BEAM, UserHandle.myUserId())).thenReturn(false);
when(NfcAdapter.getDefaultAdapter(mContext)).thenReturn(mNfcAdapter);
mAndroidBeamController = new AndroidBeamPreferenceController(mContext);
mAndroidBeamPreference = new RestrictedPreference(RuntimeEnvironment.application);
when(mScreen.findPreference(mAndroidBeamController.getPreferenceKey())).thenReturn(
mAndroidBeamPreference);
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
Settings.Global.RADIO_NFC);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON,
0);
mAndroidBeamController.displayPreference(mScreen);
}
@Test
public void isAvailable_hasNfc_shouldReturnTrue() {
when(mNfcAdapter.isEnabled()).thenReturn(true);
assertThat(mAndroidBeamController.isAvailable()).isTrue();
}
@Test
public void isAvailable_noNfcAdapter_shouldReturnFalse() {
ReflectionHelpers.setField(mAndroidBeamController, "mNfcAdapter", null);
assertThat(mAndroidBeamController.isAvailable()).isFalse();
}
@Test
public void isBeamEnable_disAllowBeam_shouldReturnFalse() {
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_OFF);
when(RestrictedLockUtils.hasBaseUserRestriction(mContext,
UserManager.DISALLOW_OUTGOING_BEAM, UserHandle.myUserId())).thenReturn(true);
mAndroidBeamController.displayPreference(mScreen);
assertThat(mAndroidBeamPreference.isEnabled()).isFalse();
}
@Test
public void isBeamEnable_nfcStateOn_shouldReturnTrue() {
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_ON);
try {
mAndroidBeamController.onResume();
} catch (NullPointerException e) {
// skip because it's just test
// it will meet NullPointerException in checkRestrictionAndSetDisabled
}
assertThat(mAndroidBeamPreference.isEnabled()).isTrue();
}
@Test
public void isBeamEnable_nfcStateNotOn_shouldReturnFalse() {
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_OFF);
mAndroidBeamController.onResume();
assertThat(mAndroidBeamPreference.isEnabled()).isFalse();
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_TURNING_ON);
mAndroidBeamController.onResume();
assertThat(mAndroidBeamPreference.isEnabled()).isFalse();
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_TURNING_OFF);
mAndroidBeamController.onResume();
assertThat(mAndroidBeamPreference.isEnabled()).isFalse();
}
}

View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2018 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.nfc;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.nfc.NfcManager;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
public class NfcPreferenceControllerTest {
Context mContext;
@Mock
private NfcAdapter mNfcAdapter;
@Mock
NfcManager mManager;
@Mock
private UserManager mUserManager;
@Mock
private PreferenceScreen mScreen;
private SwitchPreference mNfcPreference;
private NfcPreferenceController mNfcController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getApplicationContext()).thenReturn(mContext);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mContext.getSystemService(Context.NFC_SERVICE)).thenReturn(mManager);
when(NfcAdapter.getDefaultAdapter(mContext)).thenReturn(mNfcAdapter);
mNfcController = new NfcPreferenceController(mContext);
mNfcPreference = new SwitchPreference(RuntimeEnvironment.application);
when(mScreen.findPreference(mNfcController.getPreferenceKey())).thenReturn(mNfcPreference);
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
Settings.Global.RADIO_NFC);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON,
0);
mNfcController.displayPreference(mScreen);
}
@Test
public void isAvailable_hasNfc_shouldReturnTrue() {
when(mNfcAdapter.isEnabled()).thenReturn(true);
assertThat(mNfcController.isAvailable()).isTrue();
}
@Test
public void isAvailable_noNfcAdapter_shouldReturnFalse() {
ReflectionHelpers.setField(mNfcController, "mNfcAdapter", null);
assertThat(mNfcController.isAvailable()).isFalse();
}
@Test
public void isNfcEnable_nfcStateNotTurning_shouldReturnTrue() {
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_ON);
mNfcController.onResume();
assertThat(mNfcPreference.isEnabled()).isTrue();
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_OFF);
mNfcController.onResume();
assertThat(mNfcPreference.isEnabled()).isTrue();
}
@Test
public void isNfcEnable_nfcStateTurning_shouldReturnFalse() {
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_TURNING_ON);
mNfcController.onResume();
assertThat(mNfcPreference.isEnabled()).isFalse();
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_TURNING_OFF);
mNfcController.onResume();
assertThat(mNfcPreference.isEnabled()).isFalse();
}
@Test
public void isNfcChecked_nfcStateOn_shouldReturnTrue() {
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_ON);
mNfcController.onResume();
assertThat(mNfcPreference.isChecked()).isTrue();
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_TURNING_ON);
mNfcController.onResume();
assertThat(mNfcPreference.isChecked()).isTrue();
}
@Test
public void isNfcChecked_nfcStateOff_shouldReturnFalse() {
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_OFF);
mNfcController.onResume();
assertThat(mNfcPreference.isChecked()).isFalse();
when(mNfcAdapter.getAdapterState()).thenReturn(NfcAdapter.STATE_TURNING_OFF);
mNfcController.onResume();
assertThat(mNfcPreference.isChecked()).isFalse();
}
}