From 211d49f28c31e16c8161b807e16ce25a58d941f2 Mon Sep 17 00:00:00 2001 From: hughchen Date: Fri, 11 May 2018 10:16:32 +0800 Subject: [PATCH 01/31] =?UTF-8?q?Add=20=E2=80=9CRename=20device=E2=80=9D?= =?UTF-8?q?=20on=20Bluetooth=20screen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add BluetoothDeviceRenamePreferenceController in bluetooth_screen.xml * Refactor BluetoothDeviceRenamePreferenceController and BluetoothDeviceNamePreferenceController. Let these controllers can be init in xml. Bug: 78247352 Test: make -j50 RunSettingsRoboTests Change-Id: Iddd0cac1e973bbd82cb30fe4c18e8b359ba4ba2b --- res/xml/bluetooth_pairing_detail.xml | 4 +- res/xml/bluetooth_screen.xml | 6 +++ ...uetoothDeviceNamePreferenceController.java | 34 ++++---------- ...toothDeviceRenamePreferenceController.java | 45 ++++++++----------- .../bluetooth/BluetoothPairingDetail.java | 21 +++------ .../BluetoothDashboardFragment.java | 7 +++ ...othDeviceNamePreferenceControllerTest.java | 8 ++-- ...hDeviceRenamePreferenceControllerTest.java | 5 ++- 8 files changed, 57 insertions(+), 73 deletions(-) diff --git a/res/xml/bluetooth_pairing_detail.xml b/res/xml/bluetooth_pairing_detail.xml index e654a3cfa2b..86fb9e43d44 100644 --- a/res/xml/bluetooth_pairing_detail.xml +++ b/res/xml/bluetooth_pairing_detail.xml @@ -16,12 +16,14 @@ + android:summary="@string/summary_placeholder" + settings:controller="com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController"/> + + createPreferenceControllers(Context context) { - final List controllers = new ArrayList<>(); - controllers.add( - new BluetoothDeviceRenamePreferenceController(context, KEY_RENAME_DEVICES, this, - getLifecycle())); - - return controllers; - } - @Override public String getDeviceListKey() { return KEY_AVAIL_DEVICES; diff --git a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java index 77b75c51de3..3b24271664c 100644 --- a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java @@ -24,6 +24,7 @@ import android.support.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController; import com.android.settings.bluetooth.BluetoothSwitchPreferenceController; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.TogglePreferenceController; @@ -78,6 +79,12 @@ public class BluetoothDashboardFragment extends DashboardFragment { mFooterPreference = mFooterPreferenceMixin.createFooterPreference(); } + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(BluetoothDeviceRenamePreferenceController.class).setFragment(this); + } + @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java index f5070ef34a4..1d37883d65d 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceNamePreferenceControllerTest.java @@ -43,6 +43,7 @@ public class BluetoothDeviceNamePreferenceControllerTest { private static final String DEVICE_NAME = "Nightshade"; private static final int ORDER = 1; + private static final String KEY_DEVICE_NAME = "test_key_name"; private Context mContext; @Mock @@ -61,8 +62,9 @@ public class BluetoothDeviceNamePreferenceControllerTest { when(mPreferenceScreen.getContext()).thenReturn(mContext); mPreference = new Preference(mContext); - mPreference.setKey(BluetoothDeviceNamePreferenceController.KEY_DEVICE_NAME); - mController = spy(new BluetoothDeviceNamePreferenceController(mContext, mLocalAdapter)); + mPreference.setKey(KEY_DEVICE_NAME); + mController = spy(new BluetoothDeviceNamePreferenceController(mContext, mLocalAdapter, + KEY_DEVICE_NAME)); doReturn(DEVICE_NAME).when(mController).getDeviceName(); } @@ -82,7 +84,7 @@ public class BluetoothDeviceNamePreferenceControllerTest { Preference preference = mController.createBluetoothDeviceNamePreference(mPreferenceScreen, ORDER); - assertThat(preference.getKey()).isEqualTo(mController.KEY_DEVICE_NAME); + assertThat(preference.getKey()).isEqualTo(mController.getPreferenceKey()); assertThat(preference.getOrder()).isEqualTo(ORDER); verify(mPreferenceScreen).addPreference(preference); } diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java index 6ba85937277..65eae2c411e 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceControllerTest.java @@ -67,8 +67,9 @@ public class BluetoothDeviceRenamePreferenceControllerTest { mPreference = new Preference(mContext); mPreference.setKey(PREF_KEY); - mController = spy(new BluetoothDeviceRenamePreferenceController( - mContext, PREF_KEY, mFragment, mLocalAdapter)); + mController = spy(new BluetoothDeviceRenamePreferenceController(mContext, mLocalAdapter, + PREF_KEY)); + mController.setFragment(mFragment); doReturn(DEVICE_NAME).when(mController).getDeviceName(); } From 284ca4f3569f3cbdd22e0e044514329758b694f5 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Tue, 15 May 2018 16:23:49 -0400 Subject: [PATCH 02/31] Hook up slice deep links Device indexing might launch them on occassion. Test: existing test passes Test: launch deep link Change-Id: Ie4d3cef2cc384ca809e74b27638d2c5a1d4d98a2 Fixes: 79435996 --- .../android/settings/slices/SliceDeepLinkSpringBoard.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java index d02431c8f77..7f1a0f35cae 100644 --- a/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java +++ b/src/com/android/settings/slices/SliceDeepLinkSpringBoard.java @@ -45,7 +45,11 @@ public class SliceDeepLinkSpringBoard extends Activity { // This shouldn't matter since the slice is shown instead of the device // index caring about the launch uri. Uri slice = Uri.parse(intent.getStringExtra(EXTRA_SLICE)); - Log.e(TAG, "Slice intent launched: " + slice); + SlicesDatabaseAccessor slicesDatabaseAccessor = new SlicesDatabaseAccessor(this); + // Sadly have to block here because we don't know where to go. + final SliceData sliceData = slicesDatabaseAccessor.getSliceDataFromUri(slice); + Intent launchIntent = SliceBuilderUtils.getContentIntent(this, sliceData); + startActivity(launchIntent); } else { startActivity(intent); } From 52feedf3544bb399093e98a407bfcf4a2b4391ba Mon Sep 17 00:00:00 2001 From: hughchen Date: Tue, 8 May 2018 16:52:18 +0800 Subject: [PATCH 03/31] Bluetooth and NFC added back to Connection preferences * Bluetooth and NFC added back to "Connection preferences" Bug: 79299421 Test: make -j50 RunSettingsRoboTests Change-Id: I8f4c389c28c7cc752f198be2b59b28b6e9af2c90 Merged-In: I8f4c389c28c7cc752f198be2b59b28b6e9af2c90 --- res/xml/connected_devices.xml | 15 ---------- res/xml/connected_devices_advanced.xml | 22 ++++++++++++--- ...ancedConnectedDeviceDashboardFragment.java | 7 +++++ .../ConnectedDeviceDashboardFragment.java | 28 ------------------- 4 files changed, 25 insertions(+), 47 deletions(-) diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml index 1e9d97eaa90..1fb5b044c26 100644 --- a/res/xml/connected_devices.xml +++ b/res/xml/connected_devices.xml @@ -48,21 +48,6 @@ android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment" settings:allowDividerAbove="true"/> - - - - - - + + + + + android:order="-6"/> + android:order="-4"/> + android:order="-3"/> + android:order="-8"/> diff --git a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java index 45794c5a20f..a64a430e638 100644 --- a/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/AdvancedConnectedDeviceDashboardFragment.java @@ -24,6 +24,7 @@ import com.android.settings.R; import com.android.settings.bluetooth.BluetoothFilesPreferenceController; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.nfc.AndroidBeamPreferenceController; +import com.android.settings.nfc.NfcPreferenceController; import com.android.settings.print.PrintSettingPreferenceController; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; @@ -78,10 +79,16 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment final PrintSettingPreferenceController printerController = new PrintSettingPreferenceController(context); + final NfcPreferenceController nfcPreferenceController = + new NfcPreferenceController(context); + if (lifecycle != null) { lifecycle.addObserver(beamPreferenceController); lifecycle.addObserver(printerController); + lifecycle.addObserver(nfcPreferenceController); } + + controllers.add(nfcPreferenceController); controllers.add(printerController); return controllers; diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 227fd9b8ad4..3dc1437a50a 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -26,10 +26,7 @@ import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.nfc.NfcPreferenceController; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.lifecycle.Lifecycle; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -62,25 +59,6 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { return R.xml.connected_devices; } - @Override - protected List createPreferenceControllers(Context context) { - return buildPreferenceControllers(context, getLifecycle()); - } - - private static List buildPreferenceControllers(Context context, - Lifecycle lifecycle) { - final List controllers = new ArrayList<>(); - final NfcPreferenceController nfcPreferenceController = - new NfcPreferenceController(context); - controllers.add(nfcPreferenceController); - - if (lifecycle != null) { - lifecycle.addObserver(nfcPreferenceController); - } - - return controllers; - } - @Override public void onAttach(Context context) { super.onAttach(context); @@ -138,12 +116,6 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { return Arrays.asList(sir); } - @Override - public List createPreferenceControllers(Context - context) { - return buildPreferenceControllers(context, null /* lifecycle */); - } - @Override public List getNonIndexableKeys(Context context) { List keys = super.getNonIndexableKeys(context); From 3f42a2381630ae94b645eae5c5730725c982d452 Mon Sep 17 00:00:00 2001 From: Beverly Date: Wed, 16 May 2018 14:28:15 -0400 Subject: [PATCH 04/31] Get rid of divider above ringtone selector Change-Id: I939d1ab061fb55853fbc0505b8d9025715b9df97 Fixes: 79480349 Test: manual --- res/xml/sound_settings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml index 5bee7b06edf..42dc588445f 100644 --- a/res/xml/sound_settings.xml +++ b/res/xml/sound_settings.xml @@ -108,8 +108,7 @@ android:dialogTitle="@string/ringtone_title" android:summary="@string/summary_placeholder" android:ringtoneType="ringtone" - android:order="-100" - settings:allowDividerAbove="true"/> + android:order="-100"/> Date: Wed, 16 May 2018 13:26:24 -0700 Subject: [PATCH 05/31] Do not perform device index before device provision. Bug: 79841744 Test: robotests Change-Id: I74243b6f31364220156e91fe63b56138a0240714 --- .../search/DeviceIndexFeatureProvider.java | 8 ++++++++ .../DeviceIndexFeatureProviderTest.java | 19 ++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/search/DeviceIndexFeatureProvider.java b/src/com/android/settings/search/DeviceIndexFeatureProvider.java index 8e64d795b2c..bf75ee81c3e 100644 --- a/src/com/android/settings/search/DeviceIndexFeatureProvider.java +++ b/src/com/android/settings/search/DeviceIndexFeatureProvider.java @@ -24,8 +24,10 @@ import android.content.Context; import android.net.Uri; import android.os.Build; import android.provider.Settings; +import android.util.Log; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.slices.SettingsSliceProvider; import java.util.List; @@ -48,6 +50,12 @@ public interface DeviceIndexFeatureProvider { default void updateIndex(Context context, boolean force) { if (!isIndexingEnabled()) { + Log.w(TAG, "Skipping: device index is not enabled"); + return; + } + + if (!Utils.isDeviceProvisioned(context)) { + Log.w(TAG, "Skipping: device is not provisioned"); return; } diff --git a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java index 26c2830a01c..d4c15802b99 100644 --- a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java @@ -15,7 +15,6 @@ package com.android.settings.search; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -24,6 +23,7 @@ import static org.mockito.Mockito.when; import android.app.Activity; import android.app.job.JobScheduler; +import android.provider.Settings; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -47,7 +47,7 @@ public class DeviceIndexFeatureProviderTest { } @Test - public void verifyDisabled() { + public void updateIndex_disabled_shouldDoNothing() { when(mProvider.isIndexingEnabled()).thenReturn(false); mProvider.updateIndex(mActivity, false); @@ -55,7 +55,20 @@ public class DeviceIndexFeatureProviderTest { } @Test - public void verifyIndexing() { + public void updateIndex_enabled_unprovisioned_shouldDoNothing() { + when(mProvider.isIndexingEnabled()).thenReturn(true); + Settings.Global.putInt(mActivity.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0); + + mProvider.updateIndex(mActivity, false); + + verify(mProvider, never()).index(any(), any(), any(), any(), any()); + } + + @Test + public void updateIndex_enabled_provisioned_shouldIndex() { + Settings.Global.putInt(mActivity.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 1); JobScheduler jobScheduler = mock(JobScheduler.class); when(mProvider.isIndexingEnabled()).thenReturn(true); when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); From 615becb392fe57efcd8aac400a3f88924ce8c13c Mon Sep 17 00:00:00 2001 From: hughchen Date: Fri, 20 Apr 2018 10:01:59 +0800 Subject: [PATCH 06/31] Update UI when BT device is rename * Using getAliasName() instead of getName() * Add BluetoothDevice isConnected check, when BluetoothDevice is disconnected. Do not add to the show list. Bug: 77783217 Test: make -j50 RunSettingsRoboTests Change-Id: I183fc693eaefd690568ba2f1ec740258b2bb62c8 --- .../settings/sound/AudioSwitchPreferenceController.java | 4 ++-- .../sound/HandsFreeProfileOutputPreferenceController.java | 6 +++++- .../settings/sound/MediaOutputPreferenceController.java | 6 +++++- .../sound/AudioOutputSwitchPreferenceControllerTest.java | 4 ++-- .../HandsFreeProfileOutputPreferenceControllerTest.java | 4 ++-- .../settings/sound/MediaOutputPreferenceControllerTest.java | 4 ++-- 6 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java index dde2b3012ed..7ed3db9fcf7 100644 --- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java +++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java @@ -131,7 +131,7 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex); mSelectedIndex = connectedDeviceIndex; setActiveBluetoothDevice(btDevice); - listPreference.setSummary(btDevice.getName()); + listPreference.setSummary(btDevice.getAliasName()); } return true; } @@ -319,7 +319,7 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont mediaValues[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary); for (int i = 0, size = mConnectedDevices.size(); i < size; i++) { final BluetoothDevice btDevice = mConnectedDevices.get(i); - mediaOutputs[i] = btDevice.getName(); + mediaOutputs[i] = btDevice.getAliasName(); mediaValues[i] = btDevice.getAddress(); if (btDevice.equals(activeDevice)) { // select the active connected device. diff --git a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java index 20399133129..f7f547aaa40 100644 --- a/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java +++ b/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java @@ -66,7 +66,11 @@ public class HandsFreeProfileOutputPreferenceController extends if (numDevices == 0) { // No connected devices, disable switch entry. mPreference.setVisible(false); - preference.setSummary(mContext.getText(R.string.media_output_default_summary)); + final CharSequence summary = mContext.getText(R.string.media_output_default_summary); + final CharSequence[] defaultMediaOutput = new CharSequence[]{summary}; + mSelectedIndex = getDefaultDeviceIndex(); + preference.setSummary(summary); + setPreference(defaultMediaOutput, defaultMediaOutput, preference); return; } diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java index 79f3c9d9549..b456263eaf6 100644 --- a/src/com/android/settings/sound/MediaOutputPreferenceController.java +++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java @@ -78,7 +78,11 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro if (numDevices == 0) { // Disable switch entry if there is no connected devices. mPreference.setVisible(false); - preference.setSummary(mContext.getText(R.string.media_output_default_summary)); + final CharSequence summary = mContext.getText(R.string.media_output_default_summary); + final CharSequence[] defaultMediaOutput = new CharSequence[]{summary}; + mSelectedIndex = getDefaultDeviceIndex(); + preference.setSummary(summary); + setPreference(defaultMediaOutput, defaultMediaOutput, preference); return; } diff --git a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java index 272fd20cb35..7eccd42ed33 100644 --- a/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java @@ -226,7 +226,7 @@ public class AudioOutputSwitchPreferenceControllerTest { mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1); - assertThat(mPreference.getSummary()).isEqualTo(mBluetoothDevice.getName()); + assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1); } /** @@ -246,7 +246,7 @@ public class AudioOutputSwitchPreferenceControllerTest { mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2); - assertThat(mPreference.getSummary()).isEqualTo(secondBluetoothDevice.getName()); + assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2); } /** diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java index db09eab2d51..314dbfdd6dc 100644 --- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java @@ -251,7 +251,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest { mController.updateState(mPreference); assertThat(mPreference.isVisible()).isTrue(); - assertThat(mPreference.getSummary()).isEqualTo(mBluetoothDevice.getName()); + assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1); } /** @@ -273,7 +273,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest { mController.updateState(mPreference); assertThat(mPreference.isVisible()).isTrue(); - assertThat(mPreference.getSummary()).isEqualTo(mSecondBluetoothDevice.getName()); + assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2); } /** diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java index b777239760a..e8869365f4e 100644 --- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java @@ -302,7 +302,7 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); assertThat(mPreference.isVisible()).isTrue(); - assertThat(mPreference.getSummary()).isEqualTo(mBluetoothDevice.getName()); + assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1); } /** @@ -323,7 +323,7 @@ public class MediaOutputPreferenceControllerTest { mController.updateState(mPreference); assertThat(mPreference.isVisible()).isTrue(); - assertThat(mPreference.getSummary()).isEqualTo(mSecondBluetoothDevice.getName()); + assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2); } /** From b6ac12eed4e705ac4c52418c7a8905a5d332cb05 Mon Sep 17 00:00:00 2001 From: hughchen Date: Mon, 23 Apr 2018 20:13:14 +0800 Subject: [PATCH 07/31] Update DialogFragment UI when BT device is add/remove/rename * Add AudioSwitchCallback() in AudioSwitchPreferenceController. This callback is used to notify SoudSettings to update the dialogFragment UI. * Add UpdatableListPreferenceDialogFragment that updates the available options when dialog is shown * Add test to verify the adapter count when onListPreferenceUpdated() is called. Bug: 77783217 Test: make -j50 RunSettingsRoboTests Change-Id: I8cac1b30ec50df026f4b7722dd1cd2f69e77a4cb Merged-In: I8cac1b30ec50df026f4b7722dd1cd2f69e77a4cb --- .../settings/notification/SoundSettings.java | 47 ++++- .../AudioSwitchPreferenceController.java | 10 ++ ...UpdatableListPreferenceDialogFragment.java | 164 ++++++++++++++++++ ...ProfileOutputPreferenceControllerTest.java | 4 +- .../MediaOutputPreferenceControllerTest.java | 3 + ...tableListPreferenceDialogFragmentTest.java | 90 ++++++++++ 6 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 src/com/android/settings/widget/UpdatableListPreferenceDialogFragment.java create mode 100644 tests/robotests/src/com/android/settings/widget/UpdatableListPreferenceDialogFragmentTest.java diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java index 7fffb765f1c..1005d20f52f 100644 --- a/src/com/android/settings/notification/SoundSettings.java +++ b/src/com/android/settings/notification/SoundSettings.java @@ -26,16 +26,22 @@ import android.os.UserHandle; import android.preference.SeekBarVolumizer; import android.provider.SearchIndexableResource; import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.text.TextUtils; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.RingtonePreference; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.sound.HandsFreeProfileOutputPreferenceController; +import com.android.settings.sound.MediaOutputPreferenceController; import com.android.settings.widget.PreferenceCategoryController; +import com.android.settings.widget.UpdatableListPreferenceDialogFragment; import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.instrumentation.Instrumentable; import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; @@ -68,6 +74,9 @@ public class SoundSettings extends DashboardFragment { }; private RingtonePreference mRequestPreference; + private UpdatableListPreferenceDialogFragment mDialogFragment; + private String mMediaOutputControllerKey; + private String mHfpOutputControllerKey; @Override public int getMetricsCategory() { @@ -82,6 +91,11 @@ public class SoundSettings extends DashboardFragment { if (!TextUtils.isEmpty(selectedPreference)) { mRequestPreference = (RingtonePreference) findPreference(selectedPreference); } + + UpdatableListPreferenceDialogFragment dialogFragment = + (UpdatableListPreferenceDialogFragment) getFragmentManager() + .findFragmentByTag(TAG); + mDialogFragment = dialogFragment; } } @@ -111,6 +125,23 @@ public class SoundSettings extends DashboardFragment { return super.onPreferenceTreeClick(preference); } + @Override + public void onDisplayPreferenceDialog(Preference preference) { + final int metricsCategory; + if (mHfpOutputControllerKey.equals(preference.getKey())) { + metricsCategory = MetricsProto.MetricsEvent.DIALOG_SWITCH_HFP_DEVICES; + } else if (mMediaOutputControllerKey.equals(preference.getKey())) { + metricsCategory = MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES; + } else { + metricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN; + } + + mDialogFragment = UpdatableListPreferenceDialogFragment. + newInstance(preference.getKey(), metricsCategory); + mDialogFragment.setTargetFragment(this, 0); + mDialogFragment.show(getFragmentManager(), TAG); + } + @Override protected String getLogTag() { return TAG; @@ -152,6 +183,14 @@ public class SoundSettings extends DashboardFragment { volumeControllers.add(use(NotificationVolumePreferenceController.class)); volumeControllers.add(use(CallVolumePreferenceController.class)); + use(MediaOutputPreferenceController.class).setCallback(listPreference -> + onPreferenceDataChanged(listPreference)); + mMediaOutputControllerKey = use(MediaOutputPreferenceController.class).getPreferenceKey(); + use(HandsFreeProfileOutputPreferenceController.class).setCallback(listPreference -> + onPreferenceDataChanged(listPreference)); + mHfpOutputControllerKey = + use(HandsFreeProfileOutputPreferenceController.class).getPreferenceKey(); + for (VolumeSeekBarPreferenceController controller : volumeControllers) { controller.setCallback(mVolumeCallback); getLifecycle().addObserver(controller); @@ -287,4 +326,10 @@ public class SoundSettings extends DashboardFragment { workSoundController.enableWorkSync(); } } -} + + private void onPreferenceDataChanged(ListPreference preference) { + if (mDialogFragment != null) { + mDialogFragment.onListPreferenceUpdated(preference); + } + } +} \ No newline at end of file diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java index dde2b3012ed..6d9d3a46edb 100644 --- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java +++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java @@ -78,6 +78,7 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont protected final LocalBluetoothProfileManager mProfileManager; protected int mSelectedIndex; protected Preference mPreference; + protected AudioSwitchCallback mAudioSwitchPreferenceCallback; private final AudioManagerAudioDeviceCallback mAudioManagerAudioDeviceCallback; private final LocalBluetoothManager mLocalBluetoothManager; @@ -85,6 +86,10 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont private final WiredHeadsetBroadcastReceiver mReceiver; private final Handler mHandler; + public interface AudioSwitchCallback { + void onPreferenceDataChanged(ListPreference preference); + } + public AudioSwitchPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); @@ -207,6 +212,10 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) { } + public void setCallback(AudioSwitchCallback callback) { + mAudioSwitchPreferenceCallback = callback; + } + protected boolean isStreamFromOutputDevice(int streamType, int device) { return (device & mAudioManager.getDevicesForStream(streamType)) != 0; } @@ -335,6 +344,7 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont listPreference.setEntryValues(mediaValues); listPreference.setValueIndex(mSelectedIndex); listPreference.setSummary(mediaOutputs[mSelectedIndex]); + mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference); } private int getConnectedDeviceIndex(String hardwareAddress) { diff --git a/src/com/android/settings/widget/UpdatableListPreferenceDialogFragment.java b/src/com/android/settings/widget/UpdatableListPreferenceDialogFragment.java new file mode 100644 index 00000000000..93697781d9e --- /dev/null +++ b/src/com/android/settings/widget/UpdatableListPreferenceDialogFragment.java @@ -0,0 +1,164 @@ +/* + * Copyright 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.widget; + +import android.app.AlertDialog; +import android.content.res.TypedArray; +import android.os.Bundle; +import android.support.annotation.VisibleForTesting; +import android.support.v14.preference.PreferenceDialogFragment; +import android.support.v7.preference.ListPreference; +import android.widget.ArrayAdapter; +import com.android.settingslib.core.instrumentation.Instrumentable; + +import java.util.ArrayList; + +/** + * {@link PreferenceDialogFragment} that updates the available options + * when {@code onListPreferenceUpdated} is called." + */ +public class UpdatableListPreferenceDialogFragment extends PreferenceDialogFragment implements + Instrumentable { + + private static final String SAVE_STATE_INDEX = "UpdatableListPreferenceDialogFragment.index"; + private static final String SAVE_STATE_ENTRIES = + "UpdatableListPreferenceDialogFragment.entries"; + private static final String SAVE_STATE_ENTRY_VALUES = + "UpdatableListPreferenceDialogFragment.entryValues"; + private static final String METRICS_CATEGORY_KEY = "metrics_category_key"; + private ArrayAdapter mAdapter; + private int mClickedDialogEntryIndex; + private ArrayList mEntries; + private CharSequence[] mEntryValues; + private int mMetricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN; + + public static UpdatableListPreferenceDialogFragment newInstance( + String key, int metricsCategory) { + UpdatableListPreferenceDialogFragment fragment = + new UpdatableListPreferenceDialogFragment(); + Bundle args = new Bundle(1); + args.putString(ARG_KEY, key); + args.putInt(METRICS_CATEGORY_KEY, metricsCategory); + fragment.setArguments(args); + return fragment; + } + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Bundle bundle = getArguments(); + mMetricsCategory = + bundle.getInt(METRICS_CATEGORY_KEY, Instrumentable.METRICS_CATEGORY_UNKNOWN); + if (savedInstanceState == null) { + mEntries = new ArrayList<>(); + setPreferenceData(getListPreference()); + } else { + mClickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0); + mEntries = savedInstanceState.getCharSequenceArrayList(SAVE_STATE_ENTRIES); + mEntryValues = + savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(SAVE_STATE_INDEX, mClickedDialogEntryIndex); + outState.putCharSequenceArrayList(SAVE_STATE_ENTRIES, mEntries); + outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues); + } + + @Override + public void onDialogClosed(boolean positiveResult) { + final ListPreference preference = getListPreference(); + if (positiveResult && mClickedDialogEntryIndex >= 0) { + final String value = mEntryValues[mClickedDialogEntryIndex].toString(); + if (preference.callChangeListener(value)) { + preference.setValue(value); + } + } + } + + @VisibleForTesting + void setAdapter(ArrayAdapter adapter) { + mAdapter = adapter; + } + + @VisibleForTesting + void setEntries(ArrayList entries) { + mEntries = entries; + } + + @VisibleForTesting + ArrayAdapter getAdapter() { + return mAdapter; + } + + @VisibleForTesting + void setMetricsCategory(Bundle bundle) { + mMetricsCategory = + bundle.getInt(METRICS_CATEGORY_KEY, Instrumentable.METRICS_CATEGORY_UNKNOWN); + } + + @Override + protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { + super.onPrepareDialogBuilder(builder); + final TypedArray a = getContext().obtainStyledAttributes( + null, + com.android.internal.R.styleable.AlertDialog, + com.android.internal.R.attr.alertDialogStyle, 0); + + mAdapter = new ArrayAdapter<>( + getContext(), + a.getResourceId( + com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout, + com.android.internal.R.layout.select_dialog_singlechoice), + mEntries); + + builder.setSingleChoiceItems(mAdapter, mClickedDialogEntryIndex, + (dialog, which) -> { + mClickedDialogEntryIndex = which; + onClick(dialog, -1); + dialog.dismiss(); + }); + builder.setPositiveButton(null, null); + a.recycle(); + } + + @Override + public int getMetricsCategory() { + return mMetricsCategory; + } + + private ListPreference getListPreference() { + return (ListPreference) getPreference(); + } + + private void setPreferenceData(ListPreference preference) { + mEntries.clear(); + mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue()); + for (CharSequence entry : preference.getEntries()) { + mEntries.add(entry); + } + mEntryValues = preference.getEntryValues(); + } + + public void onListPreferenceUpdated(ListPreference preference) { + if (mAdapter != null) { + setPreferenceData(preference); + mAdapter.notifyDataSetChanged(); + } + } +} diff --git a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java index db09eab2d51..6a573e08748 100644 --- a/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java @@ -16,7 +16,6 @@ package com.android.settings.sound; - import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID; import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET; @@ -93,6 +92,8 @@ public class HandsFreeProfileOutputPreferenceControllerTest { private HeadsetProfile mHeadsetProfile; @Mock private HearingAidProfile mHearingAidProfile; + @Mock + private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback; private Context mContext; private PreferenceScreen mScreen; @@ -156,6 +157,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest { when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mScreen.addPreference(mPreference); mController.displayPreference(mScreen); + mController.setCallback(mAudioSwitchPreferenceCallback); } @After diff --git a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java index b777239760a..6aec5ef1196 100644 --- a/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java @@ -94,6 +94,8 @@ public class MediaOutputPreferenceControllerTest { private A2dpProfile mA2dpProfile; @Mock private HearingAidProfile mHearingAidProfile; + @Mock + private AudioSwitchPreferenceController.AudioSwitchCallback mAudioSwitchPreferenceCallback; private Context mContext; private PreferenceScreen mScreen; @@ -157,6 +159,7 @@ public class MediaOutputPreferenceControllerTest { when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); mScreen.addPreference(mPreference); mController.displayPreference(mScreen); + mController.setCallback(mAudioSwitchPreferenceCallback); } @After diff --git a/tests/robotests/src/com/android/settings/widget/UpdatableListPreferenceDialogFragmentTest.java b/tests/robotests/src/com/android/settings/widget/UpdatableListPreferenceDialogFragmentTest.java new file mode 100644 index 00000000000..cd5765452ff --- /dev/null +++ b/tests/robotests/src/com/android/settings/widget/UpdatableListPreferenceDialogFragmentTest.java @@ -0,0 +1,90 @@ +/* + * Copyright 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.widget; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.support.v7.preference.ListPreference; +import android.widget.ArrayAdapter; +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; + +import static org.mockito.Mockito.spy; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = ShadowBluetoothUtils.class) +public class UpdatableListPreferenceDialogFragmentTest { + + private Context mContext; + private UpdatableListPreferenceDialogFragment mUpdatableListPrefDlgFragment; + private static final String KEY = "Test_Key"; + private ArrayAdapter mAdapter; + private ArrayList mEntries; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + + mUpdatableListPrefDlgFragment = UpdatableListPreferenceDialogFragment + .newInstance(KEY, MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES); + mEntries = spy(new ArrayList<>()); + mUpdatableListPrefDlgFragment.setEntries(mEntries); + mUpdatableListPrefDlgFragment. + setMetricsCategory(mUpdatableListPrefDlgFragment.getArguments()); + initAdapter(); + } + + private void initAdapter() { + mAdapter = spy(new ArrayAdapter<>( + mContext, + com.android.internal.R.layout.select_dialog_singlechoice, + mEntries)); + mUpdatableListPrefDlgFragment.setAdapter(mAdapter); + } + + @Test + public void getMetricsCategory() { + assertThat(mUpdatableListPrefDlgFragment.getMetricsCategory()) + .isEqualTo(MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES); + } + + @Test + public void onListPreferenceUpdated_verifyAdapterCanBeUpdate() { + assertThat(mUpdatableListPrefDlgFragment.getAdapter().getCount()). + isEqualTo(0); + + ListPreference listPreference = new ListPreference(mContext); + final CharSequence[] charSequences = {"Test_DEVICE_1", "Test_DEVICE_2"}; + listPreference.setEntries(charSequences); + mUpdatableListPrefDlgFragment.onListPreferenceUpdated(listPreference); + + assertThat(mUpdatableListPrefDlgFragment.getAdapter().getCount()). + isEqualTo(2); + } +} \ No newline at end of file From 71560fcba151dff5423f4f0d7a99239c280bfe5a Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 17 May 2018 14:48:49 +0100 Subject: [PATCH 08/31] Setting should handle android.settings.SYNC_SETTINGS from managed profile When android.settings.SYNC_SETTINGS is fired from a managed profile, Settings should handle it properly and displays the UI to manage accounts in the profile. Since Settings uses a unified page to display both personal and work accounts, it should redirect the intent to the UserAndAccountDashboardActivity in user 0 Bug: 79561138 Test: adb shell am start -a android.settings.SYNC_SETTINGS --user 10 verifies the UI is showing work accounts Change-Id: Ib82a04ad0ec72d58d60569e38538c5dbd6181bf0 --- AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 5dd22c2833d..74a18eab61f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3137,6 +3137,8 @@ android:value="com.android.settings.accounts.AccountDashboardFragment"/> + Date: Tue, 1 May 2018 16:52:46 -0700 Subject: [PATCH 09/31] Add Wifi Slice Add a custom Wifi Slice to the Settings Slice Provider. It needs a custom Slice because of the complicated listener logic in the MasterSwitchPreferenceController, which makes it hard to work-in synchronous set/get logic. The one-off Slice requires extra changes, including: - Including it in getDescendants - Handling changes to wifi by the framework This is the first change that uses SettingsLib's broadcast relay, which allows settings to (un)register IntentFilters to a Uri, allowing Settings Slices affected by the framework (quicksettings, connectivity related, volume, etc) to be updated without action on the Slice. Fixes: 70622039 Fixes: 67997332 Test: robotests Change-Id: Ia76738dd6baacd5522d52df2c61ebad86a600282 Merged-In: Ibfe4736beecb833e3f6bb871b2eb5228a5fd3a34 --- .../slices/SettingsSliceProvider.java | 133 ++++++------- .../slices/SliceBroadcastReceiver.java | 32 ++-- .../settings/slices/SliceBuilderUtils.java | 8 +- .../settings/wifi/WifiSliceBuilder.java | 178 ++++++++++++++++++ .../wifi/calling/WifiCallingSliceHelper.java | 20 +- .../slices/SettingsSliceProviderTest.java | 46 +++-- .../settings/testutils/SliceTester.java | 8 +- .../settings/wifi/WifiSliceBuilderTest.java | 98 ++++++++++ 8 files changed, 405 insertions(+), 118 deletions(-) create mode 100644 src/com/android/settings/wifi/WifiSliceBuilder.java create mode 100644 tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index 8f07447cd80..0ebf8c001cb 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -18,41 +18,39 @@ package com.android.settings.slices; import static android.Manifest.permission.READ_SEARCH_INDEXABLES; -import static com.android.settings.wifi.calling.WifiCallingSliceHelper.PATH_WIFI_CALLING; - -import android.app.PendingIntent; import android.app.slice.SliceManager; import android.content.ContentResolver; -import android.content.Context; import android.content.Intent; -import android.graphics.drawable.Icon; +import android.content.IntentFilter; +import android.content.Context; import android.net.Uri; -import android.net.wifi.WifiManager; -import android.provider.Settings; import android.provider.SettingsSlicesContract; import android.support.annotation.VisibleForTesting; import android.support.v4.graphics.drawable.IconCompat; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import android.util.Pair; -import androidx.slice.Slice; -import androidx.slice.SliceProvider; -import androidx.slice.builders.ListBuilder; -import androidx.slice.builders.SliceAction; - -import com.android.settings.R; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.wifi.WifiSliceBuilder; +import com.android.settings.wifi.calling.WifiCallingSliceHelper; +import com.android.settingslib.SliceBroadcastRelay; import com.android.settingslib.utils.ThreadUtils; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import androidx.slice.Slice; +import androidx.slice.SliceProvider; + /** * A {@link SliceProvider} for Settings to enabled inline results in system apps. * @@ -84,10 +82,6 @@ public class SettingsSliceProvider extends SliceProvider { */ public static final String SLICE_AUTHORITY = "com.android.settings.slices"; - public static final String PATH_WIFI = "wifi"; - public static final String ACTION_WIFI_CHANGED = - "com.android.settings.slice.action.WIFI_CHANGED"; - /** * Action passed for changes to Toggle Slices. */ @@ -121,6 +115,8 @@ public class SettingsSliceProvider extends SliceProvider { @VisibleForTesting Map mSliceDataCache; + final Set mRegisteredUris = new ArraySet<>(); + public SettingsSliceProvider() { super(READ_SEARCH_INDEXABLES); } @@ -146,28 +142,37 @@ public class SettingsSliceProvider extends SliceProvider { @Override public void onSlicePinned(Uri sliceUri) { + if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { + registerIntentToUri(WifiSliceBuilder.INTENT_FILTER , sliceUri); + // TODO (b/) Register IntentFilters for database entries. + mRegisteredUris.add(sliceUri); + return; + } + // Start warming the slice, we expect someone will want it soon. loadSliceInBackground(sliceUri); } @Override public void onSliceUnpinned(Uri sliceUri) { + if (mRegisteredUris.contains(sliceUri)) { + SliceBroadcastRelay.unregisterReceivers(getContext(), sliceUri); + mRegisteredUris.remove(sliceUri); + } mSliceDataCache.remove(sliceUri); } @Override public Slice onBindSlice(Uri sliceUri) { - String path = sliceUri.getPath(); // If adding a new Slice, do not directly match Slice URIs. // Use {@link SlicesDatabaseAccessor}. - switch (path) { - case "/" + PATH_WIFI: - return createWifiSlice(sliceUri); - case "/" + PATH_WIFI_CALLING: - return FeatureFactory.getFactory(getContext()) - .getSlicesFeatureProvider() - .getNewWifiCallingSliceHelper(getContext()) - .createWifiCallingSlice(sliceUri); + if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) { + return FeatureFactory.getFactory(getContext()) + .getSlicesFeatureProvider() + .getNewWifiCallingSliceHelper(getContext()) + .createWifiCallingSlice(sliceUri); + } else if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) { + return WifiSliceBuilder.getSlice(getContext()); } SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri); @@ -223,11 +228,12 @@ public class SettingsSliceProvider extends SliceProvider { true /* isPlatformSlice */); final List oemKeys = mSlicesDatabaseAccessor.getSliceKeys( false /* isPlatformSlice */); - final List allUris = buildUrisFromKeys(platformKeys, - SettingsSlicesContract.AUTHORITY); - allUris.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY)); + descendants.addAll(buildUrisFromKeys(platformKeys, SettingsSlicesContract.AUTHORITY)); + descendants.addAll(buildUrisFromKeys(oemKeys, SettingsSliceProvider.SLICE_AUTHORITY)); + descendants.addAll(getSpecialCaseUris(true /* isPlatformSlice */)); + descendants.addAll(getSpecialCaseUris(false /* isPlatformSlice */)); - return allUris; + return descendants; } // Path is anything but empty, "action", or "intent". Return empty list. @@ -242,7 +248,9 @@ public class SettingsSliceProvider extends SliceProvider { // Can assume authority belongs to the provider. Return all Uris for the authority. final boolean isPlatformUri = TextUtils.equals(authority, SettingsSlicesContract.AUTHORITY); final List keys = mSlicesDatabaseAccessor.getSliceKeys(isPlatformUri); - return buildUrisFromKeys(keys, authority); + descendants.addAll(buildUrisFromKeys(keys, authority)); + descendants.addAll(getSpecialCaseUris(isPlatformUri)); + return descendants; } private List buildUrisFromKeys(List keys, String authority) { @@ -295,55 +303,28 @@ public class SettingsSliceProvider extends SliceProvider { return new Slice.Builder(uri).build(); } - // TODO (b/70622039) remove this when the proper wifi slice is enabled. - private Slice createWifiSlice(Uri sliceUri) { - // Get wifi state - WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - int wifiState = wifiManager.getWifiState(); - boolean wifiEnabled = false; - String state; - switch (wifiState) { - case WifiManager.WIFI_STATE_DISABLED: - case WifiManager.WIFI_STATE_DISABLING: - state = getContext().getString(R.string.disconnected); - break; - case WifiManager.WIFI_STATE_ENABLED: - case WifiManager.WIFI_STATE_ENABLING: - state = wifiManager.getConnectionInfo().getSSID(); - wifiEnabled = true; - break; - case WifiManager.WIFI_STATE_UNKNOWN: - default: - state = ""; // just don't show anything? - break; + private List getSpecialCaseUris(boolean isPlatformUri) { + if (isPlatformUri) { + return getSpecialCasePlatformUris(); } - - boolean finalWifiEnabled = wifiEnabled; - return new ListBuilder(getContext(), sliceUri) - .setColor(R.color.material_blue_500) - .addRow(b -> b - .setTitle(getContext().getString(R.string.wifi_settings)) - .setTitleItem(Icon.createWithResource(getContext(), R.drawable.wifi_signal)) - .setSubtitle(state) - .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED), - null, finalWifiEnabled)) - .setPrimaryAction( - new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS), - (IconCompat) null, null))) - .build(); + return getSpecialCaseOemUris(); } - private PendingIntent getIntent(String action) { - Intent intent = new Intent(action); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0); - return pi; + private List getSpecialCasePlatformUris() { + return Arrays.asList(WifiSliceBuilder.WIFI_URI); } - private PendingIntent getBroadcastIntent(String action) { - Intent intent = new Intent(action); - intent.setClass(getContext(), SliceBroadcastReceiver.class); - return PendingIntent.getBroadcast(getContext(), 0, intent, - PendingIntent.FLAG_CANCEL_CURRENT); + private List getSpecialCaseOemUris() { + return new ArrayList<>(); + } + + @VisibleForTesting + /** + * Registers an IntentFilter in SysUI to notify changes to {@param sliceUri} when broadcasts to + * {@param intentFilter} happen. + */ + void registerIntentToUri(IntentFilter intentFilter, Uri sliceUri) { + SliceBroadcastRelay.registerReceiver(getContext(), sliceUri, SliceBroadcastReceiver.class, + intentFilter); } } diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index 04097340ed3..3e349ff9b7e 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -18,18 +18,16 @@ package com.android.settings.slices; import static com.android.settings.slices.SettingsSliceProvider.ACTION_SLIDER_CHANGED; import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED; -import static com.android.settings.slices.SettingsSliceProvider.ACTION_WIFI_CHANGED; import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY; import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED; import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED; +import static com.android.settings.wifi.WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED; import android.app.slice.Slice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.net.wifi.WifiManager; -import android.os.Handler; import android.provider.SettingsSlicesContract; import android.text.TextUtils; import android.util.Log; @@ -40,6 +38,8 @@ import com.android.settings.core.BasePreferenceController; import com.android.settings.core.SliderPreferenceController; import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.wifi.WifiSliceBuilder; +import com.android.settingslib.SliceBroadcastRelay; /** * Responds to actions performed on slices and notifies slices of updates in state changes. @@ -67,25 +67,21 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { final int newPosition = intent.getIntExtra(Slice.EXTRA_RANGE_VALUE, -1); handleSliderAction(context, key, newPosition, isPlatformSlice); break; - case ACTION_WIFI_CHANGED: - WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - boolean newState = intent.getBooleanExtra(Slice.EXTRA_TOGGLE_STATE, - wm.isWifiEnabled()); - wm.setWifiEnabled(newState); - // Wait a bit for wifi to update (TODO: is there a better way to do this?) - Handler h = new Handler(); - h.postDelayed(() -> { - Uri uri = SliceBuilderUtils.getUri(SettingsSliceProvider.PATH_WIFI, - false /* isPlatformSlice */); - context.getContentResolver().notifyChange(uri, null); - }, 1000); + case ACTION_WIFI_SLICE_CHANGED: + WifiSliceBuilder.handleUriChange(context, intent); break; case ACTION_WIFI_CALLING_CHANGED: FeatureFactory.getFactory(context) - .getSlicesFeatureProvider() - .getNewWifiCallingSliceHelper(context) - .handleWifiCallingChanged(intent); + .getSlicesFeatureProvider() + .getNewWifiCallingSliceHelper(context) + .handleWifiCallingChanged(intent); break; + default: + final String uriString = intent.getStringExtra(SliceBroadcastRelay.EXTRA_URI); + if (!TextUtils.isEmpty(uriString)) { + final Uri uri = Uri.parse(uriString); + context.getContentResolver().notifyChange(uri, null /* observer */); + } } } diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index d744fbd3924..feb7042552d 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -39,7 +39,6 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; -import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; @@ -47,6 +46,7 @@ import com.android.settings.core.SliderPreferenceController; import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.DatabaseIndexingUtils; +import com.android.settingslib.SliceBroadcastRelay; import com.android.settingslib.core.AbstractPreferenceController; import android.support.v4.graphics.drawable.IconCompat; @@ -54,6 +54,7 @@ import android.support.v4.graphics.drawable.IconCompat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import androidx.slice.Slice; import androidx.slice.builders.ListBuilder; @@ -345,7 +346,10 @@ public class SliceBuilderUtils { final String keywordString = data.getKeywords(); if (keywordString != null) { final String[] keywordArray = keywordString.split(","); - keywords.addAll(Arrays.asList(keywordArray)); + final List strippedKeywords = Arrays.stream(keywordArray) + .map(s -> s = s.trim()) + .collect(Collectors.toList()); + keywords.addAll(strippedKeywords); } return keywords; diff --git a/src/com/android/settings/wifi/WifiSliceBuilder.java b/src/com/android/settings/wifi/WifiSliceBuilder.java new file mode 100644 index 00000000000..2ebba67c8f5 --- /dev/null +++ b/src/com/android/settings/wifi/WifiSliceBuilder.java @@ -0,0 +1,178 @@ +/* + * 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.wifi; + +import static android.provider.SettingsSlicesContract.KEY_WIFI; + +import android.annotation.ColorInt; +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.Uri; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiSsid; +import android.provider.SettingsSlicesContract; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.SubSettings; +import com.android.settings.Utils; +import com.android.settings.search.DatabaseIndexingUtils; +import com.android.settings.slices.SliceBroadcastReceiver; +import com.android.settings.slices.SliceBuilderUtils; + +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.SliceAction; + +import android.support.v4.graphics.drawable.IconCompat; +import android.text.TextUtils; + +/** + * Utility class to build a Wifi Slice, and handle all associated actions. + */ +public class WifiSliceBuilder { + + /** + * Backing Uri for the Wifi Slice. + */ + public static final Uri WIFI_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSlicesContract.AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath(KEY_WIFI) + .build(); + + /** + * Action notifying a change on the Wifi Slice. + */ + public static final String ACTION_WIFI_SLICE_CHANGED = + "com.android.settings.wifi.action.WIFI_CHANGED"; + + public static final IntentFilter INTENT_FILTER = new IntentFilter(); + + static { + INTENT_FILTER.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); + INTENT_FILTER.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + } + + private WifiSliceBuilder() { + } + + /** + * Return a Wifi Slice bound to {@link #WIFI_URI}. + *

+ * Note that you should register a listener with {@link #registerIntentFilter(Context, Uri)} + * to get changes from Wifi. + */ + public static Slice getSlice(Context context) { + final boolean isWifiEnabled = isWifiEnabled(context); + final IconCompat icon = IconCompat.createWithResource(context, + R.drawable.ic_settings_wireless); + final String title = context.getString(R.string.wifi_settings); + final CharSequence summary = getSummary(context); + @ColorInt final int color = Utils.getColorAccent(context); + final PendingIntent toggleAction = getBroadcastIntent(context); + final PendingIntent primaryAction = getPrimaryAction(context); + final SliceAction primarySliceAction = new SliceAction(primaryAction, icon, title); + final SliceAction toggleSliceAction = new SliceAction(toggleAction, null /* actionTitle */, + isWifiEnabled); + + return new ListBuilder(context, WIFI_URI, ListBuilder.INFINITY) + .setAccentColor(color) + .addRow(b -> b + .setTitle(title) + .setSubtitle(summary) + .addEndItem(toggleSliceAction) + .setPrimaryAction(primarySliceAction)) + .build(); + } + + /** + * Update the current wifi status to the boolean value keyed by + * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}. + */ + public static void handleUriChange(Context context, Intent intent) { + final WifiManager wifiManager = context.getSystemService(WifiManager.class); + final boolean newState = intent.getBooleanExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, + wifiManager.isWifiEnabled()); + wifiManager.setWifiEnabled(newState); + // Do not notifyChange on Uri. The service takes longer to update the current value than it + // does for the Slice to check the current value again. Let {@link SliceBroadcastRelay} + // handle it. + } + + private static boolean isWifiEnabled(Context context) { + final WifiManager wifiManager = context.getSystemService(WifiManager.class); + + switch (wifiManager.getWifiState()) { + case WifiManager.WIFI_STATE_ENABLED: + case WifiManager.WIFI_STATE_ENABLING: + return true; + case WifiManager.WIFI_STATE_DISABLED: + case WifiManager.WIFI_STATE_DISABLING: + case WifiManager.WIFI_STATE_UNKNOWN: + default: + return false; + } + } + + private static CharSequence getSummary(Context context) { + final WifiManager wifiManager = context.getSystemService(WifiManager.class); + + switch (wifiManager.getWifiState()) { + case WifiManager.WIFI_STATE_ENABLED: + final String ssid = WifiInfo.removeDoubleQuotes(wifiManager.getConnectionInfo() + .getSSID()); + if (TextUtils.equals(ssid, WifiSsid.NONE)) { + return context.getText(R.string.disconnected); + } + return ssid; + case WifiManager.WIFI_STATE_ENABLING: + return context.getText(R.string.disconnected); + case WifiManager.WIFI_STATE_DISABLED: + case WifiManager.WIFI_STATE_DISABLING: + return context.getText(R.string.switch_off_text); + case WifiManager.WIFI_STATE_UNKNOWN: + default: + return ""; + } + } + + private static PendingIntent getPrimaryAction(Context context) { + final String screenTitle = context.getText(R.string.wifi_settings).toString(); + final Uri contentUri = new Uri.Builder().appendPath(KEY_WIFI).build(); + final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context, + WifiSettings.class.getName(), KEY_WIFI, screenTitle, + MetricsEvent.DIALOG_WIFI_AP_EDIT); + intent.setClassName(context.getPackageName(), SubSettings.class.getName()); + intent.setData(contentUri); + + return PendingIntent.getActivity(context, 0 /* requestCode */, + intent, 0 /* flags */); + } + + private static PendingIntent getBroadcastIntent(Context context) { + final Intent intent = new Intent(ACTION_WIFI_SLICE_CHANGED); + intent.setClass(context, SliceBroadcastReceiver.class); + return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent, + PendingIntent.FLAG_CANCEL_CURRENT); + } +} diff --git a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java index 7213148e97f..a554e74352f 100644 --- a/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java +++ b/src/com/android/settings/wifi/calling/WifiCallingSliceHelper.java @@ -20,6 +20,7 @@ import static android.app.slice.Slice.EXTRA_TOGGLE_STATE; import android.app.PendingIntent; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -38,6 +39,7 @@ import androidx.slice.builders.SliceAction; import com.android.ims.ImsManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; +import com.android.settings.slices.SettingsSliceProvider; import com.android.settings.slices.SliceBroadcastReceiver; import com.android.settings.slices.SliceBuilderUtils; @@ -76,16 +78,20 @@ public class WifiCallingSliceHelper { public static final String ACTION_WIFI_CALLING_SETTINGS_ACTIVITY = "android.settings.WIFI_CALLING_SETTINGS"; + /** + * Full {@link Uri} for the Wifi Calling Slice. + */ + public static final Uri WIFI_CALLING_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(PATH_WIFI_CALLING) + .build(); + /** * Timeout for querying wifi calling setting from ims manager. */ private static final int TIMEOUT_MILLIS = 2000; - /** - * Time for which data contained in the slice can remain fresh. - */ - private static final int SLICE_TTL_MILLIS = 60000; - protected SubscriptionManager mSubscriptionManager; private final Context mContext; @@ -182,7 +188,7 @@ public class WifiCallingSliceHelper { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); final String title = mContext.getString(R.string.wifi_calling_settings_title); - return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS) + return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) .setColor(R.color.material_blue_500) .addRow(b -> b .setTitle(title) @@ -260,7 +266,7 @@ public class WifiCallingSliceHelper { private Slice getNonActionableWifiCallingSlice(String title, String subtitle, Uri sliceUri, PendingIntent primaryActionIntent) { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.wifi_signal); - return new ListBuilder(mContext, sliceUri, SLICE_TTL_MILLIS) + return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) .setColor(R.color.material_blue_500) .addRow(b -> b .setTitle(title) diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java index a0bd33aa6c8..60fb5f9c685 100644 --- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java +++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java @@ -19,6 +19,7 @@ package com.android.settings.slices; import static android.content.ContentResolver.SCHEME_CONTENT; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -31,6 +32,7 @@ import android.net.Uri; import android.os.StrictMode; import android.provider.SettingsSlicesContract; +import com.android.settings.wifi.WifiSliceBuilder; import com.android.settings.testutils.DatabaseTestUtils; import com.android.settings.testutils.FakeToggleController; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -45,6 +47,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import androidx.slice.Slice; @@ -70,6 +74,10 @@ public class SettingsSliceProviderTest { private SQLiteDatabase mDb; private SliceManager mManager; + private static final List SPECIAL_CASE_PLATFORM_URIS = Arrays.asList( + WifiSliceBuilder.WIFI_URI + ); + @Before public void setUp() { mContext = spy(RuntimeEnvironment.application); @@ -114,7 +122,7 @@ public class SettingsSliceProviderTest { } @Test - public void testLoadSlice_doesntCacheWithoutPin() { + public void testLoadSlice_doesNotCacheWithoutPin() { insertSpecialCase(KEY); Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false); @@ -226,6 +234,7 @@ public class SettingsSliceProviderTest { .build(); final Collection descendants = mProvider.onGetSliceDescendants(uri); + descendants.removeAll(SPECIAL_CASE_PLATFORM_URIS); assertThat(descendants).isEmpty(); } @@ -293,16 +302,18 @@ public class SettingsSliceProviderTest { .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .build(); - final Uri expectedUri = new Uri.Builder() + final Collection expectedUris = new HashSet<>(); + expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(key) - .build(); + .build()); final Collection descendants = mProvider.onGetSliceDescendants(uri); - assertThat(descendants).containsExactly(expectedUri); + assertThat(descendants).containsExactlyElementsIn(expectedUris); } @Test @@ -313,16 +324,18 @@ public class SettingsSliceProviderTest { .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .build(); - final Uri expectedUri = new Uri.Builder() + final Collection expectedUris = new HashSet<>(); + expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(key) - .build(); + .build()); final Collection descendants = mProvider.onGetSliceDescendants(uri); - assertThat(descendants).containsExactly(expectedUri); + assertThat(descendants).containsExactlyElementsIn(expectedUris); } @Test @@ -334,22 +347,31 @@ public class SettingsSliceProviderTest { final Uri uri = new Uri.Builder() .scheme(SCHEME_CONTENT) .build(); - final Uri expectedPlatformUri = new Uri.Builder() + final Collection expectedUris = new HashSet<>(); + expectedUris.addAll(SPECIAL_CASE_PLATFORM_URIS); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSlicesContract.AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(platformKey) - .build(); - final Uri expectedOemUri = new Uri.Builder() + .build()); + expectedUris.add(new Uri.Builder() .scheme(SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath(oemKey) - .build(); + .build()); final Collection descendants = mProvider.onGetSliceDescendants(uri); - assertThat(descendants).containsExactly(expectedPlatformUri, expectedOemUri); + assertThat(descendants).containsExactlyElementsIn(expectedUris); + } + + @Test + public void bindSlice_wifiSlice_returnsWifiSlice() { + final Slice wifiSlice = mProvider.onBindSlice(WifiSliceBuilder.WIFI_URI); + + assertThat(wifiSlice.getUri()).isEqualTo(WifiSliceBuilder.WIFI_URI); } private void insertSpecialCase(String key) { diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java index 4c4b04081fa..f617aa95c8f 100644 --- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java +++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java @@ -35,6 +35,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import androidx.slice.Slice; import androidx.slice.SliceItem; @@ -211,7 +212,7 @@ public class SliceTester { assertKeywords(metadata, sliceData); } - private static void assertTitle(List sliceItems, String title) { + public static void assertTitle(List sliceItems, String title) { boolean hasTitle = false; for (SliceItem item : sliceItems) { List titleItems = SliceQuery.findAll(item, FORMAT_TEXT, HINT_TITLE, @@ -230,8 +231,9 @@ public class SliceTester { private static void assertKeywords(SliceMetadata metadata, SliceData data) { final List keywords = metadata.getSliceKeywords(); - final Set expectedKeywords = new HashSet<>( - Arrays.asList(data.getKeywords().split(","))); + final Set expectedKeywords = Arrays.stream(data.getKeywords().split(",")) + .map(s -> s = s.trim()) + .collect(Collectors.toSet()); expectedKeywords.add(data.getTitle()); expectedKeywords.add(data.getScreenTitle().toString()); assertThat(keywords).containsExactlyElementsIn(expectedKeywords); diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java new file mode 100644 index 00000000000..f1ac5545d30 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/WifiSliceBuilderTest.java @@ -0,0 +1,98 @@ +/* + * 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.wifi; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.wifi.WifiSliceBuilder; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.SliceTester; + +import android.content.Intent; +import android.content.res.Resources; +import android.net.wifi.WifiManager; +import android.support.v4.graphics.drawable.IconCompat; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +import java.util.List; + +import androidx.slice.Slice; +import androidx.slice.SliceItem; +import androidx.slice.SliceMetadata; +import androidx.slice.SliceProvider; +import androidx.slice.core.SliceAction; +import androidx.slice.widget.SliceLiveData; + +@RunWith(SettingsRobolectricTestRunner.class) +public class WifiSliceBuilderTest { + + private Context mContext; + + @Before + public void setUp() { + mContext = spy(RuntimeEnvironment.application); + + // Prevent crash in SliceMetadata. + Resources resources = spy(mContext.getResources()); + doReturn(60).when(resources).getDimensionPixelSize(anyInt()); + doReturn(resources).when(mContext).getResources(); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + } + + @Test + public void getWifiSlice_correctData() { + final Slice wifiSlice = WifiSliceBuilder.getSlice(mContext); + final SliceMetadata metadata = SliceMetadata.from(mContext, wifiSlice); + + + final List toggles = metadata.getToggles(); + assertThat(toggles).hasSize(1); + + final SliceAction primaryAction = metadata.getPrimaryAction(); + final IconCompat expectedToggleIcon = IconCompat.createWithResource(mContext, + R.drawable.ic_settings_wireless); + assertThat(primaryAction.getIcon().toString()).isEqualTo(expectedToggleIcon.toString()); + + final List sliceItems = wifiSlice.getItems(); + SliceTester.assertTitle(sliceItems, mContext.getString(R.string.wifi_settings)); + } + + @Test + public void handleUriChange_updatesWifi() { + final Intent intent = new Intent(WifiSliceBuilder.ACTION_WIFI_SLICE_CHANGED); + intent.putExtra(android.app.slice.Slice.EXTRA_TOGGLE_STATE, true); + final WifiManager wifiManager = mContext.getSystemService(WifiManager.class); + + WifiSliceBuilder.handleUriChange(mContext, intent); + + assertThat(wifiManager.getWifiState()).isEqualTo(WifiManager.WIFI_STATE_ENABLED); + } +} From 4e9d52791bb6e805cc0a307d97bcd5b27e816e42 Mon Sep 17 00:00:00 2001 From: Daniel Nishi Date: Wed, 2 May 2018 19:29:16 -0700 Subject: [PATCH 10/31] Make the night display suggestion depend on a flag. This allows it to be enabled/disabled on certain devices. Change-Id: I7b73bb866b05b92588e15ef7ffc2834cdde041ce Fixes: 78601616 Test: Settings robotest --- res/values/config.xml | 3 +++ .../NightDisplayPreferenceController.java | 7 +++++++ .../SuggestionFeatureProviderImplTest.java | 7 ------- .../NightDisplayPreferenceControllerTest.java | 20 +++++++++++++++++++ 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index e3ec74f2636..e204b7fd7ec 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -131,4 +131,7 @@ + + true + diff --git a/src/com/android/settings/display/NightDisplayPreferenceController.java b/src/com/android/settings/display/NightDisplayPreferenceController.java index 5e8dfe01bd7..0bbab935f8a 100644 --- a/src/com/android/settings/display/NightDisplayPreferenceController.java +++ b/src/com/android/settings/display/NightDisplayPreferenceController.java @@ -18,6 +18,7 @@ import android.content.Context; import com.android.internal.app.ColorDisplayController; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settings.R; public class NightDisplayPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin { @@ -29,6 +30,12 @@ public class NightDisplayPreferenceController extends AbstractPreferenceControll } public static boolean isSuggestionComplete(Context context) { + final boolean isEnabled = context.getResources().getBoolean( + R.bool.config_night_light_suggestion_enabled); + // The suggestion is always complete if not enabled. + if (!isEnabled) { + return true; + } final ColorDisplayController controller = new ColorDisplayController(context); return controller.getAutoMode() != ColorDisplayController.AUTO_MODE_DISABLED; } diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java index bb68c0dd9c0..c62f63d20a9 100644 --- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java @@ -162,13 +162,6 @@ public class SuggestionFeatureProviderImplTest { assertThat(suggestions).hasSize(3); } - @Test - public void nightDisplaySuggestion_isNotCompleted_byDefault() { - final ComponentName componentName = - new ComponentName(mContext, NightDisplaySuggestionActivity.class); - assertThat(mProvider.isSuggestionComplete(mContext, componentName)).isFalse(); - } - @Test public void testGetSmartSuggestionEnabledTaggedData_disabled() { assertThat(mProvider.getLoggingTaggedData(mContext)).asList().containsExactly( diff --git a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java index 3bc7d521eed..7440f63d740 100644 --- a/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/NightDisplayPreferenceControllerTest.java @@ -6,15 +6,22 @@ import android.app.Application; import android.content.ComponentName; import android.provider.Settings.Secure; import com.android.internal.app.ColorDisplayController; +import com.android.settings.R; import com.android.settings.Settings.NightDisplaySuggestionActivity; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.SettingsShadowResources; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; import org.robolectric.RuntimeEnvironment; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = { + SettingsShadowResources.class +}) public class NightDisplayPreferenceControllerTest { private NightDisplayPreferenceController mPreferenceController; @@ -27,6 +34,7 @@ public class NightDisplayPreferenceControllerTest { @After public void tearDown() { mPreferenceController = null; + SettingsShadowResources.reset(); } @Test @@ -58,4 +66,16 @@ public class NightDisplayPreferenceControllerTest { new ComponentName(context, NightDisplaySuggestionActivity.class); assertThat(mPreferenceController.isSuggestionComplete(context)).isTrue(); } + + @Test + public void nightDisplaySuggestion_isCompleted_ifDisabled() { + final Application context = RuntimeEnvironment.application; + Secure.putInt(context.getContentResolver(), + Secure.NIGHT_DISPLAY_AUTO_MODE, ColorDisplayController.AUTO_MODE_DISABLED); + SettingsShadowResources.overrideResource(R.bool.config_night_light_suggestion_enabled, false); + + final ComponentName componentName = + new ComponentName(context, NightDisplaySuggestionActivity.class); + assertThat(mPreferenceController.isSuggestionComplete(context)).isTrue(); + } } From 0d9afde2712b09020fe4a591f6b6bb8ef91cbb54 Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Thu, 17 May 2018 11:55:40 -0700 Subject: [PATCH 11/31] Updated delete icon Also remove the duplicate ic_menu_delete.xml and fix up places where it was used. Bug: 77982107 Test: manual Change-Id: I23ede37b7cdf9bea59b44cd0f817bf0ad0cd1d69 --- res/drawable/ic_delete.xml | 16 ++++++++---- res/drawable/ic_menu_delete.xml | 25 ------------------- ...stricted_preference_user_delete_widget.xml | 2 +- res/layout/user_info_header.xml | 2 +- res/layout/zen_rule_widget.xml | 4 +-- res/menu/misc_files_menu.xml | 2 +- res/xml/vpn_app_management.xml | 2 +- .../accounts/AccountPreferenceController.java | 2 +- .../android/settings/network/ApnEditor.java | 2 +- 9 files changed, 19 insertions(+), 38 deletions(-) delete mode 100644 res/drawable/ic_menu_delete.xml diff --git a/res/drawable/ic_delete.xml b/res/drawable/ic_delete.xml index d4f79e3233b..d1290c50a02 100644 --- a/res/drawable/ic_delete.xml +++ b/res/drawable/ic_delete.xml @@ -16,10 +16,16 @@ Copyright (C) 2015 The Android Open Source Project + android:viewportWidth="24.0" + android:viewportHeight="24.0" + android:tint="?android:attr/colorControlNormal"> + android:fillColor="#FF000000" + android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V6h1V4H15zM17,19H7V6h10V19z"/> + + diff --git a/res/drawable/ic_menu_delete.xml b/res/drawable/ic_menu_delete.xml deleted file mode 100644 index f1ff04a5b04..00000000000 --- a/res/drawable/ic_menu_delete.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - diff --git a/res/layout/restricted_preference_user_delete_widget.xml b/res/layout/restricted_preference_user_delete_widget.xml index 7fd5d88a04c..7bafacc7ccc 100644 --- a/res/layout/restricted_preference_user_delete_widget.xml +++ b/res/layout/restricted_preference_user_delete_widget.xml @@ -52,7 +52,7 @@ android:layout_height="fill_parent" android:paddingStart="16dip" android:paddingEnd="16dip" - android:src="@drawable/ic_menu_delete" + android:src="@drawable/ic_delete" android:contentDescription="@string/user_delete_user_description" android:layout_gravity="center" android:background="?android:attr/selectableItemBackground" /> diff --git a/res/layout/user_info_header.xml b/res/layout/user_info_header.xml index 583c8473010..57f01c7673a 100644 --- a/res/layout/user_info_header.xml +++ b/res/layout/user_info_header.xml @@ -85,7 +85,7 @@ android:layout_height="fill_parent" android:paddingStart="16dip" android:paddingEnd="16dip" - android:src="@drawable/ic_menu_delete" + android:src="@drawable/ic_delete" android:contentDescription="@string/user_delete_user_description" android:layout_gravity="center" android:background="?android:attr/selectableItemBackground" /> diff --git a/res/layout/zen_rule_widget.xml b/res/layout/zen_rule_widget.xml index aa1175b5b1f..d502243049b 100644 --- a/res/layout/zen_rule_widget.xml +++ b/res/layout/zen_rule_widget.xml @@ -25,8 +25,8 @@ android:layout_height="fill_parent" android:paddingStart="16dip" android:paddingEnd="16dip" - android:src="@drawable/ic_menu_delete" + android:src="@drawable/ic_delete" android:contentDescription="@string/zen_mode_delete_rule" android:layout_gravity="center" android:background="?android:attr/selectableItemBackground" /> - \ No newline at end of file + diff --git a/res/menu/misc_files_menu.xml b/res/menu/misc_files_menu.xml index 80fdd2f652f..1170ade841a 100644 --- a/res/menu/misc_files_menu.xml +++ b/res/menu/misc_files_menu.xml @@ -17,7 +17,7 @@

+ android:icon="@drawable/ic_delete"/> diff --git a/res/xml/vpn_app_management.xml b/res/xml/vpn_app_management.xml index e18a0746795..bcaa6b0a62f 100644 --- a/res/xml/vpn_app_management.xml +++ b/res/xml/vpn_app_management.xml @@ -43,7 +43,7 @@ diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java index d9410b261d5..f33b34dc1c9 100644 --- a/src/com/android/settings/accounts/AccountPreferenceController.java +++ b/src/com/android/settings/accounts/AccountPreferenceController.java @@ -361,7 +361,7 @@ public class AccountPreferenceController extends AbstractPreferenceController RestrictedPreference preference = new RestrictedPreference( mParent.getPreferenceManager().getContext()); preference.setTitle(R.string.remove_managed_profile_label); - preference.setIcon(R.drawable.ic_menu_delete); + preference.setIcon(R.drawable.ic_delete); preference.setOnPreferenceClickListener(this); preference.setOrder(ORDER_LAST); return preference; diff --git a/src/com/android/settings/network/ApnEditor.java b/src/com/android/settings/network/ApnEditor.java index e2853a64d95..cceb31d29e7 100644 --- a/src/com/android/settings/network/ApnEditor.java +++ b/src/com/android/settings/network/ApnEditor.java @@ -721,7 +721,7 @@ public class ApnEditor extends SettingsPreferenceFragment // If it's a new APN, then cancel will delete the new entry in onPause if (!mNewApn && !mReadOnlyApn) { menu.add(0, MENU_DELETE, 0, R.string.menu_delete) - .setIcon(R.drawable.ic_menu_delete); + .setIcon(R.drawable.ic_delete); } menu.add(0, MENU_SAVE, 0, R.string.menu_save) .setIcon(android.R.drawable.ic_menu_save); From 8cbfbbd44de46ee165fc9b75272809a3893d4ee0 Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Thu, 17 May 2018 11:59:16 -0700 Subject: [PATCH 12/31] Update cancel and cast icons Bug: 77982107 Test: manual Change-Id: I7f1af280daf8944dbab48929b7fe7d82f680a448 --- res/drawable/ic_cancel.xml | 10 ++++++---- res/drawable/ic_cast_24dp.xml | 9 ++------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/res/drawable/ic_cancel.xml b/res/drawable/ic_cancel.xml index b90c18c7521..c84f18ede05 100644 --- a/res/drawable/ic_cancel.xml +++ b/res/drawable/ic_cancel.xml @@ -16,10 +16,12 @@ - + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + android:pathData="M12,2C6.47,2 2,6.47 2,12c0,5.53 4.47,10 10,10c5.53,0 10,-4.47 10,-10C22,6.47 17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/> + diff --git a/res/drawable/ic_cast_24dp.xml b/res/drawable/ic_cast_24dp.xml index 948decab7d7..e8245d96ce9 100644 --- a/res/drawable/ic_cast_24dp.xml +++ b/res/drawable/ic_cast_24dp.xml @@ -21,11 +21,6 @@ android:viewportHeight="24.0" android:tint="?android:attr/colorControlNormal"> + android:fillColor="#FF000000" + android:pathData="M21,3H3C1.9,3 1,3.9 1,5v3h2V5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2V5C23,3.9 22.1,3 21,3zM1,18v3h3C4,19.34 2.66,18 1,18zM1,14v2c2.76,0 5,2.24 5,5h2C8,17.13 4.87,14 1,14zM1,10v2c4.97,0 9,4.03 9,9h2C12,14.92 7.07,10 1,10z"/> From 4fec12cbbf290f0cf24060379ef134745ee19901 Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Thu, 17 May 2018 12:32:02 -0700 Subject: [PATCH 13/31] Fix tethering summary when airplane mode is off When airplane mode is off, fall back to default summary (tether off summary). It should be fine because once tether state get updated again, it will go through original listener to update the summary. Change-Id: Iba9b56f452e72365ea964d841ee156a2625c0ae1 Fixes: 79721162 Test: RunSettingsRoboTests --- .../tether/WifiTetherPreferenceController.java | 9 ++++++++- .../WifiTetherPreferenceControllerTest.java | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java index 1d9d3cd3cc5..9764a454719 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java +++ b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java @@ -44,6 +44,7 @@ public class WifiTetherPreferenceController extends AbstractPreferenceController private static final String WIFI_TETHER_SETTINGS = "wifi_tether"; private static final IntentFilter AIRPLANE_INTENT_FILTER = new IntentFilter( Intent.ACTION_AIRPLANE_MODE_CHANGED); + private static final int ID_NULL = -1; private final ConnectivityManager mConnectivityManager; private final String[] mWifiRegexs; @@ -152,7 +153,7 @@ public class WifiTetherPreferenceController extends AbstractPreferenceController public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) { - clearSummaryForAirplaneMode(); + clearSummaryForAirplaneMode(R.string.wifi_hotspot_off_subtext); } } }; @@ -194,10 +195,16 @@ public class WifiTetherPreferenceController extends AbstractPreferenceController } private void clearSummaryForAirplaneMode() { + clearSummaryForAirplaneMode(ID_NULL); + } + + private void clearSummaryForAirplaneMode(int defaultId) { boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0; if (isAirplaneMode) { mPreference.setSummary(R.string.wifi_tether_disabled_by_airplane); + } else if (defaultId != ID_NULL){ + mPreference.setSummary(defaultId); } } // diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java index b5d0f9dba54..149cd225072 100644 --- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherPreferenceControllerTest.java @@ -123,7 +123,7 @@ public class WifiTetherPreferenceControllerTest { } @Test - public void testReceiver_goingToAirplaneMode_shouldClearPreferenceSummary() { + public void testReceiver_turnOnAirplaneMode_clearPreferenceSummary() { final ContentResolver cr = mock(ContentResolver.class); when(mContext.getContentResolver()).thenReturn(cr); Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, 1); @@ -137,6 +137,21 @@ public class WifiTetherPreferenceControllerTest { "Unavailable because airplane mode is turned on"); } + @Test + public void testReceiver_turnOffAirplaneMode_displayOffSummary() { + final ContentResolver cr = mock(ContentResolver.class); + when(mContext.getContentResolver()).thenReturn(cr); + Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, 0); + mController.displayPreference(mScreen); + final BroadcastReceiver receiver = ReflectionHelpers.getField(mController, "mReceiver"); + final Intent broadcast = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + + receiver.onReceive(RuntimeEnvironment.application, broadcast); + + assertThat(mPreference.getSummary().toString()).isEqualTo( + "Not sharing internet or content with other devices"); + } + @Test public void testHandleWifiApStateChanged_stateEnabling_showEnablingSummary() { mController.handleWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0 /* reason */); From 3500784e82173f736af3f81661bdb4281119412a Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Thu, 17 May 2018 11:26:21 -0700 Subject: [PATCH 14/31] Adjust Lock screen message for better accessibility. - increase text height to 48dp Change-Id: Ie3ab56eeed453bb7b131458a3966534a0bf68871 Fixes: 79711251 Test: visual --- res/layout/ownerinfo.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/res/layout/ownerinfo.xml b/res/layout/ownerinfo.xml index c5eaff5f50c..29e08402158 100644 --- a/res/layout/ownerinfo.xml +++ b/res/layout/ownerinfo.xml @@ -25,6 +25,7 @@ android:id="@+id/owner_info_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="@dimen/min_tap_target_size" android:gravity="top" android:hint="@string/owner_info_settings_edit_text_hint" android:inputType="textMultiLine|textCapSentences" From 36e61e191ac8ec044dff62277b1b0c206fea7752 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Thu, 17 May 2018 14:05:53 -0700 Subject: [PATCH 15/31] Misc style updates to fix some GAR issues - Increase tap target height for add wifi dialog entries. - Increase tap height for vpn editor fields - Tap target area for switchbar toggle Change-Id: I0d0e350dd4236cd4fe73fa190fb79ca50de2da60 Fixes: 79871635 Fixes: 79887410 Test: visual --- res/values/styles.xml | 2 ++ res/values/themes.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/res/values/styles.xml b/res/values/styles.xml index 819202e0e8a..1cddcea1d45 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -219,6 +219,7 @@ 4dip 18sp viewStart + @dimen/min_tap_target_size