summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Arseneau <earseneau@google.com>2021-12-13 11:13:18 -0800
committerEric Arseneau <earseneau@google.com>2021-12-13 12:53:06 -0800
commit48cbb14e1815430efd7ff5086e7a4c70e75d475f (patch)
treea752bdec4c37856853b1e12f02daeebee65ffe13
parent88daf9ce34ae13a85aa6d41d42d7f6d5f7d07c1a (diff)
parentea8a98f046c81acd5bdb72169a00ce133e4d27c5 (diff)
Merge mpr-2021-11-05
Change-Id: If7c68a17857eee4194f28413b938d5647820162c
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java4
-rw-r--r--core/java/android/accounts/Account.java7
-rw-r--r--core/java/android/app/ActivityThread.java15
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java2
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java5
-rw-r--r--core/java/android/hardware/display/DisplayManager.java17
-rw-r--r--core/java/android/view/Surface.java4
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java16
-rw-r--r--core/java/android/view/translation/UiTranslationController.java12
-rw-r--r--core/java/android/window/ITaskOrganizer.aidl5
-rw-r--r--core/java/android/window/TaskOrganizer.java9
-rw-r--r--core/java/com/android/internal/jank/FrameTracker.java19
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java2
-rw-r--r--core/jni/android_view_Surface.cpp6
-rw-r--r--core/res/res/values-ta/strings.xml2
-rw-r--r--core/res/res/values-te/strings.xml108
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--graphics/java/android/graphics/ImageFormat.java18
-rw-r--r--keystore/java/android/security/GenerateRkpKey.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java52
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java82
-rw-r--r--libs/hwui/WebViewFunctorManager.cpp3
-rw-r--r--media/java/android/media/PlayerBase.java7
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java10
-rw-r--r--packages/PrintSpooler/res/values-ta/strings.xml2
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml8
-rw-r--r--packages/SettingsLib/BannerMessagePreference/res/values/styles.xml5
-rw-r--r--packages/SettingsLib/BarChartPreference/res/values/styles.xml6
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp1
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml3
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml (renamed from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml)4
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml (renamed from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml)0
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml (renamed from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml)4
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml (renamed from packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml)4
-rw-r--r--packages/SettingsLib/FooterPreference/res/values/styles.xml3
-rw-r--r--packages/SettingsLib/LayoutPreference/res/values/styles.xml5
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_disabled.xml (renamed from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml)0
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_off.xml (renamed from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml)0
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_on.xml (renamed from packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml)0
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml2
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml4
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml37
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml25
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml22
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/values/styles.xml9
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml18
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml7
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml25
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml1
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml37
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml8
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml2
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values/dimens.xml1
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values/themes.xml2
-rw-r--r--packages/SettingsLib/TopIntroPreference/res/values/styles.xml3
-rw-r--r--packages/SettingsLib/res/values-te/arrays.xml12
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml26
-rw-r--r--packages/SystemUI/res-keyguard/values-te/strings.xml4
-rw-r--r--packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml483
-rw-r--r--packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml486
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml17
-rw-r--r--packages/SystemUI/res/layout/udfps_enroll_view.xml17
-rw-r--r--packages/SystemUI/res/layout/udfps_view.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml14
-rw-r--r--packages/SystemUI/res/values/dimens.xml4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconView.java33
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java129
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt181
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt239
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java394
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java177
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java256
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLog.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java78
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java31
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt68
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java141
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java75
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java195
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java20
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java66
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java24
-rw-r--r--services/core/java/com/android/server/RescueParty.java58
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java7
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java5
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java1
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java246
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java6
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java12
-rw-r--r--services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/Permission.java7
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java25
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java7
-rw-r--r--services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java8
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java23
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java9
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java18
-rw-r--r--services/core/java/com/android/server/wm/InsetsPolicy.java41
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java8
-rw-r--r--services/core/java/com/android/server/wm/Task.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java11
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java69
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java13
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java10
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java64
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java204
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java68
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java34
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java29
-rwxr-xr-xservices/usb/java/com/android/server/usb/UsbDeviceManager.java3
-rw-r--r--telecomm/java/android/telecom/Connection.java15
-rw-r--r--telecomm/java/android/telecom/RemoteConnectionService.java26
164 files changed, 4237 insertions, 1493 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 45588e831cb9..9eb7bb7149ef 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -3941,6 +3941,10 @@ public class DeviceIdleController extends SystemService
if (idleUntil) {
mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
+ } else if (mState == STATE_LOCATING) {
+ // Use setExact so we don't keep the GPS active for too long.
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mNextAlarmTime, "DeviceIdleController.deep", mDeepAlarmListener, mHandler);
} else {
if (mConstants.USE_WINDOW_ALARMS) {
mAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME_WAKEUP,
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 0d6a07938e95..e6cdcc0ee742 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -31,6 +31,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import java.util.Objects;
import java.util.Set;
/**
@@ -86,6 +87,12 @@ public class Account implements Parcelable {
if (TextUtils.isEmpty(type)) {
throw new IllegalArgumentException("the type must not be empty: " + type);
}
+ if (name.length() > 200) {
+ throw new IllegalArgumentException("account name is longer than 200 characters");
+ }
+ if (type.length() > 200) {
+ throw new IllegalArgumentException("account type is longer than 200 characters");
+ }
this.name = name;
this.type = type;
this.accessId = accessId;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ba270310bc5f..8f6f552ad1ff 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -465,11 +465,7 @@ public final class ActivityThread extends ClientTransactionHandler
@Override
public int hashCode() {
- return hashCode(authority, userId);
- }
-
- public static int hashCode(final String auth, final int userIdent) {
- return ((auth != null) ? auth.hashCode() : 0) ^ userIdent;
+ return ((authority != null) ? authority.hashCode() : 0) ^ userId;
}
}
@@ -491,7 +487,7 @@ public final class ActivityThread extends ClientTransactionHandler
// Note we never removes items from this map but that's okay because there are only so many
// users and so many authorities.
@GuardedBy("mGetProviderKeys")
- final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>();
+ final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>();
final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
= new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
@@ -4912,7 +4908,8 @@ public final class ActivityThread extends ClientTransactionHandler
Slog.w(TAG, "Activity top position already set to onTop=" + onTop);
return;
}
- throw new IllegalStateException("Activity top position already set to onTop=" + onTop);
+ // TODO(b/197484331): Remove this short-term workaround while fixing the binder failure.
+ Slog.e(TAG, "Activity top position already set to onTop=" + onTop);
}
r.isTopResumedActivity = onTop;
@@ -7056,11 +7053,11 @@ public final class ActivityThread extends ClientTransactionHandler
}
private ProviderKey getGetProviderKey(String auth, int userId) {
- final int key = ProviderKey.hashCode(auth, userId);
+ final ProviderKey key = new ProviderKey(auth, userId);
synchronized (mGetProviderKeys) {
ProviderKey lock = mGetProviderKeys.get(key);
if (lock == null) {
- lock = new ProviderKey(auth, userId);
+ lock = key;
mGetProviderKeys.put(key, lock);
}
return lock;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index d6e108d42b2b..76e743f155dc 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -3466,7 +3466,6 @@ public final class BluetoothAdapter {
}
}
}
-
public void onBluetoothServiceDown() {
synchronized (mServiceLock.writeLock()) {
mService = null;
@@ -3482,7 +3481,6 @@ public final class BluetoothAdapter {
}
Log.d(TAG, "onBluetoothServiceDown: Finished sending callbacks to registered clients");
}
-
public void onBrEdrDown() {
}
};
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 19edf74a04f8..7b8c061deefc 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1478,7 +1478,10 @@ public final class BluetoothDevice implements Parcelable, Attributable {
if (alias == null) {
return getName();
}
- return alias;
+ return alias
+ .replace('\t', ' ')
+ .replace('\n', ' ')
+ .replace('\r', ' ');
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index e13a7b6eac65..fc8337ac3155 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -1257,6 +1257,23 @@ public final class DisplayManager {
*/
String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
"fixed_refresh_rate_high_ambient_brightness_thresholds";
+
+ /**
+ * Key for refresh rate when the device is in high brightness mode for sunlight visility.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.integer#config_defaultRefreshRateInHbmSunlight
+ */
+ String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight";
+
+ /**
+ * Key for refresh rate when the device is in high brightness mode for HDR.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
+ * @see android.R.integer#config_defaultRefreshRateInHbmHdr
+ */
+ String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr";
+
/**
* Key for default peak refresh rate
*
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ff2d2eb3d334..fa7330fb84eb 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -98,6 +98,7 @@ public class Surface implements Parcelable {
private static native int nativeSetFrameRate(
long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy);
+ private static native void nativeDestroy(long nativeObject);
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
@@ -339,6 +340,9 @@ public class Surface implements Parcelable {
*/
@UnsupportedAppUsage
public void destroy() {
+ if (mNativeObject != 0) {
+ nativeDestroy(mNativeObject);
+ }
release();
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index c415ad452731..af61104774cb 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -923,7 +923,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mSurfaceAlpha = 1f;
synchronized (mSurfaceControlLock) {
- mSurface.release();
+ mSurface.destroy();
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
mBlastBufferQueue = null;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4cae8cae6014..a5d3a925febd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2839,8 +2839,13 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ final boolean surfaceControlChanged =
+ (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
+ == RELAYOUT_RES_SURFACE_CHANGED;
+
if (mSurfaceControl.isValid()) {
- updateOpacity(mWindowAttributes, dragResizing);
+ updateOpacity(mWindowAttributes, dragResizing,
+ surfaceControlChanged /*forceUpdate */);
}
if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
@@ -2875,9 +2880,7 @@ public final class ViewRootImpl implements ViewParent,
// RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
// SurfaceControl.
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
- || (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
- == RELAYOUT_RES_SURFACE_CHANGED)
- && mSurface.isValid();
+ || surfaceControlChanged) && mSurface.isValid();
if (surfaceReplaced) {
mSurfaceSequenceId++;
}
@@ -7833,7 +7836,8 @@ public final class ViewRootImpl implements ViewParent,
return relayoutResult;
}
- private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing) {
+ private void updateOpacity(WindowManager.LayoutParams params, boolean dragResizing,
+ boolean forceUpdate) {
boolean opaque = false;
if (!PixelFormat.formatHasAlpha(params.format)
@@ -7849,7 +7853,7 @@ public final class ViewRootImpl implements ViewParent,
opaque = true;
}
- if (mIsSurfaceOpaque == opaque) {
+ if (!forceUpdate && mIsSurfaceOpaque == opaque) {
return;
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
index a8335918cc84..442d099f0678 100644
--- a/core/java/android/view/translation/UiTranslationController.java
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -356,7 +356,11 @@ public class UiTranslationController {
}
for (int i = 0; i < translatedResult.size(); i++) {
final AutofillId autofillId = new AutofillId(translatedResult.keyAt(i));
- final View view = mViews.get(autofillId).get();
+ final WeakReference<View> viewRef = mViews.get(autofillId);
+ if (viewRef == null) {
+ continue;
+ }
+ final View view = viewRef.get();
if (view == null) {
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
+ " may be gone.");
@@ -416,7 +420,11 @@ public class UiTranslationController {
Log.w(TAG, "No AutofillId is set in ViewTranslationResponse");
continue;
}
- final View view = mViews.get(autofillId).get();
+ final WeakReference<View> viewRef = mViews.get(autofillId);
+ if (viewRef == null) {
+ continue;
+ }
+ final View view = viewRef.get();
if (view == null) {
Log.w(TAG, "onTranslationCompleted: the view for autofill id " + autofillId
+ " may be gone.");
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index 8b8dba89ea67..69bc1b5f7763 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -88,4 +88,9 @@ oneway interface ITaskOrganizer {
* user has pressed back on the root activity of a task controlled by the task organizer.
*/
void onBackPressedOnTaskRoot(in ActivityManager.RunningTaskInfo taskInfo);
+
+ /**
+ * Called when the IME has drawn on the organized task.
+ */
+ void onImeDrawnOnTask(int taskId);
}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index c7c91cdd0941..d8723a821a22 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -144,6 +144,10 @@ public class TaskOrganizer extends WindowOrganizer {
@BinderThread
public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
+ /** @hide */
+ @BinderThread
+ public void onImeDrawnOnTask(int taskId) {}
+
/**
* Creates a persistent root task in WM for a particular windowing-mode.
* @param displayId The display to create the root task on.
@@ -287,6 +291,11 @@ public class TaskOrganizer extends WindowOrganizer {
public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) {
mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info));
}
+
+ @Override
+ public void onImeDrawnOnTask(int taskId) {
+ mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId));
+ }
};
private ITaskOrganizerController getController() {
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index 8e7fae7aa061..d12c870d2591 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -50,6 +50,7 @@ import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
/**
* A class that allows the app to get the frame metrics from HardwareRendererObserver.
@@ -103,6 +104,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
private boolean mCancelled = false;
private FrameTrackerListener mListener;
private boolean mTracingStarted = false;
+ private Runnable mWaitForFinishTimedOut;
private static class JankInfo {
long frameVsyncId;
@@ -263,10 +265,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
if (mListener != null) {
mListener.onCujEvents(mSession, ACTION_SESSION_END);
}
+ // We don't remove observer here,
+ // will remove it when all the frame metrics in this duration are called back.
+ // See onFrameMetricsAvailable for the logic of removing the observer.
+ // Waiting at most 10 seconds for all callbacks to finish.
+ mWaitForFinishTimedOut = () -> {
+ Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
+ finish(mJankInfos.size() - 1);
+ };
+ mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10));
}
- // We don't remove observer here,
- // will remove it when all the frame metrics in this duration are called back.
- // See onFrameMetricsAvailable for the logic of removing the observer.
}
/**
@@ -396,7 +404,8 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
private void finish(int indexOnOrAfterEnd) {
-
+ mHandler.removeCallbacks(mWaitForFinishTimedOut);
+ mWaitForFinishTimedOut = null;
mMetricsFinalized = true;
// The tracing has been ended, remove the observer, see if need to trigger perfetto.
@@ -481,7 +490,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
}
}
if (DEBUG) {
- Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
+ Log.i(TAG, "finish: CUJ=" + mSession.getName()
+ " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
+ " totalFrames=" + totalFramesCount
+ " missedAppFrames=" + missedAppFramesCount
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index aabcd7f82ac7..610cd7339001 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -103,7 +103,7 @@ public class InteractionJankMonitor {
private static final String ACTION_PREFIX = InteractionJankMonitor.class.getCanonicalName();
private static final String DEFAULT_WORKER_NAME = TAG + "-Worker";
- private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5L);
+ private static final long DEFAULT_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(2L);
private static final String SETTINGS_ENABLED_KEY = "enabled";
private static final String SETTINGS_SAMPLING_INTERVAL_KEY = "sampling_interval";
private static final String SETTINGS_THRESHOLD_MISSED_FRAMES_KEY =
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 0957067de603..869b53df2837 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -449,6 +449,11 @@ static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jf
int(changeFrameRateStrategy));
}
+static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ sp<Surface> surface(reinterpret_cast<Surface*>(nativeObject));
+ surface->destroy();
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gSurfaceMethods[] = {
@@ -477,6 +482,7 @@ static const JNINativeMethod gSurfaceMethods[] = {
{"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
{"nativeSetFrameRate", "(JFII)I", (void*)nativeSetFrameRate},
{"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue},
+ {"nativeDestroy", "(J)V", (void*)nativeDestroy},
};
int register_android_view_Surface(JNIEnv* env)
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 18b588cd395c..4a5be62120f6 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -169,7 +169,7 @@
<string name="httpErrorUnsupportedScheme" msgid="2664108769858966374">"நெறிமுறை ஆதரிக்கப்படவில்லை."</string>
<string name="httpErrorFailedSslHandshake" msgid="546319061228876290">"பாதுகாப்பான இணைப்பை நிறுவ முடியவில்லை."</string>
<string name="httpErrorBadUrl" msgid="754447723314832538">"URL தவறாக உள்ளதால் பக்கத்தைத் திறக்க முடியவில்லை."</string>
- <string name="httpErrorFile" msgid="3400658466057744084">"கோப்பை அணுக முடியவில்லை."</string>
+ <string name="httpErrorFile" msgid="3400658466057744084">"ஃபைலை அணுக முடியவில்லை."</string>
<string name="httpErrorFileNotFound" msgid="5191433324871147386">"கோரப்பட்ட கோப்பைக் கண்டறிய முடியவில்லை."</string>
<string name="httpErrorTooManyRequests" msgid="2149677715552037198">"மிக அதிகமான கோரிக்கைகள் செயல்படுத்தப்படுகின்றன. பிறகு முயற்சிக்கவும்."</string>
<string name="notification_title" msgid="5783748077084481121">"<xliff:g id="ACCOUNT">%1$s</xliff:g> க்கான உள்நுழைவு பிழை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 1d2fd8a0885b..08bf970fb5ab 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -82,7 +82,7 @@
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"వాయిస్ సేవ లేదు"</string>
<string name="RestrictedOnAllVoiceTitle" msgid="3982069078579103087">"వాయిస్ సేవ లేదా అత్యవసర కాలింగ్ లేదు"</string>
<string name="RestrictedStateContent" msgid="7693575344608618926">"మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేయబడింది"</string>
- <string name="RestrictedStateContentMsimTemplate" msgid="5228235722511044687">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> కోసం మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేసారు"</string>
+ <string name="RestrictedStateContentMsimTemplate" msgid="5228235722511044687">"SIM <xliff:g id="SIMNUMBER">%d</xliff:g> కోసం మీ క్యారియర్ తాత్కాలికంగా ఆఫ్ చేశారు"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"మొబైల్ నెట్‌వర్క్ అందుబాటులో లేదు"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"ప్రాధాన్య నెట్‌వర్క్‌ను మార్చుకోవడానికి ప్రయత్నించండి. మార్చడానికి నొక్కండి."</string>
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
@@ -91,8 +91,8 @@
<string name="notification_channel_call_forward" msgid="8230490317314272406">"కాల్ ఫార్వార్డింగ్"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"అత్యవసర కాల్‌బ్యాక్ మోడ్"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"మొబైల్ డేటా స్థితి"</string>
- <string name="notification_channel_sms" msgid="1243384981025535724">"SMS సందేశాలు"</string>
- <string name="notification_channel_voice_mail" msgid="8457433203106654172">"వాయిస్ మెయిల్ సందేశాలు"</string>
+ <string name="notification_channel_sms" msgid="1243384981025535724">"SMS మెసేజ్‌లు"</string>
+ <string name="notification_channel_voice_mail" msgid="8457433203106654172">"వాయిస్ మెయిల్ మెసేజ్‌లు"</string>
<string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi కాలింగ్"</string>
<string name="notification_channel_sim" msgid="5098802350325677490">"SIM స్టేటస్"</string>
<string name="notification_channel_sim_high_prio" msgid="642361929452850928">"అధిక ప్రాధాన్యత గల SIM స్థితి"</string>
@@ -124,7 +124,7 @@
<string name="roamingTextSearching" msgid="5323235489657753486">"సేవ కోసం శోధిస్తోంది"</string>
<string name="wfcRegErrorTitle" msgid="3193072971584858020">"Wi‑Fi కాలింగ్‌ని సెటప్ చేయడం సాధ్యపడలేదు"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="468830943567116703">"Wi-Fiతో కాల్స్‌ను చేయడానికి మరియు సందేశాలను పంపించడానికి, మొదట ఈ సేవను సెటప్ చేయాల్సిందిగా మీ క్యారియర్‌‌కి చెప్పండి. ఆ తర్వాత సెట్టింగ్‌ల నుండి Wi-Fi కాలింగ్‌ని మళ్లీ ఆన్ చేయండి. (లోపం కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="468830943567116703">"Wi-Fiతో కాల్స్‌ను చేయడానికి మరియు మెసేజ్‌లను పంపించడానికి, మొదట ఈ సేవను సెటప్ చేయాల్సిందిగా మీ క్యారియర్‌‌కి చెప్పండి. ఆ తర్వాత సెట్టింగ్‌ల నుండి Wi-Fi కాలింగ్‌ని మళ్లీ ఆన్ చేయండి. (లోపం కోడ్: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="4795145070505729156">"మీ క్యారియర్‌తో Wi‑Fi కాలింగ్‌ని నమోదు చేయడంలో సమస్య: <xliff:g id="CODE">%1$s</xliff:g>"</item>
@@ -190,7 +190,7 @@
<string name="work_profile_deleted" msgid="5891181538182009328">"కార్యాలయ ప్రొఫైల్ తొలగించబడింది"</string>
<string name="work_profile_deleted_details" msgid="3773706828364418016">"కార్యాలయ ప్రొఫైల్ నిర్వాహక యాప్ లేదు లేదా పాడైంది. తత్ఫలితంగా, మీ కార్యాలయ ప్రొఫైల్ మరియు సంబంధిత డేటా తొలగించబడ్డాయి. సహాయం కోసం మీ నిర్వాహకులను సంప్రదించండి."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ఈ పరికరంలో మీ కార్యాలయ ప్రొఫైల్ ఇప్పుడు అందుబాటులో లేదు"</string>
- <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"చాలా ఎక్కువ పాస్‌వర్డ్ ప్రయత్నాలు చేసారు"</string>
+ <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"చాలా ఎక్కువ పాస్‌వర్డ్ ప్రయత్నాలు చేశారు"</string>
<string name="device_ownership_relinquished" msgid="4080886992183195724">"వ్యక్తిగత వినియోగం కోసం నిర్వాహకులు పరికరాన్ని తీసి వేశారు"</string>
<string name="network_logging_notification_title" msgid="554983187553845004">"పరికరం నిర్వహించబడింది"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"మీ సంస్థ ఈ పరికరాన్ని నిర్వహిస్తుంది మరియు నెట్‌వర్క్ ట్రాఫిక్‌ని పర్యవేక్షించవచ్చు. వివరాల కోసం నొక్కండి."</string>
@@ -251,7 +251,7 @@
<string name="global_action_logout" msgid="6093581310002476511">"సెషన్‌ను ముగించు"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"స్క్రీన్‌షాట్"</string>
<string name="bugreport_title" msgid="8549990811777373050">"బగ్ రిపోర్ట్‌"</string>
- <string name="bugreport_message" msgid="5212529146119624326">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ రిపోర్ట్‌ను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
+ <string name="bugreport_message" msgid="5212529146119624326">"ఇది ఇ-మెయిల్ మెసేజ్‌ రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ రిపోర్ట్‌ను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
<string name="bugreport_option_interactive_title" msgid="7968287837902871289">"ప్రభావశీల రిపోర్ట్‌"</string>
<string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"చాలా సందర్భాల్లో దీన్ని ఉపయోగించండి. ఇది రిపోర్ట్‌ ప్రోగ్రెస్‌ను ట్రాక్ చేయడానికి, సమస్య గురించి మరిన్ని వివరాలను నమోదు చేయడానికి మరియు స్క్రీన్‌షాట్‌లు తీయడానికి మిమ్మల్ని అనుమతిస్తుంది. ఇది నివేదించడానికి ఎక్కువ సమయం పట్టే తక్కువ వినియోగ విభాగాలను విడిచిపెట్టవచ్చు."</string>
<string name="bugreport_option_full_title" msgid="7681035745950045690">"పూర్తి రిపోర్ట్‌"</string>
@@ -279,8 +279,8 @@
<string name="notification_channel_security" msgid="8516754650348238057">"సెక్యూరిటీ"</string>
<string name="notification_channel_car_mode" msgid="2123919247040988436">"కార్‌ మోడ్"</string>
<string name="notification_channel_account" msgid="6436294521740148173">"ఖాతా స్థితి"</string>
- <string name="notification_channel_developer" msgid="1691059964407549150">"డెవలపర్ సందేశాలు"</string>
- <string name="notification_channel_developer_important" msgid="7197281908918789589">"ముఖ్యమైన డెవలపర్ సందేశాలు"</string>
+ <string name="notification_channel_developer" msgid="1691059964407549150">"డెవలపర్ మెసేజ్‌లు"</string>
+ <string name="notification_channel_developer_important" msgid="7197281908918789589">"ముఖ్యమైన డెవలపర్ మెసేజ్‌లు"</string>
<string name="notification_channel_updates" msgid="7907863984825495278">"అప్‌డేట్‌లు"</string>
<string name="notification_channel_network_status" msgid="2127687368725272809">"నెట్‌వర్క్ స్థితి"</string>
<string name="notification_channel_network_alerts" msgid="6312366315654526528">"నెట్‌వర్క్ హెచ్చరికలు"</string>
@@ -309,7 +309,7 @@
<string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"మీ క్యాలెండర్‌ను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
- <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string>
+ <string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS మెసేజ్‌లను పంపడం మరియు వీక్షించడం"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"ఫైల్స్, మీడియా"</string>
<string name="permgroupdesc_storage" msgid="6351503740613026600">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైళ్లను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"మైక్రోఫోన్"</string>
@@ -356,26 +356,26 @@
<string name="permdesc_processOutgoingCalls" msgid="7833149750590606334">"కాల్‌ను వేరే నంబర్‌కు దారి మళ్లించే లేదా మొత్తంగా కాల్‌ను ఆపివేసే ఎంపిక సహాయంతో అవుట్‌గోయింగ్ కాల్ సమయంలో డయల్ చేయబడుతున్న నంబర్‌ను చూడటానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"ఫోన్ కాల్స్‌కు సమాధానమివ్వు"</string>
<string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"ఇన్‌కమింగ్ ఫోన్ కాల్స్‌కు సమాధానమివ్వడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_receiveSms" msgid="505961632050451881">"వచన సందేశాలను (SMS) స్వీకరించడం"</string>
- <string name="permdesc_receiveSms" msgid="1797345626687832285">"SMS సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
- <string name="permlab_receiveMms" msgid="4000650116674380275">"వచన సందేశాలను (MMS) స్వీకరించడం"</string>
- <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
- <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"సెల్ ప్రసార సందేశాలను ఫార్వర్డ్ చేయడం"</string>
- <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార సందేశాలను అందుకుంటే, వాటిని ఫార్వర్డ్ చేసే విధంగా సెల్ ప్రసార మాడ్యూల్‌కు కట్టుబడి ఉండటానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం అందుకున్నప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string>
+ <string name="permlab_receiveSms" msgid="505961632050451881">"వచన మెసేజ్‌లను (SMS) స్వీకరించడం"</string>
+ <string name="permdesc_receiveSms" msgid="1797345626687832285">"SMS మెసేజ్‌లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన మెసేజ్‌లను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
+ <string name="permlab_receiveMms" msgid="4000650116674380275">"వచన మెసేజ్‌లను (MMS) స్వీకరించడం"</string>
+ <string name="permdesc_receiveMms" msgid="958102423732219710">"MMS మెసేజ్‌లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. యాప్ మీ డివైజ్‌కు పంపబడిన మెసేజ్‌లను మీకు చూపకుండానే పర్యవేక్షించగలదని లేదా తొలగించగలదని దీని అర్థం."</string>
+ <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"సెల్ ప్రసార మెసేజ్‌లను ఫార్వర్డ్ చేయడం"</string>
+ <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్‌లను అందుకుంటే, వాటిని ఫార్వర్డ్ చేసే విధంగా సెల్ ప్రసార మాడ్యూల్‌కు కట్టుబడి ఉండటానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం అందుకున్నప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్‌ను మేనేజ్ చేయి"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"మీ పరికరంలో కొనసాగుతున్న కాల్స్‌ను చూడటానికి అలాగే వాటిని కంట్రోల్ చేయడానికి ఒక యాప్‌కు అనుమతిస్తోంది."</string>
- <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార సందేశాలను చదవడం"</string>
- <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార సందేశాలను చదవడానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం స్వీకరించినప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string>
+ <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార మెసేజ్‌లను చదవడం"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్‌లను చదవడానికి యాప్‌ను అనుమతిస్తుంది. సెల్ ప్రసార హెచ్చరికలు అత్యవసర పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని స్థానాల్లో అందించబడతాయి. అత్యవసర సెల్ ప్రసారం స్వీకరించినప్పుడు హానికరమైన యాప్‌లు మీ పరికరం యొక్క పనితీరు లేదా నిర్వహణకు అంతరాయం కలిగించవచ్చు."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"చందా చేయబడిన ఫీడ్‌లను చదవడం"</string>
<string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"ప్రస్తుతం సమకాలీకరించిన ఫీడ్‌ల గురించి వివరాలను పొందడానికి యాప్‌ను అనుమతిస్తుంది."</string>
- <string name="permlab_sendSms" msgid="7757368721742014252">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string>
- <string name="permdesc_sendSms" msgid="6757089798435130769">"SMS సందేశాలు పంపడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన ఊహించని ఛార్జీలు విధించబడవచ్చు. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే సందేశాలను పంపడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
- <string name="permlab_readSms" msgid="5164176626258800297">"మీ వచన సందేశాలు (SMS లేదా MMS) చదవడం"</string>
- <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ఈ యాప్‌ మీ టాబ్లెట్‌లో నిల్వ చేసిన అన్ని SMS (వచన) సందేశాలను చదవగలదు."</string>
+ <string name="permlab_sendSms" msgid="7757368721742014252">"SMS మెసేజ్‌లను పంపడం మరియు వీక్షించడం"</string>
+ <string name="permdesc_sendSms" msgid="6757089798435130769">"SMS మెసేజ్‌లు పంపడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన ఊహించని ఛార్జీలు విధించబడవచ్చు. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే మెసేజ్‌లను పంపడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
+ <string name="permlab_readSms" msgid="5164176626258800297">"మీ వచన మెసేజ్‌లు (SMS లేదా MMS) చదవడం"</string>
+ <string name="permdesc_readSms" product="tablet" msgid="7912990447198112829">"ఈ యాప్‌ మీ టాబ్లెట్‌లో నిల్వ చేసిన అన్ని SMS (వచన) మెసేజ్‌లను చదవగలదు."</string>
<string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"ఈ యాప్ మీ Android TV పరికరంలో నిల్వ అయిన SMS (వచనం) సందేశాలన్నింటినీ చదవగలదు."</string>
- <string name="permdesc_readSms" product="default" msgid="774753371111699782">"ఈ యాప్‌ మీ ఫోన్‌లో నిల్వ చేసిన అన్ని SMS (వచన) సందేశాలను చదవగలదు."</string>
- <string name="permlab_receiveWapPush" msgid="4223747702856929056">"వచన సందేశాలను (WAP) స్వీకరించడం"</string>
- <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP సందేశాలను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి మీకు పంపబడిన సందేశాలను మీకు చూపకుండానే పర్యవేక్షించగల లేదా తొలగించగల సామర్థ్యాన్ని కలిగి ఉంటుంది."</string>
+ <string name="permdesc_readSms" product="default" msgid="774753371111699782">"ఈ యాప్‌ మీ ఫోన్‌లో నిల్వ చేసిన అన్ని SMS (వచన) మెసేజ్‌లను చదవగలదు."</string>
+ <string name="permlab_receiveWapPush" msgid="4223747702856929056">"వచన మెసేజ్‌లను (WAP) స్వీకరించడం"</string>
+ <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP మెసేజ్‌లను స్వీకరించడానికి మరియు ప్రాసెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి మీకు పంపబడిన మెసేజ్‌లను మీకు చూపకుండానే పర్యవేక్షించగల లేదా తొలగించగల సామర్థ్యాన్ని కలిగి ఉంటుంది."</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"అమలవుతున్న యాప్‌లను పునరుద్ధరించడం"</string>
<string name="permdesc_getTasks" msgid="7388138607018233726">"ప్రస్తుతం మరియు ఇటీవల అమలవుతున్న విధుల గురించి వివరణాత్మక సమాచారాన్ని తిరిగి పొందడానికి యాప్‌ను అనుమతిస్తుంది. ఇది పరికరంలో ఉపయోగించబడిన యాప్‌ల గురించి సమాచారాన్ని కనుగొనడానికి యాప్‌ను అనుమతించవచ్చు."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"ప్రొఫైల్ మరియు పరికర యజమానులను నిర్వహించడం"</string>
@@ -431,9 +431,9 @@
<string name="permdesc_readCalendar" product="tv" msgid="5811726712981647628">"ఈ యాప్‌ మీ Android TV పరికరంలో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్‌లన్నీ చదవగలదు, మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string>
<string name="permdesc_readCalendar" product="default" msgid="9118823807655829957">"ఈ యాప్ మీ ఫోన్‌లో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్‌లన్నీ చదవగలదు మరియు మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string>
<string name="permlab_writeCalendar" msgid="6422137308329578076">"యజమానికి తెలియకుండానే క్యాలెండర్ ఈవెంట్‌లను జోడించి లేదా సవరించి, అతిథులకు ఇమెయిల్ పంపడం"</string>
- <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
- <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
- <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్‌లను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్‌లను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్‌లను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర స్థాన మూలాల నిర్వహణలో యాప్‌ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string>
<string name="permlab_accessFineLocation" msgid="6426318438195622966">"స్క్రీన్‌పై ఉన్నప్పుడు మాత్రమే ఖచ్చితమైన స్థానాన్ని యాక్సెస్ చేయండి"</string>
@@ -594,8 +594,8 @@
<string name="fingerprint_error_no_space" msgid="7285481581905967580">"వేలిముద్రను సెటప్ చేయడం సాధ్యం కాదు"</string>
<string name="fingerprint_error_timeout" msgid="2946635815726054226">"వేలిముద్ర గడువు సమయం చేరుకుంది. మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_error_canceled" msgid="540026881380070750">"వేలిముద్ర కార్యకలాపం రద్దయింది."</string>
- <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేసారు."</string>
- <string name="fingerprint_error_lockout" msgid="7853461265604738671">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+ <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"వేలిముద్ర చర్యని వినియోగదారు రద్దు చేశారు."</string>
+ <string name="fingerprint_error_lockout" msgid="7853461265604738671">"చాలా ఎక్కువ ప్రయత్నాలు చేశారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"అనేకసార్లు ప్రయత్నించారు. వేలిముద్ర సెన్సార్ నిలిపివేయబడింది."</string>
<string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"మళ్లీ ప్రయత్నించండి."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"వేలిముద్రలు నమోదు చేయబడలేదు."</string>
@@ -647,7 +647,7 @@
<string name="face_error_no_space" msgid="5649264057026021723">"కొత్త ముఖం డేటాను నిల్వ చేయడం కాదు. మొదట పాతది తొలిగించండి."</string>
<string name="face_error_canceled" msgid="2164434737103802131">"ముఖ కార్యకలాపం రద్దయింది."</string>
<string name="face_error_user_canceled" msgid="5766472033202928373">"ఫేస్ అన్‌లాక్‌ను యూజర్ రద్దు చేశారు"</string>
- <string name="face_error_lockout" msgid="7864408714994529437">"చాలా ఎక్కువ ప్రయత్నాలు చేసారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
+ <string name="face_error_lockout" msgid="7864408714994529437">"చాలా ఎక్కువ ప్రయత్నాలు చేశారు. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
<string name="face_error_lockout_permanent" msgid="3277134834042995260">"చాలా ఎక్కువ సార్లు ప్రయత్నించారు. ఫేస్ అన్‌లాక్ డిజేబుల్ చేయబడింది."</string>
<string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"చాలా ఎక్కువ సార్లు ప్రయత్నించారు. బదులుగా స్క్రీన్ లాక్‌ను ఎంటర్ చేయండి."</string>
<string name="face_error_unable_to_process" msgid="5723292697366130070">"ముఖం ధృవీకరించలేకపోయింది. మళ్లీ ప్రయత్నించండి."</string>
@@ -713,7 +713,7 @@
<string name="permlab_removeDrmCertificates" msgid="710576248717404416">"DRM ప్రమాణపత్రాలను తీసివేయడం"</string>
<string name="permdesc_removeDrmCertificates" msgid="4068445390318355716">"DRM ప్రమాణపత్రాలను తీసివేయడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindCarrierMessagingService" msgid="3363450860593096967">"క్యారియర్ సందేశ సేవకు అనుబంధించడం"</string>
- <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="6316457028173478345">"క్యారియర్ మెసేజింగ్ సర్వీస్‌ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindCarrierServices" msgid="2395596978626237474">"క్యారియర్ సేవలకు అనుబంధించడం"</string>
<string name="permdesc_bindCarrierServices" msgid="9185614481967262900">"క్యారియర్ సేవలకు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_access_notification_policy" msgid="5524112842876975537">"అంతరాయం కలిగించవద్దును యాక్సెస్ చేయడం"</string>
@@ -911,21 +911,21 @@
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"సిమ్ కార్డు లాక్ చేయబడింది."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"సిమ్ కార్డు‌ను అన్‌లాక్ చేస్తోంది…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"మీరు మీ అన్‌లాక్ నమూనాని <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విజయవంతం కాని ప్రయత్నాల తర్వాత, మీరు మీ Google సైన్ఇన్‌ను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి అడగబడతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"మీరు మీ అన్‌లాక్ నమూనాని <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు మీ Google సైన్ఇన్‌ను ఉపయోగించి మీ Android TV పరికరాన్ని అన్‌లాక్ చేయాల్సిందిగా మీకు తెలపబడుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"మీరు మీ అన్‌లాక్ నమూనాని <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విజయవంతం కాని ప్రయత్నాల తర్వాత, మీరు మీ Google సైన్ఇన్‌ను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయడానికి అడగబడతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> వైఫల్య ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్‌కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్‌కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> వైఫల్య ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"నమూనాను మర్చిపోయారా?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"ఖాతా అన్‌లాక్"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేసారు"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేశారు"</string>
<string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"అన్‌లాక్ చేయడానికి, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి."</string>
<string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"వినియోగదారు పేరు (ఇమెయిల్)"</string>
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"పాస్‌వర్డ్"</string>
@@ -1012,7 +1012,7 @@
<string name="permlab_setAlarm" msgid="1158001610254173567">"అలారం సెట్ చేయడం"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"ఇన్‌స్టాల్ చేయబడిన అలారం గడియారం యాప్‌లో అలారంను సెట్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. కొన్ని అలారం గల గడియారం యాప్‌లు ఈ ఫీచర్‌ను అమలు చేయకపోవచ్చు."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"వాయిస్ మెయిల్‌ను జోడించడం"</string>
- <string name="permdesc_addVoicemail" msgid="5470312139820074324">"మీ వాయిస్ మెయిల్ ఇన్‌బాక్స్‌కి సందేశాలను జోడించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
+ <string name="permdesc_addVoicemail" msgid="5470312139820074324">"మీ వాయిస్ మెయిల్ ఇన్‌బాక్స్‌కి మెసేజ్‌లను జోడించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"బ్రౌజర్ భౌగోళిక స్థానం అనుమతులను సవరించడం"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"బ్రౌజర్ యొక్క భౌగోళిక స్థానం అనుమతులను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు ఏకపక్ష వెబ్ సైట్‌లకు స్థాన సమాచారాన్ని అనుమతించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
<string name="save_password_message" msgid="2146409467245462965">"మీరు బ్రౌజర్ ఈ పాస్‌వర్డ్‌ను గుర్తుపెట్టుకోవాలని కోరుకుంటున్నారా?"</string>
@@ -1325,11 +1325,11 @@
<string name="accept" msgid="5447154347815825107">"ఆమోదిస్తున్నాను"</string>
<string name="decline" msgid="6490507610282145874">"తిరస్కరిస్తున్నాను"</string>
<string name="select_character" msgid="3352797107930786979">"అక్షరాన్ని చొప్పించండి"</string>
- <string name="sms_control_title" msgid="4748684259903148341">"SMS సందేశాలు పంపుతోంది"</string>
- <string name="sms_control_message" msgid="6574313876316388239">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; పెద్ద సంఖ్యలో SMS సందేశాలను పంపుతోంది. సందేశాలను పంపడం కొనసాగించడానికి మీరు ఈ యాప్‌ను అనుమతించాలనుకుంటున్నారా?"</string>
+ <string name="sms_control_title" msgid="4748684259903148341">"SMS మెసేజ్‌లు పంపుతోంది"</string>
+ <string name="sms_control_message" msgid="6574313876316388239">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; పెద్ద సంఖ్యలో SMS మెసేజ్‌లను పంపుతోంది. మెసేజ్‌లను పంపడం కొనసాగించడానికి మీరు ఈ యాప్‌ను అనుమతించాలనుకుంటున్నారా?"</string>
<string name="sms_control_yes" msgid="4858845109269524622">"అనుమతిస్తున్నాను"</string>
<string name="sms_control_no" msgid="4845717880040355570">"తిరస్కరిస్తున్నాను"</string>
- <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ఒక సందేశాన్ని &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;కి పంపాలనుకుంటోంది."</string>
+ <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ఒక మెసేజ్‌ను &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;కి పంపాలనుకుంటోంది."</string>
<string name="sms_short_code_details" msgid="2723725738333388351">"దీని వలన మీ మొబైల్ ఖాతాకు "<b>"ఛార్జీలు విధించబడవచ్చు"</b>"."</string>
<string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"దీని వలన మీ మొబైల్ ఖాతాకు ఛార్జీలు విధించబడవచ్చు."</b></string>
<string name="sms_short_code_confirm_allow" msgid="920477594325526691">"పంపు"</string>
@@ -1664,7 +1664,7 @@
<string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"PUK కోడ్ 8 సంఖ్యలు ఉండాలి."</string>
<string name="kg_invalid_puk" msgid="4809502818518963344">"సరైన PUK కోడ్‌ను మళ్లీ నమోదు చేయండి. పునరావృత ప్రయత్నాల వలన సిమ్ శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"పిన్‌ కోడ్‌లు సరిపోలలేదు"</string>
- <string name="kg_login_too_many_attempts" msgid="699292728290654121">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేసారు"</string>
+ <string name="kg_login_too_many_attempts" msgid="699292728290654121">"చాలా ఎక్కువ ఆకృతి ప్రయత్నాలు చేశారు"</string>
<string name="kg_login_instructions" msgid="3619844310339066827">"అన్‌లాక్ చేయడానికి, మీ Google ఖాతాతో సైన్ ఇన్ చేయండి."</string>
<string name="kg_login_username_hint" msgid="1765453775467133251">"వినియోగదారు పేరు (ఇమెయిల్)"</string>
<string name="kg_login_password_hint" msgid="3330530727273164402">"పాస్‌వర్డ్"</string>
@@ -1672,15 +1672,15 @@
<string name="kg_login_invalid_input" msgid="8292367491901220210">"చెల్లని వినియోగదారు పేరు లేదా పాస్‌వర్డ్."</string>
<string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"మీ వినియోగదారు పేరు లేదా పాస్‌వర్డ్‌ను మర్చిపోయారా?\n"<b>"google.com/accounts/recovery"</b>"ని సందర్శించండి."</string>
<string name="kg_login_checking_password" msgid="4676010303243317253">"ఖాతాను తనిఖీ చేస్తోంది…"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్‌కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
- <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
- <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేసారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
- <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేసారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్‌కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"మీరు టాబ్లెట్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"మీరు మీ Android TV పరికరాన్ని అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"మీరు ఫోన్‌ను అన్‌లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్‌కు రీసెట్ చేయబడుతుంది."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత మీ Android TV పరికరాన్ని ఇమెయిల్ ఖాతా ద్వారా అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని కోరడం జరుగుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్‌ను అన్‌లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
@@ -1869,7 +1869,7 @@
<string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
<string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ ఆకృతి కోసం అడుగు"</string>
<string name="lock_to_app_unlock_password" msgid="9126722403506560473">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
- <string name="package_installed_device_owner" msgid="7035926868974878525">"మీ నిర్వాహకులు ఇన్‌స్టాల్ చేసారు"</string>
+ <string name="package_installed_device_owner" msgid="7035926868974878525">"మీ నిర్వాహకులు ఇన్‌స్టాల్ చేశారు"</string>
<string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
@@ -1961,7 +1961,7 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఎంచుకోబడింది</item>
</plurals>
<string name="default_notification_channel_label" msgid="3697928973567217330">"వర్గీకరించబడలేదు"</string>
- <string name="importance_from_user" msgid="2782756722448800447">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
+ <string name="importance_from_user" msgid="2782756722448800447">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేశారు."</string>
<string name="importance_from_person" msgid="4235804979664465383">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
<string name="notification_history_title_placeholder" msgid="7748630986182249599">"అనుకూల యాప్ నోటిఫికేషన్"</string>
<string name="user_creation_account_exists" msgid="2239146360099708035">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా (ఈ ఖాతాతో ఇప్పటికే ఒక వినియోగదారు ఉన్నారు) ?"</string>
@@ -1984,7 +1984,7 @@
<string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు."</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ఈ యాప్ పాత వెర్షన్ Android కోసం రూపొందించబడింది మరియు అది సరిగ్గా పని చేయకపోవచ్చు. అప్‌డేట్‌ల కోసం తనిఖీ చేయడానికి ప్రయత్నించండి లేదా డెవలపర్‌ని సంప్రదించండి."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"అప్‌డేట్ కోసం తనిఖీ చేయండి"</string>
- <string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త సందేశాలు ఉన్నాయి"</string>
+ <string name="new_sms_notification_title" msgid="6528758221319927107">"మీకు కొత్త మెసేజ్‌లు ఉన్నాయి"</string>
<string name="new_sms_notification_content" msgid="3197949934153460639">"వీక్షించడానికి SMS యాప్‌ను తెరవండి"</string>
<string name="profile_encrypted_title" msgid="9001208667521266472">"కొంత ఫంక్షనాలిటీ పరిమితం కావచ్చు"</string>
<string name="profile_encrypted_detail" msgid="5279730442756849055">"కార్యాలయ ప్రొఫైల్ లాక్ అయింది"</string>
@@ -2053,8 +2053,8 @@
<string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string>
<string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"వెంటనే తీర ప్రాంతాలు మరియు నదీ పరీవాహక ప్రాంతాలను ఖాళీ చేసి మెట్ట ప్రాంతాలకు తరలి వెళ్లండి."</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"ప్రశాంతంగా ఉండండి మరియు దగ్గర్లో తలదాచుకోండి."</string>
- <string name="etws_primary_default_message_test" msgid="4583367373909549421">"అత్యవసర సందేశాల పరీక్ష"</string>
- <string name="notification_reply_button_accessibility" msgid="5235776156579456126">"ప్రత్యుత్తరం పంపండి"</string>
+ <string name="etws_primary_default_message_test" msgid="4583367373909549421">"అత్యవసర మెసేజ్‌ల పరీక్ష"</string>
+ <string name="notification_reply_button_accessibility" msgid="5235776156579456126">"రిప్లయి పంపండి"</string>
<string name="etws_primary_default_message_others" msgid="7958161706019130739"></string>
<string name="mmcc_authentication_reject" msgid="4891965994643876369">"వాయిస్ కోసం SIM అనుమతించబడదు"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="227760698553988751">"వాయిస్ కోసం SIM సదుపాయం లేదు"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a3f4b0c651fe..7f6ade48cced 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4515,6 +4515,13 @@
If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
<integer name="config_fixedRefreshRateInHighZone">0</integer>
+ <!-- Default refresh rate while the device has high brightness mode enabled for Sunlight.
+ This value overrides values from DisplayDeviceConfig -->
+ <integer name="config_defaultRefreshRateInHbmSunlight">0</integer>
+
+ <!-- Default refresh rate while the device has high brightness mode enabled for HDR. -->
+ <integer name="config_defaultRefreshRateInHbmHdr">0</integer>
+
<!-- The type of the light sensor to be used by the display framework for things like
auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
<string name="config_displayLightSensorType" translatable="false" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 20b6b38951ba..5742ae8835fe 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3975,6 +3975,8 @@
<java-symbol type="integer" name="config_defaultRefreshRateInZone" />
<java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
<java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
+ <java-symbol type="integer" name="config_defaultRefreshRateInHbmSunlight" />
+ <java-symbol type="integer" name="config_defaultRefreshRateInHbmHdr" />
<!-- For fixed refresh rate displays in high brightness-->
<java-symbol type="integer" name="config_fixedRefreshRateInHighZone" />
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index ccb121770977..9feb619b34e3 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -178,22 +178,8 @@ public class ImageFormat {
* <p>Android YUV P010 format.</p>
*
* P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
- * followed immediately by a Wx(H/2) CbCr plane. Each sample is
- * represented by a 16-bit little-endian value, with the lower 6 bits set
- * to zero.
- *
- * <p>This format assumes
- * <ul>
- * <li>an even height</li>
- * <li>a vertical stride equal to the height</li>
- * </ul>
- * </p>
- *
- * <pre> stride_in_bytes = stride * 2 </pre>
- * <pre> y_size = stride_in_bytes * height </pre>
- * <pre> cbcr_size = stride_in_bytes * (height / 2) </pre>
- * <pre> cb_offset = y_size </pre>
- * <pre> cr_offset = cb_offset + 2 </pre>
+ * followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
+ * little-endian value, with the lower 6 bits set to zero.
*
* <p>For example, the {@link android.media.Image} object can provide data
* in this format from a {@link android.hardware.camera2.CameraDevice}
diff --git a/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java
index 053bec74405e..2e54e63a5b7a 100644
--- a/keystore/java/android/security/GenerateRkpKey.java
+++ b/keystore/java/android/security/GenerateRkpKey.java
@@ -25,6 +25,8 @@ import android.os.RemoteException;
import android.util.Log;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
@@ -88,7 +90,8 @@ public class GenerateRkpKey {
}
intent.setComponent(comp);
mCountDownLatch = new CountDownLatch(1);
- if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ Executor executor = Executors.newCachedThreadPool();
+ if (!mContext.bindService(intent, Context.BIND_AUTO_CREATE, executor, mConnection)) {
throw new RemoteException("Failed to bind to GenerateRkpKeyService");
}
try {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index ba0ab6db1003..656bdff0c782 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -336,6 +336,13 @@ public class ShellTaskOrganizer extends TaskOrganizer implements
}
@Override
+ public void onImeDrawnOnTask(int taskId) {
+ if (mStartingWindow != null) {
+ mStartingWindow.onImeDrawnOnTask(taskId);
+ }
+ }
+
+ @Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
synchronized (mLock) {
onTaskAppeared(new TaskAppearedInfo(taskInfo, leash));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index fc7c86d669cb..147f5e30f9d6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -545,6 +545,15 @@ public class StartingSurfaceDrawer {
removeWindowSynced(taskId, null, null, false);
}
+ void onImeDrawnOnTask(int taskId) {
+ final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+ if (record != null && record.mTaskSnapshotWindow != null
+ && record.mTaskSnapshotWindow.hasImeSurface()) {
+ record.mTaskSnapshotWindow.removeImmediately();
+ }
+ mStartingWindowRecords.remove(taskId);
+ }
+
protected void removeWindowSynced(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation) {
final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
@@ -572,14 +581,15 @@ public class StartingSurfaceDrawer {
Slog.e(TAG, "Found empty splash screen, remove!");
removeWindowInner(record.mDecorView, false);
}
+ mStartingWindowRecords.remove(taskId);
}
if (record.mTaskSnapshotWindow != null) {
if (DEBUG_TASK_SNAPSHOT) {
Slog.v(TAG, "Removing task snapshot window for " + taskId);
}
- record.mTaskSnapshotWindow.remove();
+ record.mTaskSnapshotWindow.scheduleRemove(
+ () -> mStartingWindowRecords.remove(taskId));
}
- mStartingWindowRecords.remove(taskId);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index e84d498a9258..dee21b093dce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -177,6 +177,13 @@ public class StartingWindowController implements RemoteCallable<StartingWindowCo
}
/**
+ * Called when the IME has drawn on the organized task.
+ */
+ public void onImeDrawnOnTask(int taskId) {
+ mSplashScreenExecutor.execute(() -> mStartingSurfaceDrawer.onImeDrawnOnTask(taskId));
+ }
+
+ /**
* Called when the content of a task is ready to show, starting window can be removed.
*/
public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 6052d3dee891..dfb1ae3ef2a0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -64,7 +64,6 @@ import android.graphics.RectF;
import android.hardware.HardwareBuffer;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.Trace;
import android.util.MergedConfiguration;
import android.util.Slog;
@@ -119,7 +118,12 @@ public class TaskSnapshotWindow {
private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
private static final long DELAY_REMOVAL_TIME_GENERAL = 100;
- private static final long DELAY_REMOVAL_TIME_IME_VISIBLE = 350;
+ /**
+ * The max delay time in milliseconds for removing the task snapshot window with IME visible.
+ * Ideally the delay time will be shorter when receiving
+ * {@link StartingSurfaceDrawer#onImeDrawnOnTask(int)}.
+ */
+ private static final long MAX_DELAY_REMOVAL_TIME_IME_VISIBLE = 600;
//tmp vars for unused relayout params
private static final Point TMP_SURFACE_SIZE = new Point();
@@ -138,7 +142,6 @@ public class TaskSnapshotWindow {
private final RectF mTmpDstFrame = new RectF();
private final CharSequence mTitle;
private boolean mHasDrawn;
- private long mShownTime;
private boolean mSizeMismatch;
private final Paint mBackgroundPaint = new Paint();
private final int mActivityType;
@@ -148,6 +151,8 @@ public class TaskSnapshotWindow {
private final SurfaceControl.Transaction mTransaction;
private final Matrix mSnapshotMatrix = new Matrix();
private final float[] mTmpFloat9 = new float[9];
+ private Runnable mScheduledRunnable;
+ private final boolean mHasImeSurface;
static TaskSnapshotWindow create(StartingWindowInfo info, IBinder appToken,
TaskSnapshot snapshot, ShellExecutor splashScreenExecutor,
@@ -216,7 +221,7 @@ public class TaskSnapshotWindow {
taskDescription.setBackgroundColor(WHITE);
}
- final long delayRemovalTime = snapshot.hasImeSurface() ? DELAY_REMOVAL_TIME_IME_VISIBLE
+ final long delayRemovalTime = snapshot.hasImeSurface() ? MAX_DELAY_REMOVAL_TIME_IME_VISIBLE
: DELAY_REMOVAL_TIME_GENERAL;
final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
@@ -281,12 +286,17 @@ public class TaskSnapshotWindow {
mDelayRemovalTime = delayRemovalTime;
mTransaction = new SurfaceControl.Transaction();
mClearWindowHandler = clearWindowHandler;
+ mHasImeSurface = snapshot.hasImeSurface();
}
int getBackgroundColor() {
return mBackgroundPaint.getColor();
}
+ boolean hasImeSurface() {
+ return mHasImeSurface;
+ }
+
/**
* Ask system bar background painter to draw status bar background.
* @hide
@@ -304,21 +314,32 @@ public class TaskSnapshotWindow {
mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
}
- void remove() {
- final long now = SystemClock.uptimeMillis();
- if ((now - mShownTime < mDelayRemovalTime)
- // Show the latest content as soon as possible for unlocking to home.
- && mActivityType != ACTIVITY_TYPE_HOME) {
- final long delayTime = mShownTime + mDelayRemovalTime - now;
- mSplashScreenExecutor.executeDelayed(() -> remove(), delayTime);
- if (DEBUG) {
- Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
- }
+ void scheduleRemove(Runnable onRemove) {
+ // Show the latest content as soon as possible for unlocking to home.
+ if (mActivityType == ACTIVITY_TYPE_HOME) {
+ removeImmediately();
+ onRemove.run();
return;
}
+ if (mScheduledRunnable != null) {
+ mSplashScreenExecutor.removeCallbacks(mScheduledRunnable);
+ mScheduledRunnable = null;
+ }
+ mScheduledRunnable = () -> {
+ TaskSnapshotWindow.this.removeImmediately();
+ onRemove.run();
+ };
+ mSplashScreenExecutor.executeDelayed(mScheduledRunnable, mDelayRemovalTime);
+ if (DEBUG) {
+ Slog.d(TAG, "Defer removing snapshot surface in " + mDelayRemovalTime);
+ }
+ }
+
+ void removeImmediately() {
+ mSplashScreenExecutor.removeCallbacks(mScheduledRunnable);
try {
if (DEBUG) {
- Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
+ Slog.d(TAG, "Removing taskSnapshot surface, mHasDrawn: " + mHasDrawn);
}
mSession.remove(mWindow);
} catch (RemoteException e) {
@@ -356,7 +377,6 @@ public class TaskSnapshotWindow {
} else {
drawSizeMatchSnapshot();
}
- mShownTime = SystemClock.uptimeMillis();
mHasDrawn = true;
reportDrawn();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index d536adb9f8ae..eef0d9bb268f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -15,38 +15,53 @@
*/
package com.android.wm.shell.startingsurface;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
import android.testing.TestableContext;
+import android.view.IWindowSession;
+import android.view.InsetsState;
+import android.view.Surface;
import android.view.SurfaceControl;
import android.view.View;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.WindowMetrics;
import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -61,6 +76,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import java.util.function.IntSupplier;
@@ -78,6 +94,7 @@ public class StartingSurfaceDrawerTests {
private TransactionPool mTransactionPool;
private final Handler mTestHandler = new Handler(Looper.getMainLooper());
+ private ShellExecutor mTestExecutor;
private final TestableContext mTestContext = new TestContext(
InstrumentationRegistry.getInstrumentation().getTargetContext());
TestStartingSurfaceDrawer mStartingSurfaceDrawer;
@@ -138,9 +155,9 @@ public class StartingSurfaceDrawerTests {
doReturn(metrics).when(mMockWindowManager).getMaximumWindowMetrics();
doNothing().when(mMockWindowManager).addView(any(), any());
-
- mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(mTestContext,
- new HandlerExecutor(mTestHandler), mTransactionPool));
+ mTestExecutor = new HandlerExecutor(mTestHandler);
+ mStartingSurfaceDrawer = spy(
+ new TestStartingSurfaceDrawer(mTestContext, mTestExecutor, mTransactionPool));
}
@Test
@@ -205,6 +222,48 @@ public class StartingSurfaceDrawerTests {
assertEquals(0, windowColor3.mReuseCount);
}
+ @Test
+ public void testRemoveTaskSnapshotWithImeSurfaceWhenOnImeDrawn() throws Exception {
+ final int taskId = 1;
+ final StartingWindowInfo windowInfo =
+ createWindowInfo(taskId, android.R.style.Theme);
+ TaskSnapshot snapshot = createTaskSnapshot(100, 100, new Point(100, 100),
+ new Rect(0, 0, 0, 50), true /* hasImeSurface */);
+ final IWindowSession session = WindowManagerGlobal.getWindowSession();
+ spyOn(session);
+ doReturn(WindowManagerGlobal.ADD_OKAY).when(session).addToDisplay(
+ any() /* window */, any() /* attrs */,
+ anyInt() /* viewVisibility */, anyInt() /* displayId */,
+ any() /* requestedVisibility */, any() /* outInputChannel */,
+ any() /* outInsetsState */, any() /* outActiveControls */);
+ TaskSnapshotWindow mockSnapshotWindow = TaskSnapshotWindow.create(windowInfo,
+ mBinder,
+ snapshot, mTestExecutor, () -> {
+ });
+ spyOn(mockSnapshotWindow);
+ try (AutoCloseable mockTaskSnapshotSession = new AutoCloseable() {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .mockStatic(TaskSnapshotWindow.class)
+ .startMocking();
+ @Override
+ public void close() {
+ mockSession.finishMocking();
+ }
+ }) {
+ when(TaskSnapshotWindow.create(eq(windowInfo), eq(mBinder), eq(snapshot), any(),
+ any())).thenReturn(mockSnapshotWindow);
+ // Simulate a task snapshot window created with IME snapshot shown.
+ mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, mBinder, snapshot);
+ waitHandlerIdle(mTestHandler);
+
+ // Verify the task snapshot with IME snapshot will be removed when received the real IME
+ // drawn callback.
+ mStartingSurfaceDrawer.onImeDrawnOnTask(1);
+ verify(mockSnapshotWindow).removeImmediately();
+ }
+ }
+
private StartingWindowInfo createWindowInfo(int taskId, int themeResId) {
StartingWindowInfo windowInfo = new StartingWindowInfo();
final ActivityInfo info = new ActivityInfo();
@@ -216,10 +275,27 @@ public class StartingSurfaceDrawerTests {
taskInfo.taskId = taskId;
windowInfo.targetActivityInfo = info;
windowInfo.taskInfo = taskInfo;
+ windowInfo.topOpaqueWindowInsetsState = new InsetsState();
+ windowInfo.mainWindowLayoutParams = new WindowManager.LayoutParams();
+ windowInfo.topOpaqueWindowLayoutParams = new WindowManager.LayoutParams();
return windowInfo;
}
private static void waitHandlerIdle(Handler handler) {
handler.runWithScissors(() -> { }, 0 /* timeout */);
}
+
+ private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
+ Rect contentInsets, boolean hasImeSurface) {
+ final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
+ 1, HardwareBuffer.USAGE_CPU_READ_RARELY);
+ return new TaskSnapshot(
+ System.currentTimeMillis(),
+ new ComponentName("", ""), buffer,
+ ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
+ Surface.ROTATION_0, taskSize, contentInsets, false,
+ true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
+ 0 /* systemUiVisibility */, false /* isTranslucent */,
+ hasImeSurface /* hasImeSurface */);
+ }
}
diff --git a/libs/hwui/WebViewFunctorManager.cpp b/libs/hwui/WebViewFunctorManager.cpp
index df4101109a18..5aad821ad59f 100644
--- a/libs/hwui/WebViewFunctorManager.cpp
+++ b/libs/hwui/WebViewFunctorManager.cpp
@@ -100,6 +100,9 @@ WebViewFunctor::~WebViewFunctor() {
destroyContext();
ATRACE_NAME("WebViewFunctor::onDestroy");
+ if (mSurfaceControl) {
+ removeOverlays();
+ }
mCallbacks.onDestroyed(mFunctor, mData);
}
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 86ed50bacb63..72ee00f03774 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -102,6 +102,13 @@ public abstract class PlayerBase {
mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE;
};
+ /** @hide */
+ public int getPlayerIId() {
+ synchronized (mLock) {
+ return mPlayerIId;
+ }
+ }
+
/**
* Call from derived class when instantiation / initialization is successful
*/
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index c1a0a9a92cc2..b4cafd8548f4 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -93,9 +93,9 @@ public class CompanionDeviceActivity extends Activity {
final DeviceFilterPair selectedDevice = getService().mDevicesFound.get(0);
setTitle(Html.fromHtml(getString(
R.string.confirmation_title,
- getCallingAppName(),
- profileName,
- selectedDevice.getDisplayName()), 0));
+ Html.escapeHtml(getCallingAppName()),
+ Html.escapeHtml(selectedDevice.getDisplayName())), 0));
+
mPairButton = findViewById(R.id.button_pair);
mPairButton.setOnClickListener(v -> onDeviceConfirmed(getService().mSelectedDevice));
getService().mSelectedDevice = selectedDevice;
@@ -108,8 +108,8 @@ public class CompanionDeviceActivity extends Activity {
mPairButton = findViewById(R.id.button_pair);
mPairButton.setVisibility(View.GONE);
setTitle(Html.fromHtml(getString(R.string.chooser_title,
- profileName,
- getCallingAppName()), 0));
+ Html.escapeHtml(profileName),
+ Html.escapeHtml(getCallingAppName())), 0));
mDeviceListView = findViewById(R.id.device_list);
mDevicesAdapter = new DevicesAdapter();
mDeviceListView.setAdapter(mDevicesAdapter);
diff --git a/packages/PrintSpooler/res/values-ta/strings.xml b/packages/PrintSpooler/res/values-ta/strings.xml
index eaf05b104046..7ffac67c5a8e 100644
--- a/packages/PrintSpooler/res/values-ta/strings.xml
+++ b/packages/PrintSpooler/res/values-ta/strings.xml
@@ -63,7 +63,7 @@
<string name="printer_info_desc" msgid="7181988788991581654">"இந்தப் பிரிண்டர் பற்றிய கூடுதல் தகவல்"</string>
<string name="notification_channel_progress" msgid="872788690775721436">"இயக்கத்திலுள்ள அச்சுப் பணிகள்"</string>
<string name="notification_channel_failure" msgid="9042250774797916414">"தோல்வியடைந்த அச்சுப் பணிகள்"</string>
- <string name="could_not_create_file" msgid="3425025039427448443">"கோப்பை உருவாக்க முடியவில்லை"</string>
+ <string name="could_not_create_file" msgid="3425025039427448443">"ஃபைலை உருவாக்க முடியவில்லை"</string>
<string name="print_services_disabled_toast" msgid="9089060734685174685">"சில அச்சுப் பொறிகள் முடக்கப்பட்டன"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"பிரிண்டர்களைத் தேடுகிறது"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"அச்சுப் பொறிகள் இல்லை"</string>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
index e74ac44ec8a4..fede44feb090 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-v31/styles.xml
@@ -33,18 +33,18 @@
<style name="Banner.Title.SettingsLib"
parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textSize">20sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="Banner.Subtitle.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
<style name="Banner.Summary.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
@@ -58,4 +58,4 @@
parent="android:Widget.DeviceDefault.Button.Borderless.Colored">
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
-</resources> \ No newline at end of file
+</resources>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
index df47c642e402..4c6ed58f4a58 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values/styles.xml
@@ -17,14 +17,13 @@
<resources>
<style name="Banner.Text.Title"
- parent="@android:style/TextAppearance.Material.Subhead">
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textSize">16sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
<style name="Banner.Text.Summary"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
index 92514ad58b77..1c4420717188 100644
--- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -87,9 +87,9 @@
</style>
<style name="BarChart.Text"
- parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">16sp</item>
</style>
<style name="BarChart.Text.HeaderTitle">
@@ -101,7 +101,7 @@
</style>
<style name="BarChart.Text.Summary"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">12sp</item>
</style>
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
index 2f911c4e6546..238e65ec9a3c 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/Android.bp
@@ -19,6 +19,7 @@ android_library {
"com.google.android.material_material",
"SettingsLibSettingsTransition",
"SettingsLibUtils",
+ "SettingsLibSettingsTheme",
],
sdk_version: "system_current",
min_sdk_version: "29",
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
index 59506564400b..907863e19972 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_base_layout.xml
@@ -16,7 +16,6 @@
-->
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content_parent"
android:layout_width="match_parent"
@@ -40,7 +39,7 @@
android:clipToPadding="false"
app:forceApplySystemWindowInsetTop="true"
app:extraMultilineHeightEnabled="true"
- app:contentScrim="?androidprv:attr/colorSurfaceHeader"
+ app:contentScrim="@color/settingslib_colorSurfaceHeader"
app:maxLines="3"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:scrimAnimationDuration="50"
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
index 878275a08752..c20beaf9bf93 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v31/themes.xml
@@ -18,7 +18,7 @@
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
- <item name="colorPrimary">@*android:color/primary_dark_device_default_settings</item>
- <item name="colorAccent">@*android:color/accent_device_default_dark</item>
+ <item name="colorPrimary">@color/settingslib_primary_dark_device_default_settings</item>
+ <item name="colorAccent">@color/settingslib_accent_device_default_dark</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml
index 15c1abbf97ba..15c1abbf97ba 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/dimens.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/dimens.xml
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
index 63d397c69353..d0b6c4d54bb1 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/styles.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/styles.xml
@@ -16,11 +16,13 @@
-->
<resources>
<style name="CollapsingToolbarTitle.Collapsed" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20dp</item>
+ <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
</style>
<style name="CollapsingToolbarTitle.Expanded" parent="CollapsingToolbarTitle.Collapsed">
<item name="android:textSize">36dp</item>
+ <item name="android:textColor">@color/settingslib_text_color_primary_device_default</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
index 2e7a6a9181fe..9ecc297c6d36 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values/themes.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v31/themes.xml
@@ -18,7 +18,7 @@
<style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight">
<item name="elevationOverlayEnabled">true</item>
<item name="elevationOverlayColor">?attr/colorPrimary</item>
- <item name="colorPrimary">@*android:color/primary_device_default_settings_light</item>
- <item name="colorAccent">@*android:color/accent_device_default_light</item>
+ <item name="colorPrimary">@color/settingslib_primary_device_default_settings_light</item>
+ <item name="colorAccent">@color/settingslib_accent_device_default_light</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/FooterPreference/res/values/styles.xml b/packages/SettingsLib/FooterPreference/res/values/styles.xml
index 08dd35991f69..5a3bada3e594 100644
--- a/packages/SettingsLib/FooterPreference/res/values/styles.xml
+++ b/packages/SettingsLib/FooterPreference/res/values/styles.xml
@@ -17,9 +17,8 @@
<resources>
<style name="TextAppearance.Footer.Title.SettingsLib"
- parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textSize">14sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
<item name="android:textColor">?android:attr/colorAccent</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/LayoutPreference/res/values/styles.xml b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
index 4a99e845a5fc..2ffe6d91651b 100644
--- a/packages/SettingsLib/LayoutPreference/res/values/styles.xml
+++ b/packages/SettingsLib/LayoutPreference/res/values/styles.xml
@@ -24,14 +24,13 @@
</style>
<style name="TextAppearance.EntityHeaderTitle"
- parent="@android:style/TextAppearance.Material.Subhead">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ parent="@android:style/TextAppearance.DeviceDefault.WindowTitle">
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:textSize">20sp</item>
</style>
<style name="TextAppearance.EntityHeaderSummary"
- parent="@*android:style/TextAppearance.DeviceDefault.Body1">
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textAlignment">viewStart</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:singleLine">true</item>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_disabled.xml
index 088e82bb4260..088e82bb4260 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_disabled.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_disabled.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_off.xml
index 088e82bb4260..088e82bb4260 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_off.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_off.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_on.xml
index 250188b892f4..250188b892f4 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/drawable/settingslib_switch_bar_bg_on.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg_on.xml
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index 6e5911cbf0a0..30748e6244cb 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -50,7 +50,7 @@
android:tint="?android:attr/colorAccent"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@*android:drawable/ic_info"
+ android:src="@android:drawable/ic_info"
android:visibility="gone" />
<Switch
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
index 306145a3e689..d0c2d0b5937d 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_bar.xml
@@ -28,7 +28,7 @@
android:layout_gravity="center_vertical"
android:maxLines="2"
android:ellipsize="end"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title"
android:textSize="16sp"
android:textColor="?android:attr/textColorPrimaryInverse"
android:layout_marginStart="@dimen/settingslib_switchbar_subsettings_margin_start"
@@ -42,7 +42,7 @@
android:theme="@android:style/Theme.Material"
android:layout_gravity="center_vertical"
android:layout_marginEnd="@dimen/settingslib_restricted_icon_margin_end"
- android:src="@*android:drawable/ic_info"
+ android:src="@android:drawable/ic_info"
android:visibility="gone"/>
<Switch
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
new file mode 100644
index 000000000000..2272a375fb83
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/dimens.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<resources>
+
+ <!-- Size of layout margin -->
+ <dimen name="settingslib_switchbar_margin">16dp</dimen>
+
+ <!-- Size of layout margin left -->
+ <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
+
+ <!-- Size of layout margin right -->
+ <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
+
+ <!-- Minimum width of switch -->
+ <dimen name="settingslib_min_switch_width">52dp</dimen>
+
+ <!-- Minimum width of switch bar -->
+ <dimen name="settingslib_min_switch_bar_height">72dp</dimen>
+
+ <!-- Radius of switch bar -->
+ <dimen name="settingslib_switch_bar_radius">28dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
new file mode 100644
index 000000000000..a50fc7cc0028
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/values-v31/styles.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<resources>
+
+ <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
+ <item name="android:textSize">20sp</item>
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
+ <item name="android:textColor">@android:color/black</item>
+ </style>
+</resources>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
index 16b8af6a2dab..6362882e2332 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2020 The Android Open Source Project
+ 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.
@@ -17,30 +17,12 @@
<resources>
- <!-- Size of layout margin -->
- <dimen name="settingslib_switchbar_margin">16dp</dimen>
-
- <!-- Size of layout margin left -->
- <dimen name="settingslib_switchbar_padding_left">24dp</dimen>
-
- <!-- Size of layout margin right -->
- <dimen name="settingslib_switchbar_padding_right">16dp</dimen>
-
- <!-- Minimum width of switch -->
- <dimen name="settingslib_min_switch_width">52dp</dimen>
-
- <!-- Minimum width of switch bar -->
- <dimen name="settingslib_min_switch_bar_height">72dp</dimen>
-
<!-- Restricted icon size in switch bar -->
- <dimen name="settingslib_restricted_icon_size">@*android:dimen/config_restrictedIconSize</dimen>
+ <dimen name="settingslib_restricted_icon_size">@android:dimen/config_restrictedIconSize</dimen>
<!-- Restricted icon in switch bar -->
<dimen name="settingslib_restricted_icon_margin_end">16dp</dimen>
- <!-- Radius of switch bar -->
- <dimen name="settingslib_switch_bar_radius">28dp</dimen>
-
<!-- Size of title margin -->
<dimen name="settingslib_switch_title_margin">16dp</dimen>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
index 3924e301a2d3..870812ae6caf 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/values/styles.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright (C) 2020 The Android Open Source Project
+ 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.
@@ -17,13 +17,6 @@
<resources>
- <style name="MainSwitchText.Settingslib" parent="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title">
- <item name="android:textSize">20sp</item>
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@android:color/black</item>
- </style>
-
-
<style name="SwitchBar.Switch.Settingslib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:trackTint">@color/settingslib_switchbar_switch_track_tint</item>
<item name="android:thumbTint">@color/settingslib_switchbar_switch_thumb_tint</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
new file mode 100644
index 000000000000..037b80abc6f9
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
index 8c7c7ed5b120..c20690342c19 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml
@@ -36,4 +36,11 @@
<color name="settingslib_dialog_colorError">#f28b82</color> <!-- Red 300 -->
<color name="settingslib_colorSurfaceVariant">@android:color/system_neutral1_700</color>
+
+ <color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_700</color>
+
+ <!-- copy from accent_primary_variant_dark_device_default-->
+ <color name="settingslib_accent_primary_variant">@android:color/system_accent1_300</color>
+
+ <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_50</color>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
index 77f1bcd17371..04010985fe74 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml
@@ -37,9 +37,32 @@
<!-- Dialog accent color -->
<color name="settingslib_dialog_accent">@android:color/system_accent1_600</color>
<!-- Dialog background color -->
- <color name="settingslib_dialog_background">@*android:color/surface_light</color>
+ <color name="settingslib_dialog_background">@color/settingslib_surface_light</color>
<!-- Dialog error color. -->
<color name="settingslib_dialog_colorError">#d93025</color> <!-- Red 600 -->
<color name="settingslib_colorSurfaceVariant">@android:color/system_neutral2_100</color>
+
+ <color name="settingslib_colorSurfaceHeader">@android:color/system_neutral1_100</color>
+
+ <color name="settingslib_accent_device_default_dark">@android:color/system_accent1_100</color>
+
+ <color name="settingslib_accent_device_default_light">@android:color/system_accent1_600</color>
+
+ <color name="settingslib_primary_dark_device_default_settings">@android:color/system_neutral1_900</color>
+
+ <color name="settingslib_primary_device_default_settings_light">@android:color/system_neutral1_50</color>
+
+ <color name="settingslib_accent_primary_device_default">@android:color/system_accent1_100</color>
+
+ <!-- copy from accent_primary_variant_light_device_default-->
+ <color name="settingslib_accent_primary_variant">@android:color/system_accent1_600</color>
+
+ <color name="settingslib_accent_secondary_device_default">@android:color/system_accent2_100</color>
+
+ <color name="settingslib_background_device_default_dark">@android:color/system_neutral1_900</color>
+
+ <color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color>
+
+ <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_900</color>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
index ddcc83eee4bf..1c33f1a57ea5 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/dimens.xml
@@ -19,4 +19,5 @@
<dimen name="app_preference_padding_start">20dp</dimen>
<dimen name="app_icon_min_width">52dp</dimen>
<dimen name="settingslib_preferred_minimum_touch_target">48dp</dimen>
+ <dimen name="settingslib_dialogCornerRadius">28dp</dimen>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml
new file mode 100644
index 000000000000..6d072a936b15
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Name of a font family to use for headlines in SettingsLib. -->
+ <string name="settingslib_config_headlineFontFamily" translatable="false">
+ @*android:string/config_headlineFontFamily
+ </string>
+
+ <!-- Name of a font family to use for headlines-medium in SettingsLib. -->
+ <string name="settingslib_config_headlineFontFamilyMedium" translatable="false">
+ @*android:string/config_headlineFontFamilyMedium
+ </string>
+
+ <!-- Name of a font family to use for body in SettingsLib. -->
+ <string name="settingslib_config_bodyFontFamily" translatable="false">
+ @*android:string/config_bodyFontFamily
+ </string>
+
+ <!-- Name of a font family to use for body-medium in SettingsLib. -->
+ <string name="settingslib_config_bodyFontFamilyMedium" translatable="false">
+ @*android:string/config_bodyFontFamilyMedium
+ </string>
+</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
index 46f1e030af23..58006369988e 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles.xml
@@ -16,12 +16,16 @@
-->
<resources>
<style name="TextAppearance.PreferenceTitle.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.ListItem">
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:fontFamily">@string/settingslib_config_headlineFontFamily</item>
<item name="android:textSize">20sp</item>
</style>
<style name="TextAppearance.CategoryTitle.SettingsLib"
- parent="@*android:style/TextAppearance.DeviceDefault.Body2" />
+ parent="@android:style/TextAppearance.DeviceDefault.Medium">
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">14sp</item>
+ </style>
<style name="Switch.SettingsLib" parent="@android:style/Widget.Material.CompoundButton.Switch">
<item name="android:switchMinWidth">52dp</item>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
index 8034710b4341..6bf288b74d5a 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/themes.xml
@@ -50,6 +50,6 @@
<item name="android:clipToPadding">true</item>
<item name="android:clipChildren">true</item>
- <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+ <item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
index 25f9514c29b7..18af1f9c15d0 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/dimens.xml
@@ -20,4 +20,5 @@
<dimen name="app_preference_padding_start">?android:attr/listPreferredItemPaddingStart</dimen>
<dimen name="app_icon_min_width">56dp</dimen>
<dimen name="two_target_min_width">72dp</dimen>
+ <dimen name="settingslib_dialogCornerRadius">8dp</dimen>
</resources>
diff --git a/packages/SettingsLib/SettingsTheme/res/values/themes.xml b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
index 6f2517746ddc..2d881d1a8a7b 100644
--- a/packages/SettingsLib/SettingsTheme/res/values/themes.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values/themes.xml
@@ -35,7 +35,7 @@
<!-- TODO(b/189308264): fix the crash in Android R if set the attributes:
<item name="colorAccent">@*android:color/accent_device_default_light</item>
<item name="android:colorBackground">@color/settingslib_dialog_background</item>
- <item name="dialogCornerRadius">@*android:dimen/config_dialogCornerRadius</item>
+ <item name="dialogCornerRadius">@dimen/settingslib_dialogCornerRadius</item>
-->
<item name="android:windowSoftInputMode">adjustResize</item>
<item name="android:clipToPadding">true</item>
diff --git a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
index 65869b5580b5..b6ca41fb6b6d 100644
--- a/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
+++ b/packages/SettingsLib/TopIntroPreference/res/values/styles.xml
@@ -16,8 +16,7 @@
-->
<resources>
<style name="TextAppearance.TopIntroText"
- parent="@*android:style/TextAppearance.DeviceDefault">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index 1ac36aad293b..db3002f2ff23 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -142,15 +142,15 @@
<item msgid="1333279807604675720">"స్టీరియో"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
- <item msgid="1241278021345116816">"ఆడియో నాణ్యత (990kbps/909kbps) కోసం అనుకూలీకరించబడింది"</item>
- <item msgid="3523665555859696539">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత (660kbps/606kbps)"</item>
- <item msgid="886408010459747589">"కనెక్షన్ నాణ్యత (330kbps/303kbps) కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="1241278021345116816">"ఆడియో క్వాలిటీ (990kbps/909kbps) కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="3523665555859696539">"సమతుల్య ఆడియో మరియు కనెక్షన్ క్వాలిటీ (660kbps/606kbps)"</item>
+ <item msgid="886408010459747589">"కనెక్షన్ క్వాలిటీ (330kbps/303kbps) కోసం అనుకూలీకరించబడింది"</item>
<item msgid="3808414041654351577">"ఉత్తమ కృషి (అనుకూల బిట్ రేట్)"</item>
</string-array>
<string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
- <item msgid="804499336721569838">"ఆడియో నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
- <item msgid="7451422070435297462">"సమతుల్య ఆడియో మరియు కనెక్షన్ నాణ్యత"</item>
- <item msgid="6173114545795428901">"కనెక్షన్ నాణ్యత కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="804499336721569838">"ఆడియో క్వాలిటీ కోసం అనుకూలీకరించబడింది"</item>
+ <item msgid="7451422070435297462">"సమతుల్య ఆడియో మరియు కనెక్షన్ క్వాలిటీ"</item>
+ <item msgid="6173114545795428901">"కనెక్షన్ క్వాలిటీ కోసం అనుకూలీకరించబడింది"</item>
<item msgid="4349908264188040530">"ఉత్తమ కృషి (అనుకూల బిట్ రేట్)"</item>
</string-array>
<string-array name="bluetooth_audio_active_device_summaries">
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 9a1e4f4297c4..6df6d2d00298 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -90,7 +90,7 @@
<string name="bluetooth_profile_pbap" msgid="7064307749579335765">"కాంటాక్ట్ షేరింగ్"</string>
<string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"పరిచయ భాగస్వామ్యం కోసం ఉపయోగించు"</string>
<string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ భాగస్వామ్యం"</string>
- <string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన సందేశాలు"</string>
+ <string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన మెసేజ్‌లు"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM యాక్సెస్"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ఆడియో: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"HD ఆడియో"</string>
@@ -116,7 +116,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"జత చేయి"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"జత చేయి"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"రద్దు చేయి"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"జత చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ పరిచయాలకు మరియు కాల్ చరిత్రకు ప్రాప్యతను మంజూరు చేస్తుంది."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"జత చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ పరిచయాలకు మరియు కాల్ చరిత్రకు యాక్సెస్‌ను మంజూరు చేస్తుంది."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో జత చేయడం సాధ్యపడలేదు."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"పిన్ లేదా పాస్‌కీ చెల్లని కారణంగా <xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో పెయిర్ చేయడం సాధ్యపడలేదు."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో కమ్యూనికేట్ చేయడం సాధ్యపడదు."</string>
@@ -199,7 +199,7 @@
<string name="category_work" msgid="4014193632325996115">"ఆఫీస్"</string>
<string name="development_settings_title" msgid="140296922921597393">"డెవలపర్ ఆప్షన్‌లు"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"డెవలపర్ ఎంపికలను ప్రారంభించండి"</string>
- <string name="development_settings_summary" msgid="8718917813868735095">"అనువర్తన అభివృద్ధి కోసం ఎంపికలను సెట్ చేయండి"</string>
+ <string name="development_settings_summary" msgid="8718917813868735095">"యాప్‌ అభివృద్ధి కోసం ఎంపికలను సెట్ చేయండి"</string>
<string name="development_settings_not_available" msgid="355070198089140951">"ఈ వినియోగదారు కోసం డెవలపర్ ఎంపికలు అందుబాటులో లేవు"</string>
<string name="vpn_settings_not_available" msgid="2894137119965668920">"VPN సెట్టింగ్‌లు ఈ వినియోగదారుకి అందుబాటులో లేవు"</string>
<string name="tethering_settings_not_available" msgid="266821736434699780">"టీథరింగ్ సెట్టింగ్‌లు ఈ వినియోగదారుకి అందుబాటులో లేవు"</string>
@@ -227,12 +227,12 @@
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi పెయిరింగ్ కోడ్"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"పెయిరింగ్ విఫలమైంది"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"పరికరం అదే నెట్‌వర్క్‌కు కనెక్ట్ చేయబడి ఉందని నిర్ధారించుకోండి."</string>
- <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చెయ్యండి"</string>
+ <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"పరికరం పెయిర్ చేయబడుతోంది…"</string>
<string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"పరికరాన్ని పెయిర్ చేయడం విఫలమైంది. QR కోడ్ తప్పుగా ఉండడం గాని, లేదా పరికరం అదే నెట్‌వర్క్‌కు కనెక్ట్ అయి లేకపోవడం గాని జరిగింది."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP అడ్రస్ &amp; పోర్ట్"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"QR కోడ్‌ను స్కాన్ చేయండి"</string>
- <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చెయ్యండి"</string>
+ <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"QR కోడ్‌ను స్కాన్ చేయడం ద్వారా Wi-Fiని ఉపయోగించి పరికరాన్ని పెయిర్ చేయండి"</string>
<string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"దయచేసి Wi-Fi నెట్‌వర్క్‌కు కనెక్ట్ చేయండి"</string>
<string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, డీబగ్, dev"</string>
<string name="bugreport_in_power" msgid="8664089072534638709">"బగ్ రిపోర్ట్ షార్ట్‌కట్"</string>
@@ -271,8 +271,8 @@
<string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"బ్లూటూత్ ఆడియో కోడెక్‌ని సక్రియం చేయండి\nఎంపిక: ఒక్కో నమూనాలో బిట్‌లు"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"బ్లూటూత్ ఆడియో ఛానెల్ మోడ్"</string>
<string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="2076949781460359589">"బ్లూటూత్ ఆడియో కోడెక్‌ని సక్రియం చేయండి\nఎంపిక: ఛానెల్ మోడ్"</string>
- <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"బ్లూటూత్ ఆడియో LDAC కోడెక్: ప్లేబ్యాక్ నాణ్యత"</string>
- <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"బ్లూటూత్ ఆడియో LDAC యాక్టివ్ చేయండి\nకోడెక్ ఎంపిక: ప్లేబ్యాక్ నాణ్యత"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="3233402355917446304">"బ్లూటూత్ ఆడియో LDAC కోడెక్: ప్లేబ్యాక్ క్వాలిటీ"</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"బ్లూటూత్ ఆడియో LDAC యాక్టివ్ చేయండి\nకోడెక్ ఎంపిక: ప్లేబ్యాక్ క్వాలిటీ"</string>
<string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"ప్రసారం చేస్తోంది: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
<string name="select_private_dns_configuration_title" msgid="7887550926056143018">"ప్రైవేట్ DNS"</string>
<string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"ప్రైవేట్ DNS మోడ్‌ను ఎంచుకోండి"</string>
@@ -304,7 +304,7 @@
<string name="adb_warning_message" msgid="8145270656419669221">"USB డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్ మరియు మీ పరికరం మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్‌లను ఇన్‌స్టాల్ చేయడానికి మరియు లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
<string name="adbwifi_warning_title" msgid="727104571653031865">"వైర్‌లెస్ డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
<string name="adbwifi_warning_message" msgid="8005936574322702388">"వైర్‌లెస్ డీబగ్గింగ్ అనేది అభివృద్ధి ప్రయోజనాల కోసం మాత్రమే ఉద్దేశించబడింది. మీ కంప్యూటర్, పరికరాల మధ్య డేటాను కాపీ చేయడానికి, నోటిఫికేషన్ లేకుండా మీ పరికరంలో యాప్‌లను ఇన్‌స్టాల్ చేయడానికి, లాగ్ డేటాను చదవడానికి దీన్ని ఉపయోగించండి."</string>
- <string name="adb_keys_warning_message" msgid="2968555274488101220">"మీరు గతంలో ప్రామాణీకరించిన అన్ని కంప్యూటర్‌ల నుండి USB డీబగ్గింగ్‌కు ప్రాప్యతను ఉపసంహరించాలా?"</string>
+ <string name="adb_keys_warning_message" msgid="2968555274488101220">"మీరు గతంలో ప్రామాణీకరించిన అన్ని కంప్యూటర్‌ల నుండి USB డీబగ్గింగ్‌కు యాక్సెస్‌ను ఉపసంహరించాలా?"</string>
<string name="dev_settings_warning_title" msgid="8251234890169074553">"అభివృద్ధి సెట్టింగ్‌లను అనుమతించాలా?"</string>
<string name="dev_settings_warning_message" msgid="37741686486073668">"ఈ సెట్టింగ్‌లు అభివృద్ధి వినియోగం కోసం మాత్రమే ఉద్దేశించబడినవి. వీటి వలన మీ పరికరం మరియు దీనిలోని యాప్‌లు విచ్ఛిన్నం కావచ్చు లేదా తప్పుగా ప్రవర్తించవచ్చు."</string>
<string name="verify_apps_over_usb_title" msgid="6031809675604442636">"USB ద్వారా యాప్‌లను వెరిఫై చేయి"</string>
@@ -314,7 +314,7 @@
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"బ్లూటూత్ Gabeldorsche ఫీచర్ స్ట్యాక్‌ను ఎనేబుల్ చేస్తుంది."</string>
<string name="enhanced_connectivity_summary" msgid="1576414159820676330">"మెరుగైన కనెక్టివిటీ ఫీచర్‌ను ఎనేబుల్ చేస్తుంది."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"స్థానిక టెర్మినల్"</string>
- <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ ప్రాప్యతను అందించే టెర్మినల్ యాప్‌ను ప్రారంభించు"</string>
+ <string name="enable_terminal_summary" msgid="2481074834856064500">"స్థానిక షెల్ యాక్సెస్‌ను అందించే టెర్మినల్ యాప్‌ను ప్రారంభించు"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP చెకింగ్‌"</string>
<string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP తనిఖీ ప్రవర్తనను సెట్ చేయండి"</string>
<string name="debug_debugging_category" msgid="535341063709248842">"డీబగ్గింగ్"</string>
@@ -383,7 +383,7 @@
<string name="local_backup_password_title" msgid="4631017948933578709">"డెస్క్‌టాప్ బ్యాకప్ పాస్‌వర్డ్"</string>
<string name="local_backup_password_summary_none" msgid="7646898032616361714">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌లు ప్రస్తుతం రక్షించబడలేదు"</string>
<string name="local_backup_password_summary_change" msgid="1707357670383995567">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి నొక్కండి"</string>
- <string name="local_backup_password_toast_success" msgid="4891666204428091604">"కొత్త బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేసారు"</string>
+ <string name="local_backup_password_toast_success" msgid="4891666204428091604">"కొత్త బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేశారు"</string>
<string name="local_backup_password_toast_confirmation_mismatch" msgid="2994718182129097733">"కొత్త పాస్‌వర్డ్ మరియు నిర్ధారణ సరిపోలడం లేదు"</string>
<string name="local_backup_password_toast_validation_failure" msgid="714669442363647122">"బ్యాకప్ పాస్‌వర్డ్‌ను సెట్ చేయడంలో వైఫల్యం"</string>
<string name="loading_injected_setting_summary" msgid="8394446285689070348">"లోడ్ చేస్తోంది…"</string>
@@ -408,7 +408,7 @@
<string name="transcode_notification" msgid="5560515979793436168">"ట్రాన్స్‌కోడింగ్ నోటిఫికేషన్‌లను చూపండి"</string>
<string name="transcode_disable_cache" msgid="3160069309377467045">"ట్రాన్స్‌కోడింగ్ కాష్‌ను డిజేబుల్ చేయండి"</string>
<string name="runningservices_settings_title" msgid="6460099290493086515">"అమలులో ఉన్న సర్వీస్‌లు"</string>
- <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సర్వీస్‌లను వీక్షించండి, కంట్రోల్‌ చేయండి"</string>
+ <string name="runningservices_settings_summary" msgid="1046080643262665743">"ప్రస్తుతం అమలులో ఉన్న సర్వీస్‌లను చూడండి, కంట్రోల్‌ చేయండి"</string>
<string name="select_webview_provider_title" msgid="3917815648099445503">"వెబ్ వీక్షణ అమలు"</string>
<string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
<string name="select_webview_provider_toast_text" msgid="8512254949169359848">"ఈ ఎంపిక ఇప్పుడు లేదు. మళ్లీ ప్రయత్నించండి."</string>
@@ -529,7 +529,7 @@
<string name="help_label" msgid="3528360748637781274">"సహాయం &amp; ఫీడ్‌బ్యాక్"</string>
<string name="storage_category" msgid="2287342585424631813">"స్టోరేజ్"</string>
<string name="shared_data_title" msgid="1017034836800864953">"షేర్ చేసిన డేటా"</string>
- <string name="shared_data_summary" msgid="5516326713822885652">"షేర్ చేసిన డేటాను చూసి, సవరించండి"</string>
+ <string name="shared_data_summary" msgid="5516326713822885652">"షేర్ చేసిన డేటాను చూసి, ఎడిట్ చేయండి"</string>
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"ఈ యూజర్ కోసం షేర్ చేసిన డేటా ఏదీ లేదు."</string>
<string name="shared_data_query_failure_text" msgid="3489828881998773687">"షేర్ చేసిన డేటా పొందడంలో ఎర్రర్ ఏర్పడింది. మళ్లీ ట్రై చేయండి."</string>
<string name="blob_id_text" msgid="8680078988996308061">"షేర్ చేసిన డేటా ID: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
@@ -542,7 +542,7 @@
<string name="delete_blob_text" msgid="2819192607255625697">"షేర్ చేసిన డేటాను తొలగించు"</string>
<string name="delete_blob_confirmation_text" msgid="7807446938920827280">"మీరు ఖచ్చితంగా ఈ షేర్ చేసిన డేటాను తొలగించాలనుకుంటున్నారా?"</string>
<string name="user_add_user_item_summary" msgid="5748424612724703400">"వినియోగదారులు వారి స్వంత యాప్‌లను మరియు కంటెంట్‌ను కలిగి ఉన్నారు"</string>
- <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి యాప్‌లకు మరియు కంటెంట్‌కు ప్రాప్యతను పరిమితం చేయవచ్చు"</string>
+ <string name="user_add_profile_item_summary" msgid="5418602404308968028">"మీరు మీ ఖాతా నుండి యాప్‌లకు మరియు కంటెంట్‌కు యాక్సెస్‌ను పరిమితం చేయవచ్చు"</string>
<string name="user_add_user_item_title" msgid="2394272381086965029">"యూజర్"</string>
<string name="user_add_profile_item_title" msgid="3111051717414643029">"పరిమితం చేయబడిన ప్రొఫైల్"</string>
<string name="user_add_user_title" msgid="5457079143694924885">"కొత్త వినియోగదారుని జోడించాలా?"</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 03bb5ccb333b..ffc875bc22df 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -83,8 +83,8 @@
<string name="kg_invalid_sim_puk_hint" msgid="5319756880543857694">"PUK కోడ్ అనేది 8 లేదా అంతకంటే ఎక్కువ సంఖ్యలు ఉండాలి."</string>
<string name="kg_invalid_puk" msgid="1774337070084931186">"సరైన PUK కోడ్‌ను మళ్లీ నమోదు చేయండి. ఎక్కువసార్లు ప్రయత్నించడం వలన SIM శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
<string name="kg_login_too_many_attempts" msgid="4519957179182578690">"నమూనాని చాలా ఎక్కువసార్లు గీసారు"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="544687656831558971">"మీరు మీ పిన్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"మీరు మీ పాస్‌వర్డ్‌ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"మీరు మీ అన్‌లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"SIM పిన్ కోడ్ తప్పు, ఇప్పుడు మీ డివైజ్‌ను అన్‌లాక్ చేయాలంటే, మీరు తప్పనిసరిగా మీ క్యారియర్‌ను సంప్రదించాలి."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="7030584350995485026">
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
index 33263a9131a0..0ae5dc745478 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_error_to_fp.xml
@@ -1,413 +1,242 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ 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
- -->
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- 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.
+-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt">
+ xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
- <vector
- android:width="60dp"
- android:height="60dp"
- android:viewportHeight="60"
- android:viewportWidth="60">
+ <vector android:height="60dp" android:width="60dp" android:viewportHeight="60"
+ android:viewportWidth="60">
<group android:name="_R_G">
- <group
- android:name="_R_G_L_1_G_N_4_T_0"
- android:translateX="30"
- android:translateY="30">
- <group
- android:name="_R_G_L_1_G"
- android:pivotX="114"
- android:pivotY="114"
- android:scaleX="0.42200000000000004"
- android:scaleY="0.42200000000000004"
- android:translateX="-114"
- android:translateY="-114">
- <path
- android:name="_R_G_L_1_G_D_0_P_0"
- android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_1_P_0"
- android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_2_P_0"
- android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_3_P_0"
- android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_4_P_0"
- android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="0"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
+ <group android:name="_R_G_L_1_G" android:translateX="-0.05000000000000071">
+ <group android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0" android:translateX="30"
+ android:translateY="38.75" android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="@color/biometric_dialog_error"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c "/>
</group>
- </group>
- <group
- android:name="_R_G_L_0_G_N_4_T_0"
- android:translateX="30"
- android:translateY="30">
- <group
- android:name="_R_G_L_0_G"
- android:translateX="-30.05"
- android:translateY="-30">
- <group
- android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
- android:scaleX="1"
- android:scaleY="1"
- android:translateX="30"
- android:translateY="38.75">
- <path
- android:name="_R_G_L_0_G_D_0_P_0"
- android:fillAlpha="1"
- android:fillColor="@color/biometric_dialog_error"
- android:fillType="nonZero"
- android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
- </group>
- <group
- android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
- android:pivotX="0.002"
- android:pivotY="7.488"
- android:scaleX="1"
- android:scaleY="1"
- android:translateX="30"
- android:translateY="25">
- <path
- android:name="_R_G_L_0_G_D_1_P_0"
- android:fillAlpha="1"
- android:fillColor="@color/biometric_dialog_error"
- android:fillType="nonZero"
- android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
- </group>
- <path
- android:name="_R_G_L_0_G_D_2_P_0"
- android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_error"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="2.5"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
+ <group android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0" android:translateX="30"
+ android:translateY="25" android:pivotX="0.002" android:pivotY="7.488"
+ android:scaleX="1" android:scaleY="1">
+ <path android:name="_R_G_L_1_G_D_1_P_0"
+ android:fillColor="@color/biometric_dialog_error"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c "/>
</group>
+ <path android:name="_R_G_L_1_G_D_2_P_0"
+ android:strokeColor="@color/biometric_dialog_error"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2.5" android:strokeAlpha="1"
+ android:trimPathStart="0" android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-10.325"
+ android:translateY="-10.25">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="0" android:trimPathOffset="0"
+ android:pathData=" M31.41 48.43 C30.78,46.69 30.78,44.91 30.78,44.91 C30.78,40.09 34.88,36.16 40.32,36.16 C45.77,36.16 49.87,40.09 49.87,44.91 C49.87,44.91 49.87,45.17 49.87,45.17 C49.87,46.97 48.41,48.43 46.61,48.43 C45.28,48.43 44.09,47.63 43.6,46.39 C43.6,46.39 42.51,43.66 42.51,43.66 C42.02,42.42 40.82,41.61 39.49,41.61 C37.69,41.61 36.23,43.07 36.23,44.87 C36.23,47.12 37.26,49.26 39.02,50.67 C39.02,50.67 39.64,51.16 39.64,51.16 "/>
+ <path android:name="_R_G_L_0_G_D_1_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="0" android:trimPathOffset="0"
+ android:pathData=" M32.14 27.3 C34.5,26 37.31,25.25 40.33,25.25 C43.34,25.25 46.15,26 48.51,27.3 "/>
+ <path android:name="_R_G_L_0_G_D_2_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="0" android:trimPathOffset="0"
+ android:pathData=" M29.42 36.16 C31.35,32.94 35.51,30.71 40.33,30.71 C45.14,30.71 49.3,32.94 51.23,36.16 "/>
+ <path android:name="_R_G_L_0_G_D_3_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="0" android:trimPathOffset="0"
+ android:pathData=" M47.14 52.52 C45.33,54.21 42.94,55.25 40.33,55.25 C37.71,55.25 35.32,54.21 33.51,52.52 "/>
</group>
</group>
- <group android:name="time_group" />
+ <group android:name="time_group"/>
</vector>
</aapt:attr>
- <target android:name="_R_G_L_1_G_D_0_P_0">
+ <target android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="83"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="67"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1.1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="250"
- android:propertyName="trimPathEnd"
- android:startOffset="83"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="67"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1.1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_1_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="83"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="67" android:valueFrom="1.1" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="250"
- android:propertyName="trimPathEnd"
- android:startOffset="83"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="67" android:valueFrom="1.1" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_1_G_D_2_P_0">
+ <target android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="83"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="67"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="250"
- android:propertyName="trimPathEnd"
- android:startOffset="83"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="67"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1.1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_3_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="83"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="67" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="250"
- android:propertyName="trimPathEnd"
- android:startOffset="83"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="67" android:valueFrom="1.1" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_1_G_D_4_P_0">
+ <target android:name="_R_G_L_1_G_D_2_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="83"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="67"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="250"
- android:propertyName="trimPathEnd"
- android:startOffset="83"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="133"
+ android:startOffset="67" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <target android:name="_R_G_L_0_G_D_0_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleX"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1.1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleY"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1.1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.853,0 0.6,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleX"
- android:startOffset="67"
- android:valueFrom="1.1"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleY"
- android:startOffset="67"
- android:valueFrom="1.1"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+ android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.06 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <target android:name="_R_G_L_0_G_D_1_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleX"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.659,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleY"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1.1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+ android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleX"
- android:startOffset="67"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleY"
- android:startOffset="67"
- android:valueFrom="1.1"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+ android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.8,0 0.92,1.096 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_2_P_0">
+ <target android:name="_R_G_L_0_G_D_3_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="67"
- android:propertyName="trimPathEnd"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="83"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="133"
- android:propertyName="trimPathEnd"
- android:startOffset="67"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathEnd" android:duration="250"
+ android:startOffset="83" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
@@ -416,14 +245,10 @@
<target android:name="time_group">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="350"
- android:propertyName="translateX"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType" />
+ <objectAnimator android:propertyName="translateX" android:duration="417"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
</set>
</aapt:attr>
</target>
-</animated-vector> \ No newline at end of file
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
index b899828cd85c..fc2c7d00f3a7 100644
--- a/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
+++ b/packages/SystemUI/res/drawable/fingerprint_dialog_fp_to_error.xml
@@ -1,391 +1,235 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ 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
- -->
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- 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.
+-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt">
+ xmlns:aapt="http://schemas.android.com/aapt">
<aapt:attr name="android:drawable">
- <vector
- android:width="60dp"
- android:height="60dp"
- android:viewportHeight="60"
- android:viewportWidth="60">
+ <vector android:height="60dp" android:width="60dp" android:viewportHeight="60"
+ android:viewportWidth="60">
<group android:name="_R_G">
- <group
- android:name="_R_G_L_1_G_N_4_T_0"
- android:translateX="30"
- android:translateY="30">
- <group
- android:name="_R_G_L_1_G"
- android:pivotX="114"
- android:pivotY="114"
- android:scaleX="0.42244"
- android:scaleY="0.42244"
- android:translateX="-114"
- android:translateY="-114">
- <path
- android:name="_R_G_L_1_G_D_0_P_0"
- android:pathData=" M79.63 67.24 C79.63,67.24 111.5,47.42 147.83,67.24 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_1_P_0"
- android:pathData=" M64.27 98.07 C64.27,98.07 80.13,73.02 113.98,73.02 C147.83,73.02 163.56,97.26 163.56,97.26 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_2_P_0"
- android:pathData=" M72.53 151.07 C72.53,151.07 62.46,122.89 76.16,105.55 C89.86,88.21 106.72,86.73 113.98,86.73 C121.08,86.73 153.51,90.62 158.7,125.87 C159.14,128.82 158.8,132.88 157.18,136.09 C154.88,140.63 150.62,143.63 145.85,143.97 C133.78,144.85 129.76,137.92 129.26,128.49 C128.88,121.19 122.49,115.35 113.15,115.35 C102.91,115.35 95.97,126.69 99.77,139.74 C103.57,152.78 111.33,163.85 130.32,169.13 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_3_P_0"
- android:pathData=" M100.6 167.84 C100.6,167.84 82.76,152.1 83.75,130.31 C84.75,108.53 102.58,100.7 113.73,100.7 C124.87,100.7 144.19,108.56 144.19,130.01 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
- <path
- android:name="_R_G_L_1_G_D_4_P_0"
- android:pathData=" M113.73 129.17 C113.73,129.17 113.15,161.33 149.15,156.58 "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_accent"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="5.5"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="0" />
+ <group android:name="_R_G_L_1_G" android:translateX="-0.05000000000000071">
+ <group android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0" android:translateX="30"
+ android:translateY="38.75" android:scaleX="0" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_0_P_0"
+ android:fillColor="@color/biometric_dialog_error"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c "/>
</group>
- </group>
- <group
- android:name="_R_G_L_0_G_N_4_T_0"
- android:translateX="30"
- android:translateY="30">
- <group
- android:name="_R_G_L_0_G"
- android:translateX="-30.05"
- android:translateY="-30">
- <group
- android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0"
- android:scaleX="0"
- android:scaleY="0"
- android:translateX="30"
- android:translateY="38.75">
- <path
- android:name="_R_G_L_0_G_D_0_P_0"
- android:fillAlpha="1"
- android:fillColor="@color/biometric_dialog_error"
- android:fillType="nonZero"
- android:pathData=" M-1.2 -1.25 C-1.2,-1.25 1.2,-1.25 1.2,-1.25 C1.2,-1.25 1.2,1.25 1.2,1.25 C1.2,1.25 -1.2,1.25 -1.2,1.25 C-1.2,1.25 -1.2,-1.25 -1.2,-1.25c " />
- </group>
- <group
- android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0"
- android:pivotX="0.002"
- android:pivotY="7.488"
- android:scaleX="1"
- android:scaleY="0"
- android:translateX="30"
- android:translateY="25">
- <path
- android:name="_R_G_L_0_G_D_1_P_0"
- android:fillAlpha="1"
- android:fillColor="@color/biometric_dialog_error"
- android:fillType="nonZero"
- android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c " />
- </group>
- <path
- android:name="_R_G_L_0_G_D_2_P_0"
- android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "
- android:strokeAlpha="1"
- android:strokeColor="@color/biometric_dialog_error"
- android:strokeLineCap="round"
- android:strokeLineJoin="round"
- android:strokeWidth="2.5"
- android:trimPathEnd="1"
- android:trimPathOffset="0"
- android:trimPathStart="1" />
+ <group android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0" android:translateX="30"
+ android:translateY="25" android:pivotX="0.002" android:pivotY="7.488"
+ android:scaleX="1" android:scaleY="0">
+ <path android:name="_R_G_L_1_G_D_1_P_0"
+ android:fillColor="@color/biometric_dialog_error"
+ android:fillAlpha="1" android:fillType="nonZero"
+ android:pathData=" M-1.2 -7.5 C-1.2,-7.5 1.2,-7.5 1.2,-7.5 C1.2,-7.5 1.2,7.5 1.2,7.5 C1.2,7.5 -1.2,7.5 -1.2,7.5 C-1.2,7.5 -1.2,-7.5 -1.2,-7.5c "/>
</group>
+ <path android:name="_R_G_L_1_G_D_2_P_0"
+ android:strokeColor="@color/biometric_dialog_error"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2.5" android:strokeAlpha="1"
+ android:trimPathStart="1" android:trimPathEnd="1"
+ android:trimPathOffset="0"
+ android:pathData=" M30 6.2 C16.9,6.2 6.3,16.8 6.3,30 C6.3,43.2 16.9,53.8 30,53.8 C43.1,53.8 53.8,43.2 53.8,30 C53.8,16.8 43.1,6.2 30,6.2c "/>
+ </group>
+ <group android:name="_R_G_L_0_G" android:translateX="-10.325"
+ android:translateY="-10.25">
+ <path android:name="_R_G_L_0_G_D_0_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="1" android:trimPathOffset="0"
+ android:pathData=" M31.41 48.43 C30.78,46.69 30.78,44.91 30.78,44.91 C30.78,40.09 34.88,36.16 40.32,36.16 C45.77,36.16 49.87,40.09 49.87,44.91 C49.87,44.91 49.87,45.17 49.87,45.17 C49.87,46.97 48.41,48.43 46.61,48.43 C45.28,48.43 44.09,47.63 43.6,46.39 C43.6,46.39 42.51,43.66 42.51,43.66 C42.02,42.42 40.82,41.61 39.49,41.61 C37.69,41.61 36.23,43.07 36.23,44.87 C36.23,47.12 37.26,49.26 39.02,50.67 C39.02,50.67 39.64,51.16 39.64,51.16 "/>
+ <path android:name="_R_G_L_0_G_D_1_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="1" android:trimPathOffset="0"
+ android:pathData=" M32.14 27.3 C34.5,26 37.31,25.25 40.33,25.25 C43.34,25.25 46.15,26 48.51,27.3 "/>
+ <path android:name="_R_G_L_0_G_D_2_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="1" android:trimPathOffset="0"
+ android:pathData=" M29.42 36.16 C31.35,32.94 35.51,30.71 40.33,30.71 C45.14,30.71 49.3,32.94 51.23,36.16 "/>
+ <path android:name="_R_G_L_0_G_D_3_P_0"
+ android:strokeColor="@color/biometric_dialog_accent"
+ android:strokeLineCap="round" android:strokeLineJoin="round"
+ android:strokeWidth="2" android:strokeAlpha="1" android:trimPathStart="0"
+ android:trimPathEnd="1" android:trimPathOffset="0"
+ android:pathData=" M47.14 52.52 C45.33,54.21 42.94,55.25 40.33,55.25 C37.71,55.25 35.32,54.21 33.51,52.52 "/>
</group>
</group>
- <group android:name="time_group" />
+ <group android:name="time_group"/>
</vector>
</aapt:attr>
- <target android:name="_R_G_L_1_G_D_0_P_0">
+ <target android:name="_R_G_L_1_G_D_0_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_1_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_2_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="167" android:valueFrom="0"
+ android:valueTo="1.1" android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_3_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="167" android:valueFrom="0"
+ android:valueTo="1.1" android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- </set>
- </aapt:attr>
- </target>
- <target android:name="_R_G_L_1_G_D_4_P_0">
- <aapt:attr name="android:animation">
- <set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="67"
+ android:startOffset="267" android:valueFrom="1.1"
+ android:valueTo="1" android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0"/>
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator android:propertyName="scaleY" android:duration="67"
+ android:startOffset="267" android:valueFrom="1.1"
+ android:valueTo="1" android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.6,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_0_P_0_G_0_T_0">
+ <target android:name="_R_G_L_1_G_D_1_P_0_G_0_T_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="scaleX"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="167"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="167"
- android:propertyName="scaleY"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="167"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleX"
- android:startOffset="167"
- android:valueFrom="0"
- android:valueTo="1.1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="100"
+ android:startOffset="167" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleY"
- android:startOffset="167"
- android:valueFrom="0"
- android:valueTo="1.1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="100"
+ android:startOffset="167" android:valueFrom="0"
+ android:valueTo="1.1" android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.06 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleX"
- android:startOffset="267"
- android:valueFrom="1.1"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleX" android:duration="67"
+ android:startOffset="267" android:valueFrom="1" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.341,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleY"
- android:startOffset="267"
- android:valueFrom="1.1"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="scaleY" android:duration="67"
+ android:startOffset="267" android:valueFrom="1.1"
+ android:valueTo="1" android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.147,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_1_P_0_G_0_T_0">
+ <target android:name="_R_G_L_1_G_D_2_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="167"
- android:propertyName="scaleX"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathStart" android:duration="267"
+ android:startOffset="0" android:valueFrom="1" android:valueTo="0"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="167"
- android:propertyName="scaleY"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="0"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleX"
- android:startOffset="167"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
- <aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
- </aapt:attr>
- </objectAnimator>
- <objectAnimator
- android:duration="100"
- android:propertyName="scaleY"
- android:startOffset="167"
- android:valueFrom="0"
- android:valueTo="1.1"
- android:valueType="floatType">
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.08,0.096 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleX"
- android:startOffset="267"
- android:valueFrom="1"
- android:valueTo="1"
- android:valueType="floatType">
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.341,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
- <objectAnimator
- android:duration="67"
- android:propertyName="scaleY"
- android:startOffset="267"
- android:valueFrom="1.1"
- android:valueTo="1"
- android:valueType="floatType">
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
</aapt:attr>
</target>
- <target android:name="_R_G_L_0_G_D_2_P_0">
+ <target android:name="_R_G_L_0_G_D_3_P_0">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="267"
- android:propertyName="trimPathStart"
- android:startOffset="0"
- android:valueFrom="1"
- android:valueTo="0"
- android:valueType="floatType">
+ <objectAnimator android:propertyName="trimPathStart" android:duration="167"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType">
<aapt:attr name="android:interpolator">
- <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0" />
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.4,0 0.2,1 1.0,1.0"/>
</aapt:attr>
</objectAnimator>
</set>
@@ -394,14 +238,10 @@
<target android:name="time_group">
<aapt:attr name="android:animation">
<set android:ordering="together">
- <objectAnimator
- android:duration="350"
- android:propertyName="translateX"
- android:startOffset="0"
- android:valueFrom="0"
- android:valueTo="1"
- android:valueType="floatType" />
+ <objectAnimator android:propertyName="translateX" android:duration="350"
+ android:startOffset="0" android:valueFrom="0" android:valueTo="1"
+ android:valueType="floatType"/>
</set>
</aapt:attr>
</target>
-</animated-vector> \ No newline at end of file
+</animated-vector>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 6d5be301a82d..8b787323ccb6 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -54,8 +54,7 @@
<com.android.keyguard.LockIconView
android:id="@+id/lock_icon_view"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center">
+ android:layout_height="wrap_content">
<!-- Background protection -->
<ImageView
android:id="@+id/lock_icon_bg"
@@ -71,6 +70,19 @@
android:padding="@dimen/lock_icon_padding"
android:layout_gravity="center"
android:scaleType="centerCrop"/>
+
+ <!-- Fingerprint -->
+ <!-- AOD dashed fingerprint icon with moving dashes -->
+ <com.airbnb.lottie.LottieAnimationView
+ android:id="@+id/lock_udfps_aod_fp"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:padding="@dimen/lock_icon_padding"
+ android:layout_gravity="center"
+ android:scaleType="centerCrop"
+ systemui:lottie_autoPlay="false"
+ systemui:lottie_loop="true"
+ systemui:lottie_rawRes="@raw/udfps_aod_fp"/>
</com.android.keyguard.LockIconView>
<com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer
@@ -114,6 +126,7 @@
android:layout_width="@dimen/notification_panel_width"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/close_handle_underlap"
+ android:importantForAccessibility="no"
systemui:layout_constraintStart_toStartOf="parent"
systemui:layout_constraintEnd_toEndOf="parent"
/>
diff --git a/packages/SystemUI/res/layout/udfps_enroll_view.xml b/packages/SystemUI/res/layout/udfps_enroll_view.xml
index f1ff6d669256..e41a632fa70a 100644
--- a/packages/SystemUI/res/layout/udfps_enroll_view.xml
+++ b/packages/SystemUI/res/layout/udfps_enroll_view.xml
@@ -20,10 +20,23 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <!-- The layout height/width are placeholders, which will be overwritten by
+ FingerprintSensorPropertiesInternal. -->
+ <View
+ android:id="@+id/udfps_enroll_accessibility_view"
+ android:layout_gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_fingerprint_label"/>
+
+ <ImageView
+ android:id="@+id/udfps_enroll_animation_fp_progress_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
<!-- Fingerprint -->
<ImageView
android:id="@+id/udfps_enroll_animation_fp_view"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:contentDescription="@string/accessibility_fingerprint_label"/>
+ android:layout_height="match_parent"/>
</com.android.systemui.biometrics.UdfpsEnrollView>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index 687830d5c7b3..0fcbfa161ddf 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -20,7 +20,7 @@
android:id="@+id/udfps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- systemui:sensorTouchAreaCoefficient="0.75"
+ systemui:sensorTouchAreaCoefficient="1.0"
android:contentDescription="@string/accessibility_fingerprint_label">
<ViewStub
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 45236a795573..e285796f6037 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -54,7 +54,7 @@
<string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ని నిర్వహించడానికి <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవాలా?"</string>
<string name="usb_accessory_uri_prompt" msgid="6756649383432542382">"ఈ USB ఉపకరణంతో ఇన్‌స్టాల్ చేయబడిన యాప్‌లు ఏవీ పని చేయవు. ఈ ఉపకరణం గురించి <xliff:g id="URL">%1$s</xliff:g>లో మరింత తెలుసుకోండి"</string>
<string name="title_usb_accessory" msgid="1236358027511638648">"USB ఉపకరణం"</string>
- <string name="label_view" msgid="6815442985276363364">"వీక్షించండి"</string>
+ <string name="label_view" msgid="6815442985276363364">"చూడండి"</string>
<string name="always_use_device" msgid="210535878779644679">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> కనెక్ట్ అయి ఉన్న ఎల్లప్పుడూ <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవండి"</string>
<string name="always_use_accessory" msgid="1977225429341838444">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g> కనెక్ట్ అయి ఉన్న ఎల్లప్పుడూ <xliff:g id="APPLICATION">%1$s</xliff:g>ని తెరవండి"</string>
<string name="usb_debugging_title" msgid="8274884945238642726">"USB డీబగ్గింగ్‌ను అనుమతించాలా?"</string>
@@ -506,7 +506,7 @@
<string name="battery_saver_notification_title" msgid="8419266546034372562">"బ్యాటరీ సేవర్ ఆన్‌లో ఉంది"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
<string name="battery_saver_notification_action_text" msgid="6022091913807026887">"బ్యాటరీ సేవర్‌ను ఆఫ్ చేయండి"</string>
- <string name="media_projection_dialog_text" msgid="1755705274910034772">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, చెల్లింపు వివరాలు, ఫోటోలు, సందేశాలు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
+ <string name="media_projection_dialog_text" msgid="1755705274910034772">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> యాక్సెస్ చేయగలుగుతుంది. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, చెల్లింపు వివరాలు, ఫోటోలు, మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్‌ను అందిస్తున్న సర్వీస్ యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
<string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>తో రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
@@ -552,7 +552,7 @@
<string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"CA ప్రమాణపత్రాలు"</string>
<string name="disable_vpn" msgid="482685974985502922">"VPNని నిలిపివేయి"</string>
<string name="disconnect_vpn" msgid="26286850045344557">"VPNను డిస్‌కనెక్ట్ చేయి"</string>
- <string name="monitoring_button_view_policies" msgid="3869724835853502410">"విధానాలను వీక్షించండి"</string>
+ <string name="monitoring_button_view_policies" msgid="3869724835853502410">"విధానాలను చూడండి"</string>
<string name="monitoring_button_view_controls" msgid="8316440345340701117">"నియంత్రణలను చూడండి"</string>
<string name="monitoring_description_named_management" msgid="505833016545056036">"ఈ పరికరం <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>కు చెందినది.\n\nసెట్టింగ్‌లను, కార్పొరేట్ యాక్సెస్‌ను, యాప్‌లను, మీ పరికరానికి సంబంధించిన డేటాను, అలాగే మీ పరికరం యొక్క లొకేషన్ సమాచారాన్ని మీ IT అడ్మిన్ పర్యవేక్షించగలరు, మేనేజ్ చేయగలరు.\n\nమరింత సమాచారం కోసం, మీ IT అడ్మిన్‌ను సంప్రదించండి."</string>
<string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"<xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g>, ఈ పరికరంతో అనుబంధించబడిన డేటాను యాక్సెస్ చేయవచ్చు, యాప్‌లను మేనేజ్ చేయవచ్చు అలాగే ఈ పరికరాల సెట్టింగ్‌లను మార్చవచ్చు.\n\nమీకు ఏవైనా సందేహాలు ఉంటే, <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>ను కాంటాక్ట్ చేయండి."</string>
@@ -560,7 +560,7 @@
<string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"ఈ పరికరంలో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్‌స్టాల్ చేసింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
<string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"మీ కార్యాలయ ప్రొఫైల్‌లో మీ సంస్థ ఒక ప్రమాణపత్ర అధికారాన్ని ఇన్‌స్టాల్ చేసింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"ఈ పరికరంలో ప్రమాణపత్ర అధికారం ఇన్‌స్టాల్ చేయబడింది. మీ సురక్షిత నెట్‌వర్క్ ట్రాఫిక్ పర్యవేక్షించబడవచ్చు లేదా సవరించబడవచ్చు."</string>
- <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేసారు."</string>
+ <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేశారు."</string>
<string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"మీ అడ్మిన్ నెట్‌వర్క్ లాగింగ్‌ను ఆన్ చేశారు, ఇది మీ వర్క్ ప్రొఫైల్‌లోని ట్రాఫిక్‌ను పర్యవేక్షిస్తుంది కానీ మీ వ్యక్తిగత ప్రొఫైల్‌లో కాదు."</string>
<string name="monitoring_description_named_vpn" msgid="5749932930634037027">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"మీరు ఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP_0">%1$s</xliff:g> మరియు <xliff:g id="VPN_APP_1">%2$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు."</string>
@@ -576,7 +576,7 @@
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"VPN సెట్టింగ్‌లను తెరవండి"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"విశ్వసనీయ ఆధారాలను తెరువు"</string>
- <string name="monitoring_description_network_logging" msgid="577305979174002252">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేసారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string>
+ <string name="monitoring_description_network_logging" msgid="577305979174002252">"మీ నిర్వాహకులు మీ పరికరంలోని ట్రాఫిక్‌ని పర్యవేక్షించగల నెట్‌వర్క్ లాగింగ్‌ని ఆన్ చేశారు.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"మీరు VPN కనెక్షన్ సెటప్ చేయడానికి ఒక యాప్‌నకు అనుమతి ఇచ్చారు.\n\nఈ యాప్ ఇమెయిల్‌లు,యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ డివైజ్ మరియు నెట్‌వర్క్ కార్యకలాపాన్ని పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ద్వారా మీ కార్యాలయ ప్రొఫైల్ నిర్వహించబడుతోంది.\n\nఇమెయిల్‌లు, యాప్‌లు మరియు వెబ్‌సైట్‌లతో సహా మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల సామర్థ్యం మీ నిర్వాహకులకు ఉంది.\n\nమరింత సమాచారం కావాలంటే, మీ నిర్వాహకులను సంప్రదించండి.\n\nమీరు VPNకి కూడా కనెక్ట్ అయ్యారు, ఇది మీ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"ఈ పరికరాన్ని మీ తల్లి/తండ్రి మేనేజ్ చేస్తున్నారు. మీ తల్లి/తండ్రి, మీరు ఉపయోగించే యాప్‌లు, మీ లొకేషన్, అలాగే మీ పరికర వినియోగ వ్యవధి వంటి సమాచారాన్ని చూడగలరు, మేనేజ్ చేయగలరు."</string>
@@ -925,7 +925,7 @@
<string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"శీఘ్ర సెట్టింగ్‌లను తెరవండి."</string>
<string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"శీఘ్ర సెట్టింగ్‌లను మూసివేయండి."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"అలారం సెట్ చేయబడింది."</string>
- <string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> వలె సైన్ ఇన్ చేసారు"</string>
+ <string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g> వలె సైన్ ఇన్ చేశారు"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"యూజర్‌ను ఎంపిక చేయండి"</string>
<string name="data_connection_no_internet" msgid="691058178914184544">"ఇంటర్నెట్ లేదు"</string>
<string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"వివరాలను తెరవండి."</string>
@@ -963,7 +963,7 @@
<string name="notification_channel_alerts" msgid="3385787053375150046">"అలర్ట్‌లు"</string>
<string name="notification_channel_battery" msgid="9219995638046695106">"బ్యాటరీ"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"స్క్రీన్‌షాట్‌లు"</string>
- <string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ సందేశాలు"</string>
+ <string name="notification_channel_general" msgid="4384774889645929705">"సాధారణ మెసేజ్‌లు"</string>
<string name="notification_channel_storage" msgid="2720725707628094977">"స్టోరేజ్"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"సూచనలు"</string>
<string name="instant_apps" msgid="8337185853050247304">"ఇన్‌స్టంట్ యాప్‌లు"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6ad9ab9a26ec..78db2a8a3485 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1462,6 +1462,10 @@
<!-- Maximum overshoot for the pulse expansion -->
<dimen name="pulse_expansion_max_top_overshoot">32dp</dimen>
+ <!-- Alpha in duration in ms for the auth ripple to become fully vislble. If set to 0,
+ it is immediately visible. -->
+ <integer name="auth_ripple_alpha_in_duration">100</integer>
+
<dimen name="people_space_widget_radius">28dp</dimen>
<dimen name="people_space_image_radius">20dp</dimen>
<dimen name="people_space_messages_count_radius">12dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index 622419a86bfc..5c34bebdaa4e 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -22,7 +22,6 @@ import android.graphics.PointF;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -45,7 +44,7 @@ public class LockIconView extends FrameLayout implements Dumpable {
private int mRadius;
private ImageView mLockIcon;
- private ImageView mUnlockBgView;
+ private ImageView mBgView;
private int mLockIconColor;
@@ -58,19 +57,19 @@ public class LockIconView extends FrameLayout implements Dumpable {
public void onFinishInflate() {
super.onFinishInflate();
mLockIcon = findViewById(R.id.lock_icon);
- mUnlockBgView = findViewById(R.id.lock_icon_bg);
+ mBgView = findViewById(R.id.lock_icon_bg);
}
void updateColorAndBackgroundVisibility(boolean useBackground) {
- if (useBackground) {
+ if (useBackground && mLockIcon.getDrawable() != null) {
mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
android.R.attr.textColorPrimary);
- mUnlockBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
- mUnlockBgView.setVisibility(View.VISIBLE);
+ mBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg));
+ mBgView.setVisibility(View.VISIBLE);
} else {
mLockIconColor = Utils.getColorAttrDefaultColor(getContext(),
R.attr.wallpaperTextColorAccent);
- mUnlockBgView.setVisibility(View.GONE);
+ mBgView.setVisibility(View.GONE);
}
mLockIcon.setImageTintList(ColorStateList.valueOf(mLockIconColor));
@@ -78,9 +77,14 @@ public class LockIconView extends FrameLayout implements Dumpable {
void setImageDrawable(Drawable drawable) {
mLockIcon.setImageDrawable(drawable);
+ if (drawable == null) {
+ mBgView.setVisibility(View.INVISIBLE);
+ } else {
+ mBgView.setVisibility(View.VISIBLE);
+ }
}
- void setCenterLocation(@NonNull PointF center, int radius) {
+ public void setCenterLocation(@NonNull PointF center, int radius) {
mLockIconCenter = center;
mRadius = radius;
@@ -91,13 +95,11 @@ public class LockIconView extends FrameLayout implements Dumpable {
mLockIconCenter.x + mRadius,
mLockIconCenter.y + mRadius);
- setX(mSensorRect.left);
- setY(mSensorRect.top);
-
- final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
- (int) (mSensorRect.right - mSensorRect.left),
- (int) (mSensorRect.bottom - mSensorRect.top));
- lp.gravity = Gravity.CENTER;
+ final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+ lp.width = (int) (mSensorRect.right - mSensorRect.left);
+ lp.height = (int) (mSensorRect.bottom - mSensorRect.top);
+ lp.topMargin = (int) mSensorRect.top;
+ lp.setMarginStart((int) mSensorRect.left);
setLayoutParams(lp);
}
@@ -114,5 +116,6 @@ public class LockIconView extends FrameLayout implements Dumpable {
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")");
pw.println("Radius in pixels: " + mRadius);
+ pw.println("topLeft= (" + getX() + ", " + getY() + ")");
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 509ac8a6d9fe..a41997ce3107 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -19,6 +19,8 @@ package com.android.keyguard;
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static com.android.systemui.classifier.Classifier.LOCK_ICON;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInProgressOffset;
import android.content.Context;
import android.content.res.Configuration;
@@ -32,6 +34,7 @@ import android.media.AudioAttributes;
import android.os.Process;
import android.os.Vibrator;
import android.util.DisplayMetrics;
+import android.util.MathUtils;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
@@ -58,6 +61,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.airbnb.lottie.LottieAnimationView;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Objects;
@@ -92,6 +97,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@NonNull private final DelayableExecutor mExecutor;
private boolean mUdfpsEnrolled;
+ @NonNull private LottieAnimationView mAodFp;
+
@NonNull private final AnimatedVectorDrawable mFpToUnlockIcon;
@NonNull private final AnimatedVectorDrawable mLockToUnlockIcon;
@NonNull private final Drawable mLockIcon;
@@ -109,6 +116,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private boolean mIsKeyguardShowing;
private boolean mUserUnlockedWithBiometric;
private Runnable mCancelDelayedUpdateVisibilityRunnable;
+ private Runnable mOnGestureDetectedRunnable;
private boolean mUdfpsSupported;
private float mHeightPixels;
@@ -118,6 +126,12 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
private boolean mShowUnlockIcon;
private boolean mShowLockIcon;
+ // for udfps when strong auth is required or unlocked on AOD
+ private boolean mShowAODFpIcon;
+ private final int mMaxBurnInOffsetX;
+ private final int mMaxBurnInOffsetY;
+ private float mInterpolatedDarkAmount;
+
private boolean mDownDetected;
private boolean mDetectedLongPress;
private final Rect mSensorTouchLocation = new Rect();
@@ -150,6 +164,12 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mVibrator = vibrator;
final Context context = view.getContext();
+ mAodFp = mView.findViewById(R.id.lock_udfps_aod_fp);
+ mMaxBurnInOffsetX = context.getResources()
+ .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
+ mMaxBurnInOffsetY = context.getResources()
+ .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
+
mUnlockIcon = mView.getContext().getResources().getDrawable(
R.drawable.ic_unlock,
mView.getContext().getTheme());
@@ -173,15 +193,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@Override
protected void onViewAttached() {
- // we check this here instead of onInit since the FingerprintManager + FaceManager may not
- // have started up yet onInit
- mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
-
+ updateIsUdfpsEnrolled();
updateConfiguration();
updateKeyguardShowing();
mUserUnlockedWithBiometric = false;
+
mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
mIsDozing = mStatusBarStateController.isDozing();
+ mInterpolatedDarkAmount = mStatusBarStateController.getDozeAmount();
mRunningFPS = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
mStatusBarState = mStatusBarStateController.getState();
@@ -189,15 +208,18 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
updateColors();
mConfigurationController.addCallback(mConfigurationListener);
+ mAuthController.addCallback(mAuthControllerCallback);
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mKeyguardStateController.addCallback(mKeyguardStateCallback);
mDownDetected = false;
+ updateBurnInOffsets();
updateVisibility();
}
@Override
protected void onViewDetached() {
+ mAuthController.removeCallback(mAuthControllerCallback);
mConfigurationController.removeCallback(mConfigurationListener);
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
@@ -227,7 +249,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mCancelDelayedUpdateVisibilityRunnable = null;
}
- if (!mIsKeyguardShowing) {
+ if (!mIsKeyguardShowing && !mIsDozing) {
mView.setVisibility(View.INVISIBLE);
return;
}
@@ -238,6 +260,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen()
&& (!mUdfpsEnrolled || !mRunningFPS);
mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
+ mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS;
final CharSequence prevContentDescription = mView.getContentDescription();
if (mShowLockIcon) {
@@ -260,10 +283,22 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
mView.setVisibility(View.VISIBLE);
mView.setContentDescription(mUnlockedLabel);
+ } else if (mShowAODFpIcon) {
+ mView.setImageDrawable(null);
+ mView.setContentDescription(null);
+ mAodFp.setVisibility(View.VISIBLE);
+ mAodFp.setContentDescription(mCanDismissLockScreen ? mUnlockedLabel : mLockedLabel);
+ mView.setVisibility(View.VISIBLE);
} else {
mView.setVisibility(View.INVISIBLE);
mView.setContentDescription(null);
}
+
+ if (!mShowAODFpIcon) {
+ mAodFp.setVisibility(View.INVISIBLE);
+ mAodFp.setContentDescription(null);
+ }
+
if (!Objects.equals(prevContentDescription, mView.getContentDescription())
&& mView.getContentDescription() != null) {
mView.announceForAccessibility(mView.getContentDescription());
@@ -340,10 +375,12 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("mUdfpsSupported: " + mUdfpsSupported);
pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled);
pw.println("mIsKeyguardShowing: " + mIsKeyguardShowing);
pw.println(" mShowUnlockIcon: " + mShowUnlockIcon);
pw.println(" mShowLockIcon: " + mShowLockIcon);
+ pw.println(" mShowAODFpIcon: " + mShowAODFpIcon);
pw.println(" mIsDozing: " + mIsDozing);
pw.println(" mIsBouncerShowing: " + mIsBouncerShowing);
pw.println(" mUserUnlockedWithBiometric: " + mUserUnlockedWithBiometric);
@@ -351,17 +388,57 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
pw.println(" mStatusBarState: " + StatusBarState.toShortString(mStatusBarState));
pw.println(" mQsExpanded: " + mQsExpanded);
+ pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
if (mView != null) {
mView.dump(fd, pw, args);
}
}
+ /** Every minute, update the aod icon's burn in offset */
+ public void dozeTimeTick() {
+ updateBurnInOffsets();
+ }
+
+ private void updateBurnInOffsets() {
+ float offsetX = MathUtils.lerp(0f,
+ getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
+ - mMaxBurnInOffsetX, mInterpolatedDarkAmount);
+ float offsetY = MathUtils.lerp(0f,
+ getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
+ - mMaxBurnInOffsetY, mInterpolatedDarkAmount);
+ float progress = MathUtils.lerp(0f, getBurnInProgressOffset(), mInterpolatedDarkAmount);
+
+ mAodFp.setTranslationX(offsetX);
+ mAodFp.setTranslationY(offsetY);
+ mAodFp.setProgress(progress);
+ mAodFp.setAlpha(255 * mInterpolatedDarkAmount);
+ }
+
+ private void updateIsUdfpsEnrolled() {
+ boolean wasUdfpsSupported = mUdfpsSupported;
+ boolean wasUdfpsEnrolled = mUdfpsEnrolled;
+
+ mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null;
+ mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled();
+ if (wasUdfpsSupported != mUdfpsSupported || wasUdfpsEnrolled != mUdfpsEnrolled) {
+ updateVisibility();
+ }
+ }
+
private StatusBarStateController.StateListener mStatusBarStateListener =
new StatusBarStateController.StateListener() {
@Override
+ public void onDozeAmountChanged(float linear, float eased) {
+ mInterpolatedDarkAmount = eased;
+ updateBurnInOffsets();
+ }
+
+ @Override
public void onDozingChanged(boolean isDozing) {
mIsDozing = isDozing;
+ updateBurnInOffsets();
+ updateIsUdfpsEnrolled();
updateVisibility();
}
@@ -435,7 +512,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(
KeyguardUpdateMonitor.getCurrentUser());
}
- mUdfpsEnrolled = mKeyguardUpdateMonitor.isUdfpsEnrolled();
+ updateIsUdfpsEnrolled();
updateVisibility();
}
@@ -481,8 +558,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
// intercept all following touches until we see MotionEvent.ACTION_CANCEL UP or
// MotionEvent.ACTION_UP (see #onTouchEvent)
- mDownDetected = true;
- if (mVibrator != null) {
+ if (mVibrator != null && !mDownDetected) {
mVibrator.vibrate(
Process.myUid(),
getContext().getOpPackageName(),
@@ -490,6 +566,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
"lockIcon-onDown",
VIBRATION_SONIFICATION_ATTRIBUTES);
}
+
+ mDownDetected = true;
return true;
}
@@ -497,8 +575,10 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
if (!wasClickableOnDownEvent()) {
return;
}
+ mDetectedLongPress = true;
- if (mVibrator != null) {
+ if (onAffordanceClick() && mVibrator != null) {
+ // only vibrate if the click went through and wasn't intercepted by falsing
mVibrator.vibrate(
Process.myUid(),
getContext().getOpPackageName(),
@@ -506,8 +586,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
"lockIcon-onLongPress",
VIBRATION_SONIFICATION_ATTRIBUTES);
}
- mDetectedLongPress = true;
- onAffordanceClick();
}
public boolean onSingleTapUp(MotionEvent e) {
@@ -531,15 +609,24 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
return mDownDetected;
}
- private void onAffordanceClick() {
+ /**
+ * Whether we tried to launch the affordance.
+ *
+ * If falsing intercepts the click, returns false.
+ */
+ private boolean onAffordanceClick() {
if (mFalsingManager.isFalseTouch(LOCK_ICON)) {
- return;
+ return false;
}
// pre-emptively set to true to hide view
mIsBouncerShowing = true;
updateVisibility();
+ if (mOnGestureDetectedRunnable != null) {
+ mOnGestureDetectedRunnable.run();
+ }
mKeyguardViewController.showBouncer(/* scrim */ true);
+ return true;
}
});
@@ -548,16 +635,18 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
* in a 'clickable' state
* @return whether to intercept the touch event
*/
- public boolean onTouchEvent(MotionEvent event) {
+ public boolean onTouchEvent(MotionEvent event, Runnable onGestureDetectedRunnable) {
if (mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
- && mView.getVisibility() == View.VISIBLE) {
+ && (mView.getVisibility() == View.VISIBLE
+ || mAodFp.getVisibility() == View.VISIBLE)) {
+ mOnGestureDetectedRunnable = onGestureDetectedRunnable;
mGestureDetector.onTouchEvent(event);
}
// we continue to intercept all following touches until we see MotionEvent.ACTION_CANCEL UP
// or MotionEvent.ACTION_UP. this is to avoid passing the touch to NPV
// after the lock icon disappears on device entry
- if (mDownDetected && mDetectedLongPress) {
+ if (mDownDetected) {
if (event.getAction() == MotionEvent.ACTION_CANCEL
|| event.getAction() == MotionEvent.ACTION_UP) {
mDownDetected = false;
@@ -577,4 +666,12 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
public void setAlpha(float alpha) {
mView.setAlpha(alpha);
}
+
+ private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() {
+ @Override
+ public void onAllAuthenticatorsRegistered() {
+ updateIsUdfpsEnrolled();
+ updateConfiguration();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 0ce1846e7745..a4123c769d1e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -786,7 +786,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
.build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
}
- interface Callback {
+ public interface Callback {
/**
* Called when authenticators are registered. If authenticators are already
* registered before this call, this callback will never be triggered.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 1df8ad5e51fb..2630f119de00 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -16,14 +16,19 @@
package com.android.systemui.biometrics
+import android.animation.ValueAnimator
import android.content.Context
import android.content.res.Configuration
import android.graphics.PointF
import android.hardware.biometrics.BiometricSourceType
+import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.settingslib.Utils
+import com.android.systemui.R
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.statusbar.NotificationShadeWindowController
@@ -34,9 +39,14 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.ViewController
import java.io.PrintWriter
import javax.inject.Inject
+import javax.inject.Provider
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+
+private const val WAKE_AND_UNLOCK_FADE_DURATION = 180L
/***
* Controls the ripple effect that shows when authentication is successful.
@@ -49,37 +59,65 @@ class AuthRippleController @Inject constructor(
private val authController: AuthController,
private val configurationController: ConfigurationController,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+ private val keyguardStateController: KeyguardStateController,
+ private val wakefulnessLifecycle: WakefulnessLifecycle,
private val commandRegistry: CommandRegistry,
private val notificationShadeWindowController: NotificationShadeWindowController,
private val bypassController: KeyguardBypassController,
private val biometricUnlockController: BiometricUnlockController,
+ private val udfpsControllerProvider: Provider<UdfpsController>,
+ private val statusBarStateController: StatusBarStateController,
rippleView: AuthRippleView?
-) : ViewController<AuthRippleView>(rippleView) {
+) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
+ WakefulnessLifecycle.Observer {
+
+ @VisibleForTesting
+ internal var startLightRevealScrimOnKeyguardFadingAway = false
var fingerprintSensorLocation: PointF? = null
private var faceSensorLocation: PointF? = null
private var circleReveal: LightRevealEffect? = null
+ private var udfpsController: UdfpsController? = null
+
+ private var dwellScale = 2f
+ private var expandedDwellScale = 2.5f
+ private var aodDwellScale = 1.9f
+ private var aodExpandedDwellScale = 2.3f
+ private var udfpsRadius: Float = -1f
+
+ override fun onInit() {
+ mView.setAlphaInDuration(sysuiContext.resources.getInteger(
+ R.integer.auth_ripple_alpha_in_duration).toLong())
+ }
+
@VisibleForTesting
public override fun onViewAttached() {
+ authController.addCallback(authControllerCallback)
updateRippleColor()
updateSensorLocation()
- authController.addCallback(authControllerCallback)
+ updateUdfpsDependentParams()
+ udfpsController?.addCallback(udfpsControllerCallback)
configurationController.addCallback(configurationChangedListener)
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
+ keyguardStateController.addCallback(this)
+ wakefulnessLifecycle.addObserver(this)
commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
}
@VisibleForTesting
public override fun onViewDetached() {
+ udfpsController?.removeCallback(udfpsControllerCallback)
authController.removeCallback(authControllerCallback)
keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
configurationController.removeCallback(configurationChangedListener)
+ keyguardStateController.removeCallback(this)
+ wakefulnessLifecycle.removeObserver(this)
commandRegistry.unregisterCommand("auth-ripple")
notificationShadeWindowController.setForcePluginOpen(false, this)
}
- private fun showRipple(biometricSourceType: BiometricSourceType?) {
+ fun showRipple(biometricSourceType: BiometricSourceType?) {
if (!keyguardUpdateMonitor.isKeyguardVisible ||
keyguardUpdateMonitor.userNeedsStrongAuth()) {
return
@@ -88,43 +126,61 @@ class AuthRippleController @Inject constructor(
if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
fingerprintSensorLocation != null) {
mView.setSensorLocation(fingerprintSensorLocation!!)
- showRipple()
+ showUnlockedRipple()
} else if (biometricSourceType == BiometricSourceType.FACE &&
faceSensorLocation != null) {
if (!bypassController.canBypass()) {
return
}
mView.setSensorLocation(faceSensorLocation!!)
- showRipple()
+ showUnlockedRipple()
}
}
- private fun showRipple() {
+ private fun showUnlockedRipple() {
notificationShadeWindowController.setForcePluginOpen(true, this)
- val biometricUnlockMode = biometricUnlockController.mode
- val useCircleReveal = circleReveal != null &&
- (biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK ||
- biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING ||
- biometricUnlockMode == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM)
+ val useCircleReveal = circleReveal != null && biometricUnlockController.isWakeAndUnlock
val lightRevealScrim = statusBar.lightRevealScrim
if (useCircleReveal) {
lightRevealScrim?.revealEffect = circleReveal!!
+ startLightRevealScrimOnKeyguardFadingAway = true
}
- mView.startRipple(
+ mView.startUnlockedRipple(
/* end runnable */
Runnable {
notificationShadeWindowController.setForcePluginOpen(false, this)
- },
- /* circleReveal */
- if (useCircleReveal) {
- lightRevealScrim
- } else {
- null
}
)
}
+ override fun onKeyguardFadingAwayChanged() {
+ if (keyguardStateController.isKeyguardFadingAway) {
+ val lightRevealScrim = statusBar.lightRevealScrim
+ if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) {
+ val revealAnimator = ValueAnimator.ofFloat(.1f, 1f).apply {
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ duration = RIPPLE_ANIMATION_DURATION
+ startDelay = keyguardStateController.keyguardFadingAwayDelay
+ addUpdateListener { animator ->
+ if (lightRevealScrim.revealEffect != circleReveal) {
+ // if the something else took over the reveal, let's do nothing.
+ return@addUpdateListener
+ }
+ lightRevealScrim.revealAmount = animator.animatedValue as Float
+ }
+ }
+ revealAnimator.start()
+ startLightRevealScrimOnKeyguardFadingAway = false
+ }
+ }
+ }
+
+ override fun onStartedGoingToSleep() {
+ // reset the light reveal start in case we were pending an unlock
+ startLightRevealScrimOnKeyguardFadingAway = false
+ }
+
fun updateSensorLocation() {
fingerprintSensorLocation = authController.fingerprintSensorLocation
faceSensorLocation = authController.faceAuthSensorLocation
@@ -146,7 +202,23 @@ class AuthRippleController @Inject constructor(
Utils.getColorAttr(sysuiContext, android.R.attr.colorAccent).defaultColor)
}
- val keyguardUpdateMonitorCallback =
+ private fun showDwellRipple() {
+ if (statusBarStateController.isDozing) {
+ mView.startDwellRipple(
+ /* startRadius */ udfpsRadius,
+ /* endRadius */ udfpsRadius * aodDwellScale,
+ /* expandedRadius */ udfpsRadius * aodExpandedDwellScale,
+ /* isDozing */ true)
+ } else {
+ mView.startDwellRipple(
+ /* startRadius */ udfpsRadius,
+ /* endRadius */ udfpsRadius * dwellScale,
+ /* expandedRadius */ udfpsRadius * expandedDwellScale,
+ /* isDozing */ false)
+ }
+ }
+
+ private val keyguardUpdateMonitorCallback =
object : KeyguardUpdateMonitorCallback() {
override fun onBiometricAuthenticated(
userId: Int,
@@ -155,9 +227,13 @@ class AuthRippleController @Inject constructor(
) {
showRipple(biometricSourceType)
}
+
+ override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
+ mView.retractRipple()
+ }
}
- val configurationChangedListener =
+ private val configurationChangedListener =
object : ConfigurationController.ConfigurationListener {
override fun onConfigChanged(newConfig: Configuration?) {
updateSensorLocation()
@@ -173,14 +249,70 @@ class AuthRippleController @Inject constructor(
}
}
- private val authControllerCallback = AuthController.Callback { updateSensorLocation() }
+ private val udfpsControllerCallback =
+ object : UdfpsController.Callback {
+ override fun onFingerDown() {
+ if (fingerprintSensorLocation == null) {
+ Log.e("AuthRipple", "fingerprintSensorLocation=null onFingerDown. " +
+ "Skip showing dwell ripple")
+ return
+ }
+
+ mView.setSensorLocation(fingerprintSensorLocation!!)
+ showDwellRipple()
+ }
+
+ override fun onFingerUp() {
+ mView.retractRipple()
+ }
+ }
+
+ private val authControllerCallback = AuthController.Callback {
+ updateSensorLocation()
+ updateUdfpsDependentParams()
+ }
+
+ private fun updateUdfpsDependentParams() {
+ authController.udfpsProps?.let {
+ if (it.size > 0) {
+ udfpsRadius = it[0].sensorRadius.toFloat()
+ udfpsController = udfpsControllerProvider.get()
+
+ if (mView.isAttachedToWindow) {
+ udfpsController?.addCallback(udfpsControllerCallback)
+ }
+ }
+ }
+ }
inner class AuthRippleCommand : Command {
+ fun printLockScreenDwellInfo(pw: PrintWriter) {
+ pw.println("lock screen dwell ripple: " +
+ "\n\tsensorLocation=$fingerprintSensorLocation" +
+ "\n\tdwellScale=$dwellScale" +
+ "\n\tdwellExpand=$expandedDwellScale")
+ }
+
+ fun printAodDwellInfo(pw: PrintWriter) {
+ pw.println("aod dwell ripple: " +
+ "\n\tsensorLocation=$fingerprintSensorLocation" +
+ "\n\tdwellScale=$aodDwellScale" +
+ "\n\tdwellExpand=$aodExpandedDwellScale")
+ }
+
override fun execute(pw: PrintWriter, args: List<String>) {
if (args.isEmpty()) {
invalidCommand(pw)
} else {
when (args[0]) {
+ "dwell" -> {
+ showDwellRipple()
+ if (statusBarStateController.isDozing) {
+ printAodDwellInfo(pw)
+ } else {
+ printLockScreenDwellInfo(pw)
+ }
+ }
"fingerprint" -> {
pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation")
showRipple(BiometricSourceType.FINGERPRINT)
@@ -199,7 +331,7 @@ class AuthRippleController @Inject constructor(
pw.println("custom ripple sensorLocation=" + args[1].toFloat() + ", " +
args[2].toFloat())
mView.setSensorLocation(PointF(args[1].toFloat(), args[2].toFloat()))
- showRipple()
+ showUnlockedRipple()
}
else -> invalidCommand(pw)
}
@@ -209,6 +341,7 @@ class AuthRippleController @Inject constructor(
override fun help(pw: PrintWriter) {
pw.println("Usage: adb shell cmd statusbar auth-ripple <command>")
pw.println("Available commands:")
+ pw.println(" dwell")
pw.println(" fingerprint")
pw.println(" face")
pw.println(" custom <x-location: int> <y-location: int>")
@@ -219,4 +352,8 @@ class AuthRippleController @Inject constructor(
help(pw)
}
}
+
+ companion object {
+ const val RIPPLE_ANIMATION_DURATION: Long = 1533
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 95ea81003ecb..c6d26ffb9957 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -27,21 +27,40 @@ import android.util.AttributeSet
import android.view.View
import android.view.animation.PathInterpolator
import com.android.internal.graphics.ColorUtils
-import com.android.systemui.statusbar.LightRevealScrim
+import com.android.systemui.animation.Interpolators
import com.android.systemui.statusbar.charging.RippleShader
-private const val RIPPLE_ANIMATION_DURATION: Long = 1533
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
/**
- * Expanding ripple effect on the transition from biometric authentication success to showing
+ * Expanding ripple effect
+ * - startUnlockedRipple for the transition from biometric authentication success to showing
* launcher.
+ * - startDwellRipple for the ripple expansion out when the user has their finger down on the UDFPS
+ * sensor area
+ * - retractRipple for the ripple animation inwards to signal a failure
*/
class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
- private var rippleInProgress: Boolean = false
+ private val retractInterpolator = PathInterpolator(.05f, .93f, .1f, 1f)
+
+ private val dwellPulseDuration = 50L
+ private val dwellAlphaDuration = dwellPulseDuration
+ private val dwellAlpha: Float = 1f
+ private val dwellExpandDuration = 1200L - dwellPulseDuration
+
+ private val aodDwellPulseDuration = 50L
+ private var aodDwellAlphaDuration = aodDwellPulseDuration
+ private var aodDwellAlpha: Float = .8f
+ private var aodDwellExpandDuration = 1200L - aodDwellPulseDuration
+
+ private val retractDuration = 400L
+ private var alphaInDuration: Long = 0
+ private var unlockedRippleInProgress: Boolean = false
private val rippleShader = RippleShader()
private val ripplePaint = Paint()
- private var radius: Float = 0.0f
+ private var retractAnimator: Animator? = null
+ private var dwellPulseOutAnimator: Animator? = null
+ private var radius: Float = 0f
set(value) {
rippleShader.radius = value
field = value
@@ -62,51 +81,200 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
fun setSensorLocation(location: PointF) {
origin = location
- radius = maxOf(location.x, location.y, width - location.x, height - location.y)
- .toFloat()
+ radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat()
}
- fun startRipple(onAnimationEnd: Runnable?, lightReveal: LightRevealScrim?) {
- if (rippleInProgress) {
- return // Ignore if ripple effect is already playing
+ fun setAlphaInDuration(duration: Long) {
+ alphaInDuration = duration
+ }
+
+ /**
+ * Animate ripple inwards back to radius 0
+ */
+ fun retractRipple() {
+ if (retractAnimator?.isRunning == true) {
+ return // let the animation finish
+ }
+
+ if (dwellPulseOutAnimator?.isRunning == true) {
+ val retractRippleAnimator = ValueAnimator.ofFloat(rippleShader.progress, 0f)
+ .apply {
+ interpolator = retractInterpolator
+ duration = retractDuration
+ addUpdateListener { animator ->
+ val now = animator.currentPlayTime
+ rippleShader.progress = animator.animatedValue as Float
+ rippleShader.time = now.toFloat()
+
+ invalidate()
+ }
+ }
+
+ val retractAlphaAnimator = ValueAnimator.ofInt(255, 0).apply {
+ interpolator = Interpolators.LINEAR
+ duration = retractDuration
+ addUpdateListener { animator ->
+ rippleShader.color = ColorUtils.setAlphaComponent(
+ rippleShader.color,
+ animator.animatedValue as Int
+ )
+ invalidate()
+ }
+ }
+
+ retractAnimator = AnimatorSet().apply {
+ playTogether(retractRippleAnimator, retractAlphaAnimator)
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator?) {
+ dwellPulseOutAnimator?.cancel()
+ rippleShader.shouldFadeOutRipple = false
+ visibility = VISIBLE
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ visibility = GONE
+ resetRippleAlpha()
+ }
+ })
+ start()
+ }
+ }
+ }
+
+ /**
+ * Ripple that moves animates from an outer ripple ring of
+ * startRadius => endRadius => expandedRadius
+ */
+ fun startDwellRipple(
+ startRadius: Float,
+ endRadius: Float,
+ expandedRadius: Float,
+ isDozing: Boolean
+ ) {
+ if (unlockedRippleInProgress || dwellPulseOutAnimator?.isRunning == true) {
+ return
}
- val rippleAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
- interpolator = PathInterpolator(0.4f, 0f, 0f, 1f)
- duration = RIPPLE_ANIMATION_DURATION
+ // we divide by 4 because the desired startRadius and endRadius is for the ripple's outer
+ // ring see RippleShader
+ val startDwellProgress = startRadius / radius / 4f
+ val endInitialDwellProgress = endRadius / radius / 4f
+ val endExpandDwellProgress = expandedRadius / radius / 4f
+
+ val alpha = if (isDozing) aodDwellAlpha else dwellAlpha
+ val pulseOutEndAlpha = (255 * alpha).toInt()
+ val expandDwellEndAlpha = kotlin.math.min((255 * (alpha + .25f)).toInt(), 255)
+ val dwellPulseOutRippleAnimator = ValueAnimator.ofFloat(startDwellProgress,
+ endInitialDwellProgress).apply {
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ duration = if (isDozing) aodDwellPulseDuration else dwellPulseDuration
addUpdateListener { animator ->
val now = animator.currentPlayTime
rippleShader.progress = animator.animatedValue as Float
rippleShader.time = now.toFloat()
- lightReveal?.revealAmount = animator.animatedValue as Float
invalidate()
}
}
- val revealAnimator = ValueAnimator.ofFloat(0f, 1f).apply {
- interpolator = rippleAnimator.interpolator
- startDelay = 10
- duration = rippleAnimator.duration
+ val dwellPulseOutAlphaAnimator = ValueAnimator.ofInt(0, pulseOutEndAlpha).apply {
+ interpolator = Interpolators.LINEAR
+ duration = if (isDozing) aodDwellAlphaDuration else dwellAlphaDuration
addUpdateListener { animator ->
- lightReveal?.revealAmount = animator.animatedValue as Float
+ rippleShader.color = ColorUtils.setAlphaComponent(
+ rippleShader.color,
+ animator.animatedValue as Int
+ )
+ invalidate()
}
}
- val alphaInAnimator = ValueAnimator.ofInt(0, 127).apply {
- duration = 167
+ // slowly animate outwards until we receive a call to retractRipple or startUnlockedRipple
+ val expandDwellRippleAnimator = ValueAnimator.ofFloat(endInitialDwellProgress,
+ endExpandDwellProgress).apply {
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration
+ addUpdateListener { animator ->
+ val now = animator.currentPlayTime
+ rippleShader.progress = animator.animatedValue as Float
+ rippleShader.time = now.toFloat()
+
+ invalidate()
+ }
+ }
+
+ val expandDwellAlphaAnimator = ValueAnimator.ofInt(pulseOutEndAlpha, expandDwellEndAlpha)
+ .apply {
+ interpolator = Interpolators.LINEAR
+ duration = if (isDozing) aodDwellExpandDuration else dwellExpandDuration
addUpdateListener { animator ->
rippleShader.color = ColorUtils.setAlphaComponent(
- rippleShader.color,
- animator.animatedValue as Int
+ rippleShader.color,
+ animator.animatedValue as Int
)
invalidate()
}
}
- val alphaOutAnimator = ValueAnimator.ofInt(127, 0).apply {
- startDelay = 417
- duration = 1116
+ val initialDwellPulseOutAnimator = AnimatorSet().apply {
+ playTogether(dwellPulseOutRippleAnimator, dwellPulseOutAlphaAnimator)
+ }
+ val expandDwellAnimator = AnimatorSet().apply {
+ playTogether(expandDwellRippleAnimator, expandDwellAlphaAnimator)
+ }
+
+ dwellPulseOutAnimator = AnimatorSet().apply {
+ playSequentially(
+ initialDwellPulseOutAnimator,
+ expandDwellAnimator
+ )
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator?) {
+ retractAnimator?.cancel()
+ rippleShader.shouldFadeOutRipple = false
+ visibility = VISIBLE
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ visibility = GONE
+ resetRippleAlpha()
+ }
+ })
+ start()
+ }
+ }
+
+ /**
+ * Ripple that bursts outwards from the position of the sensor to the edges of the screen
+ */
+ fun startUnlockedRipple(onAnimationEnd: Runnable?) {
+ if (unlockedRippleInProgress) {
+ return // Ignore if ripple effect is already playing
+ }
+
+ var rippleStart = 0f
+ var alphaDuration = alphaInDuration
+ if (dwellPulseOutAnimator?.isRunning == true || retractAnimator?.isRunning == true) {
+ rippleStart = rippleShader.progress
+ alphaDuration = 0
+ dwellPulseOutAnimator?.cancel()
+ retractAnimator?.cancel()
+ }
+
+ val rippleAnimator = ValueAnimator.ofFloat(rippleStart, 1f).apply {
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ duration = AuthRippleController.RIPPLE_ANIMATION_DURATION
+ addUpdateListener { animator ->
+ val now = animator.currentPlayTime
+ rippleShader.progress = animator.animatedValue as Float
+ rippleShader.time = now.toFloat()
+
+ invalidate()
+ }
+ }
+
+ val alphaInAnimator = ValueAnimator.ofInt(0, 255).apply {
+ duration = alphaDuration
addUpdateListener { animator ->
rippleShader.color = ColorUtils.setAlphaComponent(
rippleShader.color,
@@ -119,19 +287,18 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
val animatorSet = AnimatorSet().apply {
playTogether(
rippleAnimator,
- revealAnimator,
- alphaInAnimator,
- alphaOutAnimator
+ alphaInAnimator
)
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animation: Animator?) {
- rippleInProgress = true
+ unlockedRippleInProgress = true
+ rippleShader.shouldFadeOutRipple = true
visibility = VISIBLE
}
override fun onAnimationEnd(animation: Animator?) {
onAnimationEnd?.run()
- rippleInProgress = false
+ unlockedRippleInProgress = false
visibility = GONE
}
})
@@ -139,8 +306,16 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
animatorSet.start()
}
+ fun resetRippleAlpha() {
+ rippleShader.color = ColorUtils.setAlphaComponent(
+ rippleShader.color,
+ 255
+ )
+ }
+
fun setColor(color: Int) {
rippleShader.color = color
+ resetRippleAlpha()
}
override fun onDraw(canvas: Canvas?) {
@@ -148,7 +323,7 @@ class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, at
// the active effect area. Values here should be kept in sync with the
// animation implementation in the ripple shader.
val maskRadius = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) *
- (1 - rippleShader.progress)) * radius * 1.5f
+ (1 - rippleShader.progress)) * radius * 2f
canvas?.drawCircle(origin.x, origin.y, maskRadius, ripplePaint)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index e612fb4712fc..54f932184331 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -77,7 +77,9 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.Execution;
+import java.util.HashSet;
import java.util.Optional;
+import java.util.Set;
import javax.inject.Inject;
@@ -157,6 +159,7 @@ public class UdfpsController implements DozeReceiver {
private Runnable mAodInterruptRunnable;
private boolean mOnFingerDown;
private boolean mAttemptedToDismissKeyguard;
+ private Set<Callback> mCallbacks = new HashSet<>();
@VisibleForTesting
public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
@@ -210,12 +213,14 @@ public class UdfpsController implements DozeReceiver {
}
void onAcquiredGood() {
+ Log.d(TAG, "onAcquiredGood");
if (mEnrollHelper != null) {
mEnrollHelper.animateIfLastStep();
}
}
void onEnrollmentHelp() {
+ Log.d(TAG, "onEnrollmentHelp");
if (mEnrollHelper != null) {
mEnrollHelper.onEnrollmentHelp();
}
@@ -759,6 +764,7 @@ public class UdfpsController implements DozeReceiver {
UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate(
R.layout.udfps_enroll_view, null);
mView.addView(enrollView);
+ enrollView.updateSensorLocation(mSensorProps);
return new UdfpsEnrollViewController(
enrollView,
mServerRequest.mEnrollHelper,
@@ -781,6 +787,7 @@ public class UdfpsController implements DozeReceiver {
mKeyguardViewMediator,
mLockscreenShadeTransitionController,
mConfigurationController,
+ mKeyguardStateController,
this
);
case IUdfpsOverlayController.REASON_AUTH_BP:
@@ -841,6 +848,10 @@ public class UdfpsController implements DozeReceiver {
return;
}
+ if (!mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
+ return;
+ }
+
mAodInterruptRunnable = () -> {
mIsAodInterruptActive = true;
// Since the sensor that triggers the AOD interrupt doesn't provide
@@ -860,6 +871,20 @@ public class UdfpsController implements DozeReceiver {
}
/**
+ * Add a callback for fingerUp and fingerDown events
+ */
+ public void addCallback(Callback cb) {
+ mCallbacks.add(cb);
+ }
+
+ /**
+ * Remove callback
+ */
+ public void removeCallback(Callback cb) {
+ mCallbacks.remove(cb);
+ }
+
+ /**
* Cancel updfs scan affordances - ability to hide the HbmSurfaceView (white circle) before
* user explicitly lifts their finger. Generally, this should be called whenever udfps fails
* or errors.
@@ -913,6 +938,10 @@ public class UdfpsController implements DozeReceiver {
mFingerprintManager.onUiReady(mSensorProps.sensorId);
Trace.endAsyncSection("UdfpsController.e2e.startIllumination", 0);
});
+
+ for (Callback cb : mCallbacks) {
+ cb.onFingerDown();
+ }
}
private void onFingerUp() {
@@ -925,6 +954,9 @@ public class UdfpsController implements DozeReceiver {
}
if (mOnFingerDown) {
mFingerprintManager.onPointerUp(mSensorProps.sensorId);
+ for (Callback cb : mCallbacks) {
+ cb.onFingerUp();
+ }
}
mOnFingerDown = false;
if (mView.isIlluminationRequested()) {
@@ -945,4 +977,19 @@ public class UdfpsController implements DozeReceiver {
mView.setOnTouchListener(mOnTouchListener);
}
}
+
+ /**
+ * Callback for fingerUp and fingerDown events.
+ */
+ public interface Callback {
+ /**
+ * Called onFingerUp events. Will only be called if the finger was previously down.
+ */
+ void onFingerUp();
+
+ /**
+ * Called onFingerDown events.
+ */
+ void onFingerDown();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index ea69b1d626ae..2034ff35be70 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -16,9 +16,11 @@
package com.android.systemui.biometrics;
+import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -26,11 +28,17 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.TypedValue;
import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.graphics.ColorUtils;
import com.android.systemui.R;
/**
@@ -39,11 +47,20 @@ import com.android.systemui.R;
public class UdfpsEnrollDrawable extends UdfpsDrawable {
private static final String TAG = "UdfpsAnimationEnroll";
- private static final long ANIM_DURATION = 800;
+ private static final long HINT_COLOR_ANIM_DELAY_MS = 233L;
+ private static final long HINT_COLOR_ANIM_DURATION_MS = 517L;
+ private static final long HINT_WIDTH_ANIM_DURATION_MS = 233L;
+ private static final long TARGET_ANIM_DURATION_LONG = 800L;
+ private static final long TARGET_ANIM_DURATION_SHORT = 600L;
// 1 + SCALE_MAX is the maximum that the moving target will animate to
private static final float SCALE_MAX = 0.25f;
- @NonNull private final UdfpsEnrollProgressBarDrawable mProgressDrawable;
+ private static final float HINT_PADDING_DP = 10f;
+ private static final float HINT_MAX_WIDTH_DP = 6f;
+ private static final float HINT_ANGLE = 40f;
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
@NonNull private final Drawable mMovingTargetFpIcon;
@NonNull private final Paint mSensorOutlinePaint;
@NonNull private final Paint mBlueFill;
@@ -52,18 +69,41 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
@Nullable private UdfpsEnrollHelper mEnrollHelper;
// Moving target animator set
- @Nullable AnimatorSet mAnimatorSet;
+ @Nullable AnimatorSet mTargetAnimatorSet;
// Moving target location
float mCurrentX;
float mCurrentY;
// Moving target size
float mCurrentScale = 1.f;
+ @ColorInt private final int mHintColorFaded;
+ @ColorInt private final int mHintColorHighlight;
+ private final float mHintMaxWidthPx;
+ private final float mHintPaddingPx;
+
+ @NonNull private final Animator.AnimatorListener mTargetAnimListener;
+
+ private boolean mShouldShowTipHint = false;
+ @NonNull private final Paint mTipHintPaint;
+ @Nullable private AnimatorSet mTipHintAnimatorSet;
+ @Nullable private ValueAnimator mTipHintColorAnimator;
+ @Nullable private ValueAnimator mTipHintWidthAnimator;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mTipHintColorUpdateListener;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mTipHintWidthUpdateListener;
+ @NonNull private final Animator.AnimatorListener mTipHintPulseListener;
+
+ private boolean mShouldShowEdgeHint = false;
+ @NonNull private final Paint mEdgeHintPaint;
+ @Nullable private AnimatorSet mEdgeHintAnimatorSet;
+ @Nullable private ValueAnimator mEdgeHintColorAnimator;
+ @Nullable private ValueAnimator mEdgeHintWidthAnimator;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mEdgeHintColorUpdateListener;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mEdgeHintWidthUpdateListener;
+ @NonNull private final Animator.AnimatorListener mEdgeHintPulseListener;
+
UdfpsEnrollDrawable(@NonNull Context context) {
super(context);
- mProgressDrawable = new UdfpsEnrollProgressBarDrawable(context, this);
-
mSensorOutlinePaint = new Paint(0 /* flags */);
mSensorOutlinePaint.setAntiAlias(true);
mSensorOutlinePaint.setColor(mContext.getColor(R.color.udfps_enroll_icon));
@@ -80,6 +120,117 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
mMovingTargetFpIcon.mutate();
mFingerprintDrawable.setTint(mContext.getColor(R.color.udfps_enroll_icon));
+
+ mHintColorFaded = getHintColorFaded(context);
+ mHintColorHighlight = context.getColor(R.color.udfps_enroll_progress);
+ mHintMaxWidthPx = Utils.dpToPixels(context, HINT_MAX_WIDTH_DP);
+ mHintPaddingPx = Utils.dpToPixels(context, HINT_PADDING_DP);
+
+ mTargetAnimListener = new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ updateTipHintVisibility();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {}
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {}
+ };
+
+ mTipHintPaint = new Paint(0 /* flags */);
+ mTipHintPaint.setAntiAlias(true);
+ mTipHintPaint.setColor(mHintColorFaded);
+ mTipHintPaint.setStyle(Paint.Style.STROKE);
+ mTipHintPaint.setStrokeCap(Paint.Cap.ROUND);
+ mTipHintPaint.setStrokeWidth(0f);
+ mTipHintColorUpdateListener = animation -> {
+ mTipHintPaint.setColor((int) animation.getAnimatedValue());
+ invalidateSelf();
+ };
+ mTipHintWidthUpdateListener = animation -> {
+ mTipHintPaint.setStrokeWidth((float) animation.getAnimatedValue());
+ invalidateSelf();
+ };
+ mTipHintPulseListener = new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHandler.postDelayed(() -> {
+ mTipHintColorAnimator =
+ ValueAnimator.ofArgb(mTipHintPaint.getColor(), mHintColorFaded);
+ mTipHintColorAnimator.setInterpolator(new LinearInterpolator());
+ mTipHintColorAnimator.setDuration(HINT_COLOR_ANIM_DURATION_MS);
+ mTipHintColorAnimator.addUpdateListener(mTipHintColorUpdateListener);
+ mTipHintColorAnimator.start();
+ }, HINT_COLOR_ANIM_DELAY_MS);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {}
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {}
+ };
+
+ mEdgeHintPaint = new Paint(0 /* flags */);
+ mEdgeHintPaint.setAntiAlias(true);
+ mEdgeHintPaint.setColor(mHintColorFaded);
+ mEdgeHintPaint.setStyle(Paint.Style.STROKE);
+ mEdgeHintPaint.setStrokeCap(Paint.Cap.ROUND);
+ mEdgeHintPaint.setStrokeWidth(0f);
+ mEdgeHintColorUpdateListener = animation -> {
+ mEdgeHintPaint.setColor((int) animation.getAnimatedValue());
+ invalidateSelf();
+ };
+ mEdgeHintWidthUpdateListener = animation -> {
+ mEdgeHintPaint.setStrokeWidth((float) animation.getAnimatedValue());
+ invalidateSelf();
+ };
+ mEdgeHintPulseListener = new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {}
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mHandler.postDelayed(() -> {
+ mEdgeHintColorAnimator =
+ ValueAnimator.ofArgb(mEdgeHintPaint.getColor(), mHintColorFaded);
+ mEdgeHintColorAnimator.setInterpolator(new LinearInterpolator());
+ mEdgeHintColorAnimator.setDuration(HINT_COLOR_ANIM_DURATION_MS);
+ mEdgeHintColorAnimator.addUpdateListener(mEdgeHintColorUpdateListener);
+ mEdgeHintColorAnimator.start();
+ }, HINT_COLOR_ANIM_DELAY_MS);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {}
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {}
+ };
+ }
+
+ @ColorInt
+ private static int getHintColorFaded(@NonNull Context context) {
+ final TypedValue tv = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, tv, true);
+ final int alpha = (int) (tv.getFloat() * 255f);
+
+ final int[] attrs = new int[] {android.R.attr.colorControlNormal};
+ final TypedArray ta = context.obtainStyledAttributes(attrs);
+ try {
+ @ColorInt final int color = ta.getColor(0, context.getColor(R.color.white_disabled));
+ return ColorUtils.setAlphaComponent(color, alpha);
+ } finally {
+ ta.recycle();
+ }
}
void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
@@ -100,59 +251,164 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
}
void onEnrollmentProgress(int remaining, int totalSteps) {
- mProgressDrawable.setEnrollmentProgress(remaining, totalSteps);
+ if (mEnrollHelper == null) {
+ return;
+ }
- if (mEnrollHelper.isCenterEnrollmentComplete()) {
- if (mAnimatorSet != null && mAnimatorSet.isRunning()) {
- mAnimatorSet.end();
+ if (!mEnrollHelper.isCenterEnrollmentStage()) {
+ if (mTargetAnimatorSet != null && mTargetAnimatorSet.isRunning()) {
+ mTargetAnimatorSet.end();
}
final PointF point = mEnrollHelper.getNextGuidedEnrollmentPoint();
+ if (mCurrentX != point.x || mCurrentY != point.y) {
+ final ValueAnimator x = ValueAnimator.ofFloat(mCurrentX, point.x);
+ x.addUpdateListener(animation -> {
+ mCurrentX = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ });
+
+ final ValueAnimator y = ValueAnimator.ofFloat(mCurrentY, point.y);
+ y.addUpdateListener(animation -> {
+ mCurrentY = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ });
+
+ final boolean isMovingToCenter = point.x == 0f && point.y == 0f;
+ final long duration = isMovingToCenter
+ ? TARGET_ANIM_DURATION_SHORT
+ : TARGET_ANIM_DURATION_LONG;
+
+ final ValueAnimator scale = ValueAnimator.ofFloat(0, (float) Math.PI);
+ scale.setDuration(duration);
+ scale.addUpdateListener(animation -> {
+ // Grow then shrink
+ mCurrentScale = 1
+ + SCALE_MAX * (float) Math.sin((float) animation.getAnimatedValue());
+ invalidateSelf();
+ });
+
+ mTargetAnimatorSet = new AnimatorSet();
+
+ mTargetAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
+ mTargetAnimatorSet.setDuration(duration);
+ mTargetAnimatorSet.addListener(mTargetAnimListener);
+ mTargetAnimatorSet.playTogether(x, y, scale);
+ mTargetAnimatorSet.start();
+ } else {
+ updateTipHintVisibility();
+ }
+ } else {
+ updateTipHintVisibility();
+ }
+
+ updateEdgeHintVisibility();
+ }
+
+ private void updateTipHintVisibility() {
+ final boolean shouldShow = mEnrollHelper != null && mEnrollHelper.isTipEnrollmentStage();
+ if (mShouldShowTipHint == shouldShow) {
+ return;
+ }
+ mShouldShowTipHint = shouldShow;
+
+ if (mTipHintWidthAnimator != null && mTipHintWidthAnimator.isRunning()) {
+ mTipHintWidthAnimator.cancel();
+ }
+
+ final float targetWidth = shouldShow ? mHintMaxWidthPx : 0f;
+ mTipHintWidthAnimator = ValueAnimator.ofFloat(mTipHintPaint.getStrokeWidth(), targetWidth);
+ mTipHintWidthAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS);
+ mTipHintWidthAnimator.addUpdateListener(mTipHintWidthUpdateListener);
+
+ if (shouldShow) {
+ startTipHintPulseAnimation();
+ } else {
+ mTipHintWidthAnimator.start();
+ }
+ }
- final ValueAnimator x = ValueAnimator.ofFloat(mCurrentX, point.x);
- x.addUpdateListener(animation -> {
- mCurrentX = (float) animation.getAnimatedValue();
- invalidateSelf();
- });
-
- final ValueAnimator y = ValueAnimator.ofFloat(mCurrentY, point.y);
- y.addUpdateListener(animation -> {
- mCurrentY = (float) animation.getAnimatedValue();
- invalidateSelf();
- });
-
- final ValueAnimator scale = ValueAnimator.ofFloat(0, (float) Math.PI);
- scale.setDuration(ANIM_DURATION);
- scale.addUpdateListener(animation -> {
- // Grow then shrink
- mCurrentScale = 1 +
- SCALE_MAX * (float) Math.sin((float) animation.getAnimatedValue());
- invalidateSelf();
- });
-
- mAnimatorSet = new AnimatorSet();
-
- mAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
- mAnimatorSet.setDuration(ANIM_DURATION);
- mAnimatorSet.playTogether(x, y, scale);
- mAnimatorSet.start();
+ private void updateEdgeHintVisibility() {
+ final boolean shouldShow = mEnrollHelper != null && mEnrollHelper.isEdgeEnrollmentStage();
+ if (mShouldShowEdgeHint == shouldShow) {
+ return;
+ }
+ mShouldShowEdgeHint = shouldShow;
+
+ if (mEdgeHintWidthAnimator != null && mEdgeHintWidthAnimator.isRunning()) {
+ mEdgeHintWidthAnimator.cancel();
+ }
+
+ final float targetWidth = shouldShow ? mHintMaxWidthPx : 0f;
+ mEdgeHintWidthAnimator =
+ ValueAnimator.ofFloat(mEdgeHintPaint.getStrokeWidth(), targetWidth);
+ mEdgeHintWidthAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS);
+ mEdgeHintWidthAnimator.addUpdateListener(mEdgeHintWidthUpdateListener);
+
+ if (shouldShow) {
+ startEdgeHintPulseAnimation();
+ } else {
+ mEdgeHintWidthAnimator.start();
}
}
- void onLastStepAcquired() {
- mProgressDrawable.onLastStepAcquired();
+ private void startTipHintPulseAnimation() {
+ mHandler.removeCallbacksAndMessages(null);
+ if (mTipHintAnimatorSet != null && mTipHintAnimatorSet.isRunning()) {
+ mTipHintAnimatorSet.cancel();
+ }
+ if (mTipHintColorAnimator != null && mTipHintColorAnimator.isRunning()) {
+ mTipHintColorAnimator.cancel();
+ }
+
+ mTipHintColorAnimator = ValueAnimator.ofArgb(mTipHintPaint.getColor(), mHintColorHighlight);
+ mTipHintColorAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS);
+ mTipHintColorAnimator.addUpdateListener(mTipHintColorUpdateListener);
+ mTipHintColorAnimator.addListener(mTipHintPulseListener);
+
+ mTipHintAnimatorSet = new AnimatorSet();
+ mTipHintAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
+ mTipHintAnimatorSet.playTogether(mTipHintColorAnimator, mTipHintWidthAnimator);
+ mTipHintAnimatorSet.start();
+ }
+
+ private void startEdgeHintPulseAnimation() {
+ mHandler.removeCallbacksAndMessages(null);
+ if (mEdgeHintAnimatorSet != null && mEdgeHintAnimatorSet.isRunning()) {
+ mEdgeHintAnimatorSet.cancel();
+ }
+ if (mEdgeHintColorAnimator != null && mEdgeHintColorAnimator.isRunning()) {
+ mEdgeHintColorAnimator.cancel();
+ }
+
+ mEdgeHintColorAnimator =
+ ValueAnimator.ofArgb(mEdgeHintPaint.getColor(), mHintColorHighlight);
+ mEdgeHintColorAnimator.setDuration(HINT_WIDTH_ANIM_DURATION_MS);
+ mEdgeHintColorAnimator.addUpdateListener(mEdgeHintColorUpdateListener);
+ mEdgeHintColorAnimator.addListener(mEdgeHintPulseListener);
+
+ mEdgeHintAnimatorSet = new AnimatorSet();
+ mEdgeHintAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
+ mEdgeHintAnimatorSet.playTogether(mEdgeHintColorAnimator, mEdgeHintWidthAnimator);
+ mEdgeHintAnimatorSet.start();
+ }
+
+ private boolean isTipHintVisible() {
+ return mTipHintPaint.getStrokeWidth() > 0f;
+ }
+
+ private boolean isEdgeHintVisible() {
+ return mEdgeHintPaint.getStrokeWidth() > 0f;
}
@Override
public void draw(@NonNull Canvas canvas) {
- mProgressDrawable.draw(canvas);
-
if (isIlluminationShowing()) {
return;
}
// Draw moving target
- if (mEnrollHelper.isCenterEnrollmentComplete()) {
+ if (mEnrollHelper != null && !mEnrollHelper.isCenterEnrollmentStage()) {
canvas.save();
canvas.translate(mCurrentX, mCurrentY);
@@ -172,11 +428,59 @@ public class UdfpsEnrollDrawable extends UdfpsDrawable {
mFingerprintDrawable.setAlpha(mAlpha);
mSensorOutlinePaint.setAlpha(mAlpha);
}
- }
- @Override
- public void onBoundsChange(@NonNull Rect rect) {
- mProgressDrawable.setBounds(rect);
+ // Draw the finger tip or edges hint.
+ if (isTipHintVisible() || isEdgeHintVisible()) {
+ canvas.save();
+
+ // Make arcs start from the top, rather than the right.
+ canvas.rotate(-90f, mSensorRect.centerX(), mSensorRect.centerY());
+
+ final float halfSensorHeight = Math.abs(mSensorRect.bottom - mSensorRect.top) / 2f;
+ final float halfSensorWidth = Math.abs(mSensorRect.right - mSensorRect.left) / 2f;
+ final float hintXOffset = halfSensorWidth + mHintPaddingPx;
+ final float hintYOffset = halfSensorHeight + mHintPaddingPx;
+
+ if (isTipHintVisible()) {
+ canvas.drawArc(
+ mSensorRect.centerX() - hintXOffset,
+ mSensorRect.centerY() - hintYOffset,
+ mSensorRect.centerX() + hintXOffset,
+ mSensorRect.centerY() + hintYOffset,
+ -HINT_ANGLE / 2f,
+ HINT_ANGLE,
+ false /* useCenter */,
+ mTipHintPaint);
+ }
+
+ if (isEdgeHintVisible()) {
+ // Draw right edge hint.
+ canvas.rotate(-90f, mSensorRect.centerX(), mSensorRect.centerY());
+ canvas.drawArc(
+ mSensorRect.centerX() - hintXOffset,
+ mSensorRect.centerY() - hintYOffset,
+ mSensorRect.centerX() + hintXOffset,
+ mSensorRect.centerY() + hintYOffset,
+ -HINT_ANGLE / 2f,
+ HINT_ANGLE,
+ false /* useCenter */,
+ mEdgeHintPaint);
+
+ // Draw left edge hint.
+ canvas.rotate(180f, mSensorRect.centerX(), mSensorRect.centerY());
+ canvas.drawArc(
+ mSensorRect.centerX() - hintXOffset,
+ mSensorRect.centerY() - hintYOffset,
+ mSensorRect.centerX() + hintXOffset,
+ mSensorRect.centerY() + hintYOffset,
+ -HINT_ANGLE / 2f,
+ HINT_ANGLE,
+ false /* useCenter */,
+ mEdgeHintPaint);
+ }
+
+ canvas.restore();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 6a918a6c8d39..8ac6df7198b7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -44,11 +44,19 @@ public class UdfpsEnrollHelper {
private static final String NEW_COORDS_OVERRIDE =
"com.android.systemui.biometrics.UdfpsNewCoords";
- // Enroll with two center touches before going to guided enrollment
- private static final int NUM_CENTER_TOUCHES = 2;
+ static final int ENROLL_STAGE_COUNT = 4;
+
+ // TODO(b/198928407): Consolidate with FingerprintEnrollEnrolling
+ private static final int[] STAGE_THRESHOLDS = new int[] {
+ 2, // center
+ 18, // guided
+ 22, // fingertip
+ 38, // edges
+ };
interface Listener {
void onEnrollmentProgress(int remaining, int totalSteps);
+ void onEnrollmentHelp(int remaining, int totalSteps);
void onLastStepAcquired();
}
@@ -65,6 +73,8 @@ public class UdfpsEnrollHelper {
// interface makes no promises about monotonically increasing by one each time.
private int mLocationsEnrolled = 0;
+ private int mCenterTouchCount = 0;
+
@Nullable Listener mListener;
public UdfpsEnrollHelper(@NonNull Context context, int reason) {
@@ -117,17 +127,43 @@ public class UdfpsEnrollHelper {
}
}
+ static int getStageThreshold(int index) {
+ return STAGE_THRESHOLDS[index];
+ }
+
+ static int getLastStageThreshold() {
+ return STAGE_THRESHOLDS[ENROLL_STAGE_COUNT - 1];
+ }
+
boolean shouldShowProgressBar() {
return mEnrollReason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING;
}
void onEnrollmentProgress(int remaining) {
- if (mTotalSteps == -1) {
- mTotalSteps = remaining;
- }
+ Log.d(TAG, "onEnrollmentProgress: remaining = " + remaining
+ + ", mRemainingSteps = " + mRemainingSteps
+ + ", mTotalSteps = " + mTotalSteps
+ + ", mLocationsEnrolled = " + mLocationsEnrolled
+ + ", mCenterTouchCount = " + mCenterTouchCount);
if (remaining != mRemainingSteps) {
mLocationsEnrolled++;
+ if (isCenterEnrollmentStage()) {
+ mCenterTouchCount++;
+ }
+ }
+
+ if (mTotalSteps == -1) {
+ mTotalSteps = remaining;
+
+ // Allocate (or subtract) any extra steps for the first enroll stage.
+ final int extraSteps = mTotalSteps - getLastStageThreshold();
+ if (extraSteps != 0) {
+ for (int stageIndex = 0; stageIndex < ENROLL_STAGE_COUNT; stageIndex++) {
+ STAGE_THRESHOLDS[stageIndex] =
+ Math.max(0, STAGE_THRESHOLDS[stageIndex] + extraSteps);
+ }
+ }
}
mRemainingSteps = remaining;
@@ -138,7 +174,9 @@ public class UdfpsEnrollHelper {
}
void onEnrollmentHelp() {
-
+ if (mListener != null) {
+ mListener.onEnrollmentHelp(mRemainingSteps, mTotalSteps);
+ }
}
void setListener(Listener listener) {
@@ -152,19 +190,39 @@ public class UdfpsEnrollHelper {
}
}
- boolean isCenterEnrollmentComplete() {
+ boolean isCenterEnrollmentStage() {
+ if (mTotalSteps == -1 || mRemainingSteps == -1) {
+ return true;
+ }
+ return mTotalSteps - mRemainingSteps < STAGE_THRESHOLDS[0];
+ }
+
+ boolean isGuidedEnrollmentStage() {
+ if (mAccessibilityEnabled || mTotalSteps == -1 || mRemainingSteps == -1) {
+ return false;
+ }
+ final int progressSteps = mTotalSteps - mRemainingSteps;
+ return progressSteps >= STAGE_THRESHOLDS[0] && progressSteps < STAGE_THRESHOLDS[1];
+ }
+
+ boolean isTipEnrollmentStage() {
if (mTotalSteps == -1 || mRemainingSteps == -1) {
return false;
- } else if (mAccessibilityEnabled) {
+ }
+ final int progressSteps = mTotalSteps - mRemainingSteps;
+ return progressSteps >= STAGE_THRESHOLDS[1] && progressSteps < STAGE_THRESHOLDS[2];
+ }
+
+ boolean isEdgeEnrollmentStage() {
+ if (mTotalSteps == -1 || mRemainingSteps == -1) {
return false;
}
- final int stepsEnrolled = mTotalSteps - mRemainingSteps;
- return stepsEnrolled >= NUM_CENTER_TOUCHES;
+ return mTotalSteps - mRemainingSteps >= STAGE_THRESHOLDS[2];
}
@NonNull
PointF getNextGuidedEnrollmentPoint() {
- if (mAccessibilityEnabled) {
+ if (mAccessibilityEnabled || !isGuidedEnrollmentStage()) {
return new PointF(0f, 0f);
}
@@ -174,13 +232,14 @@ public class UdfpsEnrollHelper {
SCALE_OVERRIDE, SCALE,
UserHandle.USER_CURRENT);
}
- final int index = mLocationsEnrolled - NUM_CENTER_TOUCHES;
+ final int index = mLocationsEnrolled - mCenterTouchCount;
final PointF originalPoint = mGuidedEnrollmentPoints
.get(index % mGuidedEnrollmentPoints.size());
return new PointF(originalPoint.x * scale, originalPoint.y * scale);
}
void animateIfLastStep() {
+ Log.d(TAG, "animateIfLastStep: mRemainingSteps = " + mRemainingSteps);
if (mListener == null) {
Log.e(TAG, "animateIfLastStep, null listener");
return;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index 4195009937c2..b56543f4851b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -16,148 +16,107 @@
package com.android.systemui.biometrics;
-import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
-import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.Log;
-import android.util.TypedValue;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.systemui.R;
+import java.util.ArrayList;
+import java.util.List;
/**
* UDFPS enrollment progress bar.
*/
public class UdfpsEnrollProgressBarDrawable extends Drawable {
+ private static final String TAG = "UdfpsProgressBar";
- private static final String TAG = "UdfpsEnrollProgressBarDrawable";
-
- private static final float PROGRESS_BAR_THICKNESS_DP = 12;
-
- @NonNull private final Context mContext;
- @NonNull private final UdfpsEnrollDrawable mParent;
- @NonNull private final Paint mBackgroundCirclePaint;
- @NonNull private final Paint mProgressPaint;
-
- @Nullable private ValueAnimator mProgressAnimator;
- private float mProgress;
- private int mRotation; // After last step, rotate the progress bar once
- private boolean mLastStepAcquired;
-
- public UdfpsEnrollProgressBarDrawable(@NonNull Context context,
- @NonNull UdfpsEnrollDrawable parent) {
- mContext = context;
- mParent = parent;
-
- mBackgroundCirclePaint = new Paint();
- mBackgroundCirclePaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP));
- mBackgroundCirclePaint.setColor(context.getColor(R.color.white_disabled));
- mBackgroundCirclePaint.setAntiAlias(true);
- mBackgroundCirclePaint.setStyle(Paint.Style.STROKE);
-
- // Background circle color + alpha
- TypedArray tc = context.obtainStyledAttributes(
- new int[] {android.R.attr.colorControlNormal});
- int tintColor = tc.getColor(0, mBackgroundCirclePaint.getColor());
- mBackgroundCirclePaint.setColor(tintColor);
- tc.recycle();
- TypedValue alpha = new TypedValue();
- context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true);
- mBackgroundCirclePaint.setAlpha((int) (alpha.getFloat() * 255));
-
- // Progress should not be color extracted
- mProgressPaint = new Paint();
- mProgressPaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP));
- mProgressPaint.setColor(context.getColor(R.color.udfps_enroll_progress));
- mProgressPaint.setAntiAlias(true);
- mProgressPaint.setStyle(Paint.Style.STROKE);
- mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
- }
+ private static final float SEGMENT_GAP_ANGLE = 12f;
- void setEnrollmentProgress(int remaining, int totalSteps) {
- // Add one so that the first steps actually changes progress, but also so that the last
- // step ends at 1.0
- final float progress = (totalSteps - remaining + 1) / (float) (totalSteps + 1);
- setEnrollmentProgress(progress);
- }
+ @NonNull private final List<UdfpsEnrollProgressBarSegment> mSegments;
- private void setEnrollmentProgress(float progress) {
- if (mLastStepAcquired) {
- return;
+ public UdfpsEnrollProgressBarDrawable(@NonNull Context context) {
+ mSegments = new ArrayList<>(UdfpsEnrollHelper.ENROLL_STAGE_COUNT);
+ float startAngle = SEGMENT_GAP_ANGLE / 2f;
+ final float sweepAngle = (360f / UdfpsEnrollHelper.ENROLL_STAGE_COUNT) - SEGMENT_GAP_ANGLE;
+ final Runnable invalidateRunnable = this::invalidateSelf;
+ for (int index = 0; index < UdfpsEnrollHelper.ENROLL_STAGE_COUNT; index++) {
+ mSegments.add(new UdfpsEnrollProgressBarSegment(context, getBounds(), startAngle,
+ sweepAngle, SEGMENT_GAP_ANGLE, invalidateRunnable));
+ startAngle += sweepAngle + SEGMENT_GAP_ANGLE;
}
+ }
- long animationDuration = 150;
-
- if (progress == 1.f) {
- animationDuration = 400;
- final ValueAnimator rotationAnimator = ValueAnimator.ofInt(0, 400);
- rotationAnimator.setDuration(animationDuration);
- rotationAnimator.addUpdateListener(animation -> {
- Log.d(TAG, "Rotation: " + mRotation);
- mRotation = (int) animation.getAnimatedValue();
- mParent.invalidateSelf();
- });
- rotationAnimator.start();
+ void setEnrollmentProgress(int remaining, int totalSteps) {
+ if (remaining == totalSteps) {
+ // Show some progress for the initial touch.
+ setEnrollmentProgress(1);
+ } else {
+ setEnrollmentProgress(totalSteps - remaining);
}
+ }
- if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
- mProgressAnimator.cancel();
+ private void setEnrollmentProgress(int progressSteps) {
+ Log.d(TAG, "setEnrollmentProgress: progressSteps = " + progressSteps);
+
+ int segmentIndex = 0;
+ int prevThreshold = 0;
+ while (segmentIndex < mSegments.size()) {
+ final UdfpsEnrollProgressBarSegment segment = mSegments.get(segmentIndex);
+ final int threshold = UdfpsEnrollHelper.getStageThreshold(segmentIndex);
+
+ if (progressSteps >= threshold && !segment.isFilledOrFilling()) {
+ Log.d(TAG, "setEnrollmentProgress: segment[" + segmentIndex + "] complete");
+ segment.updateProgress(1f);
+ break;
+ } else if (progressSteps >= prevThreshold && progressSteps < threshold) {
+ final int relativeSteps = progressSteps - prevThreshold;
+ final int relativeThreshold = threshold - prevThreshold;
+ final float segmentProgress = (float) relativeSteps / (float) relativeThreshold;
+ Log.d(TAG, "setEnrollmentProgress: segment[" + segmentIndex + "] progress = "
+ + segmentProgress);
+ segment.updateProgress(segmentProgress);
+ break;
+ }
+
+ segmentIndex++;
+ prevThreshold = threshold;
}
- mProgressAnimator = ValueAnimator.ofFloat(mProgress, progress);
- mProgressAnimator.setDuration(animationDuration);
- mProgressAnimator.addUpdateListener(animation -> {
- mProgress = (float) animation.getAnimatedValue();
- // Use the parent to invalidate, since it's the one that's attached as the view's
- // drawable and has its callback set automatically. Invalidating via
- // `this.invalidateSelf` actually does not invoke draw(), since this drawable's callback
- // is not really set.
- mParent.invalidateSelf();
- });
- mProgressAnimator.start();
+ if (progressSteps >= UdfpsEnrollHelper.getLastStageThreshold()) {
+ Log.d(TAG, "setEnrollmentProgress: startCompletionAnimation");
+ for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
+ segment.startCompletionAnimation();
+ }
+ } else {
+ Log.d(TAG, "setEnrollmentProgress: cancelCompletionAnimation");
+ for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
+ segment.cancelCompletionAnimation();
+ }
+ }
}
void onLastStepAcquired() {
- setEnrollmentProgress(1.f);
- mLastStepAcquired = true;
+ Log.d(TAG, "setEnrollmentProgress: onLastStepAcquired");
+ setEnrollmentProgress(UdfpsEnrollHelper.getLastStageThreshold());
}
@Override
public void draw(@NonNull Canvas canvas) {
+ Log.d(TAG, "setEnrollmentProgress: draw");
+
canvas.save();
// Progress starts from the top, instead of the right
- canvas.rotate(-90 + mRotation, getBounds().centerX(), getBounds().centerY());
-
- // Progress bar "background track"
- final float halfPaddingPx = Utils.dpToPixels(mContext, PROGRESS_BAR_THICKNESS_DP) / 2;
- canvas.drawArc(halfPaddingPx,
- halfPaddingPx,
- getBounds().right - halfPaddingPx,
- getBounds().bottom - halfPaddingPx,
- 0,
- 360,
- false,
- mBackgroundCirclePaint
- );
-
- final float progress = 360.f * mProgress;
- // Progress
- canvas.drawArc(halfPaddingPx,
- halfPaddingPx,
- getBounds().right - halfPaddingPx,
- getBounds().bottom - halfPaddingPx,
- 0,
- progress,
- false,
- mProgressPaint
- );
+ canvas.rotate(-90f, getBounds().centerX(), getBounds().centerY());
+
+ // Draw each of the enroll segments.
+ for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
+ segment.draw(canvas);
+ }
canvas.restore();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java
new file mode 100644
index 000000000000..5f24380b6ce3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarSegment.java
@@ -0,0 +1,256 @@
+/*
+ * 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.systemui.biometrics;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.util.TypedValue;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * A single segment of the UDFPS enrollment progress bar.
+ */
+public class UdfpsEnrollProgressBarSegment {
+ private static final String TAG = "UdfpsProgressBarSegment";
+
+ private static final long PROGRESS_ANIMATION_DURATION_MS = 400L;
+ private static final long OVER_SWEEP_ANIMATION_DELAY_MS = 200L;
+ private static final long OVER_SWEEP_ANIMATION_DURATION_MS = 200L;
+
+ private static final float STROKE_WIDTH_DP = 12f;
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+ @NonNull private final Rect mBounds;
+ @NonNull private final Runnable mInvalidateRunnable;
+ private final float mStartAngle;
+ private final float mSweepAngle;
+ private final float mMaxOverSweepAngle;
+ private final float mStrokeWidthPx;
+
+ @NonNull private final Paint mBackgroundPaint;
+ @NonNull private final Paint mProgressPaint;
+
+ private boolean mIsFilledOrFilling = false;
+
+ private float mProgress = 0f;
+ @Nullable private ValueAnimator mProgressAnimator;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mProgressUpdateListener;
+
+ private float mOverSweepAngle = 0f;
+ @Nullable private ValueAnimator mOverSweepAnimator;
+ @Nullable private ValueAnimator mOverSweepReverseAnimator;
+ @NonNull private final ValueAnimator.AnimatorUpdateListener mOverSweepUpdateListener;
+ @NonNull private final Runnable mOverSweepAnimationRunnable;
+
+ public UdfpsEnrollProgressBarSegment(@NonNull Context context, @NonNull Rect bounds,
+ float startAngle, float sweepAngle, float maxOverSweepAngle,
+ @NonNull Runnable invalidateRunnable) {
+
+ mBounds = bounds;
+ mInvalidateRunnable = invalidateRunnable;
+ mStartAngle = startAngle;
+ mSweepAngle = sweepAngle;
+ mMaxOverSweepAngle = maxOverSweepAngle;
+ mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP);
+
+ mBackgroundPaint = new Paint();
+ mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
+ mBackgroundPaint.setColor(context.getColor(R.color.white_disabled));
+ mBackgroundPaint.setAntiAlias(true);
+ mBackgroundPaint.setStyle(Paint.Style.STROKE);
+ mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
+
+ // Background paint color + alpha
+ final int[] attrs = new int[] {android.R.attr.colorControlNormal};
+ final TypedArray ta = context.obtainStyledAttributes(attrs);
+ @ColorInt final int tintColor = ta.getColor(0, mBackgroundPaint.getColor());
+ mBackgroundPaint.setColor(tintColor);
+ ta.recycle();
+ TypedValue alpha = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true);
+ mBackgroundPaint.setAlpha((int) (alpha.getFloat() * 255f));
+
+ // Progress should not be color extracted
+ mProgressPaint = new Paint();
+ mProgressPaint.setStrokeWidth(mStrokeWidthPx);
+ mProgressPaint.setColor(context.getColor(R.color.udfps_enroll_progress));
+ mProgressPaint.setAntiAlias(true);
+ mProgressPaint.setStyle(Paint.Style.STROKE);
+ mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
+
+ mProgressUpdateListener = animation -> {
+ mProgress = (float) animation.getAnimatedValue();
+ mInvalidateRunnable.run();
+ };
+
+ mOverSweepUpdateListener = animation -> {
+ mOverSweepAngle = (float) animation.getAnimatedValue();
+ mInvalidateRunnable.run();
+ };
+ mOverSweepAnimationRunnable = () -> {
+ if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) {
+ mOverSweepAnimator.cancel();
+ }
+ mOverSweepAnimator = ValueAnimator.ofFloat(mOverSweepAngle, mMaxOverSweepAngle);
+ mOverSweepAnimator.setDuration(OVER_SWEEP_ANIMATION_DURATION_MS);
+ mOverSweepAnimator.addUpdateListener(mOverSweepUpdateListener);
+ mOverSweepAnimator.start();
+ };
+ }
+
+ /**
+ * Draws this segment to the given canvas.
+ */
+ public void draw(@NonNull Canvas canvas) {
+ Log.d(TAG, "draw: mProgress = " + mProgress);
+
+ final float halfPaddingPx = mStrokeWidthPx / 2f;
+
+ if (mProgress < 1f) {
+ // Draw the unfilled background color of the segment.
+ canvas.drawArc(
+ halfPaddingPx,
+ halfPaddingPx,
+ mBounds.right - halfPaddingPx,
+ mBounds.bottom - halfPaddingPx,
+ mStartAngle,
+ mSweepAngle,
+ false /* useCenter */,
+ mBackgroundPaint);
+ }
+
+ if (mProgress > 0f) {
+ // Draw the filled progress portion of the segment.
+ canvas.drawArc(
+ halfPaddingPx,
+ halfPaddingPx,
+ mBounds.right - halfPaddingPx,
+ mBounds.bottom - halfPaddingPx,
+ mStartAngle,
+ mSweepAngle * mProgress + mOverSweepAngle,
+ false /* useCenter */,
+ mProgressPaint);
+ }
+ }
+
+ /**
+ * @return Whether this segment is filled or in the process of being filled.
+ */
+ public boolean isFilledOrFilling() {
+ return mIsFilledOrFilling;
+ }
+
+ /**
+ * Updates the fill progress of this segment, animating if necessary.
+ *
+ * @param progress The new fill progress, in the range [0, 1].
+ */
+ public void updateProgress(float progress) {
+ updateProgress(progress, PROGRESS_ANIMATION_DURATION_MS);
+ }
+
+ private void updateProgress(float progress, long animationDurationMs) {
+ Log.d(TAG, "updateProgress: progress = " + progress
+ + ", duration = " + animationDurationMs);
+
+ if (mProgress == progress) {
+ Log.d(TAG, "updateProgress skipped: progress == mProgress");
+ return;
+ }
+
+ mIsFilledOrFilling = progress >= 1f;
+
+ if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
+ mProgressAnimator.cancel();
+ }
+
+ mProgressAnimator = ValueAnimator.ofFloat(mProgress, progress);
+ mProgressAnimator.setDuration(animationDurationMs);
+ mProgressAnimator.addUpdateListener(mProgressUpdateListener);
+ mProgressAnimator.start();
+ }
+
+ /**
+ * Queues and runs the completion animation for this segment.
+ */
+ public void startCompletionAnimation() {
+ final boolean hasCallback = mHandler.hasCallbacks(mOverSweepAnimationRunnable);
+ if (hasCallback || mOverSweepAngle >= mMaxOverSweepAngle) {
+ Log.d(TAG, "startCompletionAnimation skipped: hasCallback = " + hasCallback
+ + ", mOverSweepAngle = " + mOverSweepAngle);
+ return;
+ }
+
+ Log.d(TAG, "startCompletionAnimation: mProgress = " + mProgress
+ + ", mOverSweepAngle = " + mOverSweepAngle);
+
+ // Reset sweep angle back to zero if the animation is being rolled back.
+ if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) {
+ mOverSweepReverseAnimator.cancel();
+ mOverSweepAngle = 0f;
+ }
+
+ // Start filling the segment if it isn't already.
+ if (mProgress < 1f) {
+ updateProgress(1f, OVER_SWEEP_ANIMATION_DELAY_MS);
+ }
+
+ // Queue the animation to run after fill completes.
+ mHandler.postDelayed(mOverSweepAnimationRunnable, OVER_SWEEP_ANIMATION_DELAY_MS);
+ }
+
+ /**
+ * Cancels (and reverses, if necessary) a queued or running completion animation.
+ */
+ public void cancelCompletionAnimation() {
+ Log.d(TAG, "cancelCompletionAnimation: mProgress = " + mProgress
+ + ", mOverSweepAngle = " + mOverSweepAngle);
+
+ // Cancel the animation if it's queued or running.
+ mHandler.removeCallbacks(mOverSweepAnimationRunnable);
+ if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) {
+ mOverSweepAnimator.cancel();
+ }
+
+ // Roll back the animation if it has at least partially run.
+ if (mOverSweepAngle > 0f) {
+ if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) {
+ mOverSweepReverseAnimator.cancel();
+ }
+
+ final float completion = mOverSweepAngle / mMaxOverSweepAngle;
+ final long proratedDuration = (long) (OVER_SWEEP_ANIMATION_DURATION_MS * completion);
+ mOverSweepReverseAnimator = ValueAnimator.ofFloat(mOverSweepAngle, 0f);
+ mOverSweepReverseAnimator.setDuration(proratedDuration);
+ mOverSweepReverseAnimator.addUpdateListener(mOverSweepUpdateListener);
+ mOverSweepReverseAnimator.start();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
index 2cdf49d6fc3c..6f02c64e4cf7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -17,9 +17,12 @@
package com.android.systemui.biometrics;
import android.content.Context;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
@@ -32,20 +35,25 @@ import com.android.systemui.R;
*/
public class UdfpsEnrollView extends UdfpsAnimationView {
@NonNull private final UdfpsEnrollDrawable mFingerprintDrawable;
+ @NonNull private final UdfpsEnrollProgressBarDrawable mFingerprintProgressDrawable;
@NonNull private final Handler mHandler;
@NonNull private ImageView mFingerprintView;
+ @NonNull private ImageView mFingerprintProgressView;
public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mFingerprintDrawable = new UdfpsEnrollDrawable(mContext);
+ mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context);
mHandler = new Handler(Looper.getMainLooper());
}
@Override
protected void onFinishInflate() {
mFingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view);
+ mFingerprintProgressView = findViewById(R.id.udfps_enroll_animation_fp_progress_view);
mFingerprintView.setImageDrawable(mFingerprintDrawable);
+ mFingerprintProgressView.setImageDrawable(mFingerprintProgressDrawable);
}
@Override
@@ -53,15 +61,36 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
return mFingerprintDrawable;
}
+ void updateSensorLocation(@NonNull FingerprintSensorPropertiesInternal sensorProps) {
+ View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view);
+ final int sensorHeight = sensorProps.sensorRadius * 2;
+ final int sensorWidth = sensorHeight;
+ ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams();
+ params.width = sensorWidth;
+ params.height = sensorHeight;
+ fingerprintAccessibilityView.setLayoutParams(params);
+ fingerprintAccessibilityView.requestLayout();
+ }
+
void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
mFingerprintDrawable.setEnrollHelper(enrollHelper);
}
void onEnrollmentProgress(int remaining, int totalSteps) {
- mHandler.post(() -> mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps));
+ mHandler.post(() -> {
+ mFingerprintProgressDrawable.setEnrollmentProgress(remaining, totalSteps);
+ mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps);
+ });
+ }
+
+ void onEnrollmentHelp(int remaining, int totalSteps) {
+ mHandler.post(
+ () -> mFingerprintProgressDrawable.setEnrollmentProgress(remaining, totalSteps));
}
void onLastStepAcquired() {
- mHandler.post(mFingerprintDrawable::onLastStepAcquired);
+ mHandler.post(() -> {
+ mFingerprintProgressDrawable.onLastStepAcquired();
+ });
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index 3dab010d917c..6cdd1c8b0d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -33,16 +33,21 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
@NonNull private final UdfpsEnrollHelper mEnrollHelper;
@NonNull private final UdfpsEnrollHelper.Listener mEnrollHelperListener =
new UdfpsEnrollHelper.Listener() {
- @Override
- public void onEnrollmentProgress(int remaining, int totalSteps) {
- mView.onEnrollmentProgress(remaining, totalSteps);
- }
+ @Override
+ public void onEnrollmentProgress(int remaining, int totalSteps) {
+ mView.onEnrollmentProgress(remaining, totalSteps);
+ }
- @Override
- public void onLastStepAcquired() {
- mView.onLastStepAcquired();
- }
- };
+ @Override
+ public void onEnrollmentHelp(int remaining, int totalSteps) {
+ mView.onEnrollmentHelp(remaining, totalSteps);
+ }
+
+ @Override
+ public void onLastStepAcquired() {
+ mView.onLastStepAcquired();
+ }
+ };
protected UdfpsEnrollViewController(
@NonNull UdfpsEnrollView view,
@@ -74,7 +79,7 @@ public class UdfpsEnrollViewController extends UdfpsAnimationViewController<Udfp
@NonNull
@Override
public PointF getTouchTranslation() {
- if (!mEnrollHelper.isCenterEnrollmentComplete()) {
+ if (!mEnrollHelper.isGuidedEnrollmentStage()) {
return new PointF(0, 0);
} else {
return mEnrollHelper.getNextGuidedEnrollmentPoint();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index d46426a03621..9015396d26ab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -155,6 +155,13 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
updateAlpha();
}
+ /**
+ * @return alpha between 0 and 255
+ */
+ int getUnpausedAlpha() {
+ return mAlpha;
+ }
+
@Override
protected int updateAlpha() {
int alpha = super.updateAlpha();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 4896305daa2e..888672316c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -34,12 +34,12 @@ import com.android.systemui.statusbar.phone.KeyguardBouncer;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-
/**
* Class that coordinates non-HBM animations during keyguard authentication.
*/
@@ -50,6 +50,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
@NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
@NonNull private final ConfigurationController mConfigurationController;
+ @NonNull private final KeyguardStateController mKeyguardStateController;
@NonNull private final UdfpsController mUdfpsController;
private boolean mShowingUdfpsBouncer;
@@ -60,6 +61,9 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
private float mTransitionToFullShadeProgress;
private float mLastDozeAmount;
+ private float mStatusBarExpansion;
+ private boolean mLaunchTransitionFadingAway;
+
/**
* hidden amount of pin/pattern/password bouncer
* {@link KeyguardBouncer#EXPANSION_VISIBLE} (0f) to
@@ -79,6 +83,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull KeyguardViewMediator keyguardViewMediator,
@NonNull LockscreenShadeTransitionController transitionController,
@NonNull ConfigurationController configurationController,
+ @NonNull KeyguardStateController keyguardStateController,
@NonNull UdfpsController udfpsController) {
super(view, statusBarStateController, statusBar, dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
@@ -87,6 +92,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mKeyguardViewMediator = keyguardViewMediator;
mLockScreenShadeTransitionController = transitionController;
mConfigurationController = configurationController;
+ mKeyguardStateController = keyguardStateController;
mUdfpsController = udfpsController;
}
@@ -105,11 +111,14 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mUdfpsRequested = false;
+ mLaunchTransitionFadingAway = mKeyguardStateController.isLaunchTransitionFadingAway();
+ mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
mStatusBarState = mStatusBarStateController.getState();
mQsExpanded = mKeyguardViewManager.isQsExpanded();
mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
mConfigurationController.addCallback(mConfigurationListener);
+ mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener);
updateAlpha();
updatePauseAuth();
@@ -122,10 +131,12 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
super.onViewDetached();
mFaceDetectRunning = false;
+ mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
mStatusBarStateController.removeCallback(mStateListener);
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
mConfigurationController.removeCallback(mConfigurationListener);
+ mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener);
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
@@ -140,9 +151,11 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
pw.println("mQsExpanded=" + mQsExpanded);
pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
- pw.println("mAlpha=" + mView.getAlpha());
+ pw.println("mStatusBarExpansion=" + mStatusBarExpansion);
+ pw.println("unpausedAlpha=" + mView.getUnpausedAlpha());
pw.println("mUdfpsRequested=" + mUdfpsRequested);
pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
+ pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway);
}
/**
@@ -154,10 +167,10 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
return false;
}
+ boolean udfpsAffordanceWasNotShowing = shouldPauseAuth();
mShowingUdfpsBouncer = show;
- updatePauseAuth();
if (mShowingUdfpsBouncer) {
- if (mStatusBarState == StatusBarState.SHADE_LOCKED) {
+ if (udfpsAffordanceWasNotShowing) {
mView.animateInUdfpsBouncer(null);
}
@@ -170,6 +183,8 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
} else {
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
}
+ updateAlpha();
+ updatePauseAuth();
return true;
}
@@ -189,6 +204,10 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
return false;
}
+ if (mLaunchTransitionFadingAway) {
+ return true;
+ }
+
if (mStatusBarState != KEYGUARD) {
return true;
}
@@ -237,12 +256,17 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
}
private void updateAlpha() {
- // fade icon on transition to showing bouncer
+ // fade icon on transitions to showing the status bar, but if mUdfpsRequested, then
+ // the keyguard is occluded by some application - so instead use the input bouncer
+ // hidden amount to determine the fade
+ float expansion = mUdfpsRequested ? mInputBouncerHiddenAmount : mStatusBarExpansion;
int alpha = mShowingUdfpsBouncer ? 255
: (int) MathUtils.constrain(
- MathUtils.map(.5f, .9f, 0f, 255f, mInputBouncerHiddenAmount),
+ MathUtils.map(.5f, .9f, 0f, 255f, expansion),
0f, 255f);
- alpha *= (1.0f - mTransitionToFullShadeProgress);
+ if (!mShowingUdfpsBouncer) {
+ alpha *= (1.0f - mTransitionToFullShadeProgress);
+ }
mView.setUnpausedAlpha(alpha);
}
@@ -287,6 +311,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
public void requestUdfps(boolean request, int color) {
mUdfpsRequested = request;
mView.requestUdfps(request, color);
+ updateAlpha();
updatePauseAuth();
}
@@ -356,4 +381,23 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mView.updateColor();
}
};
+
+ private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
+ new StatusBar.ExpansionChangedListener() {
+ @Override
+ public void onExpansionChanged(float expansion, boolean expanded) {
+ mStatusBarExpansion = expansion;
+ updateAlpha();
+ }
+ };
+
+ private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onLaunchTransitionFadingAwayChanged() {
+ mLaunchTransitionFadingAway =
+ mKeyguardStateController.isLaunchTransitionFadingAway();
+ updatePauseAuth();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index e1349f2aba6d..40c28fab51b8 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -21,6 +21,7 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHT
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.LOCK_ICON;
import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
import android.graphics.Point;
@@ -89,7 +90,9 @@ class ZigZagClassifier extends FalsingClassifier {
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
- if (interactionType == BRIGHTNESS_SLIDER || interactionType == SHADE_DRAG) {
+ if (interactionType == BRIGHTNESS_SLIDER
+ || interactionType == SHADE_DRAG
+ || interactionType == LOCK_ICON) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 41964652ac49..657d9246be8f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -214,6 +214,14 @@ public class DozeLog implements Dumpable {
}
/**
+ * Appends display state delayed by UDFPS event to the logs
+ * @param delayedDisplayState the display screen state that was delayed
+ */
+ public void traceDisplayStateDelayedByUdfps(int delayedDisplayState) {
+ mLogger.logDisplayStateDelayedByUdfps(delayedDisplayState);
+ }
+
+ /**
* Appends display state changed event to the logs
* @param displayState new DozeMachine state
*/
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index 9bc74be9b9c3..fe37d49980b2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -160,6 +160,14 @@ class DozeLogger @Inject constructor(
})
}
+ fun logDisplayStateDelayedByUdfps(delayedDisplayState: Int) {
+ buffer.log(TAG, INFO, {
+ str1 = Display.stateToString(delayedDisplayState)
+ }, {
+ "Delaying display state change to: $str1 due to UDFPS activity"
+ })
+ }
+
fun logDisplayStateChanged(displayState: Int) {
buffer.log(TAG, INFO, {
str1 = Display.stateToString(displayState)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 470d2f364c1c..8d4ac75a0748 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -36,6 +36,7 @@ import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.doze.dagger.WrappedService;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.util.sensors.AsyncSensorManager;
import java.io.PrintWriter;
@@ -55,6 +56,16 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
"com.android.systemui.doze.AOD_BRIGHTNESS";
protected static final String BRIGHTNESS_BUCKET = "brightness_bucket";
+ /**
+ * Just before the screen times out from user inactivity, DisplayPowerController dims the screen
+ * brightness to the lower of {@link #mScreenBrightnessDim}, or the current brightness minus
+ * DisplayPowerController#SCREEN_DIM_MINIMUM_REDUCTION_FLOAT.
+ *
+ * This value is 0.04f * 255, which converts SCREEN_DIM_MINIMUM_REDUCTION_FLOAT to the integer
+ * brightness values used by doze.
+ */
+ private static final int SCREEN_DIM_MINIMUM_REDUCTION_INT = 10;
+
private final Context mContext;
private final DozeMachine.Service mDozeService;
private final DozeHost mDozeHost;
@@ -81,13 +92,16 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
*/
private int mDebugBrightnessBucket = -1;
+ private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+
@Inject
public DozeScreenBrightness(Context context, @WrappedService DozeMachine.Service service,
AsyncSensorManager sensorManager,
@BrightnessSensor Optional<Sensor> lightSensorOptional, DozeHost host, Handler handler,
AlwaysOnDisplayPolicy alwaysOnDisplayPolicy,
WakefulnessLifecycle wakefulnessLifecycle,
- DozeParameters dozeParameters) {
+ DozeParameters dozeParameters,
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController) {
mContext = context;
mDozeService = service;
mSensorManager = sensorManager;
@@ -96,6 +110,7 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
mDozeParameters = dozeParameters;
mDozeHost = host;
mHandler = handler;
+ mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mDefaultDozeBrightness = alwaysOnDisplayPolicy.defaultDozeBrightness;
mScreenBrightnessDim = alwaysOnDisplayPolicy.dimBrightness;
@@ -146,14 +161,15 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
}
}
- private void updateBrightnessAndReady(boolean force) {
+ public void updateBrightnessAndReady(boolean force) {
if (force || mRegistered || mDebugBrightnessBucket != -1) {
int sensorValue = mDebugBrightnessBucket == -1
? mLastSensorValue : mDebugBrightnessBucket;
int brightness = computeBrightness(sensorValue);
boolean brightnessReady = brightness > 0;
if (brightnessReady) {
- mDozeService.setDozeScreenBrightness(clampToUserSetting(brightness));
+ mDozeService.setDozeScreenBrightness(
+ clampToDimBrightnessForScreenOff(clampToUserSetting(brightness)));
}
int scrimOpacity = -1;
@@ -205,13 +221,21 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi
/**
* Clamp the brightness to the dim brightness value used by PowerManagerService just before the
* device times out and goes to sleep, if we are sleeping from a timeout. This ensures that we
- * don't raise the brightness back to the user setting before playing the screen off animation.
+ * don't raise the brightness back to the user setting before or during the screen off
+ * animation.
*/
private int clampToDimBrightnessForScreenOff(int brightness) {
- if (mDozeParameters.shouldControlUnlockedScreenOff()
+ if (mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
&& mWakefulnessLifecycle.getLastSleepReason()
== PowerManager.GO_TO_SLEEP_REASON_TIMEOUT) {
- return Math.min(mScreenBrightnessDim, brightness);
+ return Math.max(
+ PowerManager.BRIGHTNESS_OFF,
+ // Use the lower of either the dim brightness, or the current brightness reduced
+ // by the minimum dim amount. This is the same logic used in
+ // DisplayPowerController#updatePowerState to apply a minimum dim amount.
+ Math.min(
+ brightness - SCREEN_DIM_MINIMUM_REDUCTION_INT,
+ mScreenBrightnessDim));
} else {
return brightness;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 8c50a16b566f..038be48b53ee 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -26,6 +26,11 @@ import android.os.Handler;
import android.util.Log;
import android.view.Display;
+import androidx.annotation.Nullable;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.UdfpsController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.doze.dagger.WrappedService;
@@ -34,6 +39,7 @@ import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
import javax.inject.Inject;
+import javax.inject.Provider;
/**
* Controls the screen when dozing.
@@ -56,23 +62,64 @@ public class DozeScreenState implements DozeMachine.Part {
*/
public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 2500;
+ /**
+ * Add an extra delay to the transition to DOZE when udfps is current activated before
+ * the display state transitions from ON => DOZE.
+ */
+ public static final int UDFPS_DISPLAY_STATE_DELAY = 1200;
+
private final DozeMachine.Service mDozeService;
private final Handler mHandler;
private final Runnable mApplyPendingScreenState = this::applyPendingScreenState;
private final DozeParameters mParameters;
private final DozeHost mDozeHost;
+ private final AuthController mAuthController;
+ private final Provider<UdfpsController> mUdfpsControllerProvider;
+ @Nullable private UdfpsController mUdfpsController;
+ private final DozeLog mDozeLog;
+ private final DozeScreenBrightness mDozeScreenBrightness;
private int mPendingScreenState = Display.STATE_UNKNOWN;
private SettableWakeLock mWakeLock;
@Inject
- public DozeScreenState(@WrappedService DozeMachine.Service service, @Main Handler handler,
- DozeHost host, DozeParameters parameters, WakeLock wakeLock) {
+ public DozeScreenState(
+ @WrappedService DozeMachine.Service service,
+ @Main Handler handler,
+ DozeHost host,
+ DozeParameters parameters,
+ WakeLock wakeLock,
+ AuthController authController,
+ Provider<UdfpsController> udfpsControllerProvider,
+ DozeLog dozeLog,
+ DozeScreenBrightness dozeScreenBrightness) {
mDozeService = service;
mHandler = handler;
mParameters = parameters;
mDozeHost = host;
mWakeLock = new SettableWakeLock(wakeLock, TAG);
+ mAuthController = authController;
+ mUdfpsControllerProvider = udfpsControllerProvider;
+ mDozeLog = dozeLog;
+ mDozeScreenBrightness = dozeScreenBrightness;
+
+ updateUdfpsController();
+ if (mUdfpsController == null) {
+ mAuthController.addCallback(new AuthController.Callback() {
+ @Override
+ public void onAllAuthenticatorsRegistered() {
+ updateUdfpsController();
+ }
+ });
+ }
+ }
+
+ private void updateUdfpsController() {
+ if (mAuthController.isUdfpsEnrolled(KeyguardUpdateMonitor.getCurrentUser())) {
+ mUdfpsController = mUdfpsControllerProvider.get();
+ } else {
+ mUdfpsController = null;
+ }
}
@Override
@@ -110,21 +157,28 @@ public class DozeScreenState implements DozeMachine.Part {
mPendingScreenState = screenState;
// Delay screen state transitions even longer while animations are running.
- boolean shouldDelayTransition = newState == DOZE_AOD
+ boolean shouldDelayTransitionEnteringDoze = newState == DOZE_AOD
&& mParameters.shouldControlScreenOff() && !turningOn;
- if (shouldDelayTransition) {
+ // Delay screen state transition longer if UDFPS is actively authenticating a fp
+ boolean shouldDelayTransitionForUDFPS = newState == DOZE_AOD
+ && mUdfpsController != null && mUdfpsController.isFingerDown();
+
+ if (shouldDelayTransitionEnteringDoze || shouldDelayTransitionForUDFPS) {
mWakeLock.setAcquired(true);
}
if (!messagePending) {
if (DEBUG) {
Log.d(TAG, "Display state changed to " + screenState + " delayed by "
- + (shouldDelayTransition ? ENTER_DOZE_DELAY : 1));
+ + (shouldDelayTransitionEnteringDoze ? ENTER_DOZE_DELAY : 1));
}
- if (shouldDelayTransition) {
+ if (shouldDelayTransitionEnteringDoze) {
mHandler.postDelayed(mApplyPendingScreenState, ENTER_DOZE_DELAY);
+ } else if (shouldDelayTransitionForUDFPS) {
+ mDozeLog.traceDisplayStateDelayedByUdfps(mPendingScreenState);
+ mHandler.postDelayed(mApplyPendingScreenState, UDFPS_DISPLAY_STATE_DELAY);
} else {
mHandler.post(mApplyPendingScreenState);
}
@@ -139,6 +193,12 @@ public class DozeScreenState implements DozeMachine.Part {
}
private void applyPendingScreenState() {
+ if (mUdfpsController != null && mUdfpsController.isFingerDown()) {
+ mDozeLog.traceDisplayStateDelayedByUdfps(mPendingScreenState);
+ mHandler.postDelayed(mApplyPendingScreenState, UDFPS_DISPLAY_STATE_DELAY);
+ return;
+ }
+
applyScreenState(mPendingScreenState);
mPendingScreenState = Display.STATE_UNKNOWN;
}
@@ -147,6 +207,12 @@ public class DozeScreenState implements DozeMachine.Part {
if (screenState != Display.STATE_UNKNOWN) {
if (DEBUG) Log.d(TAG, "setDozeScreenState(" + screenState + ")");
mDozeService.setDozeScreenState(screenState);
+ if (screenState == Display.STATE_DOZE) {
+ // If we're entering doze, update the doze screen brightness. We might have been
+ // clamping it to the dim brightness during the screen off animation, and we should
+ // now change it to the brightness we actually want according to the sensor.
+ mDozeScreenBrightness.updateBrightnessAndReady(false /* force */);
+ }
mPendingScreenState = Display.STATE_UNKNOWN;
mWakeLock.setAcquired(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index a641ad4b338b..c4508e043c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -97,7 +97,7 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks
int backgroundAlpha = (int) (ScrimController.BUSY_SCRIM_ALPHA * 255);
background.setAlpha(backgroundAlpha);
mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
- mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
+ (int) mBlurUtils.blurRadiusOfRatio(1), backgroundAlpha == 255);
} else {
float backgroundAlpha = mContext.getResources().getFloat(
com.android.systemui.R.dimen.shutdown_scrim_behind_alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 09810b3db107..5751c0fddde0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -821,6 +821,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
private final KeyguardStateController mKeyguardStateController;
private final Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+ private boolean mWallpaperSupportsAmbientMode;
/**
* Injected constructor. See {@link KeyguardModule}.
@@ -2096,13 +2097,14 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
int flags = 0;
if (mKeyguardViewControllerLazy.get().shouldDisableWindowAnimationsForUnlock()
- || (mWakeAndUnlocking && !mPulsing)
- || isAnimatingBetweenKeyguardAndSurfaceBehindOrWillBe()) {
+ || mWakeAndUnlocking && !mWallpaperSupportsAmbientMode) {
flags |= WindowManagerPolicyConstants
.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
}
if (mKeyguardViewControllerLazy.get().isGoingToNotificationShade()
- || (mWakeAndUnlocking && mPulsing)) {
+ || mWakeAndUnlocking && mWallpaperSupportsAmbientMode) {
+ // When the wallpaper supports ambient mode, the scrim isn't fully opaque during
+ // wake and unlock and we should fade in the app on top of the wallpaper
flags |= WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
}
if (mKeyguardViewControllerLazy.get().isUnlockWithWallpaper()) {
@@ -2791,6 +2793,15 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable,
mPulsing = pulsing;
}
+ /**
+ * Set if the wallpaper supports ambient mode. This is used to trigger the right animation.
+ * In case it does support it, we have to fade in the incoming app, otherwise we'll reveal it
+ * with the light reveal scrim.
+ */
+ public void setWallpaperSupportsAmbientMode(boolean supportsAmbientMode) {
+ mWallpaperSupportsAmbientMode = supportsAmbientMode;
+ }
+
private static class StartKeyguardExitAnimParams {
@WindowManager.TransitionOldType int mTransit;
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 89786ee880ad..a617850ef0ae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -139,7 +139,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
+ " with ducking", e);
}
player.start();
- if (DEBUG) { Log.d(mTag, "player.start"); }
+ if (DEBUG) { Log.d(mTag, "player.start piid:" + player.getPlayerIId()); }
} catch (Exception e) {
if (player != null) {
player.release();
@@ -155,7 +155,13 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
mPlayer = player;
}
if (mp != null) {
- if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
+ if (DEBUG) {
+ Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId());
+ }
+ mp.pause();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) { }
mp.release();
}
this.notify();
@@ -244,6 +250,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
try {
mp.stop();
} catch (Exception e) { }
+ if (DEBUG) {
+ Log.i(mTag, "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to notif cancelled");
+ }
mp.release();
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
@@ -284,7 +294,7 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
public void onCompletion(MediaPlayer mp) {
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
- if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus");
+ if (DEBUG) Log.d(mTag, "onCompletion() abandoning AudioFocus");
mAudioManagerWithAudioFocus.abandonAudioFocus(null);
mAudioManagerWithAudioFocus = null;
} else {
@@ -310,6 +320,10 @@ public class NotificationPlayer implements OnCompletionListener, OnErrorListener
}
}
if (mp != null) {
+ if (DEBUG) {
+ Log.i("NotificationPlayer", "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to onCompletion");
+ }
mp.release();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 541ee2c4fe8f..4a75810f86db 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -51,6 +51,7 @@ import com.android.systemui.qs.external.TileServices;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -95,6 +96,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
private final UiEventLogger mUiEventLogger;
private final InstanceIdSequence mInstanceIdSequence;
private final CustomTileStatePersister mCustomTileStatePersister;
+ private final FeatureFlags mFeatureFlags;
private final List<Callback> mCallbacks = new ArrayList<>();
private AutoTileManager mAutoTiles;
@@ -122,7 +124,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
UiEventLogger uiEventLogger,
UserTracker userTracker,
SecureSettings secureSettings,
- CustomTileStatePersister customTileStatePersister
+ CustomTileStatePersister customTileStatePersister,
+ FeatureFlags featureFlags
) {
mIconController = iconController;
mContext = context;
@@ -144,6 +147,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
mUserTracker = userTracker;
mSecureSettings = secureSettings;
mCustomTileStatePersister = customTileStatePersister;
+ mFeatureFlags = featureFlags;
mainHandler.post(() -> {
// This is technically a hack to avoid circular dependency of
@@ -265,7 +269,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
if (newValue == null && UserManager.isDeviceInDemoMode(mContext)) {
newValue = mContext.getResources().getString(R.string.quick_settings_tiles_retail_mode);
}
- final List<String> tileSpecs = loadTileSpecs(mContext, newValue);
+ final List<String> tileSpecs = loadTileSpecs(mContext, newValue, mFeatureFlags);
int currentUser = mUserTracker.getUserId();
if (currentUser != mCurrentUser) {
mUserContext = mUserTracker.getUserContext();
@@ -334,7 +338,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
if (newTiles.isEmpty() && !tileSpecs.isEmpty()) {
// If we didn't manage to create any tiles, set it to empty (default)
Log.d(TAG, "No valid tiles on tuning changed. Setting to default.");
- changeTiles(currentSpecs, loadTileSpecs(mContext, ""));
+ changeTiles(currentSpecs, loadTileSpecs(mContext, "", mFeatureFlags));
} else {
for (int i = 0; i < mCallbacks.size(); i++) {
mCallbacks.get(i).onTilesChanged();
@@ -389,7 +393,7 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
private void changeTileSpecs(Predicate<List<String>> changeFunction) {
final String setting = mSecureSettings.getStringForUser(TILES_SETTING, mCurrentUser);
- final List<String> tileSpecs = loadTileSpecs(mContext, setting);
+ final List<String> tileSpecs = loadTileSpecs(mContext, setting, mFeatureFlags);
if (changeFunction.test(tileSpecs)) {
saveTilesToSettings(tileSpecs);
}
@@ -478,7 +482,8 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
throw new RuntimeException("Default factory didn't create view for " + tile.getTileSpec());
}
- protected static List<String> loadTileSpecs(Context context, String tileList) {
+ protected static List<String> loadTileSpecs(
+ Context context, String tileList, FeatureFlags featureFlags) {
final Resources res = context.getResources();
if (TextUtils.isEmpty(tileList)) {
@@ -511,6 +516,21 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
}
}
}
+ if (featureFlags.isProviderModelSettingEnabled()) {
+ if (!tiles.contains("internet")) {
+ if (tiles.contains("wifi")) {
+ // Replace the WiFi with Internet, and remove the Cell
+ tiles.set(tiles.indexOf("wifi"), "internet");
+ tiles.remove("cell");
+ } else if (tiles.contains("cell")) {
+ // Replace the Cell with Internet
+ tiles.set(tiles.indexOf("cell"), "internet");
+ }
+ } else {
+ tiles.remove("wifi");
+ tiles.remove("cell");
+ }
+ }
return tiles;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 3c2f35b954ea..f2832b3d45ff 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -41,6 +41,7 @@ import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.leak.GarbageMonitor;
import java.util.ArrayList;
@@ -62,6 +63,7 @@ public class TileQueryHelper {
private final Executor mBgExecutor;
private final Context mContext;
private final UserTracker mUserTracker;
+ private final FeatureFlags mFeatureFlags;
private TileStateListener mListener;
private boolean mFinished;
@@ -71,12 +73,14 @@ public class TileQueryHelper {
Context context,
UserTracker userTracker,
@Main Executor mainExecutor,
- @Background Executor bgExecutor
+ @Background Executor bgExecutor,
+ FeatureFlags featureFlags
) {
mContext = context;
mMainExecutor = mainExecutor;
mBgExecutor = bgExecutor;
mUserTracker = userTracker;
+ mFeatureFlags = featureFlags;
}
public void setListener(TileStateListener listener) {
@@ -117,6 +121,10 @@ public class TileQueryHelper {
}
final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
+ if (mFeatureFlags.isProviderModelSettingEnabled()) {
+ possibleTiles.remove("cell");
+ possibleTiles.remove("wifi");
+ }
for (String spec : possibleTiles) {
// Only add current and stock tiles that can be created from QSFactoryImpl.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index dce19cf86b35..cfbe3b29783a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -54,22 +54,22 @@ open class BlurUtils @Inject constructor(
/**
* Translates a ratio from 0 to 1 to a blur radius in pixels.
*/
- fun blurRadiusOfRatio(ratio: Float): Int {
+ fun blurRadiusOfRatio(ratio: Float): Float {
if (ratio == 0f) {
- return 0
+ return 0f
}
- return MathUtils.lerp(minBlurRadius.toFloat(), maxBlurRadius.toFloat(), ratio).toInt()
+ return MathUtils.lerp(minBlurRadius.toFloat(), maxBlurRadius.toFloat(), ratio)
}
/**
* Translates a blur radius in pixels to a ratio between 0 to 1.
*/
- fun ratioOfBlurRadius(blur: Int): Float {
- if (blur == 0) {
+ fun ratioOfBlurRadius(blur: Float): Float {
+ if (blur == 0f) {
return 0f
}
return MathUtils.map(minBlurRadius.toFloat(), maxBlurRadius.toFloat(),
- 0f /* maxStart */, 1f /* maxStop */, blur.toFloat())
+ 0f /* maxStart */, 1f /* maxStop */, blur)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 503b5c0ee4b0..1c933505172f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -811,13 +811,8 @@ public class KeyguardIndicationController {
mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
}
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
- if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
- showTransientIndication(mContext.getString(R.string.keyguard_unlock_press),
- false /* isError */, true /* hideOnScreenOff */);
- } else {
- showTransientIndication(mContext.getString(R.string.keyguard_unlock),
- false /* isError */, true /* hideOnScreenOff */);
- }
+ showTransientIndication(mContext.getString(R.string.keyguard_unlock),
+ false /* isError */, true /* hideOnScreenOff */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 002c9c7d2544..b8334272c157 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -68,7 +68,7 @@ class NotificationShadeDepthController @Inject constructor(
private const val VELOCITY_SCALE = 100f
private const val MAX_VELOCITY = 3000f
private const val MIN_VELOCITY = -MAX_VELOCITY
- private const val INTERACTION_BLUR_FRACTION = 0.4f
+ private const val INTERACTION_BLUR_FRACTION = 0.8f
private const val ANIMATION_BLUR_FRACTION = 1f - INTERACTION_BLUR_FRACTION
private const val TAG = "DepthController"
}
@@ -92,8 +92,6 @@ class NotificationShadeDepthController @Inject constructor(
// Only for dumpsys
private var lastAppliedBlur = 0
- @VisibleForTesting
- var shadeSpring = DepthAnimation()
var shadeAnimation = DepthAnimation()
@VisibleForTesting
@@ -101,12 +99,16 @@ class NotificationShadeDepthController @Inject constructor(
var brightnessMirrorVisible: Boolean = false
set(value) {
field = value
- brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f)
+ brightnessMirrorSpring.animateTo(if (value) blurUtils.blurRadiusOfRatio(1f).toInt()
else 0)
}
var qsPanelExpansion = 0f
set(value) {
+ if (value.isNaN()) {
+ Log.w(TAG, "Invalid qs expansion")
+ return
+ }
if (field == value) return
field = value
scheduleUpdate()
@@ -134,15 +136,13 @@ class NotificationShadeDepthController @Inject constructor(
field = value
scheduleUpdate()
- if (shadeSpring.radius == 0 && shadeAnimation.radius == 0) {
+ if (shadeExpansion == 0f && shadeAnimation.radius == 0f) {
return
}
// Do not remove blurs when we're re-enabling them
if (!value) {
return
}
- shadeSpring.animateTo(0)
- shadeSpring.finishIfRunning()
shadeAnimation.animateTo(0)
shadeAnimation.finishIfRunning()
@@ -161,7 +161,7 @@ class NotificationShadeDepthController @Inject constructor(
/**
* Blur radius of the wake-up animation on this frame.
*/
- private var wakeAndUnlockBlurRadius = 0
+ private var wakeAndUnlockBlurRadius = 0f
set(value) {
if (field == value) return
field = value
@@ -174,26 +174,30 @@ class NotificationShadeDepthController @Inject constructor(
@VisibleForTesting
val updateBlurCallback = Choreographer.FrameCallback {
updateScheduled = false
- val normalizedBlurRadius = MathUtils.constrain(shadeAnimation.radius,
- blurUtils.minBlurRadius, blurUtils.maxBlurRadius)
- var combinedBlur = (shadeSpring.radius * INTERACTION_BLUR_FRACTION +
- normalizedBlurRadius * ANIMATION_BLUR_FRACTION).toInt()
+ val animationRadius = MathUtils.constrain(shadeAnimation.radius,
+ blurUtils.minBlurRadius.toFloat(), blurUtils.maxBlurRadius.toFloat())
+ val expansionRadius = blurUtils.blurRadiusOfRatio(
+ Interpolators.getNotificationScrimAlpha(
+ if (shouldApplyShadeBlur()) shadeExpansion else 0f, false))
+ var combinedBlur = (expansionRadius * INTERACTION_BLUR_FRACTION +
+ animationRadius * ANIMATION_BLUR_FRACTION)
val qsExpandedRatio = qsPanelExpansion * shadeExpansion
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
- var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius).toFloat()
+ var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius)
if (blursDisabledForAppLaunch) {
shadeRadius = 0f
}
+ var zoomOut = MathUtils.saturate(blurUtils.ratioOfBlurRadius(shadeRadius))
var blur = shadeRadius.toInt()
// Make blur be 0 if it is necessary to stop blur effect.
if (scrimsVisible) {
blur = 0
+ zoomOut = 0f
}
- val zoomOut = blurUtils.ratioOfBlurRadius(blur)
if (!blurUtils.supportsBlursOnWindows()) {
blur = 0
@@ -266,12 +270,11 @@ class NotificationShadeDepthController @Inject constructor(
override fun onStateChanged(newState: Int) {
updateShadeAnimationBlur(
shadeExpansion, prevTracking, prevShadeVelocity, prevShadeDirection)
- updateShadeBlur()
+ scheduleUpdate()
}
override fun onDozingChanged(isDozing: Boolean) {
if (isDozing) {
- shadeSpring.finishIfRunning()
shadeAnimation.finishIfRunning()
brightnessMirrorSpring.finishIfRunning()
}
@@ -336,7 +339,7 @@ class NotificationShadeDepthController @Inject constructor(
prevTracking = tracking
prevTimestamp = timestamp
- updateShadeBlur()
+ scheduleUpdate()
}
private fun updateShadeAnimationBlur(
@@ -399,15 +402,7 @@ class NotificationShadeDepthController @Inject constructor(
}
shadeAnimation.setStartVelocity(velocity)
- shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized))
- }
-
- private fun updateShadeBlur() {
- var newBlur = 0
- if (shouldApplyShadeBlur()) {
- newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion)
- }
- shadeSpring.animateTo(newBlur)
+ shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized).toInt())
}
private fun scheduleUpdate(viewToBlur: View? = null) {
@@ -433,7 +428,8 @@ class NotificationShadeDepthController @Inject constructor(
IndentingPrintWriter(pw, " ").let {
it.println("StatusBarWindowBlurController:")
it.increaseIndent()
- it.println("shadeRadius: ${shadeSpring.radius}")
+ it.println("shadeExpansion: $shadeExpansion")
+ it.println("shouldApplyShaeBlur: ${shouldApplyShadeBlur()}")
it.println("shadeAnimation: ${shadeAnimation.radius}")
it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
@@ -452,7 +448,7 @@ class NotificationShadeDepthController @Inject constructor(
/**
* Blur radius visible on the UI, in pixels.
*/
- var radius = 0
+ var radius = 0f
/**
* Depth ratio of the current blur radius.
@@ -473,12 +469,12 @@ class NotificationShadeDepthController @Inject constructor(
private var springAnimation = SpringAnimation(this, object :
FloatPropertyCompat<DepthAnimation>("blurRadius") {
override fun setValue(rect: DepthAnimation?, value: Float) {
- radius = value.toInt()
+ radius = value
scheduleUpdate(view)
}
override fun getValue(rect: DepthAnimation?): Float {
- return radius.toFloat()
+ return radius
}
})
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt b/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
index 146046b33375..5175977d4e81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/charging/RippleShader.kt
@@ -147,8 +147,12 @@ class RippleShader internal constructor() : RuntimeShader(SHADER, false) {
val fadeIn = subProgress(0f, 0.1f, value)
val fadeOutNoise = subProgress(0.4f, 1f, value)
- val fadeOutRipple = subProgress(0.3f, 1f, value)
- val fadeCircle = subProgress(0f, 0.2f, value)
+ var fadeOutRipple = 0f
+ var fadeCircle = 0f
+ if (shouldFadeOutRipple) {
+ fadeCircle = subProgress(0f, 0.2f, value)
+ fadeOutRipple = subProgress(0.3f, 1f, value)
+ }
setUniform("in_fadeSparkle", Math.min(fadeIn, 1 - fadeOutNoise))
setUniform("in_fadeCircle", 1 - fadeCircle)
setUniform("in_fadeRing", Math.min(fadeIn, 1 - fadeOutRipple))
@@ -200,4 +204,6 @@ class RippleShader internal constructor() : RuntimeShader(SHADER, false) {
field = value
setUniform("in_pixelDensity", value)
}
+
+ var shouldFadeOutRipple: Boolean = true
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index 86c90c7bcb2e..9eb95c409009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.row;
-import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -28,15 +27,12 @@ import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.ViewState;
public class FooterView extends StackScrollerDecorView {
- private final int mClearAllTopPadding;
private FooterViewButton mDismissButton;
private FooterViewButton mManageButton;
private boolean mShowHistory;
public FooterView(Context context, AttributeSet attrs) {
super(context, attrs);
- mClearAllTopPadding = context.getResources().getDimensionPixelSize(
- R.dimen.clear_all_padding_top);
}
@Override
@@ -55,11 +51,6 @@ public class FooterView extends StackScrollerDecorView {
mManageButton = findViewById(R.id.manage_text);
}
- public void setTextColor(@ColorInt int color) {
- mManageButton.setTextColor(color);
- mDismissButton.setTextColor(color);
- }
-
public void setManageButtonClickListener(OnClickListener listener) {
mManageButton.setOnClickListener(listener);
}
@@ -95,21 +86,25 @@ public class FooterView extends StackScrollerDecorView {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- int textColor = getResources().getColor(R.color.notif_pill_text);
- Resources.Theme theme = getContext().getTheme();
- mDismissButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
- mDismissButton.setTextColor(textColor);
- mManageButton.setBackground(
- getResources().getDrawable(R.drawable.notif_footer_btn_background, theme));
- mManageButton = findViewById(R.id.manage_text);
+ updateColors();
mDismissButton.setText(R.string.clear_all_notifications_text);
- mManageButton.setTextColor(textColor);
mDismissButton.setContentDescription(
mContext.getString(R.string.accessibility_clear_all));
showHistory(mShowHistory);
}
+ /**
+ * Update the text and background colors for the current color palette and night mode setting.
+ */
+ public void updateColors() {
+ Resources.Theme theme = mContext.getTheme();
+ int textColor = getResources().getColor(R.color.notif_pill_text, theme);
+ mDismissButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ mDismissButton.setTextColor(textColor);
+ mManageButton.setBackground(theme.getDrawable(R.drawable.notif_footer_btn_background));
+ mManageButton.setTextColor(textColor);
+ }
+
@Override
public ExpandableViewState createExpandableViewState() {
return new FooterViewState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 289c32f17b31..0660daab3720 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -4231,7 +4231,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
final @ColorInt int textColor =
Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary);
mSectionsManager.setHeaderForegroundColor(textColor);
- mFooterView.setTextColor(textColor);
+ mFooterView.updateColors();
mEmptyShadeView.setTextColor(textColor);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 6e201048abdb..2c76cfeff733 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -116,7 +116,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
/**
* Mode in which fingerprint unlocks the device or passive auth (ie face auth) unlocks the
- * device while being requested when keyguard is occluded.
+ * device while being requested when keyguard is occluded or showing.
*/
public static final int MODE_UNLOCK_COLLAPSING = 5;
@@ -425,6 +425,11 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
if (!wasDeviceInteractive) {
mPendingShowBouncer = true;
} else {
+ mShadeController.animateCollapsePanels(
+ CommandQueue.FLAG_EXCLUDE_NONE,
+ true /* force */,
+ false /* delayed */,
+ BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR);
mPendingShowBouncer = false;
mKeyguardViewController.notifyKeyguardAuthenticated(
false /* strongAuth */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 5aa18e9a3356..373a276e5326 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -3666,6 +3666,7 @@ public class NotificationPanelViewController extends PanelViewController {
}
public void dozeTimeTick() {
+ mLockIconViewController.dozeTimeTick();
mKeyguardBottomArea.dozeTimeTick();
mKeyguardStatusViewController.dozeTimeTick();
if (mInterpolatedDarkAmount > 0) {
@@ -3879,6 +3880,9 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
protected TouchHandler createTouchHandler() {
return new TouchHandler() {
+
+ private long mLastTouchDownTime = -1L;
+
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (mBlockTouches || mQsFullyExpanded && mQs.disallowPanelTouches()) {
@@ -3908,6 +3912,19 @@ public class NotificationPanelViewController extends PanelViewController {
@Override
public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (event.getDownTime() == mLastTouchDownTime) {
+ // An issue can occur when swiping down after unlock, where multiple down
+ // events are received in this handler with identical downTimes. Until the
+ // source of the issue can be located, detect this case and ignore.
+ // see b/193350347
+ Log.w(TAG, "Duplicate down event detected... ignoring");
+ return true;
+ }
+ mLastTouchDownTime = event.getDownTime();
+ }
+
+
if (mBlockTouches || (mQsFullyExpanded && mQs != null
&& mQs.disallowPanelTouches())) {
return false;
@@ -3969,10 +3986,6 @@ public class NotificationPanelViewController extends PanelViewController {
mStatusBarKeyguardViewManager.updateKeyguardPosition(event.getX());
}
- if (mLockIconViewController.onTouchEvent(event)) {
- return true;
- }
-
handled |= super.onTouch(v, event);
return !mDozing || mPulsing || handled;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index b5d9bd67bd2d..66a6e723ede2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -35,6 +35,7 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.LockIconViewController;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dock.DockManager;
@@ -88,6 +89,7 @@ public class NotificationShadeWindowViewController {
private final NotificationShadeDepthController mDepthController;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ private final LockIconViewController mLockIconViewController;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private GestureDetector mGestureDetector;
@@ -138,7 +140,8 @@ public class NotificationShadeWindowViewController {
NotificationPanelViewController notificationPanelViewController,
SuperStatusBarViewFactory statusBarViewFactory,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ LockIconViewController lockIconViewController) {
mInjectionInflationController = injectionInflationController;
mCoordinator = coordinator;
mPulseExpansionHandler = pulseExpansionHandler;
@@ -163,6 +166,7 @@ public class NotificationShadeWindowViewController {
mStatusBarViewFactory = statusBarViewFactory;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mLockIconViewController = lockIconViewController;
// This view is not part of the newly inflated expanded status bar.
mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -235,6 +239,7 @@ public class NotificationShadeWindowViewController {
if (!isCancel && mService.shouldIgnoreTouch()) {
return false;
}
+
if (isDown) {
setTouchActive(true);
mTouchCancelled = false;
@@ -245,6 +250,7 @@ public class NotificationShadeWindowViewController {
if (mTouchCancelled || mExpandAnimationRunning) {
return false;
}
+
mFalsingCollector.onTouchEvent(ev);
mGestureDetector.onTouchEvent(ev);
mStatusBarKeyguardViewManager.onTouch(ev);
@@ -260,9 +266,17 @@ public class NotificationShadeWindowViewController {
if (isDown) {
mNotificationStackScrollLayoutController.closeControlsIfOutsideTouch(ev);
}
+
if (mStatusBarStateController.isDozing()) {
mService.mDozeScrimController.extendPulse();
}
+ mLockIconViewController.onTouchEvent(
+ ev,
+ () -> mService.wakeUpIfDozing(
+ SystemClock.uptimeMillis(),
+ mView,
+ "LOCK_ICON_TOUCH"));
+
// In case we start outside of the view bounds (below the status bar), we need to
// dispatch
// the touch manually as the view system can't accommodate for touches outside of
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cfcea9684c3b..7d25aeef6f98 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -111,6 +111,20 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
*/
private boolean mTransitioningToFullShade;
+ /**
+ * Is there currently an unocclusion animation running. Used to avoid bright flickers
+ * of the notification scrim.
+ */
+ private boolean mUnOcclusionAnimationRunning;
+
+ /**
+ * Set whether an unocclusion animation is currently running on the notification panel. Used
+ * to avoid bright flickers of the notification scrim.
+ */
+ public void setUnocclusionAnimationRunning(boolean unocclusionAnimationRunning) {
+ mUnOcclusionAnimationRunning = unocclusionAnimationRunning;
+ }
+
@IntDef(prefix = {"VISIBILITY_"}, value = {
TRANSPARENT,
SEMI_TRANSPARENT,
@@ -418,7 +432,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
scheduleUpdate();
- } else if ((oldState == ScrimState.AOD // leaving doze
+ } else if (((oldState == ScrimState.AOD || oldState == ScrimState.PULSING) // leaving doze
&& (!mDozeParameters.getAlwaysOn() || mState == ScrimState.UNLOCKED))
|| (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
// Scheduling a frame isn't enough when:
@@ -466,6 +480,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
public void onExpandingFinished() {
mTracking = false;
+ setUnocclusionAnimationRunning(false);
}
@VisibleForTesting
@@ -694,6 +709,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mNotificationsTint = mState.getNotifTint();
mBehindTint = behindTint;
}
+ if (mUnOcclusionAnimationRunning && mState == ScrimState.KEYGUARD) {
+ // We're unoccluding the keyguard and don't want to have a bright flash.
+ mNotificationsAlpha = KEYGUARD_SCRIM_ALPHA;
+ mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
+ }
}
if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 06811932ac0c..2c0de629de8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -244,7 +244,8 @@ public enum ScrimState {
? mKeyguardFadingAwayDuration
: StatusBar.FADE_KEYGUARD_DURATION;
- mAnimateChange = !mLaunchingAffordanceWithPreview;
+ boolean fromAod = previousState == AOD || previousState == PULSING;
+ mAnimateChange = !mLaunchingAffordanceWithPreview && !fromAod;
mFrontTint = Color.TRANSPARENT;
mBehindTint = Color.BLACK;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index d257165ae24e..e2194ad61b45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -592,6 +592,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
+ mKeyguardViewMediator.setWallpaperSupportsAmbientMode(supportsAmbientMode);
}
};
@@ -1148,6 +1149,9 @@ public class StatusBar extends SystemUI implements DemoMode,
mStatusBarView.setPanel(mNotificationPanelViewController);
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
+ for (ExpansionChangedListener listener : mExpansionChangedListeners) {
+ sendInitialExpansionAmount(listener);
+ }
// CollapsedStatusBarFragment re-inflated PhoneStatusBarView and both of
// mStatusBarView.mExpanded and mStatusBarView.mBouncerShowing are false.
@@ -3579,6 +3583,7 @@ public class StatusBar extends SystemUI implements DemoMode,
public void animateKeyguardUnoccluding() {
mNotificationPanelViewController.setExpandedFraction(0f);
animateExpandNotificationsPanel();
+ mScrimController.setUnocclusionAnimationRunning(true);
}
/**
@@ -3909,7 +3914,8 @@ public class StatusBar extends SystemUI implements DemoMode,
@Override
public void onDozeAmountChanged(float linear, float eased) {
if (mFeatureFlags.useNewLockscreenAnimations()
- && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
+ && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)
+ && !mBiometricUnlockController.isWakeAndUnlock()) {
mLightRevealScrim.setRevealAmount(1f - linear);
}
}
@@ -4466,10 +4472,8 @@ public class StatusBar extends SystemUI implements DemoMode,
ScrimState state = mStatusBarKeyguardViewManager.bouncerNeedsScrimming()
? ScrimState.BOUNCER_SCRIMMED : ScrimState.BOUNCER;
mScrimController.transitionTo(state);
- } else if (isInLaunchTransition()
- || mLaunchCameraWhenFinishedWaking
- || launchingAffordanceWithPreview) {
- // TODO(b/170133395) Investigate whether Emergency Gesture flag should be included here.
+ } else if (launchingAffordanceWithPreview) {
+ // We want to avoid animating when launching with a preview.
mScrimController.transitionTo(ScrimState.UNLOCKED, mUnlockScrimCallback);
} else if (mBrightnessMirrorVisible) {
mScrimController.transitionTo(ScrimState.BRIGHTNESS_MIRROR);
@@ -4934,6 +4938,14 @@ public class StatusBar extends SystemUI implements DemoMode,
public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
mExpansionChangedListeners.add(listener);
+ sendInitialExpansionAmount(listener);
+ }
+
+ private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) {
+ if (mStatusBarView != null) {
+ expansionChangedListener.onExpansionChanged(mStatusBarView.getExpansionFraction(),
+ mStatusBarView.isExpanded());
+ }
}
public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 8a7708aaa8c2..3188a522dfad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -194,6 +194,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private boolean mLastGesturalNav;
private boolean mLastIsDocked;
private boolean mLastPulsing;
+ private boolean mLastAnimatedToSleep;
private int mLastBiometricMode;
private boolean mQsExpanded;
private boolean mAnimatedToSleep;
@@ -990,6 +991,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mLastBiometricMode = mBiometricUnlockController.getMode();
mLastGesturalNav = mGesturalNav;
mLastIsDocked = mIsDocked;
+ mLastAnimatedToSleep = mAnimatedToSleep;
mStatusBar.onKeyguardViewManagerStatesUpdated();
}
@@ -1033,7 +1035,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
boolean hideWhileDozing = mLastDozing && mLastBiometricMode != MODE_WAKE_AND_UNLOCK_PULSING;
boolean keyguardWithGestureNav = (keyguardShowing && !mLastDozing
|| mLastPulsing && !mLastIsDocked) && mLastGesturalNav;
- return (!keyguardShowing && !hideWhileDozing || mLastBouncerShowing
+ return (!mLastAnimatedToSleep && !keyguardShowing && !hideWhileDozing || mLastBouncerShowing
|| mLastRemoteInputActive || keyguardWithGestureNav
|| mLastGlobalActionsVisible);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index fcfc9670b8b0..705761854532 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -245,5 +245,11 @@ public interface KeyguardStateController extends CallbackController<Callback> {
* animation.
*/
default void onKeyguardDismissAmountChanged() {}
+
+ /**
+ * Triggered when the notification panel is starting or has finished
+ * fading away on transition to an app.
+ */
+ default void onLaunchTransitionFadingAwayChanged() {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 64750bd803d5..f787ecf37372 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -343,6 +343,7 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum
@Override
public void setLaunchTransitionFadingAway(boolean fadingAway) {
mLaunchTransitionFadingAway = fadingAway;
+ new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index d87a26b096fd..f2f0029708ed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -19,16 +19,23 @@ package com.android.systemui.biometrics
import android.graphics.PointF
import android.hardware.biometrics.BiometricSourceType
import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.statusbar.LightRevealScrim
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.StatusBar
import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -42,6 +49,8 @@ import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import javax.inject.Provider
+
@SmallTest
@RunWith(AndroidTestingRunner::class)
class AuthRippleControllerTest : SysuiTestCase() {
@@ -52,26 +61,39 @@ class AuthRippleControllerTest : SysuiTestCase() {
@Mock private lateinit var configurationController: ConfigurationController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var authController: AuthController
+ @Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
@Mock private lateinit var bypassController: KeyguardBypassController
@Mock private lateinit var biometricUnlockController: BiometricUnlockController
+ @Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController>
+ @Mock private lateinit var udfpsController: UdfpsController
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var lightRevealScrim: LightRevealScrim
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ `when`(udfpsControllerProvider.get()).thenReturn(udfpsController)
+
controller = AuthRippleController(
statusBar,
context,
authController,
configurationController,
keyguardUpdateMonitor,
+ keyguardStateController,
+ wakefulnessLifecycle,
commandRegistry,
notificationShadeWindowController,
bypassController,
biometricUnlockController,
+ udfpsControllerProvider,
+ statusBarStateController,
rippleView
)
controller.init()
+ `when`(statusBar.lightRevealScrim).thenReturn(lightRevealScrim)
}
@Test
@@ -93,7 +115,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
// THEN update sensor location and show ripple
verify(rippleView).setSensorLocation(fpsLocation)
- verify(rippleView).startRipple(any(), any())
+ verify(rippleView).startUnlockedRipple(any())
}
@Test
@@ -114,7 +136,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
false /* isStrongBiometric */)
// THEN no ripple
- verify(rippleView, never()).startRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -135,7 +157,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
false /* isStrongBiometric */)
// THEN no ripple
- verify(rippleView, never()).startRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -159,7 +181,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
// THEN show ripple
verify(rippleView).setSensorLocation(faceLocation)
- verify(rippleView).startRipple(any(), any())
+ verify(rippleView).startUnlockedRipple(any())
}
@Test
@@ -179,7 +201,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
false /* isStrongBiometric */)
// THEN no ripple
- verify(rippleView, never()).startRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -194,7 +216,7 @@ class AuthRippleControllerTest : SysuiTestCase() {
0 /* userId */,
BiometricSourceType.FACE /* type */,
false /* isStrongBiometric */)
- verify(rippleView, never()).startRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
}
@Test
@@ -209,7 +231,39 @@ class AuthRippleControllerTest : SysuiTestCase() {
0 /* userId */,
BiometricSourceType.FINGERPRINT /* type */,
false /* isStrongBiometric */)
- verify(rippleView, never()).startRipple(any(), any())
+ verify(rippleView, never()).startUnlockedRipple(any())
+ }
+
+ @Test
+ fun registersAndDeregisters() {
+ controller.onViewAttached()
+ val captor = ArgumentCaptor
+ .forClass(KeyguardStateController.Callback::class.java)
+ verify(keyguardStateController).addCallback(captor.capture())
+ val captor2 = ArgumentCaptor
+ .forClass(WakefulnessLifecycle.Observer::class.java)
+ verify(wakefulnessLifecycle).addObserver(captor2.capture())
+ controller.onViewDetached()
+ verify(keyguardStateController).removeCallback(any())
+ verify(wakefulnessLifecycle).removeObserver(any())
+ }
+
+ @Test
+ @RunWithLooper(setAsMainLooper = true)
+ fun testAnimatorRunWhenWakeAndUnlock() {
+ val fpsLocation = PointF(5f, 5f)
+ `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
+ controller.onViewAttached()
+ `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+ `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
+
+ controller.showRipple(BiometricSourceType.FINGERPRINT)
+ assertTrue("reveal didn't start on keyguardFadingAway",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
+ `when`(keyguardStateController.isKeyguardFadingAway).thenReturn(true)
+ controller.onKeyguardFadingAwayChanged()
+ assertFalse("reveal triggers multiple times",
+ controller.startLightRevealScrimOnKeyguardFadingAway)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 2120b0ee4790..1a390170c736 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -456,11 +456,12 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Test
public void aodInterrupt() throws RemoteException {
- // GIVEN that the overlay is showing and screen is on
+ // GIVEN that the overlay is showing and screen is on and fp is running
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
// WHEN fingerprint is requested because of AOD interrupt
mUdfpsController.onAodInterrupt(0, 0, 2f, 3f);
// THEN illumination begins
@@ -478,6 +479,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
when(mUdfpsView.isIlluminationRequested()).thenReturn(true);
// WHEN it is cancelled
@@ -493,6 +495,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
mScreenObserver.onScreenTurnedOn();
mFgExecutor.runAllReady();
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
when(mUdfpsView.isIlluminationRequested()).thenReturn(true);
// WHEN it times out
@@ -511,6 +514,23 @@ public class UdfpsControllerTest extends SysuiTestCase {
mFgExecutor.runAllReady();
// WHEN aod interrupt is received
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+ mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
+
+ // THEN no illumination because screen is off
+ verify(mUdfpsView, never()).startIllumination(any());
+ }
+
+ @Test
+ public void aodInterrupt_fingerprintNotRunning() throws RemoteException {
+ // GIVEN showing overlay
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mScreenObserver.onScreenTurnedOn();
+ mFgExecutor.runAllReady();
+
+ // WHEN aod interrupt is received when the fingerprint service isn't running
+ when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
// THEN no illumination because screen is off
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 0c03a51f816e..0fbf9af159a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -20,6 +20,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeast;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -30,7 +35,6 @@ import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -40,6 +44,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import org.junit.Before;
@@ -50,6 +55,8 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -75,6 +82,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
private KeyguardViewMediator mKeyguardViewMediator;
@Mock
private ConfigurationController mConfigurationController;
@@ -88,14 +97,15 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
private StatusBarStateController.StateListener mStatusBarStateListener;
@Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
- private StatusBar.ExpansionChangedListener mExpansionListener;
+ private List<StatusBar.ExpansionChangedListener> mExpansionListeners;
@Captor private ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor>
mAltAuthInterceptorCaptor;
private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAltAuthInterceptor;
- @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateMonitorCallbackCaptor;
- private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+ @Captor private ArgumentCaptor<KeyguardStateController.Callback>
+ mKeyguardStateControllerCallbackCaptor;
+ private KeyguardStateController.Callback mKeyguardStateControllerCallback;
@Before
public void setUp() {
@@ -114,13 +124,14 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mKeyguardViewMediator,
mLockscreenShadeTransitionController,
mConfigurationController,
+ mKeyguardStateController,
mUdfpsController);
}
@Test
public void testRegistersExpansionChangedListenerOnAttached() {
mController.onViewAttached();
- captureExpansionListener();
+ captureExpansionListeners();
}
@Test
@@ -149,11 +160,15 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
public void testListenersUnregisteredOnDetached() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
+ captureExpansionListeners();
+ captureKeyguardStateControllerCallback();
mController.onViewDetached();
verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
- verify(mStatusBar).removeExpansionChangedListener(mExpansionListener);
+ for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+ verify(mStatusBar).removeExpansionChangedListener(listener);
+ }
+ verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback);
}
@Test
@@ -172,7 +187,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
public void testShouldPauseAuthBouncerShowing() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -183,7 +197,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
public void testShouldNotPauseAuthOnKeyguard() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -191,10 +204,25 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
}
@Test
+ public void testShouldPauseAuthIsLaunchTransitionFadingAway() {
+ // GIVEN view is attached and we're on the keyguard (see testShouldNotPauseAuthOnKeyguard)
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+ sendStatusBarStateChanged(StatusBarState.KEYGUARD);
+
+ // WHEN isLaunchTransitionFadingAway=true
+ captureKeyguardStateControllerCallback();
+ when(mKeyguardStateController.isLaunchTransitionFadingAway()).thenReturn(true);
+ mKeyguardStateControllerCallback.onLaunchTransitionFadingAwayChanged();
+
+ // THEN pause auth
+ assertTrue(mController.shouldPauseAuth());
+ }
+
+ @Test
public void testShouldPauseAuthOnShadeLocked() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
@@ -205,7 +233,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
public void testShouldPauseAuthOnShade() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
// WHEN not on keyguard yet (shade = home)
sendStatusBarStateChanged(StatusBarState.SHADE);
@@ -218,7 +245,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
public void testShouldPauseAuthAnimatingScreenOffFromShade() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
// WHEN transitioning from home/shade => keyguard + animating screen off
mStatusBarStateListener.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD);
@@ -232,7 +258,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
public void testDoNotPauseAuthAnimatingScreenOffFromLS() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
// WHEN animating screen off transition from LS => AOD
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -273,6 +298,74 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
verify(mStatusBarKeyguardViewManager).removeAlternateAuthInterceptor(mAltAuthInterceptor);
}
+ @Test
+ public void testFadeInWithStatusBarExpansion() {
+ // GIVEN view is attached
+ mController.onViewAttached();
+ captureExpansionListeners();
+ captureKeyguardStateControllerCallback();
+ reset(mView);
+
+ // WHEN status bar expansion is 0
+ updateStatusBarExpansion(0, true);
+
+ // THEN alpha is 0
+ verify(mView).setUnpausedAlpha(0);
+ }
+
+ @Test
+ public void testShowUdfpsBouncer() {
+ // GIVEN view is attached and status bar expansion is 0
+ mController.onViewAttached();
+ captureExpansionListeners();
+ captureKeyguardStateControllerCallback();
+ captureAltAuthInterceptor();
+ updateStatusBarExpansion(0, true);
+ reset(mView);
+ when(mView.getContext()).thenReturn(mResourceContext);
+ when(mResourceContext.getString(anyInt())).thenReturn("test string");
+
+ // WHEN status bar expansion is 0 but udfps bouncer is requested
+ mAltAuthInterceptor.showAlternateAuthBouncer();
+
+ // THEN alpha is 255
+ verify(mView).setUnpausedAlpha(255);
+ }
+
+ @Test
+ public void testTransitionToFullShadeProgress() {
+ // GIVEN view is attached and status bar expansion is 1f
+ mController.onViewAttached();
+ captureExpansionListeners();
+ updateStatusBarExpansion(1f, true);
+ reset(mView);
+
+ // WHEN we're transitioning to the full shade
+ float transitionProgress = .6f;
+ mController.setTransitionToFullShadeProgress(transitionProgress);
+
+ // THEN alpha is between 0 and 255
+ verify(mView).setUnpausedAlpha((int) ((1f - transitionProgress) * 255));
+ }
+
+ @Test
+ public void testShowUdfpsBouncer_transitionToFullShadeProgress() {
+ // GIVEN view is attached and status bar expansion is 1f
+ mController.onViewAttached();
+ captureExpansionListeners();
+ captureKeyguardStateControllerCallback();
+ captureAltAuthInterceptor();
+ updateStatusBarExpansion(1f, true);
+ mAltAuthInterceptor.showAlternateAuthBouncer();
+ reset(mView);
+
+ // WHEN we're transitioning to the full shade
+ mController.setTransitionToFullShadeProgress(1.0f);
+
+ // THEN alpha is 255 (b/c udfps bouncer is requested)
+ verify(mView).setUnpausedAlpha(255);
+ }
+
private void sendStatusBarStateChanged(int statusBarState) {
mStatusBarStateListener.onStateChanged(statusBarState);
}
@@ -282,9 +375,18 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mStatusBarStateListener = mStateListenerCaptor.getValue();
}
- private void captureExpansionListener() {
- verify(mStatusBar).addExpansionChangedListener(mExpansionListenerCaptor.capture());
- mExpansionListener = mExpansionListenerCaptor.getValue();
+ private void captureExpansionListeners() {
+ verify(mStatusBar, times(2))
+ .addExpansionChangedListener(mExpansionListenerCaptor.capture());
+ // first (index=0) is from super class, UdfpsAnimationViewController.
+ // second (index=1) is from UdfpsKeyguardViewController
+ mExpansionListeners = mExpansionListenerCaptor.getAllValues();
+ }
+
+ private void updateStatusBarExpansion(float expansion, boolean expanded) {
+ for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+ listener.onExpansionChanged(expansion, expanded);
+ }
}
private void captureAltAuthInterceptor() {
@@ -293,8 +395,9 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue();
}
- private void captureKeyguardUpdateMonitorCallback() {
- verify(mKeyguardUpdateMonitor).registerCallback(mUpdateMonitorCallbackCaptor.capture());
- mKeyguardUpdateMonitorCallback = mUpdateMonitorCallbackCaptor.getValue();
+ private void captureKeyguardStateControllerCallback() {
+ verify(mKeyguardStateController).addCallback(
+ mKeyguardStateControllerCallbackCaptor.capture());
+ mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 4e8b59c95681..81bae0bd6dd1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -49,6 +49,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.concurrency.FakeThreadFactory;
import com.android.systemui.util.sensors.AsyncSensorManager;
@@ -82,6 +83,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
WakefulnessLifecycle mWakefulnessLifecycle;
@Mock
DozeParameters mDozeParameters;
+ @Mock
+ private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private FakeThreadFactory mFakeThreadFactory = new FakeThreadFactory(mFakeExecutor);
@@ -109,8 +112,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mSensor = fakeSensorManager.getFakeLightSensor();
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
Optional.of(mSensor.getSensor()), mDozeHost, null /* handler */,
- mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
-
+ mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters,
+ mUnlockedScreenOffAnimationController);
mScreen.onScreenState(Display.STATE_ON);
}
@@ -175,7 +178,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
public void testPulsing_withoutLightSensor_setsAoDDimmingScrimTransparent() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
Optional.empty() /* sensor */, mDozeHost, null /* handler */,
- mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+ mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters,
+ mUnlockedScreenOffAnimationController);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE);
reset(mDozeHost);
@@ -216,7 +220,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
public void testNullSensor() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
Optional.empty() /* sensor */, mDozeHost, null /* handler */,
- mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters);
+ mAlwaysOnDisplayPolicy, mWakefulnessLifecycle, mDozeParameters,
+ mUnlockedScreenOffAnimationController);
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index 41d7fd64fe7a..3e19cc436dca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -21,6 +21,7 @@ import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
import static com.android.systemui.doze.DozeMachine.State.FINISH;
@@ -34,6 +35,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -45,6 +47,8 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.UdfpsController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.wakelock.WakeLockFake;
import com.android.systemui.utils.os.FakeHandler;
@@ -56,6 +60,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import javax.inject.Provider;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DozeScreenStateTest extends SysuiTestCase {
@@ -68,17 +74,32 @@ public class DozeScreenStateTest extends SysuiTestCase {
private DozeParameters mDozeParameters;
private WakeLockFake mWakeLock;
private DozeScreenState mScreen;
+ @Mock
+ private Provider<UdfpsController> mUdfpsControllerProvider;
+ @Mock
+ private AuthController mAuthController;
+ @Mock
+ private UdfpsController mUdfpsController;
+ @Mock
+ private DozeLog mDozeLog;
+ @Mock
+ private DozeScreenBrightness mDozeScreenBrightness;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
when(mDozeParameters.getAlwaysOn()).thenReturn(true);
+ when(mUdfpsControllerProvider.get()).thenReturn(mUdfpsController);
+ when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(true);
+ when(mUdfpsController.isFingerDown()).thenReturn(false);
+
mServiceFake = new DozeServiceFake();
mHandlerFake = new FakeHandler(Looper.getMainLooper());
mWakeLock = new WakeLockFake();
mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeHost, mDozeParameters,
- mWakeLock);
+ mWakeLock, mAuthController, mUdfpsControllerProvider, mDozeLog,
+ mDozeScreenBrightness);
}
@Test
@@ -233,4 +254,56 @@ public class DozeScreenStateTest extends SysuiTestCase {
assertEquals(Display.STATE_OFF, mServiceFake.screenState);
}
+ @Test
+ public void testDelayEnterDozeScreenState_whenUdfpsFingerDown() {
+ // GIVEN AOD is initialized
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
+ mHandlerFake.setMode(QUEUEING);
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mHandlerFake.dispatchQueuedMessages();
+
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+ // WHEN udfps is activated (fingerDown)
+ when(mUdfpsController.isFingerDown()).thenReturn(true);
+ mHandlerFake.dispatchQueuedMessages();
+
+ // THEN the display screen state doesn't immediately change
+ assertEquals(Display.STATE_ON, mServiceFake.screenState);
+
+ // WHEN udfpsController finger is no longer down and the queued messages are run
+ when(mUdfpsController.isFingerDown()).thenReturn(false);
+ mHandlerFake.dispatchQueuedMessages();
+
+ // THEN the display screen state will change
+ assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
+ }
+
+ @Test
+ public void testDelayExitPulsingScreenState_whenUdfpsFingerDown() {
+ // GIVEN we're pulsing
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
+ mHandlerFake.setMode(QUEUEING);
+ mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+ mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+ mScreen.transitionTo(DOZE_AOD, DOZE_REQUEST_PULSE);
+ mScreen.transitionTo(DOZE_REQUEST_PULSE, DOZE_PULSING);
+ mScreen.transitionTo(DOZE_PULSING, DOZE_PULSE_DONE);
+ mHandlerFake.dispatchQueuedMessages();
+
+ // WHEN udfps is activated while are transitioning back to DOZE_AOD
+ mScreen.transitionTo(DOZE_PULSE_DONE, DOZE_AOD);
+ when(mUdfpsController.isFingerDown()).thenReturn(true);
+ mHandlerFake.dispatchQueuedMessages();
+
+ // THEN the display screen state doesn't immediately change
+ assertEquals(Display.STATE_ON, mServiceFake.screenState);
+
+ // WHEN udfpsController finger is no longer down and the queued messages are run
+ when(mUdfpsController.isFingerDown()).thenReturn(false);
+ mHandlerFake.dispatchQueuedMessages();
+
+ // THEN the display screen state will change
+ assertEquals(Display.STATE_DOZE_SUSPEND, mServiceFake.screenState);
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
new file mode 100644
index 000000000000..9c3016c57ccf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.systemui.keyguard;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.PointF;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.os.Vibrator;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardViewController;
+import com.android.keyguard.LockIconView;
+import com.android.keyguard.LockIconViewController;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.biometrics.AuthRippleController;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+
+import com.airbnb.lottie.LottieAnimationView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class LockIconViewControllerTest extends SysuiTestCase {
+ private @Mock LockIconView mLockIconView;
+ private @Mock Context mContext;
+ private @Mock Resources mResources;
+ private @Mock DisplayMetrics mDisplayMetrics;
+ private @Mock StatusBarStateController mStatusBarStateController;
+ private @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private @Mock KeyguardViewController mKeyguardViewController;
+ private @Mock KeyguardStateController mKeyguardStateController;
+ private @Mock FalsingManager mFalsingManager;
+ private @Mock AuthController mAuthController;
+ private @Mock DumpManager mDumpManager;
+ private @Mock AccessibilityManager mAccessibilityManager;
+ private @Mock ConfigurationController mConfigurationController;
+ private @Mock DelayableExecutor mDelayableExecutor;
+ private @Mock Vibrator mVibrator;
+ private @Mock AuthRippleController mAuthRippleController;
+ private @Mock LottieAnimationView mAodFp;
+
+ private LockIconViewController mLockIconViewController;
+
+ // Capture listeners so that they can be used to send events
+ @Captor private ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+ private View.OnAttachStateChangeListener mAttachListener;
+
+ @Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor;
+ private AuthController.Callback mAuthControllerCallback;
+
+ @Captor private ArgumentCaptor<PointF> mPointCaptor;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mLockIconView.getResources()).thenReturn(mResources);
+ when(mLockIconView.getContext()).thenReturn(mContext);
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
+ when(mLockIconView.findViewById(anyInt())).thenReturn(mAodFp);
+
+ mLockIconViewController = new LockIconViewController(
+ mLockIconView,
+ mStatusBarStateController,
+ mKeyguardUpdateMonitor,
+ mKeyguardViewController,
+ mKeyguardStateController,
+ mFalsingManager,
+ mAuthController,
+ mDumpManager,
+ mAccessibilityManager,
+ mConfigurationController,
+ mDelayableExecutor,
+ mVibrator
+ );
+ }
+
+ @Test
+ public void testUpdateFingerprintLocationOnInit() {
+ // GIVEN fp sensor location is available pre-attached
+ final PointF udfpsLocation = new PointF(50, 75);
+ final int radius = 33;
+ final FingerprintSensorPropertiesInternal fpProps =
+ new FingerprintSensorPropertiesInternal(
+ /* sensorId */ 0,
+ /* strength */ 0,
+ /* max enrollments per user */ 5,
+ /* component info */ new ArrayList<>(),
+ /* sensorType */ 3,
+ /* resetLockoutRequiresHwToken */ false,
+ (int) udfpsLocation.x, (int) udfpsLocation.y, radius);
+ when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
+ when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
+
+ // WHEN lock icon view controller is initialized and attached
+ mLockIconViewController.init();
+ captureAttachListener();
+ mAttachListener.onViewAttachedToWindow(mLockIconView);
+
+ // THEN lock icon view location is updated with the same coordinates as fpProps
+ verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
+ assertEquals(udfpsLocation, mPointCaptor.getValue());
+ }
+
+ @Test
+ public void testUpdateFingerprintLocationOnAuthenticatorsRegistered() {
+ // GIVEN fp sensor location is not available pre-init
+ when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
+ when(mAuthController.getUdfpsProps()).thenReturn(null);
+ mLockIconViewController.init();
+ captureAttachListener();
+ mAttachListener.onViewAttachedToWindow(mLockIconView);
+
+ // GIVEN fp sensor location is available post-atttached
+ captureAuthControllerCallback();
+ final PointF udfpsLocation = new PointF(50, 75);
+ final int radius = 33;
+ final FingerprintSensorPropertiesInternal fpProps =
+ new FingerprintSensorPropertiesInternal(
+ /* sensorId */ 0,
+ /* strength */ 0,
+ /* max enrollments per user */ 5,
+ /* component info */ new ArrayList<>(),
+ /* sensorType */ 3,
+ /* resetLockoutRequiresHwToken */ false,
+ (int) udfpsLocation.x, (int) udfpsLocation.y, radius);
+ when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation);
+ when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps));
+
+ // WHEN all authenticators are registered
+ mAuthControllerCallback.onAllAuthenticatorsRegistered();
+
+ // THEN lock icon view location is updated with the same coordinates as fpProps
+ verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius));
+ assertEquals(udfpsLocation, mPointCaptor.getValue());
+ }
+
+ private void captureAuthControllerCallback() {
+ verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture());
+ mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue();
+ }
+
+ private void captureAttachListener() {
+ verify(mLockIconView).addOnAttachStateChangeListener(mAttachCaptor.capture());
+ mAttachListener = mAttachCaptor.getValue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 3ee3e55c749a..7f89b2629a6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -139,7 +139,7 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
() -> mock(AutoTileManager.class), mock(DumpManager.class),
mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)),
mock(QSLogger.class), mock(UiEventLogger.class), mock(UserTracker.class),
- mock(SecureSettings.class), mock(CustomTileStatePersister.class));
+ mock(SecureSettings.class), mock(CustomTileStatePersister.class), mFeatureFlags);
qs.setHost(host);
qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 9e97f801be3e..4cbad5f15c5f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -63,6 +63,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -124,6 +125,8 @@ public class QSTileHostTest extends SysuiTestCase {
private SecureSettings mSecureSettings;
@Mock
private CustomTileStatePersister mCustomTileStatePersister;
+ @Mock
+ private FeatureFlags mFeatureFlags;
private Handler mHandler;
private TestableLooper mLooper;
@@ -137,9 +140,9 @@ public class QSTileHostTest extends SysuiTestCase {
mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
mLooper.getLooper(), mPluginManager, mTunerService, mAutoTiles, mDumpManager,
mBroadcastDispatcher, mStatusBar, mQSLogger, mUiEventLogger, mUserTracker,
- mSecureSettings, mCustomTileStatePersister);
+ mSecureSettings, mCustomTileStatePersister, mFeatureFlags);
setUpTileFactory();
-
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false);
when(mSecureSettings.getStringForUser(eq(QSTileHost.TILES_SETTING), anyInt()))
.thenReturn("");
}
@@ -169,13 +172,13 @@ public class QSTileHostTest extends SysuiTestCase {
@Test
public void testLoadTileSpecs_emptySetting() {
- List<String> tiles = QSTileHost.loadTileSpecs(mContext, "");
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, "", mFeatureFlags);
assertFalse(tiles.isEmpty());
}
@Test
public void testLoadTileSpecs_nullSetting() {
- List<String> tiles = QSTileHost.loadTileSpecs(mContext, null);
+ List<String> tiles = QSTileHost.loadTileSpecs(mContext, null, mFeatureFlags);
assertFalse(tiles.isEmpty());
}
@@ -189,6 +192,55 @@ public class QSTileHostTest extends SysuiTestCase {
}
@Test
+ public void testRemoveWifiAndCellularWithoutInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2");
+
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveWifiAndCellularWithInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "wifi, spec1, cell, spec2, internet");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveWifiWithoutInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, wifi, spec2");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testRemoveCellWithInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1, spec2, cell, internet");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ assertEquals("internet", mQSTileHost.mTileSpecs.get(2));
+ }
+
+ @Test
+ public void testNoWifiNoCellularNoInternet() {
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(true);
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1,spec2");
+
+ assertEquals("spec1", mQSTileHost.mTileSpecs.get(0));
+ assertEquals("spec2", mQSTileHost.mTileSpecs.get(1));
+ }
+
+ @Test
public void testSpecWithInvalidDoesNotUseDefault() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles, "spec1,spec2");
@@ -321,7 +373,7 @@ public class QSTileHostTest extends SysuiTestCase {
@Test
public void testLoadTileSpec_repeated() {
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2", mFeatureFlags);
assertEquals(2, specs.size());
assertEquals("spec1", specs.get(0));
@@ -332,7 +384,7 @@ public class QSTileHostTest extends SysuiTestCase {
public void testLoadTileSpec_repeatedInDefault() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles_default, "spec1,spec1");
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "default");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "default", mFeatureFlags);
// Remove spurious tiles, like dbg:mem
specs.removeIf(spec -> !"spec1".equals(spec));
@@ -343,7 +395,7 @@ public class QSTileHostTest extends SysuiTestCase {
public void testLoadTileSpec_repeatedDefaultAndSetting() {
mContext.getOrCreateTestableResources()
.addOverride(R.string.quick_settings_tiles_default, "spec1");
- List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1");
+ List<String> specs = QSTileHost.loadTileSpecs(mContext, "default,spec1", mFeatureFlags);
// Remove spurious tiles, like dbg:mem
specs.removeIf(spec -> !"spec1".equals(spec));
@@ -371,11 +423,12 @@ public class QSTileHostTest extends SysuiTestCase {
Provider<AutoTileManager> autoTiles, DumpManager dumpManager,
BroadcastDispatcher broadcastDispatcher, StatusBar statusBar, QSLogger qsLogger,
UiEventLogger uiEventLogger, UserTracker userTracker,
- SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister) {
+ SecureSettings secureSettings, CustomTileStatePersister customTileStatePersister,
+ FeatureFlags featureFlags) {
super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
tunerService, autoTiles, dumpManager, broadcastDispatcher,
Optional.of(statusBar), qsLogger, uiEventLogger, userTracker, secureSettings,
- customTileStatePersister);
+ customTileStatePersister, featureFlags);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
index 4efcc5c3fc73..c5b67091d197 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java
@@ -58,6 +58,7 @@ import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -108,6 +109,8 @@ public class TileQueryHelperTest extends SysuiTestCase {
private PackageManager mPackageManager;
@Mock
private UserTracker mUserTracker;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Captor
private ArgumentCaptor<List<TileQueryHelper.TileInfo>> mCaptor;
@@ -133,12 +136,12 @@ public class TileQueryHelperTest extends SysuiTestCase {
}
}
).when(mQSTileHost).createTile(anyString());
-
+ when(mFeatureFlags.isProviderModelSettingEnabled()).thenReturn(false);
FakeSystemClock clock = new FakeSystemClock();
mMainExecutor = new FakeExecutor(clock);
mBgExecutor = new FakeExecutor(clock);
mTileQueryHelper = new TileQueryHelper(
- mContext, mUserTracker, mMainExecutor, mBgExecutor);
+ mContext, mUserTracker, mMainExecutor, mBgExecutor, mFeatureFlags);
mTileQueryHelper.setListener(mListener);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 2b1840462291..01fa222896d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -48,6 +48,7 @@ import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSFactoryImpl;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.phone.AutoTileManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -98,6 +99,8 @@ public class TileServicesTest extends SysuiTestCase {
private UserTracker mUserTracker;
@Mock
private SecureSettings mSecureSettings;
+ @Mock
+ private FeatureFlags mFeatureFlags;
@Before
public void setUp() throws Exception {
@@ -119,7 +122,8 @@ public class TileServicesTest extends SysuiTestCase {
mUiEventLogger,
mUserTracker,
mSecureSettings,
- mock(CustomTileStatePersister.class));
+ mock(CustomTileStatePersister.class),
+ mFeatureFlags);
mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher,
mUserTracker);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 7c045c1f2894..a7b14460f925 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -69,7 +69,6 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Mock private lateinit var root: View
@Mock private lateinit var viewRootImpl: ViewRootImpl
@Mock private lateinit var windowToken: IBinder
- @Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var shadeAnimation: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var brightnessSpring: NotificationShadeDepthController.DepthAnimation
@Mock private lateinit var listener: NotificationShadeDepthController.DepthListener
@@ -89,10 +88,10 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
`when`(root.isAttachedToWindow).thenReturn(true)
`when`(statusBarStateController.state).then { statusBarState }
`when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
- (answer.arguments[0] as Float * maxBlur).toInt()
+ answer.arguments[0] as Float * maxBlur.toFloat()
}
- `when`(blurUtils.ratioOfBlurRadius(anyInt())).then { answer ->
- answer.arguments[0] as Int / maxBlur.toFloat()
+ `when`(blurUtils.ratioOfBlurRadius(anyFloat())).then { answer ->
+ answer.arguments[0] as Float / maxBlur.toFloat()
}
`when`(blurUtils.supportsBlursOnWindows()).thenReturn(true)
`when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
@@ -102,7 +101,6 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
statusBarStateController, blurUtils, biometricUnlockController,
keyguardStateController, choreographer, wallpaperManager,
notificationShadeWindowController, dozeParameters, dumpManager)
- notificationShadeDepthController.shadeSpring = shadeSpring
notificationShadeDepthController.shadeAnimation = shadeAnimation
notificationShadeDepthController.brightnessMirrorSpring = brightnessSpring
notificationShadeDepthController.root = root
@@ -123,7 +121,6 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun onPanelExpansionChanged_apliesBlur_ifShade() {
notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
false /* tracking */)
- verify(shadeSpring).animateTo(eq(maxBlur), any())
verify(shadeAnimation).animateTo(eq(maxBlur), any())
}
@@ -172,12 +169,10 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Test
fun onStateChanged_reevalutesBlurs_ifSameRadiusAndNewState() {
onPanelExpansionChanged_apliesBlur_ifShade()
- clearInvocations(shadeSpring)
- clearInvocations(shadeAnimation)
+ clearInvocations(choreographer)
statusBarState = StatusBarState.KEYGUARD
statusBarStateListener.onStateChanged(statusBarState)
- verify(shadeSpring).animateTo(eq(0), any())
verify(shadeAnimation).animateTo(eq(0), any())
}
@@ -186,7 +181,7 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
notificationShadeDepthController.qsPanelExpansion = 1f
notificationShadeDepthController.onPanelExpansionChanged(0.5f, tracking = false)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), eq(maxBlur / 2), eq(false))
+ verify(blurUtils).applyBlur(any(), anyInt(), eq(false))
}
@Test
@@ -207,10 +202,10 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
reset(blurUtils)
`when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
- (answer.arguments[0] as Float * maxBlur).toInt()
+ answer.arguments[0] as Float * maxBlur
}
- `when`(blurUtils.ratioOfBlurRadius(anyInt())).then { answer ->
- answer.arguments[0] as Int / maxBlur.toFloat()
+ `when`(blurUtils.ratioOfBlurRadius(anyFloat())).then { answer ->
+ answer.arguments[0] as Float / maxBlur.toFloat()
}
`when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
`when`(blurUtils.maxBlurRadius).thenReturn(maxBlur)
@@ -239,16 +234,16 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Test
fun updateBlurCallback_setsBlur_whenExpanded() {
- `when`(shadeSpring.radius).thenReturn(maxBlur)
- `when`(shadeAnimation.radius).thenReturn(maxBlur)
+ notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
}
@Test
fun updateBlurCallback_ignoreShadeBlurUntilHidden_overridesZoom() {
- `when`(shadeSpring.radius).thenReturn(maxBlur)
- `when`(shadeAnimation.radius).thenReturn(maxBlur)
+ notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.blursDisabledForAppLaunch = true
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(blurUtils).applyBlur(any(), eq(0), eq(false))
@@ -293,8 +288,8 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
// Brightness mirror is fully visible
`when`(brightnessSpring.ratio).thenReturn(1f)
// And shade is blurred
- `when`(shadeSpring.radius).thenReturn(maxBlur)
- `when`(shadeAnimation.radius).thenReturn(maxBlur)
+ notificationShadeDepthController.onPanelExpansionChanged(1f, false)
+ `when`(shadeAnimation.radius).thenReturn(maxBlur.toFloat())
notificationShadeDepthController.updateBlurCallback.doFrame(0)
verify(notificationShadeWindowController).setBackgroundBlurRadius(eq(0))
@@ -304,10 +299,8 @@ class NotificationShadeDepthControllerTest : SysuiTestCase() {
@Test
fun ignoreShadeBlurUntilHidden_whennNull_ignoresIfShadeHasNoBlur() {
- `when`(shadeSpring.radius).thenReturn(0)
- `when`(shadeAnimation.radius).thenReturn(0)
+ `when`(shadeAnimation.radius).thenReturn(0f)
notificationShadeDepthController.blursDisabledForAppLaunch = true
- verify(shadeSpring, never()).animateTo(anyInt(), any())
verify(shadeAnimation, never()).animateTo(anyInt(), any())
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 60f0b68acac3..4276f7ce7b12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -274,6 +274,26 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
}
@Test
+ public void onBiometricAuthenticated_onLockScreen() {
+ // GIVEN not dozing
+ when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
+
+ // WHEN we want to unlock collapse
+ mBiometricUnlockController.startWakeAndUnlock(
+ BiometricUnlockController.MODE_UNLOCK_COLLAPSING);
+
+ // THEN we collpase the panels and notify authenticated
+ verify(mShadeController).animateCollapsePanels(
+ /* flags */ anyInt(),
+ /* force */ eq(true),
+ /* delayed */ eq(false),
+ /* speedUpFactor */ anyFloat()
+ );
+ verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(
+ /* strongAuth */ eq(false));
+ }
+
+ @Test
public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() {
reset(mUpdateMonitor);
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index 6c1a3c90d83d..9b7c78f7dba1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -27,6 +27,7 @@ import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
+import com.android.keyguard.LockIconViewController;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
@@ -90,6 +91,7 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
@Mock private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
+ @Mock private LockIconViewController mLockIconViewController;
@Before
public void setUp() {
@@ -131,7 +133,8 @@ public class NotificationShadeWindowViewTest extends SysuiTestCase {
mNotificationPanelViewController,
mStatusBarViewFactory,
mNotificationStackScrollLayoutController,
- mStatusBarKeyguardViewManager);
+ mStatusBarKeyguardViewManager,
+ mLockIconViewController);
mController.setupExpandedStatusBar();
mController.setService(mStatusBar, mNotificationShadeWindowController);
mController.setDragDownHelper(mDragDownHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 678b193073c2..c71318fa9464 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -16,10 +16,13 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -734,9 +737,9 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
- public void transitionToUnlockedFromAod() {
- // Simulate unlock with fingerprint
- mScrimController.transitionTo(ScrimState.AOD);
+ public void transitionToUnlockedFromOff() {
+ // Simulate unlock with fingerprint without AOD
+ mScrimController.transitionTo(ScrimState.OFF);
mScrimController.setPanelExpansion(0f);
finishAnimationsImmediately();
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -765,6 +768,28 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
+ public void transitionToUnlockedFromAod() {
+ // Simulate unlock with fingerprint
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.setPanelExpansion(0f);
+ finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+
+ finishAnimationsImmediately();
+
+ // All scrims should be transparent at the end of fade transition.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+
+ // Make sure at the very end of the animation, we're reset to transparent
+ assertScrimTinted(Map.of(
+ mScrimInFront, false,
+ mScrimBehind, true
+ ));
+ }
+
+ @Test
public void scrimBlanksBeforeLeavingAod() {
// Simulate unlock with fingerprint
mScrimController.transitionTo(ScrimState.AOD);
@@ -1081,6 +1106,26 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
+ public void testDoesntAnimate_whenUnlocking() {
+ // LightRevealScrim will animate the transition, we should only hide the keyguard scrims.
+ ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ ScrimState.UNLOCKED.prepare(ScrimState.PULSING);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
+
+ ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ ScrimState.UNLOCKED.prepare(ScrimState.AOD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
+
+ // LightRevealScrim doesn't animate when AOD is disabled. We need to use the legacy anim.
+ ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ ScrimState.UNLOCKED.prepare(ScrimState.OFF);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ }
+
+ @Test
public void testScrimsVisible_whenShadeVisible_clippingQs() {
mScrimController.setClipsQsScrim(true);
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -1138,6 +1183,21 @@ public class ScrimControllerTest extends SysuiTestCase {
}
@Test
+ public void testNotificationTransparency_unnocclusion() {
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ mScrimController.setUnocclusionAnimationRunning(true);
+
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
+ /* expansion */ 0.0f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
+ /* expansion */ 1.0f);
+
+ // Verify normal behavior after
+ mScrimController.setUnocclusionAnimationRunning(false);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.4f);
+ }
+
+ @Test
public void testNotificationTransparency_inKeyguardState() {
mScrimController.transitionTo(ScrimState.KEYGUARD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 2c2833a864b9..bd9835c0e8e3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -812,6 +812,30 @@ public class StatusBarTest extends SysuiTestCase {
}
@Test
+ public void testTransitionLaunch_goesToUnlocked() {
+ mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+ mStatusBar.showKeyguardImpl();
+
+ // Starting a pulse should change the scrim controller to the pulsing state
+ when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true);
+ when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(true);
+ mStatusBar.updateScrimController();
+ verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
+ }
+
+ @Test
+ public void testTransitionLaunch_noPreview_doesntGoUnlocked() {
+ mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+ mStatusBar.showKeyguardImpl();
+
+ // Starting a pulse should change the scrim controller to the pulsing state
+ when(mNotificationPanelViewController.isLaunchTransitionRunning()).thenReturn(true);
+ when(mNotificationPanelViewController.isLaunchingAffordanceWithPreview()).thenReturn(false);
+ mStatusBar.updateScrimController();
+ verify(mScrimController).transitionTo(eq(ScrimState.KEYGUARD));
+ }
+
+ @Test
public void testSetOccluded_propagatesToScrimController() {
mStatusBar.setOccluded(true);
verify(mScrimController).setKeyguardOccluded(eq(true));
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index c3543e7ba368..c1c9fbb121a8 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -327,18 +327,23 @@ public class RescueParty {
}
}
- private static int getMaxRescueLevel() {
- return SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)
- ? LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS : LEVEL_FACTORY_RESET;
+ private static int getMaxRescueLevel(boolean mayPerformFactoryReset) {
+ if (!mayPerformFactoryReset
+ || SystemProperties.getBoolean(PROP_DISABLE_FACTORY_RESET_FLAG, false)) {
+ return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
+ }
+ return LEVEL_FACTORY_RESET;
}
/**
* Get the rescue level to perform if this is the n-th attempt at mitigating failure.
*
* @param mitigationCount: the mitigation attempt number (1 = first attempt etc.)
+ * @param mayPerformFactoryReset: whether or not a factory reset may be performed for the given
+ * failure.
* @return the rescue level for the n-th mitigation attempt.
*/
- private static int getRescueLevel(int mitigationCount) {
+ private static int getRescueLevel(int mitigationCount, boolean mayPerformFactoryReset) {
if (mitigationCount == 1) {
return LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS;
} else if (mitigationCount == 2) {
@@ -346,9 +351,9 @@ public class RescueParty {
} else if (mitigationCount == 3) {
return LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS;
} else if (mitigationCount == 4) {
- return Math.min(getMaxRescueLevel(), LEVEL_WARM_REBOOT);
+ return Math.min(getMaxRescueLevel(mayPerformFactoryReset), LEVEL_WARM_REBOOT);
} else if (mitigationCount >= 5) {
- return Math.min(getMaxRescueLevel(), LEVEL_FACTORY_RESET);
+ return Math.min(getMaxRescueLevel(mayPerformFactoryReset), LEVEL_FACTORY_RESET);
} else {
Slog.w(TAG, "Expected positive mitigation count, was " + mitigationCount);
return LEVEL_NONE;
@@ -614,7 +619,8 @@ public class RescueParty {
@FailureReasons int failureReason, int mitigationCount) {
if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount,
+ mayPerformFactoryReset(failedPackage)));
} else {
return PackageHealthObserverImpact.USER_IMPACT_NONE;
}
@@ -628,7 +634,8 @@ public class RescueParty {
}
if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
|| failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
- final int level = getRescueLevel(mitigationCount);
+ final int level = getRescueLevel(mitigationCount,
+ mayPerformFactoryReset(failedPackage));
executeRescueLevel(mContext,
failedPackage == null ? null : failedPackage.getPackageName(), level);
return true;
@@ -653,12 +660,7 @@ public class RescueParty {
} catch (PackageManager.NameNotFoundException ignore) {
}
- try {
- ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
- return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
+ return isPersistentSystemApp(packageName);
}
@Override
@@ -666,7 +668,7 @@ public class RescueParty {
if (isDisabled()) {
return PackageHealthObserverImpact.USER_IMPACT_NONE;
}
- return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount));
+ return mapRescueLevelToUserImpact(getRescueLevel(mitigationCount, true));
}
@Override
@@ -674,7 +676,8 @@ public class RescueParty {
if (isDisabled()) {
return false;
}
- executeRescueLevel(mContext, /*failedPackage=*/ null, getRescueLevel(mitigationCount));
+ executeRescueLevel(mContext, /*failedPackage=*/ null,
+ getRescueLevel(mitigationCount, true));
return true;
}
@@ -683,6 +686,29 @@ public class RescueParty {
return NAME;
}
+ /**
+ * Returns {@code true} if the failing package is non-null and performing a reboot or
+ * prompting a factory reset is an acceptable mitigation strategy for the package's
+ * failure, {@code false} otherwise.
+ */
+ private boolean mayPerformFactoryReset(@Nullable VersionedPackage failingPackage) {
+ if (failingPackage == null) {
+ return false;
+ }
+
+ return isPersistentSystemApp(failingPackage.getPackageName());
+ }
+
+ private boolean isPersistentSystemApp(@NonNull String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
+ return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
private synchronized void recordDeviceConfigAccess(@NonNull String callingPackage,
@NonNull String namespace) {
// Record it in calling packages to namespace map
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index eaec73af2e0e..4e5e458d1636 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1889,11 +1889,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
try {
if (!mConfigurationProvider.isDisplayInfoNrAdvancedSupported(
r.callingPackage, Binder.getCallingUserHandle())) {
- telephonyDisplayInfo =
+ r.callback.onDisplayInfoChanged(
getBackwardCompatibleTelephonyDisplayInfo(
- telephonyDisplayInfo);
+ telephonyDisplayInfo));
+ } else {
+ r.callback.onDisplayInfoChanged(telephonyDisplayInfo);
}
- r.callback.onDisplayInfoChanged(telephonyDisplayInfo);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index e23f48742a97..6a439622627c 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1835,6 +1835,11 @@ public class AccountManagerService
+ ", skipping since the account already exists");
return false;
}
+ if (accounts.accountsDb.findAllDeAccounts().size() > 100) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ + ", skipping since more than 50 accounts on device exist");
+ return false;
+ }
long accountId = accounts.accountsDb.insertCeAccount(account, password);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index e5e1385fa605..3eb6f4ae48a2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -206,7 +206,6 @@ public abstract class BaseClientMonitor extends LoggableMonitor
}
mToken = null;
}
- mListener = null;
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index b20316e4c6df..feb9e2a5b03f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -295,6 +295,7 @@ public class BiometricScheduler {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, boolean success) {
mHandler.post(() -> {
+ clientMonitor.destroy();
if (mCurrentOperation == null) {
Slog.e(getTag(), "[Finishing] " + clientMonitor
+ " but current operation is null, success: " + success
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 37ee76adeece..4400834efb3f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -164,13 +164,17 @@ class FingerprintAuthenticationClient extends AuthenticationClient<ISession> imp
@Override
protected void stopHalOperation() {
UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController);
- try {
- mCancellationSignal.cancel();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */);
- mCallback.onClientFinished(this, false /* success */);
+ if (mCancellationSignal != null) {
+ try {
+ mCancellationSignal.cancel();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ onError(BiometricFingerprintConstants.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */);
+ mCallback.onClientFinished(this, false /* success */);
+ }
+ } else {
+ Slog.e(TAG, "cancellation signal was null");
}
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c5cffc9e7f76..604b525856dd 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -36,9 +36,14 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.net.Uri;
import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Temperature;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -48,6 +53,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayInfo;
@@ -72,7 +78,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
-
/**
* The DisplayModeDirector is responsible for determining what modes are allowed to be automatically
* picked by the system based on system-wide and display-specific configuration.
@@ -87,6 +92,8 @@ public class DisplayModeDirector {
private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4;
private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5;
private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6;
+ private static final int MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED = 7;
+ private static final int MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED = 8;
// Special ID used to indicate that given vote is to be applied globally, rather than to a
// specific display.
@@ -108,6 +115,7 @@ public class DisplayModeDirector {
private final UdfpsObserver mUdfpsObserver;
private final SensorObserver mSensorObserver;
private final HbmObserver mHbmObserver;
+ private final SkinThermalStatusObserver mSkinThermalStatusObserver;
private final DeviceConfigInterface mDeviceConfig;
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
@@ -155,8 +163,10 @@ public class DisplayModeDirector {
}
};
mSensorObserver = new SensorObserver(context, ballotBox, injector);
- mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
+ mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
+ mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(),
+ mDeviceConfigDisplaySettings);
mDeviceConfig = injector.getDeviceConfig();
mAlwaysRespectAppRequest = false;
}
@@ -174,6 +184,7 @@ public class DisplayModeDirector {
mBrightnessObserver.observe(sensorManager);
mSensorObserver.observe();
mHbmObserver.observe();
+ mSkinThermalStatusObserver.observe();
synchronized (mLock) {
// We may have a listener already registered before the call to start, so go ahead and
// notify them to pick up our newly initialized state.
@@ -605,6 +616,7 @@ public class DisplayModeDirector {
mBrightnessObserver.dumpLocked(pw);
mUdfpsObserver.dumpLocked(pw);
mHbmObserver.dumpLocked(pw);
+ mSkinThermalStatusObserver.dumpLocked(pw);
}
//mLock not needed to collect sensor dump
mSensorObserver.dumpLocked(pw);
@@ -715,6 +727,10 @@ public class DisplayModeDirector {
return mUdfpsObserver;
}
+ @VisibleForTesting
+ HbmObserver getHbmObserver() {
+ return mHbmObserver;
+ }
@VisibleForTesting
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
@@ -785,6 +801,19 @@ public class DisplayModeDirector {
(DesiredDisplayModeSpecsListener) msg.obj;
desiredDisplayModeSpecsListener.onDesiredDisplayModeSpecsChanged();
break;
+
+ case MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED: {
+ int refreshRateInHbmSunlight = msg.arg1;
+ mHbmObserver.onDeviceConfigRefreshRateInHbmSunlightChanged(
+ refreshRateInHbmSunlight);
+ break;
+ }
+
+ case MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED: {
+ int refreshRateInHbmHdr = msg.arg1;
+ mHbmObserver.onDeviceConfigRefreshRateInHbmHdrChanged(refreshRateInHbmHdr);
+ break;
+ }
}
}
}
@@ -911,16 +940,19 @@ public class DisplayModeDirector {
// result is a range.
public static final int PRIORITY_FLICKER_REFRESH_RATE = 1;
+ // High-brightness-mode may need a specific range of refresh-rates to function properly.
+ public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;
+
// SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
// It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
- public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 2;
+ public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 3;
// APP_REQUEST_REFRESH_RATE_RANGE is used to for internal apps to limit the refresh
// rate in certain cases, mostly to preserve power.
// @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
// @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
// It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
- public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 3;
+ public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 4;
// We split the app request into different priorities in case we can satisfy one desire
// without the other.
@@ -935,32 +967,32 @@ public class DisplayModeDirector {
// The preferred refresh rate is set on the main surface of the app outside of
// DisplayModeDirector.
// @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
- public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 4;
- public static final int PRIORITY_APP_REQUEST_SIZE = 5;
+ public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5;
+ public static final int PRIORITY_APP_REQUEST_SIZE = 6;
// SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest
// of low priority voters. It votes [0, max(PEAK, MIN)]
- public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 6;
+ public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 7;
// LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
- public static final int PRIORITY_LOW_POWER_MODE = 7;
+ public static final int PRIORITY_LOW_POWER_MODE = 8;
// PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
// higher priority voters' result is a range, it will fix the rate to a single choice.
// It's used to avoid refresh rate switches in certain conditions which may result in the
// user seeing the display flickering when the switches occur.
- public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
+ public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 9;
- // High-brightness-mode may need a specific range of refresh-rates to function properly.
- public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9;
+ // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
+ public static final int PRIORITY_SKIN_TEMPERATURE = 10;
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
// set to a high priority.
- public static final int PRIORITY_PROXIMITY = 10;
+ public static final int PRIORITY_PROXIMITY = 11;
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
// to function, so this needs to be the highest priority of all votes.
- public static final int PRIORITY_UDFPS = 11;
+ public static final int PRIORITY_UDFPS = 12;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -1055,6 +1087,8 @@ public class DisplayModeDirector {
return "PRIORITY_PROXIMITY";
case PRIORITY_LOW_POWER_MODE:
return "PRIORITY_LOW_POWER_MODE";
+ case PRIORITY_SKIN_TEMPERATURE:
+ return "PRIORITY_SKIN_TEMPERATURE";
case PRIORITY_UDFPS:
return "PRIORITY_UDFPS";
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
@@ -2244,33 +2278,78 @@ public class DisplayModeDirector {
* HBM that are associated with that display. Restrictions are retrieved from
* DisplayManagerInternal but originate in the display-device-config file.
*/
- private static class HbmObserver implements DisplayManager.DisplayListener {
+ public static class HbmObserver implements DisplayManager.DisplayListener {
private final BallotBox mBallotBox;
private final Handler mHandler;
- private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray();
+ private final SparseIntArray mHbmMode = new SparseIntArray();
private final Injector mInjector;
+ private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
+ private int mRefreshRateInHbmSunlight;
+ private int mRefreshRateInHbmHdr;
private DisplayManagerInternal mDisplayManagerInternal;
- HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) {
+ HbmObserver(Injector injector, BallotBox ballotBox, Handler handler,
+ DeviceConfigDisplaySettings displaySettings) {
mInjector = injector;
mBallotBox = ballotBox;
mHandler = handler;
+ mDeviceConfigDisplaySettings = displaySettings;
}
public void observe() {
+ mRefreshRateInHbmSunlight = mDeviceConfigDisplaySettings.getRefreshRateInHbmSunlight();
+ mRefreshRateInHbmHdr = mDeviceConfigDisplaySettings.getRefreshRateInHbmHdr();
+
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
mInjector.registerDisplayListener(this, mHandler,
DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
}
+ /**
+ * @return the refresh to lock to when the device is in high brightness mode for Sunlight.
+ */
+ @VisibleForTesting
+ int getRefreshRateInHbmSunlight() {
+ return mRefreshRateInHbmSunlight;
+ }
+
+ /**
+ * @return the refresh to lock to when the device is in high brightness mode for HDR.
+ */
+ @VisibleForTesting
+ int getRefreshRateInHbmHdr() {
+ return mRefreshRateInHbmHdr;
+ }
+
+ /**
+ * Recalculates the HBM vote when the device config has been changed.
+ */
+ public void onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInHbmSunlight) {
+ mRefreshRateInHbmSunlight = refreshRate;
+ onDeviceConfigRefreshRateInHbmChanged();
+ }
+ }
+
+ /**
+ * Recalculates the HBM vote when the device config has been changed.
+ */
+ public void onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate) {
+ if (refreshRate != mRefreshRateInHbmHdr) {
+ mRefreshRateInHbmHdr = refreshRate;
+ onDeviceConfigRefreshRateInHbmChanged();
+ }
+ }
+
@Override
public void onDisplayAdded(int displayId) {}
@Override
public void onDisplayRemoved(int displayId) {
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
+ mHbmMode.delete(displayId);
}
@Override
@@ -2280,31 +2359,102 @@ public class DisplayModeDirector {
// Display no longer there. Assume we'll get an onDisplayRemoved very soon.
return;
}
- final boolean isHbmEnabled =
- info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
- if (isHbmEnabled == mHbmEnabled.get(displayId)) {
+ final int hbmMode = info.highBrightnessMode;
+ if (hbmMode == mHbmMode.get(displayId)) {
// no change, ignore.
return;
}
+ mHbmMode.put(displayId, hbmMode);
+ recalculateVotesForDisplay(displayId);
+ }
+
+ private void onDeviceConfigRefreshRateInHbmChanged() {
+ final int[] displayIds = mHbmMode.copyKeys();
+ if (displayIds != null) {
+ for (int id : displayIds) {
+ recalculateVotesForDisplay(id);
+ }
+ }
+ }
+
+ private void recalculateVotesForDisplay(int displayId) {
+ final int hbmMode = mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
Vote vote = null;
- mHbmEnabled.put(displayId, isHbmEnabled);
- if (isHbmEnabled) {
- final List<RefreshRateLimitation> limits =
+ if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
+ // Device resource properties take priority over DisplayDeviceConfig
+ if (mRefreshRateInHbmSunlight > 0) {
+ vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight,
+ mRefreshRateInHbmSunlight);
+ } else {
+ final List<RefreshRateLimitation> limits =
mDisplayManagerInternal.getRefreshRateLimitations(displayId);
- for (int i = 0; limits != null && i < limits.size(); i++) {
- final RefreshRateLimitation limitation = limits.get(i);
- if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
- vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max);
- break;
+ for (int i = 0; limits != null && i < limits.size(); i++) {
+ final RefreshRateLimitation limitation = limits.get(i);
+ if (limitation.type == REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE) {
+ vote = Vote.forRefreshRates(limitation.range.min, limitation.range.max);
+ break;
+ }
}
}
}
+ if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ && mRefreshRateInHbmHdr > 0) {
+ vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr);
+ }
mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
}
void dumpLocked(PrintWriter pw) {
pw.println(" HbmObserver");
- pw.println(" mHbmEnabled: " + mHbmEnabled);
+ pw.println(" mHbmMode: " + mHbmMode);
+ pw.println(" mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight);
+ pw.println(" mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr);
+ }
+ }
+
+ private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
+ private final BallotBox mBallotBox;
+ private final Injector mInjector;
+
+ private @Temperature.ThrottlingStatus int mStatus = -1;
+
+ SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) {
+ mInjector = injector;
+ mBallotBox = ballotBox;
+ }
+
+ @Override
+ public void notifyThrottling(Temperature temp) {
+ mStatus = temp.getStatus();
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "New thermal throttling status "
+ + ", current thermal status = " + mStatus);
+ }
+ final Vote vote;
+ if (mStatus >= Temperature.THROTTLING_CRITICAL) {
+ vote = Vote.forRefreshRates(0f, 60f);
+ } else {
+ vote = null;
+ }
+ mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
+ }
+
+ public void observe() {
+ IThermalService thermalService = mInjector.getThermalService();
+ if (thermalService == null) {
+ Slog.w(TAG, "Could not observe thermal status. Service not available");
+ return;
+ }
+ try {
+ thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register thermal status listener", e);
+ }
+ }
+
+ void dumpLocked(PrintWriter writer) {
+ writer.println(" SkinThermalStatusObserver:");
+ writer.println(" mStatus: " + mStatus);
}
}
@@ -2377,6 +2527,29 @@ public class DisplayModeDirector {
return refreshRate;
}
+ public int getRefreshRateInHbmSunlight() {
+ final int defaultRefreshRateInHbmSunlight =
+ mContext.getResources().getInteger(
+ R.integer.config_defaultRefreshRateInHbmSunlight);
+
+ final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT,
+ defaultRefreshRateInHbmSunlight);
+
+ return refreshRate;
+ }
+
+ public int getRefreshRateInHbmHdr() {
+ final int defaultRefreshRateInHbmHdr =
+ mContext.getResources().getInteger(R.integer.config_defaultRefreshRateInHbmHdr);
+
+ final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR,
+ defaultRefreshRateInHbmHdr);
+
+ return refreshRate;
+ }
+
/*
* Return null if no such property
*/
@@ -2416,6 +2589,15 @@ public class DisplayModeDirector {
.sendToTarget();
mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0)
.sendToTarget();
+
+ final int refreshRateInHbmSunlight = getRefreshRateInHbmSunlight();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED,
+ refreshRateInHbmSunlight, 0)
+ .sendToTarget();
+
+ final int refreshRateInHbmHdr = getRefreshRateInHbmHdr();
+ mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED, refreshRateInHbmHdr, 0)
+ .sendToTarget();
}
private int[] getIntArrayProperty(String prop) {
@@ -2469,6 +2651,8 @@ public class DisplayModeDirector {
BrightnessInfo getBrightnessInfo(int displayId);
boolean isDozeState(Display d);
+
+ IThermalService getThermalService();
}
@VisibleForTesting
@@ -2529,6 +2713,12 @@ public class DisplayModeDirector {
return Display.isDozeState(d.getState());
}
+ @Override
+ public IThermalService getThermalService() {
+ return IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ }
+
private DisplayManager getDisplayManager() {
if (mDisplayManager == null) {
mDisplayManager = mContext.getSystemService(DisplayManager.class);
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index b58dd38348aa..0ec05a8189bd 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -411,7 +411,7 @@ final class DisplayPowerState {
* Updates the state of the screen and backlight asynchronously on a separate thread.
*/
private final class PhotonicModulator extends Thread {
- private static final int INITIAL_SCREEN_STATE = Display.STATE_OFF; // unknown, assume off
+ private static final int INITIAL_SCREEN_STATE = Display.STATE_UNKNOWN;
private static final float INITIAL_BACKLIGHT_FLOAT = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private final Object mLock = new Object();
@@ -498,7 +498,9 @@ final class DisplayPowerState {
if (!backlightChanged) {
mBacklightChangeInProgress = false;
}
- if (!stateChanged && !backlightChanged) {
+ boolean valid = state != Display.STATE_UNKNOWN && !Float.isNaN(brightnessState);
+ boolean changed = stateChanged || backlightChanged;
+ if (!valid || !changed) {
try {
mLock.wait();
} catch (InterruptedException ex) {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index dc955337fdbc..3e52f5e07e62 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2582,14 +2582,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (mCurToken != null) {
- try {
- if (DEBUG) {
- Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
- + mCurTokenDisplayId);
- }
- mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
- } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
+ + mCurTokenDisplayId);
}
+ mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */,
+ false /* animateExit */, mCurTokenDisplayId);
// Set IME window status as invisible when unbind current method.
mImeWindowVis = 0;
mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
diff --git a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
index 3019439a430b..5643873bef4d 100644
--- a/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
+++ b/services/core/java/com/android/server/pm/DefaultCrossProfileIntentFiltersUtils.java
@@ -215,7 +215,7 @@ public class DefaultCrossProfileIntentFiltersUtils {
private static final DefaultCrossProfileIntentFilter RECOGNIZE_SPEECH =
new DefaultCrossProfileIntentFilter.Builder(
DefaultCrossProfileIntentFilter.Direction.TO_PARENT,
- /* flags= */0,
+ /* flags= */ ONLY_IF_NO_MATCH_FOUND,
/* letsPersonalDataIntoProfile= */ false)
.addAction(ACTION_RECOGNIZE_SPEECH)
.addCategory(Intent.CATEGORY_DEFAULT)
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index cda48063e914..94e551a11dae 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -480,9 +480,10 @@ public final class Permission {
r.append("DUP:");
r.append(permissionInfo.name);
}
- if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
- // If this is a runtime permission and the owner has changed, or this wasn't a runtime
- // permission, then permission state should be cleaned up
+ if ((permission.isInternal() && ownerChanged)
+ || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) {
+ // If this is an internal/runtime permission and the owner has changed, or this wasn't a
+ // runtime permission, then permission state should be cleaned up.
permission.mDefinitionChanged = true;
}
if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1133faabcf69..7b12709e4efd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1643,7 +1643,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
isRolePermission = permission.isRole();
}
final boolean mayRevokeRolePermission = isRolePermission
- && mayManageRolePermission(callingUid);
+ // Allow ourselves to revoke role permissions due to definition changes.
+ && (callingUid == Process.myUid() || mayManageRolePermission(callingUid));
final boolean isRuntimePermission;
synchronized (mLock) {
@@ -2321,11 +2322,13 @@ public class PermissionManagerService extends IPermissionManager.Stub {
for (int permNum = 0; permNum < numPermissions; permNum++) {
final String permName = permissionsToRevoke.get(permNum);
+ final boolean isInternalPermission;
synchronized (mLock) {
final Permission bp = mRegistry.getPermission(permName);
- if (bp == null || !bp.isRuntime()) {
+ if (bp == null || !(bp.isInternal() || bp.isRuntime())) {
continue;
}
+ isInternalPermission = bp.isInternal();
}
mPackageManagerInt.forEachPackage(pkg -> {
final String packageName = pkg.getPackageName();
@@ -2345,12 +2348,18 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (permissionState == PackageManager.PERMISSION_GRANTED
&& (flags & flagMask) == 0) {
final int uid = UserHandle.getUid(userId, appId);
- EventLog.writeEvent(0x534e4554, "154505240", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
- EventLog.writeEvent(0x534e4554, "168319670", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
+ if (isInternalPermission) {
+ EventLog.writeEvent(0x534e4554, "195338390", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ } else {
+ EventLog.writeEvent(0x534e4554, "154505240", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ EventLog.writeEvent(0x534e4554, "168319670", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ }
Slog.e(TAG, "Revoking permission " + permName + " from package "
+ packageName + " due to definition change");
try {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2b0595492f8a..3d47dcf4eadb 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -129,6 +129,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.NoSuchElementException;
import java.util.Objects;
/**
@@ -1495,7 +1496,11 @@ public final class PowerManagerService extends SystemService
mRequestWaitForNegativeProximity = true;
}
- wakeLock.mLock.unlinkToDeath(wakeLock, 0);
+ try {
+ wakeLock.mLock.unlinkToDeath(wakeLock, 0);
+ } catch (NoSuchElementException e) {
+ Slog.wtf(TAG, "Failed to unlink wakelock", e);
+ }
removeWakeLockLocked(wakeLock, index);
}
}
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 2a95416747a6..06253a08d937 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -124,12 +124,8 @@ public class PowerStatsDataStorage {
@Override
public void read(InputStream in) throws IOException {
while (in.available() > 0) {
- try {
- DataElement dataElement = new DataElement(in);
- mCallback.onReadDataElement(dataElement.getData());
- } catch (IOException e) {
- Slog.e(TAG, "Failed to read from storage. " + e.getMessage());
- }
+ DataElement dataElement = new DataElement(in);
+ mCallback.onReadDataElement(dataElement.getData());
}
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 36a854e5374c..28947083854b 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2304,10 +2304,9 @@ public final class TvInputManagerService extends SystemService {
public void requestChannelBrowsable(Uri channelUri, int userId)
throws RemoteException {
final String callingPackageName = getCallingPackageName();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "requestChannelBrowsable");
final long identity = Binder.clearCallingIdentity();
- final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "requestChannelBrowsable");
try {
Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED);
List<ResolveInfo> list = getContext().getPackageManager()
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 03085af144e6..f6858e50d3c0 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -668,6 +668,12 @@ public final class ActivityRecord extends WindowToken implements WindowManagerSe
boolean mLastImeShown;
/**
+ * When set to true, the IME insets will be frozen until the next app becomes IME input target.
+ * @see InsetsPolicy#adjustVisibilityForIme
+ */
+ boolean mImeInsetsFrozenUntilStartInput;
+
+ /**
* A flag to determine if this AR is in the process of closing or entering PIP. This is needed
* to help AR know that the app is in the process of closing but hasn't yet started closing on
* the WM side.
@@ -1375,6 +1381,7 @@ public final class ActivityRecord extends WindowToken implements WindowManagerSe
}
if (newTask != null && isState(RESUMED)) {
newTask.setResumedActivity(this, "onParentChanged");
+ mImeInsetsFrozenUntilStartInput = false;
}
if (rootTask != null && rootTask.topRunningActivity() == this) {
@@ -4787,6 +4794,7 @@ public final class ActivityRecord extends WindowToken implements WindowManagerSe
&& imeInputTarget.getWindow().mActivityRecord == this
&& mDisplayContent.mInputMethodWindow != null
&& mDisplayContent.mInputMethodWindow.isVisible();
+ mImeInsetsFrozenUntilStartInput = true;
}
final DisplayContent displayContent = getDisplayContent();
@@ -5991,6 +5999,14 @@ public final class ActivityRecord extends WindowToken implements WindowManagerSe
// closing activity having to wait until idle timeout to be stopped or destroyed if the
// next activity won't report idle (e.g. repeated view animation).
mTaskSupervisor.scheduleProcessStoppingAndFinishingActivitiesIfNeeded();
+
+ // If the activity is visible, but no windows are eligible to start input, unfreeze
+ // to avoid permanently frozen IME insets.
+ if (mImeInsetsFrozenUntilStartInput && getWindow(
+ win -> WindowManager.LayoutParams.mayUseInputMethod(win.mAttrs.flags))
+ == null) {
+ mImeInsetsFrozenUntilStartInput = false;
+ }
}
}
@@ -7916,6 +7932,13 @@ public final class ActivityRecord extends WindowToken implements WindowManagerSe
}
}
+ @Override
+ void onResize() {
+ // Reset freezing IME insets flag when the activity resized.
+ mImeInsetsFrozenUntilStartInput = false;
+ super.onResize();
+ }
+
/** Returns true if the configuration is compatible with this activity. */
boolean isConfigurationCompatible(Configuration config) {
final int orientation = getRequestedOrientation();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index dbc1116ad389..9335846e7805 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1165,10 +1165,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- WindowToken removeWindowToken(IBinder binder) {
+ WindowToken removeWindowToken(IBinder binder, boolean animateExit) {
final WindowToken token = mTokenMap.remove(binder);
if (token != null && token.asActivityRecord() == null) {
- token.setExiting();
+ token.setExiting(animateExit);
}
return token;
}
@@ -1252,7 +1252,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void removeAppToken(IBinder binder) {
- final WindowToken token = removeWindowToken(binder);
+ final WindowToken token = removeWindowToken(binder, true /* animateExit */);
if (token == null) {
Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
return;
@@ -3971,6 +3971,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
void updateImeInputAndControlTarget(WindowState target) {
if (mImeInputTarget != target) {
ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target);
+ if (target != null && target.mActivityRecord != null) {
+ target.mActivityRecord.mImeInsetsFrozenUntilStartInput = false;
+ }
setImeInputTarget(target);
updateImeControlTarget();
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index da47328691c0..ed1e784bf275 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -90,6 +90,24 @@ final class ImeInsetsSourceProvider extends InsetsSourceProvider {
onSourceChanged();
}
+ @Override
+ protected boolean updateClientVisibility(InsetsControlTarget caller) {
+ boolean changed = super.updateClientVisibility(caller);
+ if (changed && caller.getRequestedVisibility(mSource.getType())) {
+ reportImeDrawnForOrganizer(caller);
+ }
+ return changed;
+ }
+
+ private void reportImeDrawnForOrganizer(InsetsControlTarget caller) {
+ if (caller.getWindow() != null && caller.getWindow().getTask() != null) {
+ if (caller.getWindow().getTask().isOrganized()) {
+ mWin.mWmService.mAtmService.mTaskOrganizerController.reportImeDrawnOnTask(
+ caller.getWindow().getTask());
+ }
+ }
+ }
+
private void onSourceChanged() {
if (mLastSource.equals(mSource)) {
return;
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index f2f192686ad5..a8e1c1cda72b 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -211,7 +211,7 @@ class InsetsPolicy {
InsetsState getInsetsForWindow(WindowState target) {
final InsetsState originalState = mStateController.getInsetsForWindow(target);
final InsetsState state = adjustVisibilityForTransientTypes(originalState);
- return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state;
+ return adjustVisibilityForIme(target, state, state == originalState);
}
/**
@@ -241,16 +241,37 @@ class InsetsPolicy {
return state;
}
- // Navigation bar insets is always visible to IME.
- private static InsetsState adjustVisibilityForIme(InsetsState originalState,
+ private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
boolean copyState) {
- final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
- if (originalNavSource != null && !originalNavSource.isVisible()) {
- final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
- final InsetsSource navSource = new InsetsSource(originalNavSource);
- navSource.setVisible(true);
- state.addSource(navSource);
- return state;
+ if (w.mIsImWindow) {
+ // Navigation bar insets is always visible to IME.
+ final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
+ if (originalNavSource != null && !originalNavSource.isVisible()) {
+ final InsetsState state = copyState ? new InsetsState(originalState)
+ : originalState;
+ final InsetsSource navSource = new InsetsSource(originalNavSource);
+ navSource.setVisible(true);
+ state.addSource(navSource);
+ return state;
+ }
+ } else if (w.mActivityRecord != null && w.mActivityRecord.mImeInsetsFrozenUntilStartInput) {
+ // During switching tasks with gestural navigation, if the IME is attached to
+ // one app window on that time, even the next app window is behind the IME window,
+ // conceptually the window should not receive the IME insets if the next window is
+ // not eligible IME requester and ready to show IME on top of it.
+ final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+ final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
+
+ if (shouldImeAttachedToApp && originalImeSource != null) {
+ final boolean imeVisibility =
+ w.mActivityRecord.mLastImeShown || w.getRequestedVisibility(ITYPE_IME);
+ final InsetsState state = copyState ? new InsetsState(originalState)
+ : originalState;
+ final InsetsSource imeSource = new InsetsSource(originalImeSource);
+ imeSource.setVisible(imeVisibility);
+ state.addSource(imeSource);
+ return state;
+ }
}
return originalState;
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index fe1020c86041..cf0f973fa7db 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -106,13 +106,13 @@ class KeyguardController {
}
/**
- * @return {@code true} for default display when AOD is showing. Otherwise, same as
- * {@link #isKeyguardOrAodShowing(int)}
+ * @return {@code true} for default display when AOD is showing, not going away. Otherwise, same
+ * as {@link #isKeyguardOrAodShowing(int)}
* TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic.
*/
boolean isKeyguardUnoccludedOrAodShowing(int displayId) {
if (displayId == DEFAULT_DISPLAY && mAodShowing) {
- return true;
+ return !mKeyguardGoingAway;
}
return isKeyguardOrAodShowing(displayId);
}
@@ -477,7 +477,7 @@ class KeyguardController {
final KeyguardDisplayState state = getDisplayState(displayId);
if (isKeyguardUnoccludedOrAodShowing(displayId)) {
state.mSleepTokenAcquirer.acquire(displayId);
- } else if (!isKeyguardUnoccludedOrAodShowing(displayId)) {
+ } else {
state.mSleepTokenAcquirer.release(displayId);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 251eeb1af268..3b43412f117e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5154,7 +5154,7 @@ class Task extends WindowContainer<WindowContainer> {
/**
* @return true if the task is currently focused.
*/
- private boolean isFocused() {
+ boolean isFocused() {
if (mDisplayContent == null || mDisplayContent.mCurrentFocus == null) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 09c5581385dd..88467baa6c34 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -733,6 +733,17 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
mPendingTaskEvents.clear();
}
+ void reportImeDrawnOnTask(Task task) {
+ final TaskOrganizerState state = mTaskOrganizerStates.get(task.mTaskOrganizer.asBinder());
+ if (state != null) {
+ try {
+ state.mOrganizer.mTaskOrganizer.onImeDrawnOnTask(task.mTaskId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception sending onImeDrawnOnTask callback", e);
+ }
+ }
+ }
+
void onTaskInfoChanged(Task task, boolean force) {
if (!task.mTaskAppearedSent) {
// Skip if task still not appeared.
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 194f48f57cc4..b54e8b7a7b4e 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -66,8 +66,8 @@ class WallpaperWindowToken extends WindowToken {
}
@Override
- void setExiting() {
- super.setExiting();
+ void setExiting(boolean animateExit) {
+ super.setExiting(animateExit);
mDisplayContent.mWallpaperController.removeWallpaperToken(this);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 47087cfbd147..4fac05c349c5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -445,8 +445,21 @@ public abstract class WindowManagerInternal {
* @param removeWindows Whether to also remove the windows associated with the token.
* @param displayId The display to remove the token from.
*/
+ public final void removeWindowToken(android.os.IBinder token, boolean removeWindows,
+ int displayId) {
+ removeWindowToken(token, removeWindows, true /* animateExit */, displayId);
+ }
+
+ /**
+ * Removes a window token.
+ *
+ * @param token The toke to remove.
+ * @param removeWindows Whether to also remove the windows associated with the token.
+ * @param animateExit Whether to play the windows exit animation after the token removal.
+ * @param displayId The display to remove the token from.
+ */
public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows,
- int displayId);
+ boolean animateExit, int displayId);
/**
* Registers a listener to be notified about app transition events.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1f0a4da85267..c9e596d106ca 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2820,6 +2820,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
+ void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+
+ if (dc == null) {
+ ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+ + " for non-exiting displayId=%d", binder, displayId);
+ return;
+ }
+ final WindowToken token = dc.removeWindowToken(binder, animateExit);
+ if (token == null) {
+ ProtoLog.w(WM_ERROR,
+ "removeWindowToken: Attempted to remove non-existing token: %s",
+ binder);
+ return;
+ }
+
+ if (removeWindows) {
+ token.removeAllWindowsIfPossible();
+ }
+ dc.getInputMonitor().updateInputWindowsLw(true /* force */);
+ }
+ }
+
@Override
public void removeWindowToken(IBinder binder, int displayId) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
@@ -2827,23 +2852,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
final long origId = Binder.clearCallingIdentity();
try {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
-
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
- dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
- }
+ removeWindowToken(binder, false /* removeWindows */, true /* animateExit */, displayId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -7565,28 +7574,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) {
- synchronized (mGlobalLock) {
- if (removeWindows) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
-
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
-
- token.removeAllWindowsIfPossible();
- }
- WindowManagerService.this.removeWindowToken(binder, displayId);
- }
+ public void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ WindowManagerService.this.removeWindowToken(binder, removeWindows, animateExit,
+ displayId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c3fc99554bcc..5e042efa2f11 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2180,11 +2180,18 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- boolean onSetAppExiting() {
+ boolean onSetAppExiting(boolean animateExit) {
final DisplayContent displayContent = getDisplayContent();
boolean changed = false;
- if (isVisibleNow()) {
+ if (!animateExit) {
+ // Hide the window permanently if no window exist animation is performed, so we can
+ // avoid the window surface becoming visible again unexpectedly during the next
+ // relayout.
+ mPermanentlyHidden = true;
+ hide(false /* doAnimation */, false /* requestAnim */);
+ }
+ if (isVisibleNow() && animateExit) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT);
@@ -2197,7 +2204,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
- changed |= c.onSetAppExiting();
+ changed |= c.onSetAppExiting(animateExit);
}
return changed;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index fbfa400ba852..3cbc67c004cd 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -24,6 +24,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -232,7 +233,7 @@ class WindowToken extends WindowContainer<WindowState> {
}
}
- void setExiting() {
+ void setExiting(boolean animateExit) {
if (isEmpty()) {
super.removeImmediately();
return;
@@ -247,11 +248,12 @@ class WindowToken extends WindowContainer<WindowState> {
final int count = mChildren.size();
boolean changed = false;
- final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
+ final boolean delayed = isAnimating(TRANSITION | PARENTS)
+ || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit);
for (int i = 0; i < count; i++) {
final WindowState win = mChildren.get(i);
- changed |= win.onSetAppExiting();
+ changed |= win.onSetAppExiting(animateExit);
}
final ActivityRecord app = asActivityRecord();
@@ -353,7 +355,7 @@ class WindowToken extends WindowContainer<WindowState> {
@Override
void removeImmediately() {
if (mDisplayContent != null) {
- mDisplayContent.removeWindowToken(token);
+ mDisplayContent.removeWindowToken(token, true /* animateExit */);
}
// Needs to occur after the token is removed from the display above to avoid attempt at
// duplicate removal of this window container from it's parent.
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index acf50b4569c6..e472b062388e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -323,6 +323,7 @@ public class DeviceIdleControllerTest {
when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mWakeLock);
doNothing().when(mWakeLock).acquire();
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
+ doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), anyString(), any(), any());
doNothing().when(mAlarmManager)
.setWindow(anyInt(), anyLong(), anyLong(), anyString(), any(), any());
doReturn(mock(Sensor.class)).when(mSensorManager)
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index fd364ae77240..51fa8517e45f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -37,6 +37,8 @@ import static org.mockito.Mockito.times;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.os.Bundle;
import android.os.RecoverySystem;
@@ -83,6 +85,8 @@ public class RescuePartyTest {
private static final String CALLING_PACKAGE1 = "com.package.name1";
private static final String CALLING_PACKAGE2 = "com.package.name2";
private static final String CALLING_PACKAGE3 = "com.package.name3";
+ private static final String PERSISTENT_PACKAGE = "com.persistent.package";
+ private static final String NON_PERSISTENT_PACKAGE = "com.nonpersistent.package";
private static final String NAMESPACE1 = "namespace1";
private static final String NAMESPACE2 = "namespace2";
private static final String NAMESPACE3 = "namespace3";
@@ -103,6 +107,8 @@ public class RescuePartyTest {
private PackageWatchdog mMockPackageWatchdog;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private ContentResolver mMockContentResolver;
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private PackageManager mPackageManager;
@Captor
private ArgumentCaptor<RemoteCallback> mMonitorCallbackCaptor;
@@ -129,6 +135,17 @@ public class RescuePartyTest {
mNamespacesWiped = new HashSet<>();
when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+ when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
+ ApplicationInfo persistentApplicationInfo = new ApplicationInfo();
+ persistentApplicationInfo.flags |=
+ ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_PERSISTENT;
+
+ // If the package name is PERSISTENT_PACKAGE, then set the flags to be persistent and
+ // system. Don't set any flags otherwise.
+ when(mPackageManager.getApplicationInfo(eq(PERSISTENT_PACKAGE),
+ anyInt())).thenReturn(persistentApplicationInfo);
+ when(mPackageManager.getApplicationInfo(eq(NON_PERSISTENT_PACKAGE),
+ anyInt())).thenReturn(new ApplicationInfo());
// Reset observer instance to get new mock context on every run
RescuePartyObserver.reset();
@@ -241,29 +258,53 @@ public class RescuePartyTest {
@Test
public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
- notePersistentAppCrash(1);
+ noteAppCrash(1, true);
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
/*configResetVerifiedTimesMap=*/ null);
- notePersistentAppCrash(2);
+ noteAppCrash(2, true);
verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null,
/*configResetVerifiedTimesMap=*/ null);
- notePersistentAppCrash(3);
+ noteAppCrash(3, true);
verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
/*configResetVerifiedTimesMap=*/ null);
- notePersistentAppCrash(4);
+ noteAppCrash(4, true);
assertTrue(RescueParty.isRebootPropertySet());
- notePersistentAppCrash(5);
+ noteAppCrash(5, true);
assertTrue(RescueParty.isFactoryResetPropertySet());
}
@Test
+ public void testNonPersistentAppOnlyPerformsFlagResets() {
+ noteAppCrash(1, false);
+
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
+
+ noteAppCrash(2, false);
+
+ verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
+
+ noteAppCrash(3, false);
+
+ verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS, /*resetNamespaces=*/ null,
+ /*configResetVerifiedTimesMap=*/ null);
+
+ noteAppCrash(4, false);
+ assertFalse(RescueParty.isRebootPropertySet());
+
+ noteAppCrash(5, false);
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
public void testNonPersistentAppCrashDetectionWithScopedResets() {
RescueParty.onSettingsProviderPublished(mMockContext);
verify(() -> Settings.Config.registerMonitorCallback(eq(mMockContentResolver),
@@ -311,11 +352,11 @@ public class RescuePartyTest {
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
- assertTrue(RescueParty.isRebootPropertySet());
+ assertFalse(RescueParty.isRebootPropertySet());
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
- assertTrue(RescueParty.isFactoryResetPropertySet());
+ assertFalse(RescueParty.isFactoryResetPropertySet());
}
@Test
@@ -376,11 +417,11 @@ public class RescuePartyTest {
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 4);
- assertTrue(RescueParty.isRebootPropertySet());
+ assertFalse(RescueParty.isRebootPropertySet());
observer.execute(new VersionedPackage(
CALLING_PACKAGE1, 1), PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING, 5);
- assertTrue(RescueParty.isFactoryResetPropertySet());
+ assertFalse(RescueParty.isFactoryResetPropertySet());
}
@Test
@@ -627,9 +668,10 @@ public class RescuePartyTest {
RescuePartyObserver.getInstance(mMockContext).executeBootLoopMitigation(mitigationCount);
}
- private void notePersistentAppCrash(int mitigationCount) {
+ private void noteAppCrash(int mitigationCount, boolean isPersistent) {
+ String packageName = isPersistent ? PERSISTENT_PACKAGE : NON_PERSISTENT_PACKAGE;
RescuePartyObserver.getInstance(mMockContext).execute(new VersionedPackage(
- "com.package.name", 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, mitigationCount);
+ packageName, 1), PackageWatchdog.FAILURE_REASON_APP_CRASH, mitigationCount);
}
private Bundle getConfigAccessBundle(String callingPackage, String namespace) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index f4d14995f7c7..a41f79e8f682 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -348,6 +348,17 @@ public class BiometricSchedulerTest {
verify((Interruptable) interruptableMonitor, never()).cancel();
}
+ @Test
+ public void testClientDestroyed_afterFinish() {
+ final HalClientMonitor.LazyDaemon<Object> nonNullDaemon = () -> mock(Object.class);
+ final TestClientMonitor client =
+ new TestClientMonitor(mContext, mToken, nonNullDaemon);
+ mScheduler.scheduleClientMonitor(client);
+ client.mCallback.onClientFinished(client, true /* success */);
+ waitForIdle();
+ assertTrue(client.wasDestroyed());
+ }
+
private BiometricSchedulerProto getDump(boolean clearSchedulerBuffer) throws Exception {
return BiometricSchedulerProto.parseFrom(mScheduler.dumpProtoState(clearSchedulerBuffer));
}
@@ -437,6 +448,7 @@ public class BiometricSchedulerTest {
private static class TestClientMonitor extends HalClientMonitor<Object> {
private boolean mUnableToStart;
private boolean mStarted;
+ private boolean mDestroyed;
public TestClientMonitor(@NonNull Context context, @NonNull IBinder token,
@NonNull LazyDaemon<Object> lazyDaemon) {
@@ -475,6 +487,11 @@ public class BiometricSchedulerTest {
}
+ @Override
+ public void destroy() {
+ mDestroyed = true;
+ }
+
public boolean wasUnableToStart() {
return mUnableToStart;
}
@@ -482,6 +499,11 @@ public class BiometricSchedulerTest {
public boolean hasStarted() {
return mStarted;
}
+
+ public boolean wasDestroyed() {
+ return mDestroyed;
+ }
+
}
private static void waitForIdle() {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 1ac28abb4c2f..0dd5c61121db 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -20,6 +20,8 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REF
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT;
+import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
@@ -56,7 +58,11 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
import android.os.Looper;
+import android.os.RemoteException;
+import android.os.Temperature;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
@@ -116,6 +122,8 @@ public class DisplayModeDirectorTest {
public SensorManagerInternal mSensorManagerInternalMock;
@Mock
public DisplayManagerInternal mDisplayManagerInternalMock;
+ @Mock
+ public IThermalService mThermalServiceMock;
@Before
public void setUp() throws Exception {
@@ -124,6 +132,7 @@ public class DisplayModeDirectorTest {
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
when(mContext.getContentResolver()).thenReturn(resolver);
mInjector = spy(new FakesInjector());
+ when(mInjector.getThermalService()).thenReturn(mThermalServiceMock);
mHandler = new Handler(Looper.getMainLooper());
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -1401,6 +1410,12 @@ public class DisplayModeDirectorTest {
public void testHbmVoting_forHdr() {
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ final int hbmRefreshRate = 72;
+
+ // Specify limitation before starting DisplayModeDirector to avoid waiting on property
+ // propagation
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(hbmRefreshRate);
+
director.start(createMockSensorManager());
ArgumentCaptor<DisplayListener> captor =
@@ -1425,7 +1440,7 @@ public class DisplayModeDirectorTest {
new BrightnessInfo(0.45f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
- assertVoteForRefreshRate(vote, 60.f);
+ assertVoteForRefreshRate(vote, hbmRefreshRate);
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
@@ -1436,6 +1451,44 @@ public class DisplayModeDirectorTest {
}
@Test
+ public void testHbmObserverGetsUpdatedRefreshRateInHbmSunlight() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+
+ final int initialRefreshRate = 60;
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(initialRefreshRate);
+ director.start(createMockSensorManager());
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight())
+ .isEqualTo(initialRefreshRate);
+
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight())
+ .isEqualTo(updatedRefreshRate);
+ }
+
+ @Test
+ public void testHbmObserverGetsUpdatedRefreshRateInHbmHdr() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
+
+ final int initialRefreshRate = 60;
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(initialRefreshRate);
+ director.start(createMockSensorManager());
+ assertThat(director.getHbmObserver().getRefreshRateInHbmHdr())
+ .isEqualTo(initialRefreshRate);
+
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmHdr())
+ .isEqualTo(updatedRefreshRate);
+ }
+
+ @Test
public void testHbmVoting_forSunlight() {
DisplayModeDirector director =
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
@@ -1448,11 +1501,12 @@ public class DisplayModeDirectorTest {
| DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
DisplayListener listener = captor.getValue();
+ final int initialRefreshRate = 60;
// Specify Limitation
when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID)).thenReturn(
List.of(new RefreshRateLimitation(
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE,
- 60.f, 60.f)));
+ initialRefreshRate, initialRefreshRate)));
// Verify that there is no HBM vote initially
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
@@ -1463,7 +1517,39 @@ public class DisplayModeDirectorTest {
new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
listener.onDisplayChanged(DISPLAY_ID);
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
- assertVoteForRefreshRate(vote, 60.f);
+ assertVoteForRefreshRate(vote, initialRefreshRate);
+
+ // Change refresh rate vote value through DeviceConfig, ensure it takes precedence
+ final int updatedRefreshRate = 90;
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(updatedRefreshRate);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight())
+ .isEqualTo(updatedRefreshRate);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, updatedRefreshRate);
+
+ // Turn off HBM
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(0.43f, 0.1f, 0.8f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Turn HBM on again and ensure the updated vote value stuck
+ when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
+ new BrightnessInfo(1.0f, 0.0f, 1.0f, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT));
+ listener.onDisplayChanged(DISPLAY_ID);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, updatedRefreshRate);
+
+ // Reset DeviceConfig refresh rate, ensure vote falls back to the initial value
+ mInjector.getDeviceConfig().setRefreshRateInHbmSunlight(0);
+ // Need to wait for the property change to propagate to the main thread.
+ waitForIdleSync();
+ assertThat(director.getHbmObserver().getRefreshRateInHbmSunlight()).isEqualTo(0);
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertVoteForRefreshRate(vote, initialRefreshRate);
// Turn off HBM
when(mInjector.getBrightnessInfo(DISPLAY_ID)).thenReturn(
@@ -1511,6 +1597,63 @@ public class DisplayModeDirectorTest {
assertNull(vote);
}
+ private void setHbmAndAssertRefreshRate(
+ DisplayModeDirector director, DisplayListener listener, int mode, float rr) {
+ when(mInjector.getBrightnessInfo(DISPLAY_ID))
+ .thenReturn(new BrightnessInfo(1.0f, 0.0f, 1.0f, mode));
+ listener.onDisplayChanged(DISPLAY_ID);
+
+ final Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ if (Float.isNaN(rr)) {
+ assertNull(vote);
+ } else {
+ assertVoteForRefreshRate(vote, rr);
+ }
+ }
+
+ @Test
+ public void testHbmVoting_forSunlightAndHdr() {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+
+ // Specify HDR limitation before starting DisplayModeDirector to avoid waiting on property
+ // propagation
+ final int hdrRr = 60;
+ mInjector.getDeviceConfig().setRefreshRateInHbmHdr(hdrRr);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class);
+ verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ DisplayListener listener = captor.getValue();
+
+ // Specify Sunlight limitations
+ final float sunlightRr = 90.0f;
+ when(mDisplayManagerInternalMock.getRefreshRateLimitations(DISPLAY_ID))
+ .thenReturn(List.of(new RefreshRateLimitation(
+ DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, sunlightRr,
+ sunlightRr)));
+
+ // Verify that there is no HBM vote initially
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE);
+ assertNull(vote);
+
+ // Verify all state transitions
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, sunlightRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, hdrRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, Float.NaN);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR, hdrRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT, sunlightRr);
+ setHbmAndAssertRefreshRate(
+ director, listener, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF, Float.NaN);
+ }
+
@Test
public void testHbmVoting_RemovedDisplay() {
DisplayModeDirector director =
@@ -1547,12 +1690,52 @@ public class DisplayModeDirectorTest {
assertNull(vote);
}
+ @Test
+ public void testSkinTemperature() throws RemoteException {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<IThermalEventListener> thermalEventListener =
+ ArgumentCaptor.forClass(IThermalEventListener.class);
+
+ verify(mThermalServiceMock).registerThermalEventListenerWithType(
+ thermalEventListener.capture(), eq(Temperature.TYPE_SKIN));
+ final IThermalEventListener listener = thermalEventListener.getValue();
+
+ // Verify that there is no skin temperature vote initially.
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+ assertNull(vote);
+
+ // Set the skin temperature to critical and verify that we added a vote.
+ listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+ assertVoteForRefreshRateRange(vote, 0f, 60.f);
+
+ // Set the skin temperature to severe and verify that the vote is gone.
+ listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE));
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+ assertNull(vote);
+ }
+
+ private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
+ return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
+ }
+
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
assertThat(vote).isNotNull();
final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
}
+ private void assertVoteForRefreshRateRange(
+ Vote vote, float refreshRateLow, float refreshRateHigh) {
+ assertThat(vote).isNotNull();
+ final RefreshRateRange expectedRange =
+ new RefreshRateRange(refreshRateLow, refreshRateHigh);
+ assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
+ }
+
public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
@Override
public String getProperty(String namespace, String name) {
@@ -1575,6 +1758,16 @@ public class DisplayModeDirectorTest {
String.valueOf(fps));
}
+ void setRefreshRateInHbmSunlight(int fps) {
+ putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_REFRESH_RATE_IN_HBM_SUNLIGHT, String.valueOf(fps));
+ }
+
+ void setRefreshRateInHbmHdr(int fps) {
+ putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
+ KEY_REFRESH_RATE_IN_HBM_HDR, String.valueOf(fps));
+ }
+
void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) {
String thresholds = toPropertyValue(brightnessThresholds);
@@ -1748,6 +1941,11 @@ public class DisplayModeDirectorTest {
return false;
}
+ @Override
+ public IThermalService getThermalService() {
+ return null;
+ }
+
void notifyPeakRefreshRateChanged() {
if (mPeakRefreshRateObserver != null) {
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 293e862a6b74..6f04f176afd8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -39,6 +39,7 @@ import static android.os.Process.NOBODY_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -2816,6 +2817,73 @@ public class ActivityRecordTests extends WindowTestsBase {
assertFalse(activity.mDisplayContent.mClosingApps.contains(activity));
}
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenReparented() {
+ final ActivityRecord activity = createActivityWithTask();
+ final WindowState app = createWindow(null, TYPE_APPLICATION, activity, "app");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ final Task newTask = new TaskBuilder(mSupervisor).build();
+ makeWindowVisible(app, imeWindow);
+ mDisplayContent.mInputMethodWindow = imeWindow;
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+ activity.setState(RESUMED, "test");
+ activity.reparent(newTask, 0 /* top */, "test");
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenResized() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ makeWindowVisibleAndDrawn(app, mImeWindow);
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity is reparent to the new task.
+ app.mActivityRecord.onResize();
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
+ @UseTestDisplay(addWindows = W_INPUT_METHOD)
+ @Test
+ public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ makeWindowVisibleAndDrawn(app, mImeWindow);
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+
+ // Simulate app is closing and expect the last IME is shown and IME insets is frozen.
+ app.mActivityRecord.commitVisibility(false, false);
+ app.mActivityRecord.onWindowsGone();
+
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Expect IME insets frozen state will reset when the activity has no IME focusable window.
+ app.mActivityRecord.forAllWindowsUnchecked(w -> {
+ w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+ return true;
+ }, true);
+
+ app.mActivityRecord.commitVisibility(true, false);
+ app.mActivityRecord.onWindowsVisible();
+
+ assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+ }
+
private void assertHasStartingWindow(ActivityRecord atoken) {
assertNotNull(atoken.mStartingSurface);
assertNotNull(atoken.mStartingData);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 12fc2f4ea1f4..5a6581f94154 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2166,6 +2166,21 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testKeyguardGoingAwayWhileAodShown() {
+ mDisplayContent.getDisplayPolicy().setAwake(true);
+
+ final WindowState appWin = createWindow(null, TYPE_APPLICATION, mDisplayContent, "appWin");
+ final ActivityRecord activity = appWin.mActivityRecord;
+
+ mAtm.mKeyguardController.setKeyguardShown(true /* keyguardShowing */,
+ true /* aodShowing */);
+ assertFalse(activity.isVisibleRequested());
+
+ mAtm.mKeyguardController.keyguardGoingAway(0 /* flags */);
+ assertTrue(activity.isVisibleRequested());
+ }
+
+ @Test
public void testRemoveRootTaskInWindowingModes() {
removeRootTaskTests(() -> mRootWindowContainer.removeRootTasksInWindowingModes(
WINDOWING_MODE_FULLSCREEN));
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index a8e17534e6ed..8e7ba4bc3293 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -258,6 +258,7 @@ public class SystemServicesTestRule implements TestRule {
final ActivityManagerInternal amInternal = mAmService.mInternal;
spyOn(amInternal);
doNothing().when(amInternal).trimApplications();
+ doNothing().when(amInternal).scheduleAppGcs();
doNothing().when(amInternal).updateCpuStats();
doNothing().when(amInternal).updateOomAdj();
doNothing().when(amInternal).updateBatteryStats(any(), anyInt(), anyInt(), anyBoolean());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index d6a8401f5b18..ab496cf34acc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -797,6 +797,9 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo) {
}
@Override
+ public void onImeDrawnOnTask(int taskId) throws RemoteException {
+ }
+ @Override
public void onAppSplashScreenViewRemoved(int taskId) {
}
};
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 92b670ed9699..d88ac256be5c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -891,6 +891,40 @@ public class WindowStateTests extends WindowTestsBase {
assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
}
+ @Test
+ public void testAdjustImeInsetsVisibilityWhenSwitchingApps() {
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+ final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
+ final WindowState imeWindow = createWindow(null, TYPE_APPLICATION, "imeWindow");
+ spyOn(imeWindow);
+ doReturn(true).when(imeWindow).isVisible();
+ mDisplayContent.mInputMethodWindow = imeWindow;
+
+ final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+ controller.getImeSourceProvider().setWindow(imeWindow, null, null);
+
+ // Simulate app requests IME with updating all windows Insets State when IME is above app.
+ mDisplayContent.setImeLayeringTarget(app);
+ mDisplayContent.setImeInputTarget(app);
+ assertTrue(mDisplayContent.shouldImeAttachedToApp());
+ controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+ controller.getImeSourceProvider().getSource().setVisible(true);
+ controller.updateAboveInsetsState(imeWindow, false);
+
+ // Expect all app windows behind IME can receive IME insets visible.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertTrue(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+
+ // Simulate app plays closing transition to app2.
+ app.mActivityRecord.commitVisibility(false, false);
+ assertTrue(app.mActivityRecord.mLastImeShown);
+ assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
+
+ // Verify the IME insets is visible on app, but not for app2 during app task switching.
+ assertTrue(app.getInsetsState().getSource(ITYPE_IME).isVisible());
+ assertFalse(app2.getInsetsState().getSource(ITYPE_IME).isVisible());
+ }
+
@UseTestDisplay(addWindows = { W_ACTIVITY })
@Test
public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index d048f1842aa3..589f9134f227 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -44,6 +45,7 @@ import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import java.util.function.BiFunction;
@@ -126,7 +128,7 @@ public class WindowTokenTests extends WindowTestsBase {
final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1");
final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2");
- mDisplayContent.removeWindowToken(token.token);
+ mDisplayContent.removeWindowToken(token.token, true /* animateExit */);
// Verify that the token is no longer mapped on the display
assertNull(mDisplayContent.getWindowToken(token.token));
// Verify that the token is still attached to its parent
@@ -261,4 +263,29 @@ public class WindowTokenTests extends WindowTestsBase {
assertNotNull(app.getFrozenInsetsState());
assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState());
}
+
+ @Test
+ public void testRemoveWindowToken_noAnimateExitWhenSet() {
+ final TestWindowToken token = createTestWindowToken(0, mDisplayContent);
+ final WindowState win = createWindow(null, TYPE_APPLICATION, token, "win");
+ makeWindowVisible(win);
+ assertTrue(win.isOnScreen());
+ spyOn(win);
+ spyOn(win.mWinAnimator);
+ spyOn(win.mToken);
+
+ // Invoking removeWindowToken with setting no window exit animation and not remove window
+ // immediately. verify the window will hide without applying exit animation.
+ mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */,
+ mDisplayContent.mDisplayId);
+ verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */);
+ verify(win).hide(false /* doAnimation */, false /* requestAnim */);
+ assertFalse(win.isOnScreen());
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ assertTrue(win.mToken.hasChild());
+
+ // Even though the window is being removed afterwards, it won't apply exit animation.
+ win.removeIfPossible();
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ }
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 0c1cf600ef23..b57ea0789ef8 100755
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1196,7 +1196,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
} else if (mCurrentFunctions == UsbManager.FUNCTION_MIDI) {
titleRes = com.android.internal.R.string.usb_midi_notification_title;
id = SystemMessage.NOTE_USB_MIDI;
- } else if (mCurrentFunctions == UsbManager.FUNCTION_RNDIS) {
+ } else if ((mCurrentFunctions == UsbManager.FUNCTION_RNDIS)
+ || (mCurrentFunctions == UsbManager.FUNCTION_NCM)) {
titleRes = com.android.internal.R.string.usb_tether_notification_title;
id = SystemMessage.NOTE_USB_TETHER;
} else if (mCurrentFunctions == UsbManager.FUNCTION_ACCESSORY) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 5d56461e894e..b5fdfc2d6ec6 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -791,6 +791,21 @@ public abstract class Connection extends Conferenceable {
"android.telecom.extra.REMOTE_PHONE_ACCOUNT_HANDLE";
/**
+ * The Telecom call ID of the conference an existing connection should be added to. This is
+ * required when {@link com.android.services.telephony.TelephonyConnectionService} adds a
+ * {@link Conference} to Telecom using the
+ * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection, Conference)}
+ * API. That API specifies a parent conference associated with the new existing connection
+ * being added, and there is no equivalent as part of the {@link RemoteConnectionService} API.
+ * This extra key is used to stack the ID of the conference to which the existing connection
+ * will be added so that Telecom can link it up correctly when the {@link RemoteConference}
+ * is added to Telecom by the connection manager.
+ * @hide
+ */
+ public static final String EXTRA_ADD_TO_CONFERENCE_ID =
+ "android.telecom.extra.ADD_TO_CONFERENCE_ID";
+
+ /**
* Extra key set from a {@link ConnectionService} when using the remote connection APIs
* (e.g. {@link RemoteConnectionService#createRemoteConnection(PhoneAccountHandle,
* ConnectionRequest, boolean)}) to create a remote connection. Provides the receiving
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index bf6a6ef793ff..efe35d21c003 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -239,13 +239,9 @@ final class RemoteConnectionService {
conference.addConnection(c);
}
}
- if (conference.getConnections().size() == 0) {
- // A conference was created, but none of its connections are ones that have been
- // created by, and therefore being tracked by, this remote connection service. It
- // is of no interest to us.
- Log.d(this, "addConferenceCall - skipping");
- return;
- }
+ // We used to skip adding empty conferences; however in the world of IMS conference
+ // calls we need to add them to the remote connection service because they will always
+ // start with no participants.
conference.setState(parcel.getState());
conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
@@ -379,6 +375,8 @@ final class RemoteConnectionService {
@Override
public void addExistingConnection(String callId, ParcelableConnection connection,
Session.Info sessionInfo) {
+ Log.i(RemoteConnectionService.this, "addExistingConnection: callId=%s, conn=%s", callId,
+ connection);
String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
getOpPackageName();
int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo()
@@ -390,6 +388,20 @@ final class RemoteConnectionService {
Bundle newExtras = new Bundle();
newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
connection.getPhoneAccount());
+ if (connection.getParentCallId() != null) {
+ RemoteConference parentConf = mConferenceById.get(connection.getParentCallId());
+ // If there is a parent being set, we need to stash the conference ID here.
+ // Telephony can add an existing connection while specifying a parent conference.
+ // There is no equivalent version of that operation as part of the remote connection
+ // API, so we will stash the pre-defined parent's ID in the extras. When the
+ // connectionmanager copies over the extras from the remote connection to the
+ // actual one, it'll get passed to Telecom so that it can make the association.
+ if (parentConf != null) {
+ newExtras.putString(Connection.EXTRA_ADD_TO_CONFERENCE_ID, parentConf.getId());
+ Log.i(this, "addExistingConnection: stash parent of %s as %s",
+ connection.getParentCallId(), parentConf.getId());
+ }
+ }
remoteConnection.putExtras(newExtras);
mConnectionById.put(callId, remoteConnection);
remoteConnection.registerCallback(new RemoteConnection.Callback() {