From c8bbf83baf910397201ebb9a27f9eb4ced3ebc49 Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Wed, 24 May 2023 19:36:53 +0800 Subject: [PATCH 1/5] Correct Factory Reset activity protect permission Fixes: 265676549 Test: am start -a com.android.settings.action.FACTORY_RESET Change-Id: I039b7c47897c6fe7999754dc3f776f069846c1e3 --- AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 29a0faab9b1..b4cf3812287 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4838,7 +4838,7 @@ From a425247076b9802b6c43580da8d8f0da3d23f784 Mon Sep 17 00:00:00 2001 From: Vania Januar Date: Thu, 22 Jun 2023 10:12:09 +0000 Subject: [PATCH 2/5] Clarify that enabling Notes role requires reboot in preference summary Bug: 288387225 Change-Id: Id07e3b188442c6f4695b43d62b02ea8465d76a7e Test: only a string change --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 3184a1f09e6..04d9f17de4b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11994,7 +11994,7 @@ Force enable Notes role - Enable note-taking system integrations via the Notes role. If the Notes role is already enabled, does nothing. + Enable note-taking system integrations via the Notes role. If the Notes role is already enabled, does nothing. Requires reboot. From be823bc5982df40990d92e0d342da7ea689f411e Mon Sep 17 00:00:00 2001 From: Hao Dong Date: Wed, 7 Jun 2023 00:02:48 +0000 Subject: [PATCH 3/5] Wait for systemui udfps overlay ready to show settings udfps enroll view. Previously, we show settings's udfps enroll animation view (the fingerprint icon and progress view) once the FingerprintEnrollEnrolling is shown. However, touch events have to wait for systemui's udfps overlay to be valid. This CL lets settings's udfps enroll view wait for systemui's overlay. 1. Sets udfps enroll animation view's default visibility Gone. 2. Propagates FingerprintManager#onUdfpsOverlayShown to FingerprintEnrollEnrolling and when it's called, set the enroll view visible. Besides, this CL renames onPointerDown() and onPointerUp() with Udfps. Bug: 280718879 Test: atest FingerprintEnrollEnrollingTest Change-Id: Ieed3e74c182828918785edcacb021f19a3665f2a --- res/layout/udfps_enroll_view.xml | 3 +- .../biometrics/BiometricEnrollSidecar.java | 48 ++-- .../FingerprintEnrollEnrolling.java | 11 +- .../fingerprint/FingerprintEnrollSidecar.java | 13 +- .../fingerprint/FingerprintUpdater.java | 13 +- .../fingerprint/UdfpsEnrollEnrollingView.java | 236 ++++++++++++++++++ .../FingerprintEnrollProgressViewModel.java | 4 +- .../FingerprintEnrollEnrollingTest.java | 21 +- ...ingerprintEnrollProgressViewModelTest.java | 4 +- 9 files changed, 320 insertions(+), 33 deletions(-) create mode 100644 src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java diff --git a/res/layout/udfps_enroll_view.xml b/res/layout/udfps_enroll_view.xml index 6bf339b6b07..bd626093ce4 100644 --- a/res/layout/udfps_enroll_view.xml +++ b/res/layout/udfps_enroll_view.xml @@ -18,7 +18,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/udfps_animation_view" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:visibility="gone"> { + secondaryButtonView.setLayoutParams( + new LinearLayout.LayoutParams(mHeaderView.getMeasuredWidth(), + ViewGroup.LayoutParams.WRAP_CONTENT)); + }); + } + + private void initUdfpsEnrollView(FingerprintSensorPropertiesInternal udfpsProps, + UdfpsEnrollHelper udfpsEnrollHelper) { + DisplayInfo displayInfo = new DisplayInfo(); + mContext.getDisplay().getDisplayInfo(displayInfo); + + final float scaleFactor = mUdfpsUtils.getScaleFactor(displayInfo); + Rect udfpsBounds = udfpsProps.getLocation().getRect(); + udfpsBounds.scale(scaleFactor); + + final Rect overlayBounds = new Rect( + 0, /* left */ + displayInfo.getNaturalHeight() / 2, /* top */ + displayInfo.getNaturalWidth(), /* right */ + displayInfo.getNaturalHeight() /* botom */); + + UdfpsOverlayParams params = new UdfpsOverlayParams( + udfpsBounds, + overlayBounds, + displayInfo.getNaturalWidth(), + displayInfo.getNaturalHeight(), + scaleFactor, + displayInfo.rotation); + + mUdfpsEnrollView.setOverlayParams(params); + mUdfpsEnrollView.setEnrollHelper(udfpsEnrollHelper); + } + + private void adjustPortraitPaddings() { + // In the portrait mode, layout_container's height is 0, so it's + // always shown at the bottom of the screen. + final FrameLayout portraitLayoutContainer = findViewById(R.id.layout_container); + + // In the portrait mode, the title and lottie animation view may + // overlap when title needs three lines, so adding some paddings + // between them, and adjusting the fp progress view here accordingly. + final int layoutLottieAnimationPadding = (int) getResources() + .getDimension(R.dimen.udfps_lottie_padding_top); + portraitLayoutContainer.setPadding(0, + layoutLottieAnimationPadding, 0, 0); + final ImageView progressView = mUdfpsEnrollView.findViewById( + R.id.udfps_enroll_animation_fp_progress_view); + progressView.setPadding(0, -(layoutLottieAnimationPadding), + 0, layoutLottieAnimationPadding); + final ImageView fingerprintView = mUdfpsEnrollView.findViewById( + R.id.udfps_enroll_animation_fp_view); + fingerprintView.setPadding(0, -layoutLottieAnimationPadding, + 0, layoutLottieAnimationPadding); + + // TODO(b/260970216) Instead of hiding the description text view, we should + // make the header view scrollable if the text is too long. + // If description text view has overlap with udfps progress view, hide it. + final View descView = getDescriptionTextView(); + getViewTreeObserver().addOnDrawListener(() -> { + if (descView.getVisibility() == View.VISIBLE + && hasOverlap(descView, mUdfpsEnrollView)) { + descView.setVisibility(View.GONE); + } + }); + } + + private void setOnHoverListener() { + if (!mAccessibilityManager.isEnabled()) return; + + final View.OnHoverListener onHoverListener = (v, event) -> { + // Map the touch to portrait mode if the device is in + // landscape mode. + final Point scaledTouch = + mUdfpsUtils.getTouchInNativeCoordinates(event.getPointerId(0), + event, mUdfpsEnrollView.getOverlayParams()); + + if (mUdfpsUtils.isWithinSensorArea(event.getPointerId(0), event, + mUdfpsEnrollView.getOverlayParams())) { + return false; + } + + final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea( + mAccessibilityManager.isTouchExplorationEnabled(), mContext, + scaledTouch.x, scaledTouch.y, mUdfpsEnrollView.getOverlayParams()); + if (theStr != null) { + v.announceForAccessibility(theStr); + } + return false; + }; + + findManagedViewById(mIsLandscape ? R.id.sud_landscape_content_area + : R.id.sud_layout_content).setOnHoverListener(onHoverListener); + } + + private void swapHeaderAndContent() { + // Reverse header and body + ViewGroup parentView = (ViewGroup) mHeaderView.getParent(); + parentView.removeView(mHeaderView); + parentView.addView(mHeaderView); + + // Hide scroll indicators + BottomScrollView headerScrollView = mHeaderView.findViewById(R.id.sud_header_scroll_view); + headerScrollView.setScrollIndicators(0); + } + + @VisibleForTesting + boolean hasOverlap(View view1, View view2) { + int[] firstPosition = new int[2]; + int[] secondPosition = new int[2]; + + view1.getLocationOnScreen(firstPosition); + view2.getLocationOnScreen(secondPosition); + + // Rect constructor parameters: left, top, right, bottom + Rect rectView1 = new Rect(firstPosition[0], firstPosition[1], + firstPosition[0] + view1.getMeasuredWidth(), + firstPosition[1] + view1.getMeasuredHeight()); + Rect rectView2 = new Rect(secondPosition[0], secondPosition[1], + secondPosition[0] + view2.getMeasuredWidth(), + secondPosition[1] + view2.getMeasuredHeight()); + return rectView1.intersect(rectView2); + } +} diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java index d77d9d3f7e8..7074288716e 100644 --- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java +++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java @@ -103,12 +103,12 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { } @Override - public void onPointerDown(int sensorId) { + public void onUdfpsPointerDown(int sensorId) { mPointerDownLiveData.postValue(sensorId); } @Override - public void onPointerUp(int sensorId) { + public void onUdfpsPointerUp(int sensorId) { mPointerUpLiveData.postValue(sensorId); } }; diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java index 959c6426894..e5b283ae185 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java @@ -339,6 +339,19 @@ public class FingerprintEnrollEnrollingTest { assertThat(descriptionTextView.getVisibility()).isEqualTo(View.VISIBLE); } + @Test + public void fingerprintUdfpsOverlayEnrollment_udfpsAnimationViewVisibility() { + initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL); + when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0); + createActivity(); + + final UdfpsEnrollView enrollView = mActivity.findViewById(R.id.udfps_animation_view); + assertThat(enrollView.getVisibility()).isEqualTo(View.GONE); + + mActivity.onUdfpsOverlayShown(); + assertThat(enrollView.getVisibility()).isEqualTo(View.VISIBLE); + } + @Test public void forwardEnrollProgressEvents() { initializeActivityFor(TYPE_UDFPS_OPTICAL); @@ -380,11 +393,11 @@ public class FingerprintEnrollEnrollingTest { } @Test - public void forwardEnrollPointerDownEvents() { + public void forwardUdfpsEnrollPointerDownEvents() { initializeActivityFor(TYPE_UDFPS_OPTICAL); EnrollListener listener = new EnrollListener(mActivity); - mActivity.onPointerDown(0); + mActivity.onUdfpsPointerDown(0); assertThat(listener.mProgress).isFalse(); assertThat(listener.mHelp).isFalse(); assertThat(listener.mAcquired).isFalse(); @@ -393,11 +406,11 @@ public class FingerprintEnrollEnrollingTest { } @Test - public void forwardEnrollPointerUpEvents() { + public void forwardUdfpsEnrollPointerUpEvents() { initializeActivityFor(TYPE_UDFPS_OPTICAL); EnrollListener listener = new EnrollListener(mActivity); - mActivity.onPointerUp(0); + mActivity.onUdfpsPointerUp(0); assertThat(listener.mProgress).isFalse(); assertThat(listener.mHelp).isFalse(); assertThat(listener.mAcquired).isFalse(); diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java index bdb45b0300f..2c830ad314c 100644 --- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java +++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java @@ -379,7 +379,7 @@ public class FingerprintEnrollProgressViewModelTest { // Notify acquire message final int value = 33; - mCallbackWrapper.mValue.onPointerDown(value); + mCallbackWrapper.mValue.onUdfpsPointerDown(value); assertThat(liveData.getValue()).isEqualTo(value); } @@ -397,7 +397,7 @@ public class FingerprintEnrollProgressViewModelTest { // Notify acquire message final int value = 44; - mCallbackWrapper.mValue.onPointerUp(value); + mCallbackWrapper.mValue.onUdfpsPointerUp(value); assertThat(liveData.getValue()).isEqualTo(value); } From ca617d8612c83106ad39c08fdbbd10043be6b14b Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Mon, 26 Jun 2023 18:08:22 +0000 Subject: [PATCH 4/5] [Regional Preference] Add metric in Regional Preferences Bug: 279918056 Test: manual Change-Id: I71a16a96f2e647945b20cbfeee63d96b0f3a188f --- .../regionalpreferences/NumberingSystemItemController.java | 5 +++-- .../RegionalPreferenceListBasePreferenceController.java | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java b/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java index e3a8d238c4f..2a99e9925ea 100644 --- a/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java +++ b/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java @@ -153,7 +153,7 @@ public class NumberingSystemItemController extends BasePreferenceController { private void handleLanguageSelect(Preference preference) { String selectedLanguage = preference.getKey(); mMetricsFeatureProvider.action(mContext, - SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES); + SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES, selectedLanguage); final Bundle extra = new Bundle(); extra.putString(RegionalPreferencesEntriesFragment.ARG_KEY_REGIONAL_PREFERENCE, ARG_VALUE_NUMBERING_SYSTEM_SELECT); @@ -177,7 +177,8 @@ public class NumberingSystemItemController extends BasePreferenceController { saveNumberingSystemToLocale(Locale.forLanguageTag(mSelectedLanguage), numberingSystem); mMetricsFeatureProvider.action(mContext, - SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES); + SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES, + updatedLocale.getDisplayName() + ": " + numberingSystem); // After updated locale to framework, this fragment will recreate, // so it needs to update the argument of selected language. Bundle bundle = new Bundle(); diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java index 1e39ffff5e7..432ce0e89e9 100644 --- a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java +++ b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java @@ -59,6 +59,8 @@ public abstract class RegionalPreferenceListBasePreferenceController extends TickButtonPreference pref = new TickButtonPreference(mContext); mPreferenceCategory.addPreference(pref); final String item = unitValues[i]; + final String value = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData( + mContext, getExtensionTypes()); pref.setTitle(getPreferenceTitle(item)); pref.setKey(item); pref.setOnPreferenceClickListener(clickedPref -> { @@ -66,11 +68,10 @@ public abstract class RegionalPreferenceListBasePreferenceController extends RegionalPreferencesDataUtils.savePreference(mContext, getExtensionTypes(), item.equals(RegionalPreferencesDataUtils.DEFAULT_VALUE) ? null : item); - mMetricsFeatureProvider.action(mContext, getMetricsActionKey()); + mMetricsFeatureProvider.action(mContext, getMetricsActionKey(), + getPreferenceTitle(value) + " > " + getPreferenceTitle(item)); return true; }); - String value = RegionalPreferencesDataUtils.getDefaultUnicodeExtensionData(mContext, - getExtensionTypes()); pref.setSelected(!value.isEmpty() && item.equals(value)); } } From e52320e755823fc94e3be11fefa7d5d718daba24 Mon Sep 17 00:00:00 2001 From: Edgar Wang Date: Wed, 31 May 2023 18:42:11 +0800 Subject: [PATCH 5/5] Correct used size of Storage Settings. Since StorageManager rounded the totalBytes of device storage but they don't do that rounding for freeBytes. So in some cases the freeBytes can be greater than totalBytes. We propose to get totalBytes of device storage directly to calculate correct privateUsedBytes. Test: robotest Bug: 281955532 Change-Id: I4f137c20e7c2f54f4e037d50e81b3176edc1a83a --- src/com/android/settings/Utils.java | 13 ++++++++++++- .../deviceinfo/StorageCategoryFragment.java | 4 +++- .../deviceinfo/StorageDashboardFragment.java | 4 +++- .../TopLevelStoragePreferenceController.java | 8 ++++++-- ...StorageUsageProgressBarPreferenceController.java | 5 ++++- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index a2195df1b6b..370b17a7156 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -63,6 +63,7 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.Environment; import android.os.IBinder; import android.os.INetworkManagementService; import android.os.RemoteException; @@ -97,7 +98,6 @@ import android.widget.TabWidget; import androidx.annotation.ColorInt; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.StringRes; import androidx.annotation.VisibleForTesting; import androidx.core.graphics.drawable.IconCompat; import androidx.core.graphics.drawable.RoundedBitmapDrawable; @@ -1309,4 +1309,15 @@ public final class Utils extends com.android.settingslib.Utils { com.android.internal.R.bool.config_dreamsOnlyEnabledForDockUser); return dreamsSupported && (!dreamsOnlyEnabledForDockUser || canCurrentUserDream(context)); } + + /** + * Get private total size directly. + * Referred from StorageManager + */ + public static long getPrimaryStorageSize() { + // TODO(b/288103116): remove this method once support by StorageManager. + return Environment.getDataDirectory().getTotalSpace() + + Environment.getRootDirectory().getTotalSpace(); + } + } diff --git a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java index 52f453d46a9..d1d4cbe7f50 100644 --- a/src/com/android/settings/deviceinfo/StorageCategoryFragment.java +++ b/src/com/android/settings/deviceinfo/StorageCategoryFragment.java @@ -211,7 +211,9 @@ public class StorageCategoryFragment extends DashboardFragment setLoading(false /* loading */, false /* animate */); - final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes; + // TODO(b/288103116): replace with new API to get TotalBytes before rounding + // once support by StorageManager. + final long privateUsedBytes = Utils.getPrimaryStorageSize() - mStorageInfo.freeBytes; mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); mPreferenceController.setUsedSize(privateUsedBytes); mPreferenceController.setTotalSize(mStorageInfo.totalBytes); diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index f31f2be0049..4138057a90c 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -387,7 +387,9 @@ public class StorageDashboardFragment extends DashboardFragment setLoading(false /* loading */, false /* animate */); - final long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes; + // TODO(b/288103116): replace with new API to get TotalBytes before rounding + // once support by StorageManager. + final long privateUsedBytes = Utils.getPrimaryStorageSize() - mStorageInfo.freeBytes; mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo()); mPreferenceController.setUsedSize(privateUsedBytes); mPreferenceController.setTotalSize(mStorageInfo.totalBytes); diff --git a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java index e6827832a8e..43dc9dd0d15 100644 --- a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java +++ b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java @@ -74,10 +74,14 @@ public class TopLevelStoragePreferenceController extends BasePreferenceControlle return ThreadUtils.postOnBackgroundThread(() -> { final PrivateStorageInfo info = PrivateStorageInfo.getPrivateStorageInfo( getStorageManagerVolumeProvider()); - storageCacheHelper.cacheUsedSize(info.totalBytes - info.freeBytes); + + // TODO(b/288103116): replace with new API to get TotalBytes before rounding + // once support by StorageManager. + long usedBytes = Utils.getPrimaryStorageSize() - info.freeBytes; + storageCacheHelper.cacheUsedSize(usedBytes); ThreadUtils.postOnMainThread(() -> { preference.setSummary( - getSummary(info.totalBytes - info.freeBytes, info.totalBytes)); + getSummary(usedBytes, info.totalBytes)); }); }); } diff --git a/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java index be2a64abf58..23559d4db00 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageUsageProgressBarPreferenceController.java @@ -26,6 +26,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.widget.UsageProgressBarPreference; @@ -92,7 +93,9 @@ public class StorageUsageProgressBarPreferenceController extends BasePreferenceC if (mStorageEntry.isPrivate()) { // StorageStatsManager can only query private storages. mTotalBytes = mStorageStatsManager.getTotalBytes(mStorageEntry.getFsUuid()); - mUsedBytes = mTotalBytes + // TODO(b/288103116): replace with new API to get TotalBytes before rounding + // once support by StorageManager. + mUsedBytes = Utils.getPrimaryStorageSize() - mStorageStatsManager.getFreeBytes(mStorageEntry.getFsUuid()); } else { final File rootFile = mStorageEntry.getPath();