diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml index 9b84a434d8e..66f95581b5b 100644 --- a/res/xml/connected_devices.xml +++ b/res/xml/connected_devices.xml @@ -38,9 +38,24 @@ settings:userRestriction="no_config_bluetooth" settings:useAdminDisabledSummary="true"/> + + + + + android:title="@string/connected_device_connections_title"/> diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml index 72cd2379bfa..1917df1ae92 100644 --- a/res/xml/connected_devices_advanced.xml +++ b/res/xml/connected_devices_advanced.xml @@ -20,23 +20,6 @@ android:key="connected_devices_advanced_screen" android:title="@string/connected_device_connections_title"> - - - - + android:title="@string/bluetooth_show_received_files"/> buildControllers(Context context, Lifecycle lifecycle) { final List controllers = new ArrayList<>(); - final NfcPreferenceController nfcPreferenceController = - new NfcPreferenceController(context); - controllers.add(nfcPreferenceController); - final BluetoothSwitchPreferenceController bluetoothPreferenceController = - new BluetoothSwitchPreferenceController(context); - controllers.add(bluetoothPreferenceController); + + final AndroidBeamPreferenceController beamPreferenceController = + new AndroidBeamPreferenceController(context); + controllers.add(beamPreferenceController); controllers.add(new BluetoothFilesPreferenceController(context)); controllers.add(new BluetoothOnWhileDrivingPreferenceController(context)); + final PrintSettingPreferenceController printerController = new PrintSettingPreferenceController(context); if (lifecycle != null) { + lifecycle.addObserver(beamPreferenceController); lifecycle.addObserver(printerController); - lifecycle.addObserver(nfcPreferenceController); - lifecycle.addObserver(bluetoothPreferenceController); } controllers.add(printerController); @@ -109,10 +105,8 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment final List keys = super.getNonIndexableKeys(context); PackageManager pm = context.getPackageManager(); if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { - keys.add(NfcPreferenceController.KEY_TOGGLE_NFC); - keys.add(NfcPreferenceController.KEY_ANDROID_BEAM_SETTINGS); + keys.add(AndroidBeamPreferenceController.KEY_ANDROID_BEAM_SETTINGS); } - keys.add(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH); return keys; } diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 4218219533e..ec0671614e2 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -17,11 +17,14 @@ package com.android.settings.connecteddevice; import android.app.Activity; import android.content.Context; +import android.content.pm.PackageManager; import android.provider.SearchIndexableResource; import android.support.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto; 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.SummaryLoader; 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 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; } diff --git a/src/com/android/settings/nfc/AndroidBeamEnabler.java b/src/com/android/settings/nfc/AndroidBeamEnabler.java new file mode 100644 index 00000000000..66e42b64188 --- /dev/null +++ b/src/com/android/settings/nfc/AndroidBeamEnabler.java @@ -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; + } + } +} diff --git a/src/com/android/settings/nfc/AndroidBeamPreferenceController.java b/src/com/android/settings/nfc/AndroidBeamPreferenceController.java new file mode 100644 index 00000000000..6ae7fe5ccf2 --- /dev/null +++ b/src/com/android/settings/nfc/AndroidBeamPreferenceController.java @@ -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; + } +} diff --git a/src/com/android/settings/nfc/BaseNfcEnabler.java b/src/com/android/settings/nfc/BaseNfcEnabler.java new file mode 100644 index 00000000000..5c5f95ca7cb --- /dev/null +++ b/src/com/android/settings/nfc/BaseNfcEnabler.java @@ -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); +} diff --git a/src/com/android/settings/nfc/BaseNfcPreferenceController.java b/src/com/android/settings/nfc/BaseNfcPreferenceController.java new file mode 100644 index 00000000000..b945738eab5 --- /dev/null +++ b/src/com/android/settings/nfc/BaseNfcPreferenceController.java @@ -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 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(); + } + } + +} diff --git a/src/com/android/settings/nfc/NfcEnabler.java b/src/com/android/settings/nfc/NfcEnabler.java index 14ee779bed4..29cef993552 100644 --- a/src/com/android/settings/nfc/NfcEnabler.java +++ b/src/com/android/settings/nfc/NfcEnabler.java @@ -16,90 +16,44 @@ 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.os.UserHandle; -import android.os.UserManager; -import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.RestrictedPreference; +import android.support.v14.preference.SwitchPreference; /** - * NfcEnabler is a helper to manage the Nfc on/off checkbox preference. It is - * turns on/off Nfc and ensures the summary of the preference reflects the - * current state. + * NfcEnabler is a helper to manage the Nfc on/off checkbox preference. It turns on/off Nfc + * and ensures the summary of the preference reflects the current state. */ -public class NfcEnabler implements Preference.OnPreferenceChangeListener { - private final Context mContext; - private final SwitchPreference mSwitch; - private final RestrictedPreference mAndroidBeam; - private final NfcAdapter mNfcAdapter; - private final IntentFilter mIntentFilter; - private boolean mBeamDisallowedBySystem; +public class NfcEnabler extends BaseNfcEnabler implements Preference.OnPreferenceChangeListener { + private final SwitchPreference mPreference; - 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 NfcEnabler(Context context, SwitchPreference preference) { + super(context); - public NfcEnabler(Context context, SwitchPreference switchPreference, - 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); + mPreference = preference; } public void resume() { - if (mNfcAdapter == null) { - return; + super.resume(); + if (isNfcAvailable()) { + mPreference.setOnPreferenceChangeListener(this); } - handleNfcStateChanged(mNfcAdapter.getAdapterState()); - mContext.registerReceiver(mReceiver, mIntentFilter); - mSwitch.setOnPreferenceChangeListener(this); } public void pause() { - if (mNfcAdapter == null) { - return; + super.pause(); + if (isNfcAvailable()) { + mPreference.setOnPreferenceChangeListener(null); } - mContext.unregisterReceiver(mReceiver); - mSwitch.setOnPreferenceChangeListener(null); } public boolean onPreferenceChange(Preference preference, Object value) { // Turn NFC on/off final boolean desiredState = (Boolean) value; - mSwitch.setChecked(desiredState); - mSwitch.setEnabled(false); + mPreference.setChecked(desiredState); + mPreference.setEnabled(false); if (desiredState) { mNfcAdapter.enable(); @@ -110,39 +64,25 @@ public class NfcEnabler implements Preference.OnPreferenceChangeListener { return false; } - private void handleNfcStateChanged(int newState) { + @Override + protected void handleNfcStateChanged(int newState) { switch (newState) { - case NfcAdapter.STATE_OFF: - mSwitch.setChecked(false); - mSwitch.setEnabled(true); - mAndroidBeam.setEnabled(false); - mAndroidBeam.setSummary(R.string.android_beam_disabled_summary); - break; - case NfcAdapter.STATE_ON: - mSwitch.setChecked(true); - mSwitch.setEnabled(true); - if (mBeamDisallowedBySystem) { - mAndroidBeam.setDisabledByAdmin(null); - mAndroidBeam.setEnabled(false); - } else { - mAndroidBeam.checkRestrictionAndSetDisabled(UserManager.DISALLOW_OUTGOING_BEAM); - } - if (mNfcAdapter.isNdefPushEnabled() && mAndroidBeam.isEnabled()) { - 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; + case NfcAdapter.STATE_OFF: + mPreference.setChecked(false); + mPreference.setEnabled(true); + break; + case NfcAdapter.STATE_ON: + mPreference.setChecked(true); + mPreference.setEnabled(true); + break; + case NfcAdapter.STATE_TURNING_ON: + mPreference.setChecked(true); + mPreference.setEnabled(false); + break; + case NfcAdapter.STATE_TURNING_OFF: + mPreference.setChecked(false); + mPreference.setEnabled(false); + break; } } } diff --git a/src/com/android/settings/nfc/NfcPreferenceController.java b/src/com/android/settings/nfc/NfcPreferenceController.java index 76977d24e21..a0678e0afab 100644 --- a/src/com/android/settings/nfc/NfcPreferenceController.java +++ b/src/com/android/settings/nfc/NfcPreferenceController.java @@ -16,146 +16,35 @@ 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.v14.preference.SwitchPreference; import android.support.v7.preference.PreferenceScreen; +import android.support.v14.preference.SwitchPreference; 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.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; -import java.util.List; -public class NfcPreferenceController extends AbstractPreferenceController - implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause { +public class NfcPreferenceController extends BaseNfcPreferenceController { 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) { super(context); - mNfcAdapter = NfcAdapter.getDefaultAdapter(context); } @Override public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); if (!isAvailable()) { - setVisible(screen, KEY_TOGGLE_NFC, false /* visible */); - setVisible(screen, KEY_ANDROID_BEAM_SETTINGS, false /* visible */); - mNfcEnabler = null; 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 - public void updateNonIndexableKeys(List 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; + mNfcEnabler = new NfcEnabler(mContext, (SwitchPreference) mPreference); } @Override 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(); - } - } - } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragmentTest.java index 982de54cd93..2e2dd9d7d3e 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragmentTest.java @@ -16,13 +16,10 @@ package com.android.settings.connecteddevice; import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; +; import android.provider.SearchIndexableResource; -import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController; 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.ShadowConnectivityManager; import com.android.settings.testutils.shadow.ShadowUserManager; @@ -59,8 +56,8 @@ public class AdvancedConnectedDeviceDashboardFragmentTest { @Test public void testSearchIndexProvider_shouldIndexResource() { final List indexRes = - AdvancedConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER - .getXmlResourcesToIndex(RuntimeEnvironment.application, true /* enabled */); + AdvancedConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER + .getXmlResourcesToIndex(RuntimeEnvironment.application, true /* enabled */); assertThat(indexRes).isNotNull(); assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId()); @@ -70,14 +67,4 @@ public class AdvancedConnectedDeviceDashboardFragmentTest { public void testGetCategoryKey_returnCategoryDevice() { assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_DEVICE); } - - @Test - public void testNonIndexableKeys_existInXmlLayout() { - final Context context = RuntimeEnvironment.application; - final List niks = - AdvancedConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER - .getNonIndexableKeys(context); - - assertThat(niks).contains(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH); - } -} +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java index c68771c2fdf..443e885eb4d 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java @@ -30,6 +30,7 @@ import android.content.pm.PackageManager; import android.provider.SearchIndexableResource; import com.android.settings.R; +import com.android.settings.nfc.NfcPreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowBluetoothPan; import com.android.settings.testutils.shadow.ShadowConnectivityManager; @@ -77,6 +78,7 @@ public class ConnectedDeviceDashboardFragmentTest { final List niks = ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER .getNonIndexableKeys(mContext); - assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_SAVED_DEVICES); + assertThat(niks).containsExactly(KEY_CONNECTED_DEVICES, KEY_SAVED_DEVICES, + NfcPreferenceController.KEY_TOGGLE_NFC); } } diff --git a/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java new file mode 100644 index 00000000000..cb18b5abd9e --- /dev/null +++ b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java @@ -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(); + } +} diff --git a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java new file mode 100644 index 00000000000..cd90820b449 --- /dev/null +++ b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java @@ -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(); + } +}