From 8f421b2dbf873a2023d88e918049fe44233e4dd5 Mon Sep 17 00:00:00 2001 From: Quang Luong Date: Mon, 10 May 2021 17:48:53 -0700 Subject: [PATCH 01/20] Refresh security pref in Network Details page Security type of WifiEntry may change based on available scans/configs/the current connection for entries that can support multiple security types. Refresh the security string every time the WifiEntry is updated. Bug: 185914718 Test: manual inspection that connected wifi entry has the correct security string Change-Id: I5f3b7274f1e6b68de414493a6619555ee9b17e23 --- .../details2/WifiDetailPreferenceController2.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java index b66633e03a2..18cd5530272 100644 --- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java +++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java @@ -87,14 +87,10 @@ import com.android.settingslib.widget.ActionButtonsPreference; import com.android.settingslib.widget.LayoutPreference; import com.android.wifitrackerlib.WifiEntry; import com.android.wifitrackerlib.WifiEntry.ConnectCallback; -import com.android.wifitrackerlib.WifiEntry.ConnectCallback.ConnectStatus; import com.android.wifitrackerlib.WifiEntry.ConnectedInfo; import com.android.wifitrackerlib.WifiEntry.DisconnectCallback; -import com.android.wifitrackerlib.WifiEntry.DisconnectCallback.DisconnectStatus; import com.android.wifitrackerlib.WifiEntry.ForgetCallback; -import com.android.wifitrackerlib.WifiEntry.ForgetCallback.ForgetStatus; import com.android.wifitrackerlib.WifiEntry.SignInCallback; -import com.android.wifitrackerlib.WifiEntry.SignInCallback.SignInStatus; import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback; import java.net.Inet4Address; @@ -390,8 +386,6 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle mIpv6Category = screen.findPreference(KEY_IPV6_CATEGORY); mIpv6AddressPref = screen.findPreference(KEY_IPV6_ADDRESSES_PREF); - - mSecurityPref.setSummary(mWifiEntry.getSecurityString(false /* concise */)); } /** @@ -545,6 +539,8 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle refreshRssiViews(); // Frequency Pref refreshFrequency(); + // Security Pref + refreshSecurity(); // Transmit Link Speed Pref refreshTxSpeed(); // Receive Link Speed Pref @@ -646,6 +642,10 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle mFrequencyPref.setVisible(true); } + private void refreshSecurity() { + mSecurityPref.setSummary(mWifiEntry.getSecurityString(false /* concise */)); + } + private void refreshTxSpeed() { if (mWifiInfo == null || mWifiEntry.getConnectedState() != WifiEntry.CONNECTED_STATE_CONNECTED) { From 86af9e9da0250732a446199420eeed6c019d3b6d Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Mon, 17 May 2021 11:11:29 -0400 Subject: [PATCH 02/20] Add a11y announcement Since the button for clearing recent conversations may still exist after the user triggers the button since some of the conversations might not be removable Test: manual with talkback Fixes: 185433664 Change-Id: Id58d76237643e4e206ea6d551cdf7dd9f5742282 --- res/values/strings.xml | 5 ++++- .../app/RecentConversationsPreferenceController.java | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 4f377eeaa3e..561a076fa96 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8985,9 +8985,12 @@ Recent conversations - + Clear recent conversations + + Recent conversations removed + Clear diff --git a/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java b/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java index d4ad9944765..8bb64e2fd7c 100644 --- a/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java +++ b/src/com/android/settings/notification/app/RecentConversationsPreferenceController.java @@ -92,6 +92,7 @@ public class RecentConversationsPreferenceController extends AbstractPreferenceC } } } + button.announceForAccessibility(mContext.getString(R.string.recent_convos_removed)); } catch (RemoteException e) { Slog.w(TAG, "Could not clear recents", e); } From 07dc4fe79a343377a06bf2889aeefd38d7f43726 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Tue, 18 May 2021 15:13:28 +0800 Subject: [PATCH 03/20] Shows "This device" for default internal storage Bug: 188492974 Test: atest StorageEntryTest Change-Id: I7278ff604f22acafd47cef2f5d613a2bf9f0e371 --- .../settings/deviceinfo/storage/StorageEntry.java | 13 +++++++++++-- .../deviceinfo/storage/StorageEntryTest.java | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/deviceinfo/storage/StorageEntry.java b/src/com/android/settings/deviceinfo/storage/StorageEntry.java index f71811602d5..b419370e22b 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageEntry.java +++ b/src/com/android/settings/deviceinfo/storage/StorageEntry.java @@ -26,6 +26,8 @@ import android.os.storage.VolumeInfo; import android.os.storage.VolumeRecord; import android.text.TextUtils; +import com.android.settings.R; + import java.io.File; /** @@ -44,8 +46,15 @@ public class StorageEntry implements Comparable, Parcelable { mVolumeInfo = volumeInfo; mUnsupportedDiskInfo = null; mMissingVolumeRecord = null; - mVolumeInfoDescription = context.getSystemService(StorageManager.class) - .getBestVolumeDescription(mVolumeInfo); + + if (isDefaultInternalStorage()) { + // Shows "This device" for default internal storage. + mVolumeInfoDescription = context.getResources() + .getString(R.string.storage_default_internal_storage); + } else { + mVolumeInfoDescription = context.getSystemService(StorageManager.class) + .getBestVolumeDescription(mVolumeInfo); + } } public StorageEntry(@NonNull DiskInfo diskInfo) { diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java index c2591a778da..7541e939cdd 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java @@ -31,6 +31,8 @@ import android.os.storage.VolumeRecord; import androidx.test.core.app.ApplicationProvider; import androidx.test.runner.AndroidJUnit4; +import com.android.settings.testutils.ResourcesUtils; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -246,6 +248,17 @@ public class StorageEntryTest { assertThat(recordStorage.getDescription()).isEqualTo(description); } + @Test + public void getDescription_defaultInternalStorage_returnThisDevice() { + final VolumeInfo volumeInfo = mock(VolumeInfo.class); + when(volumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PRIVATE); + when(volumeInfo.getId()).thenReturn(VolumeInfo.ID_PRIVATE_INTERNAL); + final StorageEntry volumeStorage = new StorageEntry(mContext, volumeInfo); + + assertThat(volumeStorage.getDescription()).isEqualTo( + ResourcesUtils.getResourcesString(mContext, "storage_default_internal_storage")); + } + @Test public void getDiskId_shouldReturnDiskId() { final VolumeInfo volumeInfo = mock(VolumeInfo.class); From 99d8fcfae29978f642b7271d9e6a021e3551c45b Mon Sep 17 00:00:00 2001 From: Weng Su Date: Wed, 19 May 2021 15:35:41 +0800 Subject: [PATCH 04/20] [Provider model] Revise the Internet Panel title sub-text - Display "Tap a network to connect" on sub-title when Wi-Fi networks is not empty - Screenshot: https://screenshot.googleplex.com/5TzpJDLghpCQnDP Bug: 188594439 Test: manual test atest -c InternetConnectivityPanelTest Change-Id: I0e3f0eb269fb4fe040a62be9ee84105879af82f7 --- res/values/strings.xml | 4 ++-- .../settings/panel/InternetConnectivityPanel.java | 6 +++--- .../panel/InternetConnectivityPanelTest.java | 12 +++++------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 193f521494b..bdd38789bbb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -13128,8 +13128,8 @@ To switch networks, disconnect ethernet Wi\u2011Fi is turned on - - Select the network you want to use for data + + Tap a network to connect W+ connections diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java index 50371ae8fb7..a6c18a5b749 100644 --- a/src/com/android/settings/panel/InternetConnectivityPanel.java +++ b/src/com/android/settings/panel/InternetConnectivityPanel.java @@ -65,8 +65,8 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve private static final String TAG = "InternetConnectivityPanel"; private static final int SUBTITLE_TEXT_NONE = -1; private static final int SUBTITLE_TEXT_WIFI_IS_TURNED_ON = R.string.wifi_is_turned_on_subtitle; - private static final int SUBTITLE_TEXT_SELECT_NETWORK_TO_CONNECT_INTERNET = - R.string.select_network_to_connect_internet; + private static final int SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT = + R.string.tap_a_network_to_connect; private static final int SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS = R.string.wifi_empty_list_wifi_on; private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE = @@ -326,7 +326,7 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve if (wifiList != null && wifiList.size() != 0) { // When the Wi-Fi scan result is not empty // Sub-Title: Select the network you want to use for data - mSubtitle = SUBTITLE_TEXT_SELECT_NETWORK_TO_CONNECT_INTERNET; + mSubtitle = SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT; return; } diff --git a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java index 651eb048905..150c99e2945 100644 --- a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java +++ b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java @@ -63,10 +63,9 @@ public class InternetConnectivityPanelTest { ApplicationProvider.getApplicationContext(), "airplane_mode"); public static final String SUBTITLE_WIFI_IS_TURNED_ON = ResourcesUtils.getResourcesString( ApplicationProvider.getApplicationContext(), "wifi_is_turned_on_subtitle"); - public static final String SUBTITLE_TEXT_SELECT_NETWORK_TO_CONNECT_INTERNET = - ResourcesUtils.getResourcesString( - ApplicationProvider.getApplicationContext(), - "select_network_to_connect_internet"); + public static final String SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT = + ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(), + "tap_a_network_to_connect"); public static final String BUTTON_SETTINGS = ResourcesUtils.getResourcesString( ApplicationProvider.getApplicationContext(), "settings_button"); public static final String SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE = @@ -179,7 +178,7 @@ public class InternetConnectivityPanelTest { } @Test - public void getSubTitle_apmOffWifiOnTwoWifiItemsNoCarrierData_selectNetworkToConnectInternet() { + public void getSubTitle_apmOffWifiOnTwoWifiItemsNoCarrierData_tapANetworkToConnect() { List wifiList = new ArrayList(); wifiList.add(new ScanResult()); wifiList.add(new ScanResult()); @@ -187,8 +186,7 @@ public class InternetConnectivityPanelTest { mPanel.updatePanelTitle(); - assertThat(mPanel.getSubTitle()) - .isEqualTo(SUBTITLE_TEXT_SELECT_NETWORK_TO_CONNECT_INTERNET); + assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT); } @Test From 8aaa9f55497e52651d15b8f06eb4077586012852 Mon Sep 17 00:00:00 2001 From: Yi Jiang Date: Wed, 19 May 2021 11:44:36 -0700 Subject: [PATCH 05/20] Defers initialization of preferences. In Screen Timeout Settings, preferences should not be initialized in onAttach() because the setting style hasn't been loaded yet. This change defers the initialiaztion of those preferences so that they appear correctly. Test: manually tested. Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.display Bug: 183909540 Change-Id: I86cfe196549d709ed763faa004fff7b631365b1e --- ...SleepBatterySaverPreferenceController.java | 22 +++++++++++------ ...eSleepCameraStatePreferenceController.java | 24 ++++++++++++------- .../AdaptiveSleepPreferenceController.java | 17 ++----------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/com/android/settings/display/AdaptiveSleepBatterySaverPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepBatterySaverPreferenceController.java index 855c5070bf2..528c94d7d81 100644 --- a/src/com/android/settings/display/AdaptiveSleepBatterySaverPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepBatterySaverPreferenceController.java @@ -32,23 +32,20 @@ import com.android.settingslib.widget.BannerMessagePreference; public class AdaptiveSleepBatterySaverPreferenceController { @VisibleForTesting - final BannerMessagePreference mPreference; + BannerMessagePreference mPreference; private final PowerManager mPowerManager; + private final Context mContext; public AdaptiveSleepBatterySaverPreferenceController(Context context) { - mPreference = new BannerMessagePreference(context); - mPreference.setTitle(R.string.ambient_camera_summary_battery_saver_on); - mPreference.setPositiveButtonText(R.string.disable_text); mPowerManager = context.getSystemService(PowerManager.class); - mPreference.setPositiveButtonOnClickListener(p -> { - mPowerManager.setPowerSaveModeEnabled(false); - }); + mContext = context; } /** * Adds the controlled preference to the provided preference screen. */ public void addToScreen(PreferenceScreen screen) { + initializePreference(); screen.addPreference(mPreference); updateVisibility(); } @@ -66,6 +63,17 @@ public class AdaptiveSleepBatterySaverPreferenceController { * Refreshes the visibility of the preference. */ public void updateVisibility() { + initializePreference(); mPreference.setVisible(isPowerSaveMode()); } + + private void initializePreference() { + if (mPreference == null) { + mPreference = new BannerMessagePreference(mContext); + mPreference.setTitle(R.string.ambient_camera_summary_battery_saver_on); + mPreference.setPositiveButtonText(R.string.disable_text); + mPreference.setPositiveButtonOnClickListener( + p -> mPowerManager.setPowerSaveModeEnabled(false)); + } + } } diff --git a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java index ba7a3aba752..20080ce972f 100644 --- a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java @@ -33,26 +33,22 @@ import com.android.settingslib.widget.BannerMessagePreference; */ public class AdaptiveSleepCameraStatePreferenceController { @VisibleForTesting - final BannerMessagePreference mPreference; + BannerMessagePreference mPreference; private final SensorPrivacyManager mPrivacyManager; + private final Context mContext; public AdaptiveSleepCameraStatePreferenceController(Context context) { - mPreference = new BannerMessagePreference(context); - mPreference.setTitle(R.string.auto_rotate_camera_lock_title); - mPreference.setSummary(R.string.adaptive_sleep_camera_lock_summary); - mPreference.setPositiveButtonText(R.string.allow); mPrivacyManager = SensorPrivacyManager.getInstance(context); mPrivacyManager.addSensorPrivacyListener(CAMERA, (sensor, enabled) -> updateVisibility()); - mPreference.setPositiveButtonOnClickListener(p -> { - mPrivacyManager.setSensorPrivacy(CAMERA, false); - }); + mContext = context; } /** * Adds the controlled preference to the provided preference screen. */ public void addToScreen(PreferenceScreen screen) { + initializePreference(); screen.addPreference(mPreference); updateVisibility(); } @@ -70,6 +66,18 @@ public class AdaptiveSleepCameraStatePreferenceController { * Refreshes the visibility of the preference. */ public void updateVisibility() { + initializePreference(); mPreference.setVisible(isCameraLocked()); } + + private void initializePreference() { + if (mPreference == null) { + mPreference = new BannerMessagePreference(mContext); + mPreference.setTitle(R.string.auto_rotate_camera_lock_title); + mPreference.setSummary(R.string.adaptive_sleep_camera_lock_summary); + mPreference.setPositiveButtonText(R.string.allow); + mPreference.setPositiveButtonOnClickListener( + p -> mPrivacyManager.setSensorPrivacy(CAMERA, false)); + } + } } diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java index c57904e7be6..b86a070cf84 100644 --- a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java @@ -65,19 +65,6 @@ public class AdaptiveSleepPreferenceController { mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mPrivacyManager = SensorPrivacyManager.getInstance(context); mPowerManager = context.getSystemService(PowerManager.class); - mPreference = new RestrictedSwitchPreference(context); - mPreference.setTitle(R.string.adaptive_sleep_title); - mPreference.setSummary(R.string.adaptive_sleep_description); - mPreference.setChecked(isChecked()); - mPreference.setKey(PREFERENCE_KEY); - mPreference.setOnPreferenceClickListener(preference -> { - final boolean isChecked = ((RestrictedSwitchPreference) preference).isChecked(); - mMetricsFeatureProvider.action(context, SettingsEnums.ACTION_SCREEN_ATTENTION_CHANGED, - isChecked); - Settings.Secure.putInt(context.getContentResolver(), - Settings.Secure.ADAPTIVE_SLEEP, isChecked ? 1 : DEFAULT_VALUE); - return true; - }); mPackageManager = context.getPackageManager(); } @@ -116,8 +103,8 @@ public class AdaptiveSleepPreferenceController { mPreference.setSummary(R.string.adaptive_sleep_description); mPreference.setChecked(isChecked()); mPreference.setKey(PREFERENCE_KEY); - mPreference.setOnPreferenceChangeListener((preference, value) -> { - final boolean isChecked = (Boolean) value; + mPreference.setOnPreferenceClickListener(preference -> { + final boolean isChecked = ((RestrictedSwitchPreference) preference).isChecked(); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_SCREEN_ATTENTION_CHANGED, isChecked); From ef8f5c5ca4593856ae36ab3c76b684534c5539a0 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Wed, 19 May 2021 16:32:21 +0800 Subject: [PATCH 06/20] Fix overlapping problem for device admin page The content of Activate device admin app is overlapping with the title while scrolling up. That is because the collapsing toolbar needs to work with the view that supports nested scrolling feature, and this page hasn't updated the layout to use NestedScrollView. So that caused the overlapping problem. Fix: 188184864 Test: visual verified 1) Navigate to Settings > Security > Device admin apps > pick up one to activate 2) Scrolling the content and see if the content is overlapping with the title Change-Id: Ide5ff9ed40202c3b217934db93c82a4861983416 --- res/layout/device_admin_add.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/layout/device_admin_add.xml b/res/layout/device_admin_add.xml index 7fdcd8dc7ff..05eadad45f4 100644 --- a/res/layout/device_admin_add.xml +++ b/res/layout/device_admin_add.xml @@ -4,9 +4,9 @@ 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. @@ -21,7 +21,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - - + From afffb1dd2ff98234be931228961dd5931db09828 Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Thu, 20 May 2021 14:02:05 +0800 Subject: [PATCH 07/20] Should not show top intro in search Set not searchable for top intro of credential page Test: No top intro result in settings app. Fix: 188491690 Change-Id: Ia7c4b33f72e3ea962073a552a7f57fa2072a2aa6 --- res/xml/credential_management_app_fragment.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/xml/credential_management_app_fragment.xml b/res/xml/credential_management_app_fragment.xml index 41007a2fb3d..d4b61ac2fa8 100644 --- a/res/xml/credential_management_app_fragment.xml +++ b/res/xml/credential_management_app_fragment.xml @@ -30,7 +30,8 @@ + android:title="@string/request_manage_credentials_description" + settings:searchable="false"/> Date: Thu, 20 May 2021 16:20:28 +0800 Subject: [PATCH 08/20] Refactor some transition codes. - Make the transition logic simpler in SettingsBaseActivity. - Remove the redundant transition code in SettingsActivity. Bug: 177479937 Test: rebuild and click on pages. Change-Id: I65cae59d4eae99e3b9c324c9b6ce89f2349aaf8b --- .../android/settings/SettingsActivity.java | 12 --- .../settings/core/SettingsBaseActivity.java | 81 ++++++++++--------- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 923c2bd7192..7dd5fe40e42 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -233,18 +233,6 @@ public class SettingsActivity extends SettingsBaseActivity @Override protected void onCreate(Bundle savedState) { - if (FeatureFlagUtils.isEnabled(this, FeatureFlags.SILKY_HOME)) { - // Enable Activity transitions - getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS); - final MaterialSharedAxis enterTransition = new MaterialSharedAxis( - MaterialSharedAxis.X, /* forward */true); - getWindow().setEnterTransition(enterTransition); - - final MaterialSharedAxis returnTransition = new MaterialSharedAxis( - MaterialSharedAxis.X, /* forward */false); - getWindow().setReturnTransition(returnTransition); - } - super.onCreate(savedState); Log.d(LOG_TAG, "Starting onCreate"); long startTime = System.currentTimeMillis(); diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java index 05635cb9c61..6af95b2ee9d 100644 --- a/src/com/android/settings/core/SettingsBaseActivity.java +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -77,6 +77,7 @@ public class SettingsBaseActivity extends FragmentActivity { protected CollapsingToolbarLayout mCollapsingToolbarLayout; private int mCategoriesUpdateTaskCount; + private Toolbar mToolbar; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -129,21 +130,39 @@ public class SettingsBaseActivity extends FragmentActivity { } } + @Override + public void setActionBar(@androidx.annotation.Nullable Toolbar toolbar) { + super.setActionBar(toolbar); + + mToolbar = toolbar; + } + @Override public boolean onNavigateUp() { if (!super.onNavigateUp()) { - finish(); + finishAfterTransition(); } return true; } + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + final int id = item.getItemId(); + if (id == android.R.id.home) { + // Make the up button behave the same as the back button. + finishAfterTransition(); + return true; + } + return super.onOptionsItemSelected(item); + } + @Override public void startActivity(Intent intent) { if (!Utils.isPageTransitionEnabled(this)) { super.startActivity(intent); return; } - super.startActivity(intent, getActivityOptionsBundle()); + super.startActivity(intent, createActivityOptionsBundleForTransition(null)); } @Override @@ -152,11 +171,7 @@ public class SettingsBaseActivity extends FragmentActivity { super.startActivity(intent, options); return; } - if (options != null) { - super.startActivity(intent, getMergedBundleForTransition(options)); - return; - } - super.startActivity(intent, getActivityOptionsBundle()); + super.startActivity(intent, createActivityOptionsBundleForTransition(options)); } @Override @@ -167,7 +182,8 @@ public class SettingsBaseActivity extends FragmentActivity { super.startActivityForResult(intent, requestCode); return; } - super.startActivityForResult(intent, requestCode, getActivityOptionsBundle()); + super.startActivityForResult(intent, requestCode, + createActivityOptionsBundleForTransition(null)); } @Override @@ -177,12 +193,8 @@ public class SettingsBaseActivity extends FragmentActivity { super.startActivityForResult(intent, requestCode, options); return; } - if (options != null) { - super.startActivityForResult(intent, requestCode, - getMergedBundleForTransition(options)); - return; - } - super.startActivityForResult(intent, requestCode, getActivityOptionsBundle()); + super.startActivityForResult(intent, requestCode, + createActivityOptionsBundleForTransition(options)); } @Override @@ -192,7 +204,8 @@ public class SettingsBaseActivity extends FragmentActivity { super.startActivityForResultAsUser(intent, requestCode, userHandle); return; } - super.startActivityForResultAsUser(intent, requestCode, getActivityOptionsBundle(), + super.startActivityForResultAsUser(intent, requestCode, + createActivityOptionsBundleForTransition(null), userHandle); } @@ -242,17 +255,6 @@ public class SettingsBaseActivity extends FragmentActivity { ((ViewGroup) findViewById(R.id.content_frame)).addView(view, params); } - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - final int id = item.getItemId(); - if (id == android.R.id.home) { - // Make the up button behave the same as the back button. - onBackPressed(); - return true; - } - return super.onOptionsItemSelected(item); - } - @Override public void setTitle(CharSequence title) { if (mCollapsingToolbarLayout != null) { @@ -341,20 +343,21 @@ public class SettingsBaseActivity extends FragmentActivity { } } - private Bundle getActivityOptionsBundle() { - final Toolbar toolbar = findViewById(R.id.action_bar); - return ActivityOptions.makeSceneTransitionAnimation(this, toolbar, - "shared_element_view").toBundle(); - } - - private Bundle getMergedBundleForTransition(@NonNull Bundle options) { - final Bundle mergedBundle = new Bundle(); - mergedBundle.putAll(options); - final Bundle activityOptionsBundle = getActivityOptionsBundle(); - if (activityOptionsBundle != null) { - mergedBundle.putAll(activityOptionsBundle); + @androidx.annotation.Nullable + private Bundle createActivityOptionsBundleForTransition( + @androidx.annotation.Nullable Bundle options) { + if (mToolbar == null) { + Log.w(TAG, "setActionBar(Toolbar) is not called. Cannot apply settings transition!"); + return options; } - return mergedBundle; + final Bundle transitionOptions = ActivityOptions.makeSceneTransitionAnimation(this, + mToolbar, "shared_element_view").toBundle(); + if (options == null) { + return transitionOptions; + } + final Bundle mergedOptions = new Bundle(options); + mergedOptions.putAll(transitionOptions); + return mergedOptions; } public interface CategoryListener { From 3720ae21b0a983ef1f38b09789fb1f526ad48d11 Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Thu, 20 May 2021 20:21:56 +0800 Subject: [PATCH 09/20] Fix the color of dot wrongly in device admin page In this cl, we migrate origin files/method from framework into settings app. So, we can control layout and drawble without impacting other app. And we only remove to set a tint color in app_permission_item.xml. Currently, it won't tint color for dot now. Test: See the screen and dot's color is correct. Fix: 188188444 Change-Id: I18054b47ba07e7864e7c238f2bec5fbe1d3feeea --- res/drawable/ic_text_dot.xml | 24 +++++++++ res/layout/app_permission_item.xml | 51 +++++++++++++++++++ .../deviceadmin/DeviceAdminAdd.java | 32 ++++++++++-- 3 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 res/drawable/ic_text_dot.xml create mode 100644 res/layout/app_permission_item.xml diff --git a/res/drawable/ic_text_dot.xml b/res/drawable/ic_text_dot.xml new file mode 100644 index 00000000000..1a81bc7a13e --- /dev/null +++ b/res/drawable/ic_text_dot.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/res/layout/app_permission_item.xml b/res/layout/app_permission_item.xml new file mode 100644 index 00000000000..f5e34862db1 --- /dev/null +++ b/res/layout/app_permission_item.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + diff --git a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java index 6a764d409a2..3ebbc06dc88 100644 --- a/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java +++ b/src/com/android/settings/applications/specialaccess/deviceadmin/DeviceAdminAdd.java @@ -38,6 +38,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -52,11 +53,11 @@ import android.text.method.ScrollingMovementMethod; import android.util.EventLog; import android.util.Log; import android.view.Display; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.WindowManager; -import android.widget.AppSecurityPermissions; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; @@ -134,6 +135,8 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { boolean mIsCalledFromSupportDialog = false; + private LayoutInflater mLayoutInflaternflater; + @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -142,6 +145,7 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE); + mLayoutInflaternflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); PackageManager packageManager = getPackageManager(); if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { @@ -735,14 +739,36 @@ public class DeviceAdminAdd extends CollapsingToolbarBaseActivity { for (DeviceAdminInfo.PolicyInfo pi : mDeviceAdmin.getUsedPolicies()) { int descriptionId = isAdminUser ? pi.description : pi.descriptionForSecondaryUsers; int labelId = isAdminUser ? pi.label : pi.labelForSecondaryUsers; - View view = AppSecurityPermissions.getPermissionItemView(this, getText(labelId), - showDescription ? getText(descriptionId) : "", true); + View view = getPermissionItemView(getText(labelId), + showDescription ? getText(descriptionId) : ""); mAdminPolicies.addView(view); } mAdminPoliciesInitialized = true; } } + /** + * Utility to retrieve a view displaying a single permission. This provides + * the UI layout for permissions. + */ + private View getPermissionItemView(CharSequence grpName, CharSequence description) { + Drawable icon = this.getDrawable(com.android.internal.R.drawable.ic_text_dot); + View permView = mLayoutInflaternflater.inflate(R.layout.app_permission_item, null); + TextView permGrpView = permView.findViewById(R.id.permission_group); + TextView permDescView = permView.findViewById(R.id.permission_list); + ImageView imgView = (ImageView) permView.findViewById(R.id.perm_icon); + + imgView.setImageDrawable(icon); + if (grpName != null) { + permGrpView.setText(grpName); + permDescView.setText(description); + } else { + permGrpView.setText(description); + permDescView.setVisibility(View.GONE); + } + return permView; + } + void toggleMessageEllipsis(View v) { TextView tv = (TextView) v; From a51c9988c5fd53af4bfa6a3efd47d327fa1dbdb3 Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Thu, 20 May 2021 21:25:22 +0800 Subject: [PATCH 10/20] Fix talkback doesn't speak subtext info In the original design, we only set title description for view holder, this is wrong. It causes talkback can't speak subtext info. Currently, we set the title content description in the title view directly, so talkback can say the title and subtext now when talkback focus on an app view. Test: Talkback speaks full information for an app entry Fix: 177873163 Change-Id: I94996d596a85cc2813ed1b10cdd4ed2bee62f4a9 --- .../ApplicationViewHolder.java | 15 +++++++++++---- .../manageapplications/ManageApplications.java | 3 +-- .../ApplicationViewHolderTest.java | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java index b0720473de6..e5e9b7df9fa 100644 --- a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java +++ b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java @@ -19,6 +19,7 @@ package com.android.settings.applications.manageapplications; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -37,9 +38,8 @@ import com.android.settingslib.applications.ApplicationsState.AppEntry; public class ApplicationViewHolder extends RecyclerView.ViewHolder { - private final TextView mAppName; - private final ImageView mAppIcon; - + @VisibleForTesting + final TextView mAppName; @VisibleForTesting final TextView mSummary; @VisibleForTesting @@ -49,6 +49,8 @@ public class ApplicationViewHolder extends RecyclerView.ViewHolder { @VisibleForTesting final Switch mSwitch; + private final ImageView mAppIcon; + ApplicationViewHolder(View itemView) { super(itemView); mAppName = itemView.findViewById(android.R.id.title); @@ -95,11 +97,16 @@ public class ApplicationViewHolder extends RecyclerView.ViewHolder { itemView.setEnabled(isEnabled); } - void setTitle(CharSequence title) { + void setTitle(CharSequence title, CharSequence contentDescription) { if (title == null) { return; } mAppName.setText(title); + + if (TextUtils.isEmpty(contentDescription)) { + return; + } + mAppName.setContentDescription(contentDescription); } void setIcon(int drawableRes) { diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index 7469b710597..d5162a85c2d 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -1422,9 +1422,8 @@ public class ManageApplications extends InstrumentedFragment // Bind the data efficiently with the holder final ApplicationsState.AppEntry entry = mEntries.get(position); synchronized (entry) { - holder.setTitle(entry.label); mState.ensureLabelDescription(entry); - holder.itemView.setContentDescription(entry.labelDescription); + holder.setTitle(entry.label, entry.labelDescription); mState.ensureIcon(entry); holder.setIcon(entry.icon); updateSummary(holder, entry); diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java index c3ae904bb1f..83d74a7e37c 100644 --- a/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java +++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java @@ -69,6 +69,22 @@ public class ApplicationViewHolderTest { assertThat(mHolder.mSummary.getText()).isEqualTo(mContext.getText(R.string.disabled)); } + @Test + public void setTitle_titleIsNotEmptyAndContentIsNotEmpty_shouldSetTitleAndContentDescription() { + mHolder.setTitle("title", "content"); + + assertThat(mHolder.mAppName).isEqualTo("title"); + assertThat(mHolder.mAppName.getContentDescription()).isEqualTo("content"); + } + + @Test + public void setTitle_titleIsNotEmptyButContentIsEmpty_shouldSetTitle() { + mHolder.setTitle("title", ""); + + assertThat(mHolder.mAppName).isEqualTo("title"); + assertThat(mHolder.mAppName.getContentDescription()).isEqualTo("title"); + } + @Test public void updateSize() { final String invalidStr = "invalid"; From 2bdeaae97a79a8ae1375c73362b75cb9181d1d79 Mon Sep 17 00:00:00 2001 From: Tsung-Mao Fang Date: Thu, 20 May 2021 21:40:57 +0800 Subject: [PATCH 11/20] Apply ripple on entire button Expand the width of button, so we can see ripple on entire button. Test: Click button and see ripple. Fix: 188735750 Change-Id: Ic65e3579263108c9d0de0eb405fe30f2556b5193 --- res/layout/device_admin_add.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/layout/device_admin_add.xml b/res/layout/device_admin_add.xml index 7fdcd8dc7ff..493f22c3367 100644 --- a/res/layout/device_admin_add.xml +++ b/res/layout/device_admin_add.xml @@ -134,7 +134,7 @@ android:showDividers="beginning|middle|end"> From 869e99687401a11cab27051092be4ba172315c8e Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Wed, 19 May 2021 12:03:30 -0700 Subject: [PATCH 12/20] Update UDFPS fingerprint enrollment 1) Update UDFPS FindSensor to more of an EDU flow 2) Update UDFPS enrolling page to announce strings properly Bug: 187460696 Test: manual Change-Id: I30a77bd6bba911afb82e158d5e9f35b644ec880d --- res/values/strings.xml | 16 +++++++---- .../biometrics/BiometricEnrollBase.java | 10 ++++++- .../FingerprintEnrollEnrolling.java | 28 ++++++++++++++++--- .../FingerprintEnrollFindSensor.java | 21 ++++++++++++-- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index b3dd343ab1d..3c9856a7dad 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1009,13 +1009,15 @@ Touch the sensor - Touch & hold the fingerprint icon + How to set up your fingerprint It\u2019s on the back of your phone. Use your index finger. - The fingerprint sensor is on your screen + The fingerprint sensor is on your screen. You\u2019ll capture your fingerprint on the next screen. + + Start - The fingerprint sensor is on your screen. Move your finger across the screen to find the sensor. + Move your finger across the screen to find the sensor. Touch & hold the fingerprint sensor. Illustration with device and fingerprint sensor location @@ -1029,7 +1031,9 @@ Put your finger on the sensor and lift after you feel a vibration - Keep your finger on the icon until you feel a vibration + Keep your finger on the sensor until you feel a vibration + + Touch & hold the fingerprint sensor Lift, then touch again @@ -1039,7 +1043,9 @@ Keep lifting your finger to add the different parts of your fingerprint - Touch & hold each time the icon moves. This helps capture your full fingerprint. + Touch & hold each time the fingerprint icon moves. This helps capture your full fingerprint. + + This helps capture your full fingerprint Fingerprint added diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java index 67148d141ba..f7af1939296 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollBase.java +++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java @@ -175,20 +175,28 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity { layoutTitle.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE); } getLayout().setHeaderText(title); + getLayout().getHeaderTextView().setContentDescription(title); setTitle(title); } } protected void setHeaderText(int resId) { setHeaderText(resId, false /* force */); + getLayout().getHeaderTextView().setContentDescription(getText(resId)); } protected void setHeaderText(CharSequence title) { getLayout().setHeaderText(title); + getLayout().getHeaderTextView().setContentDescription(title); } protected void setDescriptionText(int resId) { - getLayout().setDescriptionText(resId); + CharSequence previousDescription = getLayout().getDescriptionText(); + CharSequence description = getString(resId); + // Prevent a11y for re-reading the same string + if (!TextUtils.equals(previousDescription, description)) { + getLayout().setDescriptionText(resId); + } } protected void setDescriptionText(CharSequence descriptionText) { diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java index 6bdd3f7ddd1..d987c05d521 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java @@ -37,6 +37,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityManager; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.ProgressBar; @@ -111,6 +112,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { private boolean mRestoring; private Vibrator mVibrator; private boolean mIsSetupWizard; + private boolean mIsAccessibilityEnabled; @Override protected void onCreate(Bundle savedInstanceState) { @@ -121,6 +123,9 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { fingerprintManager.getSensorPropertiesInternal(); mCanAssumeUdfps = props.size() == 1 && props.get(0).isAnyUdfpsType(); + final AccessibilityManager am = getSystemService(AccessibilityManager.class); + mIsAccessibilityEnabled = am.isEnabled(); + if (mCanAssumeUdfps) { if (BiometricUtils.isReverseLandscape(getApplicationContext())) { setContentView(R.layout.udfps_enroll_enrolling_land); @@ -134,8 +139,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { } mIsSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent()); - if (mCanAssumeUdfps && !mIsSetupWizard) { - setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title); + if (mCanAssumeUdfps) { + updateTitleAndDescription(); } else { setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title); } @@ -282,7 +287,18 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { private void updateTitleAndDescription() { if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) { if (mCanAssumeUdfps) { + // setHeaderText(R.string.security_settings_fingerprint_enroll_udfps_title); + // Don't use BiometricEnrollBase#setHeaderText, since that invokes setTitle, + // which gets announced for a11y upon entering the page. For UDFPS, we want to + // announce a different string for a11y upon entering the page. + getLayout().setHeaderText( + R.string.security_settings_fingerprint_enroll_udfps_title); setDescriptionText(R.string.security_settings_udfps_enroll_start_message); + + final CharSequence description = getString( + R.string.security_settings_udfps_enroll_a11y); + getLayout().getHeaderTextView().setContentDescription(description); + setTitle(description); } else { setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message); } @@ -295,8 +311,12 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { setDescriptionText(R.string.security_settings_udfps_enroll_start_message); } else { if (mCanAssumeUdfps) { - setHeaderText(R.string.security_settings_udfps_enroll_repeat_title_touch_icon); - setDescriptionText(R.string.security_settings_udfps_enroll_repeat_message); + setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title); + if (mIsAccessibilityEnabled) { + setDescriptionText(R.string.security_settings_udfps_enroll_repeat_a11y_message); + } else { + setDescriptionText(R.string.security_settings_udfps_enroll_repeat_message); + } } else { setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_message); } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java index c7500e8e300..7c64175c786 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollFindSensor.java @@ -62,7 +62,7 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class); mFooterBarMixin.setSecondaryButton( new FooterButton.Builder(this) - .setText(R.string.skip_label) + .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip) .setListener(this::onSkipButtonClick) .setButtonType(FooterButton.ButtonType.SKIP) .setTheme(R.style.SudGlifButton_Secondary) @@ -72,8 +72,14 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements if (mCanAssumeUdfps) { setHeaderText(R.string.security_settings_udfps_enroll_find_sensor_title); setDescriptionText(R.string.security_settings_udfps_enroll_find_sensor_message); - final CharSequence description = getString(R.string.security_settings_udfps_enroll_find_sensor_a11y); - getLayout().getDescriptionTextView().setContentDescription(description); + mFooterBarMixin.setPrimaryButton( + new FooterButton.Builder(this) + .setText(R.string.security_settings_udfps_enroll_find_sensor_start_button) + .setListener(this::onStartButtonClick) + .setButtonType(FooterButton.ButtonType.NEXT) + .setTheme(R.style.SudGlifButton_Primary) + .build() + ); } else { setHeaderText(R.string.security_settings_fingerprint_enroll_find_sensor_title); setDescriptionText(R.string.security_settings_fingerprint_enroll_find_sensor_message); @@ -148,6 +154,11 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements } private void startLookingForFingerprint() { + if (mCanAssumeUdfps) { + // UDFPS devices use this screen as an educational screen. Users should tap the + // "Start" button to move to the next screen to begin enrollment. + return; + } mSidecar = (FingerprintEnrollSidecar) getSupportFragmentManager().findFragmentByTag( FingerprintEnrollEnrolling.TAG_SIDECAR); if (mSidecar == null) { @@ -201,6 +212,10 @@ public class FingerprintEnrollFindSensor extends BiometricEnrollBase implements } } + private void onStartButtonClick(View view) { + startActivityForResult(getFingerprintEnrollingIntent(), ENROLL_REQUEST); + } + protected void onSkipButtonClick(View view) { stopLookingForFingerprint(); setResult(RESULT_SKIP); From e25713054abf6a5db0774a93f9913f8965e4ddf9 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Wed, 19 May 2021 15:53:20 -0700 Subject: [PATCH 13/20] Announce UDPFS enrollment percentage Bug: 187460696 Test: manual Change-Id: I5989a67e1fa1ed078677a69b2d841d5f1f1ee691 --- res/values/strings.xml | 2 ++ .../FingerprintEnrollEnrolling.java | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 3c9856a7dad..e25deb35d69 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1046,6 +1046,8 @@ Touch & hold each time the fingerprint icon moves. This helps capture your full fingerprint. This helps capture your full fingerprint + + Enrolling fingerprint %d percent Fingerprint added diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java index d987c05d521..9b19ef796c0 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java @@ -37,6 +37,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -112,6 +113,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { private boolean mRestoring; private Vibrator mVibrator; private boolean mIsSetupWizard; + private AccessibilityManager mAccessibilityManager; private boolean mIsAccessibilityEnabled; @Override @@ -123,8 +125,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { fingerprintManager.getSensorPropertiesInternal(); mCanAssumeUdfps = props.size() == 1 && props.get(0).isAnyUdfpsType(); - final AccessibilityManager am = getSystemService(AccessibilityManager.class); - mIsAccessibilityEnabled = am.isEnabled(); + mAccessibilityManager = getSystemService(AccessibilityManager.class); + mIsAccessibilityEnabled = mAccessibilityManager.isEnabled(); if (mCanAssumeUdfps) { if (BiometricUtils.isReverseLandscape(getApplicationContext())) { @@ -359,6 +361,18 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { if (!mCanAssumeUdfps) { mErrorText.removeCallbacks(mTouchAgainRunnable); mErrorText.postDelayed(mTouchAgainRunnable, HINT_TIMEOUT_DURATION); + } else { + if (mIsAccessibilityEnabled) { + final int percent = (int) (((float)(steps - remaining) / (float) steps) * 100); + CharSequence cs = getString( + R.string.security_settings_udfps_enroll_progress_a11y_message, percent); + AccessibilityEvent e = AccessibilityEvent.obtain(); + e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); + e.setClassName(getClass().getName()); + e.setPackageName(getPackageName()); + e.getText().add(cs); + mAccessibilityManager.sendAccessibilityEvent(e); + } } } From 34eae091e4a406abbdbfc8d27483beada480dba6 Mon Sep 17 00:00:00 2001 From: Chen Xu Date: Thu, 20 May 2021 16:38:36 -0700 Subject: [PATCH 14/20] integrate config_disable_all_cb_messages to settings In R we introduced a new config (also part of GMS requirement) mainly for disable emergency alerts on devices which does not support messaging or voices e.g, data only tablets. If the config is set to true, framework should not forward any messages to users and hide emergency alert from settings menu as well. Bug: 176557108 Test: Manual Change-Id: I2705839255a8450aa80a1a503a973207fd895a33 --- .../EmergencyBroadcastPreferenceController.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java b/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java index de7e7801ac2..b456e531d58 100644 --- a/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java +++ b/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java @@ -86,7 +86,11 @@ public class EmergencyBroadcastPreferenceController extends AbstractPreferenceCo private boolean isCellBroadcastAppLinkEnabled() { // Enable link to CMAS app settings depending on the value in config.xml. boolean enabled = mContext.getResources().getBoolean( - com.android.internal.R.bool.config_cellBroadcastAppLinks); + com.android.internal.R.bool.config_cellBroadcastAppLinks) && + // For data-only tablet devices which need to not forwarding any WEA-alert and hide from + // settings menu. + !mContext.getResources().getBoolean( + com.android.internal.R.bool.config_disable_all_cb_messages); if (enabled) { try { String packageName = CellBroadcastUtils From e8c24c3e659185a6af556dcce3e423d1a86d44ef Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Thu, 20 May 2021 23:56:25 +0800 Subject: [PATCH 15/20] Remove the horizontal divider around ActionButtonsPreference Remove the horizontal divider from App info and App info > Storage since they are not required anymore with the new style. Fixes: 188742417 Test: visual Change-Id: Idc0ab5994694c490ab04fac04a8b114f9fe191a1 --- res/xml/app_info_settings_v2.xml | 13 ++----------- res/xml/app_storage_settings.xml | 8 +------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/res/xml/app_info_settings_v2.xml b/res/xml/app_info_settings_v2.xml index 8b9cf4f60e2..b4a82e0a3f3 100644 --- a/res/xml/app_info_settings_v2.xml +++ b/res/xml/app_info_settings_v2.xml @@ -24,27 +24,18 @@ android:key="header_view" android:layout="@layout/settings_entity_header" android:selectable="false" - android:order="-10000" - settings:allowDividerBelow="true"/> + android:order="-10000" /> + android:order="-9999" /> - - - - - + android:title="@string/app_info_storage_title"> Date: Mon, 3 May 2021 19:42:57 +0800 Subject: [PATCH 16/20] Introduce InteractionJankMonitor into Settings Detects the jank of page scrolling which is implemented by InstrumentedPreferenceFragment. Bug: 187306869 Test: verify with Perfetto Change-Id: Icaa557d1b47a12374298f044e2f9568281589f64 --- .../core/InstrumentedPreferenceFragment.java | 43 +++++++++++++++++++ .../password/ChooseLockGenericTest.java | 4 +- .../shadow/ShadowInteractionJankMonitor.java | 33 ++++++++++++++ .../wifi/p2p/WifiP2pSettingsTest.java | 3 ++ .../SavedAccessPointsWifiSettings2Test.java | 3 ++ 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java diff --git a/src/com/android/settings/core/InstrumentedPreferenceFragment.java b/src/com/android/settings/core/InstrumentedPreferenceFragment.java index 06e65846f2d..183c6f730ba 100644 --- a/src/com/android/settings/core/InstrumentedPreferenceFragment.java +++ b/src/com/android/settings/core/InstrumentedPreferenceFragment.java @@ -16,6 +16,8 @@ package com.android.settings.core; +import static com.android.internal.jank.InteractionJankMonitor.CUJ_SETTINGS_PAGE_SCROLL; + import android.content.Context; import android.os.Bundle; import android.text.TextUtils; @@ -24,7 +26,9 @@ import android.util.Log; import androidx.annotation.XmlRes; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import androidx.recyclerview.widget.RecyclerView; +import com.android.internal.jank.InteractionJankMonitor; import com.android.settings.overlay.FeatureFactory; import com.android.settings.survey.SurveyMixin; import com.android.settingslib.core.instrumentation.Instrumentable; @@ -47,6 +51,7 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc protected final int PLACEHOLDER_METRIC = 10000; private VisibilityLoggerMixin mVisibilityLoggerMixin; + private RecyclerView.OnScrollListener mOnScrollListener; @Override public void onAttach(Context context) { @@ -62,9 +67,25 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc @Override public void onResume() { mVisibilityLoggerMixin.setSourceMetricsCategory(getActivity()); + // Add scroll listener to trace interaction jank. + final RecyclerView recyclerView = getListView(); + if (recyclerView != null) { + mOnScrollListener = new OnScrollListener(getClass().getName()); + recyclerView.addOnScrollListener(mOnScrollListener); + } super.onResume(); } + @Override + public void onPause() { + final RecyclerView recyclerView = getListView(); + if (mOnScrollListener != null) { + recyclerView.removeOnScrollListener(mOnScrollListener); + mOnScrollListener = null; + } + super.onPause(); + } + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { final int resId = getPreferenceScreenResId(); @@ -123,4 +144,26 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc } } + private static final class OnScrollListener extends RecyclerView.OnScrollListener { + private final InteractionJankMonitor mMonitor = InteractionJankMonitor.getInstance(); + private final String mClassName; + + private OnScrollListener(String className) { + mClassName = className; + } + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + switch (newState) { + case RecyclerView.SCROLL_STATE_DRAGGING: + // TODO: Update API with tag parameter (class name). + mMonitor.begin(recyclerView, CUJ_SETTINGS_PAGE_SCROLL); + break; + case RecyclerView.SCROLL_STATE_IDLE: + mMonitor.end(CUJ_SETTINGS_PAGE_SCROLL); + break; + default: + } + } + } } diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java index 6b92e570099..fd711f8ab61 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java @@ -57,6 +57,7 @@ import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.core.FeatureFlags; import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; import com.android.settings.search.SearchFeatureProvider; +import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; import com.android.settings.testutils.shadow.ShadowLockPatternUtils; import com.android.settings.testutils.shadow.ShadowStorageManager; import com.android.settings.testutils.shadow.ShadowUserManager; @@ -81,7 +82,8 @@ import org.robolectric.shadows.ShadowPersistentDataBlockManager; ShadowPersistentDataBlockManager.class, ShadowStorageManager.class, ShadowUserManager.class, - ShadowUtils.class + ShadowUtils.class, + ShadowInteractionJankMonitor.class }) public class ChooseLockGenericTest { diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java new file mode 100644 index 00000000000..3ec07c515ce --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowInteractionJankMonitor.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2021 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.testutils.shadow; + +import static org.mockito.Mockito.mock; + +import com.android.internal.jank.InteractionJankMonitor; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(InteractionJankMonitor.class) +public class ShadowInteractionJankMonitor { + + @Implementation + public static InteractionJankMonitor getInstance() { + return mock(InteractionJankMonitor.class); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java index c9d21190bb6..ab306d9a1a1 100644 --- a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java +++ b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java @@ -45,6 +45,7 @@ import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import com.android.settings.testutils.XmlTestUtils; +import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; import com.android.settingslib.core.AbstractPreferenceController; import org.junit.Before; @@ -55,11 +56,13 @@ import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; @RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowInteractionJankMonitor.class) public class WifiP2pSettingsTest { private Context mContext; diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java index 657d3a7603e..8c07ac3f9c5 100644 --- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java +++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints2/SavedAccessPointsWifiSettings2Test.java @@ -33,6 +33,7 @@ import androidx.fragment.app.FragmentTransaction; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.testutils.shadow.ShadowInteractionJankMonitor; import com.android.settingslib.core.AbstractPreferenceController; import org.junit.Before; @@ -43,8 +44,10 @@ import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowInteractionJankMonitor.class) public class SavedAccessPointsWifiSettings2Test { @Mock From 600d023892718409b6ee8333418f14ccd2fbc3d0 Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Tue, 18 May 2021 15:46:52 +0800 Subject: [PATCH 17/20] Make preference title align after icon - Running service should use app preference layout. - RestrictedDropdownPreference should use preference layout. - Tweek Storage item icon padding - Wifi calling should use Prefernce - In Open by default page, if there is no vierfied link, we should hide the checkbox. Bug: 186069482 Test: manual Change-Id: Icc186ad79fc2bcf7ecd9c1ebba747bdad2d9b9ad Merged-In: Icc186ad79fc2bcf7ecd9c1ebba747bdad2d9b9ad --- res/layout/restricted_preference_dropdown.xml | 2 +- res/layout/running_processes_item.xml | 2 +- res/layout/storage_item.xml | 17 +---------------- res/values/styles_preference.xml | 1 + res/xml/mobile_network_settings.xml | 4 ++-- .../intentpicker/VerifiedLinksPreference.java | 2 +- 6 files changed, 7 insertions(+), 21 deletions(-) diff --git a/res/layout/restricted_preference_dropdown.xml b/res/layout/restricted_preference_dropdown.xml index 86053bf1eac..8930e24bb28 100644 --- a/res/layout/restricted_preference_dropdown.xml +++ b/res/layout/restricted_preference_dropdown.xml @@ -26,6 +26,6 @@ android:visibility="invisible" android:layout_marginStart="@dimen/preference_no_icon_padding_start"/> - + \ No newline at end of file diff --git a/res/layout/running_processes_item.xml b/res/layout/running_processes_item.xml index 2bca90e20a4..6b8547a0dd2 100644 --- a/res/layout/running_processes_item.xml +++ b/res/layout/running_processes_item.xml @@ -31,5 +31,5 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_toStartOf="@id/widget_summary" - layout="@layout/preference_material"/> + layout="@layout/preference_app"/> \ No newline at end of file diff --git a/res/layout/storage_item.xml b/res/layout/storage_item.xml index 6de2d510b17..40796f7b373 100644 --- a/res/layout/storage_item.xml +++ b/res/layout/storage_item.xml @@ -35,22 +35,7 @@ android:clipToPadding="false" android:paddingStart="?android:attr/listPreferredItemPaddingStart"> - - - + @android:string/ok @android:string/cancel + @bool/settingslib_config_icon_space_reserved