Merge "Fix profile owners uid logic" into udc-dev
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
index a9f720a..515ddc8 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
@@ -80,7 +80,7 @@
private void prepareForNextRun() {
SystemClock.sleep(COOL_OFF_PERIOD_MS);
- ShellHelper.runShellCommand("am wait-for-broadcast-idle");
+ ShellHelper.runShellCommand("am wait-for-broadcast-idle --flush-broadcast-loopers");
mStartTimeNs = System.nanoTime();
mPausedDurationNs = 0;
}
@@ -102,7 +102,7 @@
* to avoid unnecessary waiting.
*/
public void resumeTiming() {
- ShellHelper.runShellCommand("am wait-for-broadcast-idle");
+ ShellHelper.runShellCommand("am wait-for-broadcast-idle --flush-broadcast-loopers");
resumeTimer();
}
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 19a4766..6dba5b3 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -1541,7 +1541,8 @@
private void waitForBroadcastIdle() {
try {
- ShellHelper.runShellCommandWithTimeout("am wait-for-broadcast-idle", TIMEOUT_IN_SECOND);
+ ShellHelper.runShellCommandWithTimeout(
+ "am wait-for-broadcast-idle --flush-broadcast-loopers", TIMEOUT_IN_SECOND);
} catch (TimeoutException e) {
Log.e(TAG, "Ending waitForBroadcastIdle because it is taking too long", e);
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index df9257c..5c1b3ee 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5006,12 +5006,6 @@
return mUserExtras;
}
- private Bundle getAllExtras() {
- final Bundle saveExtras = (Bundle) mUserExtras.clone();
- saveExtras.putAll(mN.extras);
- return saveExtras;
- }
-
/**
* Add an action to this notification. Actions are typically displayed by
* the system as a button adjacent to the notification content.
@@ -6617,9 +6611,16 @@
+ " vs bubble: " + mN.mBubbleMetadata.getShortcutId());
}
- // first, add any extras from the calling code
+ // Adds any new extras provided by the user.
if (mUserExtras != null) {
- mN.extras = getAllExtras();
+ final Bundle saveExtras = (Bundle) mUserExtras.clone();
+ if (SystemProperties.getBoolean(
+ "persist.sysui.notification.builder_extras_override", false)) {
+ mN.extras.putAll(saveExtras);
+ } else {
+ saveExtras.putAll(mN.extras);
+ mN.extras = saveExtras;
+ }
}
mN.creationTime = System.currentTimeMillis();
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 776e34b..385fd50 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -24,9 +24,11 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UserIdInt;
import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
+import android.compat.annotation.LoggingOnly;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
@@ -49,6 +51,7 @@
import android.view.KeyEvent;
import android.view.View;
+import com.android.internal.compat.IPlatformCompat;
import com.android.internal.statusbar.AppClipsServiceConnector;
import com.android.internal.statusbar.IAddTileResultCallback;
import com.android.internal.statusbar.IStatusBarService;
@@ -170,6 +173,8 @@
public @interface Disable2Flags {}
// LINT.ThenChange(frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt)
+ private static final String TAG = "StatusBarManager";
+
/**
* Default disable flags for setup
*
@@ -572,13 +577,13 @@
private static final long MEDIA_CONTROL_SESSION_ACTIONS = 203800354L;
/**
- * Media controls based on {@link android.app.Notification.MediaStyle} notifications will be
- * required to include a non-empty title, either in the {@link android.media.MediaMetadata} or
+ * Media controls based on {@link android.app.Notification.MediaStyle} notifications should
+ * include a non-empty title, either in the {@link android.media.MediaMetadata} or
* notification title.
*/
@ChangeId
- @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
- private static final long MEDIA_CONTROL_REQUIRES_TITLE = 274775190L;
+ @LoggingOnly
+ private static final long MEDIA_CONTROL_BLANK_TITLE = 274775190L;
@UnsupportedAppUsage
private Context mContext;
@@ -586,6 +591,9 @@
@UnsupportedAppUsage
private IBinder mToken = new Binder();
+ private final IPlatformCompat mPlatformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
@UnsupportedAppUsage
StatusBarManager(Context context) {
mContext = context;
@@ -597,7 +605,7 @@
mService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
if (mService == null) {
- Slog.w("StatusBarManager", "warning: no STATUS_BAR_SERVICE");
+ Slog.w(TAG, "warning: no STATUS_BAR_SERVICE");
}
}
return mService;
@@ -1226,18 +1234,22 @@
}
/**
- * Checks whether the given package must include a non-empty title for its media controls.
+ * Log that the given package has posted media controls with a blank title
*
* @param packageName App posting media controls
- * @param user Current user handle
- * @return true if the app is required to provide a non-empty title
+ * @param userId Current user ID
+ * @throws RuntimeException if there is an error reporting the change
*
* @hide
*/
- @RequiresPermission(allOf = {android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
- android.Manifest.permission.LOG_COMPAT_CHANGE})
- public static boolean isMediaTitleRequiredForApp(String packageName, UserHandle user) {
- return CompatChanges.isChangeEnabled(MEDIA_CONTROL_REQUIRES_TITLE, packageName, user);
+ public void logBlankMediaTitle(String packageName, @UserIdInt int userId)
+ throws RuntimeException {
+ try {
+ mPlatformCompat.reportChangeByPackageName(MEDIA_CONTROL_BLANK_TITLE, packageName,
+ userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/**
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index b601275..3ffbe1d 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -1,223 +1,170 @@
{
- "imports": [
- {
- "path": "frameworks/base/core/tests/coretests/src/android/content/pm"
- },
- {
- "path": "frameworks/base/services/tests/PackageManagerServiceTests"
- },
- {
- "path": "frameworks/base/services/tests/PackageManager"
- },
- {
- "path": "frameworks/base/services/tests/PackageManagerComponentOverrideTests"
- },
- {
- "path": "frameworks/base/services/tests/servicestests/src/com/android/server/pm"
- },
- {
- "path": "cts/tests/tests/packageinstaller"
- },
- {
- "path": "cts/hostsidetests/stagedinstall"
- },
- {
- "path": "cts/hostsidetests/packagemanager"
- },
- {
- "path": "cts/hostsidetests/os/test_mappings/packagemanager"
- },
- {
- "path": "cts/hostsidetests/appsearch"
- },
- {
- "path": "system/apex/tests"
- },
- {
- "path": "cts/tests/tests/content/pm/SecureFrp"
- }
- ],
- "presubmit": [
- {
- "name": "CtsInstantAppTests",
- "file_patterns": ["(/|^)InstantApp[^/]*"]
- },
- {
- "name": "CarrierAppIntegrationTestCases"
- },
- {
- "name": "ApkVerityTest"
- },
- {
- "name": "CtsSilentUpdateHostTestCases"
- },
- {
- "name": "CtsSuspendAppsTestCases"
- },
- {
- "name": "CtsAppFgsTestCases",
- "file_patterns": ["(/|^)ServiceInfo[^/]*"],
- "options": [
+ "imports":[
{
- "include-annotation": "android.platform.test.annotations.Presubmit"
+ "path":"frameworks/base/core/tests/coretests/src/android/content/pm"
},
{
- "exclude-annotation": "androidx.test.filters.LargeTest"
+ "path":"frameworks/base/services/tests/PackageManagerServiceTests"
},
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "path":"frameworks/base/services/tests/PackageManager"
+ },
+ {
+ "path":"frameworks/base/services/tests/PackageManagerComponentOverrideTests"
+ },
+ {
+ "path":"frameworks/base/services/tests/servicestests/src/com/android/server/pm"
+ },
+ {
+ "path":"cts/tests/tests/packageinstaller"
+ },
+ {
+ "path":"cts/hostsidetests/stagedinstall"
+ },
+ {
+ "path":"cts/hostsidetests/packagemanager"
+ },
+ {
+ "path":"cts/hostsidetests/os/test_mappings/packagemanager"
+ },
+ {
+ "path":"cts/hostsidetests/appsearch"
+ },
+ {
+ "path":"system/apex/tests"
+ },
+ {
+ "path":"cts/tests/tests/content/pm/SecureFrp"
}
- ]
- },
- {
- "name": "CtsShortFgsTestCases",
- "file_patterns": ["(/|^)ServiceInfo[^/]*"],
- "options": [
+ ],
+ "presubmit":[
{
- "include-annotation": "android.platform.test.annotations.Presubmit"
+ "name":"CtsInstantAppTests",
+ "file_patterns":[
+ "(/|^)InstantApp[^/]*"
+ ]
},
{
- "exclude-annotation": "androidx.test.filters.LargeTest"
+ "name":"CarrierAppIntegrationTestCases"
},
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "name":"ApkVerityTest"
+ },
+ {
+ "name":"CtsSilentUpdateHostTestCases"
+ },
+ {
+ "name":"CtsSuspendAppsTestCases"
+ },
+ {
+ "name":"CtsAppFgsTestCases",
+ "file_patterns":[
+ "(/|^)ServiceInfo[^/]*"
+ ],
+ "options":[
+ {
+ "include-annotation":"android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation":"androidx.test.filters.LargeTest"
+ },
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name":"CtsShortFgsTestCases",
+ "file_patterns":[
+ "(/|^)ServiceInfo[^/]*"
+ ],
+ "options":[
+ {
+ "include-annotation":"android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation":"androidx.test.filters.LargeTest"
+ },
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name":"CtsIncrementalInstallHostTestCases",
+ "options":[
+ {
+ "include-filter":"android.incrementalinstall.cts.IncrementalFeatureTest"
+ }
+ ]
}
- ]
- },
- {
- "name": "CtsIncrementalInstallHostTestCases",
- "options": [
+ ],
+ "presubmit-large":[
{
- "include-filter": "android.incrementalinstall.cts.IncrementalFeatureTest"
- }
- ]
- }
- ],
- "presubmit-large": [
- {
- "name": "CtsContentTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "name":"CtsContentTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ },
+ {
+ "include-filter":"android.content.pm.cts"
+ }
+ ]
},
{
- "exclude-annotation": "org.junit.Ignore"
+ "name":"CtsUsesNativeLibraryTest",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
},
{
- "include-filter": "android.content.pm.cts"
- }
- ]
- },
- {
- "name": "CtsUsesNativeLibraryTest",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "name":"CtsSuspendAppsPermissionTestCases",
+ "options":[
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
},
{
- "exclude-annotation": "org.junit.Ignore"
+ "name":"CtsAppSecurityHostTestCases",
+ "options":[
+ {
+ "include-annotation":"android.platform.test.annotations.Presubmit"
+ },
+ {
+ "exclude-annotation":"android.platform.test.annotations.Postsubmit"
+ },
+ {
+ "exclude-annotation":"androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation":"org.junit.Ignore"
+ }
+ ]
}
- ]
- },
- {
- "name": "CtsSuspendAppsPermissionTestCases",
- "options": [
+ ],
+ "postsubmit":[
{
- "exclude-annotation": "androidx.test.filters.FlakyTest"
+ "name":"CtsAppSecurityHostTestCases",
+ "options":[
+ {
+ "include-filter":"android.appsecurity.cts.AppSecurityTests#testPermissionDiffCert"
+ }
+ ]
},
{
- "exclude-annotation": "org.junit.Ignore"
+ "name":"CtsInstallHostTestCases"
}
- ]
- },
- {
- "name": "CtsAppSecurityHostTestCases",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.Presubmit"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.Postsubmit"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
- ],
- "postsubmit": [
- {
- "name": "CtsAppSecurityHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.AppSecurityTests#testPermissionDiffCert"
- }
- ]
- },
- {
- "name": "CtsInstallHostTestCases"
- }
- ],
- "staged-platinum-postsubmit": [
- {
- "name": "CtsIncrementalInstallHostTestCases"
- },
- {
- "name": "CtsAppSecurityHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.SplitTests"
- },
- {
- "include-filter": "android.appsecurity.cts.EphemeralTest"
- }
- ]
- },
- {
- "name": "CtsContentTestCases",
- "options": [
- {
- "include-filter": "android.content.cts.IntentFilterTest"
- }
- ]
- }
- ],
- "platinum-postsubmit": [
- {
- "name": "CtsIncrementalInstallHostTestCases",
- "options": [
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- },
- {
- "name": "CtsAppSecurityHostTestCases",
- "options": [
- {
- "include-filter": "android.appsecurity.cts.SplitTests"
- },
- {
- "include-filter": "android.appsecurity.cts.EphemeralTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- },
- {
- "name": "CtsContentTestCases",
- "options":[
- {
- "include-filter": "android.content.cts.IntentFilterTest"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- }
- ]
- }
- ]
-}
+ ]
+}
\ No newline at end of file
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index 6910501..78388ef 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -246,8 +246,7 @@
@Override
public void updateTouchableInsets(@NonNull InputMethodService.Insets originalInsets,
@NonNull ViewTreeObserver.InternalInsetsInfo dest) {
- if (!mImeDrawsImeNavBar || mNavigationBarFrame == null
- || mService.isExtractViewShown()) {
+ if (!mImeDrawsImeNavBar || mNavigationBarFrame == null) {
return;
}
@@ -255,53 +254,58 @@
if (systemInsets != null) {
final Window window = mService.mWindow.getWindow();
final View decor = window.getDecorView();
- Region touchableRegion = null;
- final View inputFrame = mService.mInputFrame;
- switch (originalInsets.touchableInsets) {
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
- if (inputFrame.getVisibility() == View.VISIBLE) {
- inputFrame.getLocationInWindow(mTempPos);
- mTempRect.set(mTempPos[0], mTempPos[1],
- mTempPos[0] + inputFrame.getWidth(),
- mTempPos[1] + inputFrame.getHeight());
- touchableRegion = new Region(mTempRect);
- }
- break;
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
- if (inputFrame.getVisibility() == View.VISIBLE) {
- inputFrame.getLocationInWindow(mTempPos);
- mTempRect.set(mTempPos[0], originalInsets.contentTopInsets,
- mTempPos[0] + inputFrame.getWidth() ,
- mTempPos[1] + inputFrame.getHeight());
- touchableRegion = new Region(mTempRect);
- }
- break;
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
- if (inputFrame.getVisibility() == View.VISIBLE) {
- inputFrame.getLocationInWindow(mTempPos);
- mTempRect.set(mTempPos[0], originalInsets.visibleTopInsets,
- mTempPos[0] + inputFrame.getWidth(),
- mTempPos[1] + inputFrame.getHeight());
- touchableRegion = new Region(mTempRect);
- }
- break;
- case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION:
- touchableRegion = new Region();
- touchableRegion.set(originalInsets.touchableRegion);
- break;
- }
- // Hereafter "mTempRect" means a navigation bar rect.
- mTempRect.set(decor.getLeft(), decor.getBottom() - systemInsets.bottom,
- decor.getRight(), decor.getBottom());
- if (touchableRegion == null) {
- touchableRegion = new Region(mTempRect);
- } else {
- touchableRegion.union(mTempRect);
- }
- dest.touchableRegion.set(touchableRegion);
- dest.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ // If the extract view is shown, everything is touchable, so no need to update
+ // touchable insets, but we still update normal insets below.
+ if (!mService.isExtractViewShown()) {
+ Region touchableRegion = null;
+ final View inputFrame = mService.mInputFrame;
+ switch (originalInsets.touchableInsets) {
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
+ if (inputFrame.getVisibility() == View.VISIBLE) {
+ inputFrame.getLocationInWindow(mTempPos);
+ mTempRect.set(mTempPos[0], mTempPos[1],
+ mTempPos[0] + inputFrame.getWidth(),
+ mTempPos[1] + inputFrame.getHeight());
+ touchableRegion = new Region(mTempRect);
+ }
+ break;
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
+ if (inputFrame.getVisibility() == View.VISIBLE) {
+ inputFrame.getLocationInWindow(mTempPos);
+ mTempRect.set(mTempPos[0], originalInsets.contentTopInsets,
+ mTempPos[0] + inputFrame.getWidth(),
+ mTempPos[1] + inputFrame.getHeight());
+ touchableRegion = new Region(mTempRect);
+ }
+ break;
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
+ if (inputFrame.getVisibility() == View.VISIBLE) {
+ inputFrame.getLocationInWindow(mTempPos);
+ mTempRect.set(mTempPos[0], originalInsets.visibleTopInsets,
+ mTempPos[0] + inputFrame.getWidth(),
+ mTempPos[1] + inputFrame.getHeight());
+ touchableRegion = new Region(mTempRect);
+ }
+ break;
+ case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION:
+ touchableRegion = new Region();
+ touchableRegion.set(originalInsets.touchableRegion);
+ break;
+ }
+ // Hereafter "mTempRect" means a navigation bar rect.
+ mTempRect.set(decor.getLeft(), decor.getBottom() - systemInsets.bottom,
+ decor.getRight(), decor.getBottom());
+ if (touchableRegion == null) {
+ touchableRegion = new Region(mTempRect);
+ } else {
+ touchableRegion.union(mTempRect);
+ }
+
+ dest.touchableRegion.set(touchableRegion);
+ dest.setTouchableInsets(
+ ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ }
// TODO(b/215443343): See if we can use View#OnLayoutChangeListener().
// TODO(b/215443343): See if we can replace DecorView#mNavigationColorViewState.view
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 6f2a915..3f40139 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -37,7 +37,6 @@
import android.os.HandlerThread;
import android.os.Message;
import android.preference.VolumePreference.VolumeStore;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.System;
@@ -47,7 +46,6 @@
import android.widget.SeekBar.OnSeekBarChangeListener;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.os.SomeArgs;
import java.util.concurrent.TimeUnit;
@@ -295,14 +293,8 @@
if (zenMuted) {
mSeekBar.setProgress(mLastAudibleStreamVolume, true);
} else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
- /**
- * the first variable above is preserved and the conditions below are made explicit
- * so that when user attempts to slide the notification seekbar out of vibrate the
- * seekbar doesn't wrongly snap back to 0 when the streams aren't aliased
- */
- if (!DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false)
- || mStreamType == AudioManager.STREAM_RING
+ // For ringer-mode affected streams, show volume as zero when ringermode is vibrate
+ if (mStreamType == AudioManager.STREAM_RING
|| (mStreamType == AudioManager.STREAM_NOTIFICATION && mMuted)) {
mSeekBar.setProgress(0, true);
}
@@ -397,9 +389,7 @@
// set the time of stop volume
if ((mStreamType == AudioManager.STREAM_VOICE_CALL
|| mStreamType == AudioManager.STREAM_RING
- || (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false)
- && mStreamType == AudioManager.STREAM_NOTIFICATION)
+ || mStreamType == AudioManager.STREAM_NOTIFICATION
|| mStreamType == AudioManager.STREAM_ALARM)) {
sStopVolumeTime = java.lang.System.currentTimeMillis();
}
@@ -686,10 +676,7 @@
}
private void updateVolumeSlider(int streamType, int streamValue) {
- final boolean streamMatch = !DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false)
- && mNotificationOrRing ? isNotificationOrRing(streamType) :
- streamType == mStreamType;
+ final boolean streamMatch = (streamType == mStreamType);
if (mSeekBar != null && streamMatch && streamValue != -1) {
final boolean muted = mAudioManager.isStreamMute(mStreamType)
|| streamValue == 0;
diff --git a/core/java/android/view/SurfaceControlRegistry.java b/core/java/android/view/SurfaceControlRegistry.java
index 095189a..67ac811 100644
--- a/core/java/android/view/SurfaceControlRegistry.java
+++ b/core/java/android/view/SurfaceControlRegistry.java
@@ -62,7 +62,6 @@
private static class DefaultReporter implements Reporter {
public void onMaxLayersExceeded(WeakHashMap<SurfaceControl, Long> surfaceControls,
int limit, PrintWriter pw) {
- final int size = Math.min(surfaceControls.size(), limit);
final long now = SystemClock.elapsedRealtime();
final ArrayList<Map.Entry<SurfaceControl, Long>> entries = new ArrayList<>();
for (Map.Entry<SurfaceControl, Long> entry : surfaceControls.entrySet()) {
@@ -71,6 +70,7 @@
// Sort entries by time registered when dumping
// TODO: Or should it sort by name?
entries.sort((o1, o2) -> (int) (o1.getValue() - o2.getValue()));
+ final int size = Math.min(entries.size(), limit);
pw.println("SurfaceControlRegistry");
pw.println("----------------------");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 441636d..f1cde3b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7734,13 +7734,14 @@
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
boolean handled = false;
- final ListenerInfo li = mListenerInfo;
+ final OnLongClickListener listener =
+ mListenerInfo == null ? null : mListenerInfo.mOnLongClickListener;
boolean shouldPerformHapticFeedback = true;
- if (li != null && li.mOnLongClickListener != null) {
- handled = li.mOnLongClickListener.onLongClick(View.this);
+ if (listener != null) {
+ handled = listener.onLongClick(View.this);
if (handled) {
- shouldPerformHapticFeedback =
- li.mOnLongClickListener.onLongClickUseDefaultHapticFeedback(View.this);
+ shouldPerformHapticFeedback = listener.onLongClickUseDefaultHapticFeedback(
+ View.this);
}
}
if (!handled) {
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 34e6e49..5525336 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2598,6 +2598,11 @@
public int getActionTag() {
return VIEW_GROUP_ACTION_ADD_TAG;
}
+
+ @Override
+ public final void visitUris(@NonNull Consumer<Uri> visitor) {
+ mNestedViews.visitUris(visitor);
+ }
}
/**
diff --git a/core/java/android/window/TaskSnapshot.java b/core/java/android/window/TaskSnapshot.java
index b7bb608..41b6d31 100644
--- a/core/java/android/window/TaskSnapshot.java
+++ b/core/java/android/window/TaskSnapshot.java
@@ -28,6 +28,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemClock;
import android.view.Surface;
import android.view.WindowInsetsController;
@@ -38,6 +39,9 @@
public class TaskSnapshot implements Parcelable {
// Identifier of this snapshot
private final long mId;
+ // The elapsed real time (in nanoseconds) when this snapshot was captured, not intended for use outside the
+ // process in which the snapshot was taken (ie. this is not parceled)
+ private final long mCaptureTime;
// Top activity in task when snapshot was taken
private final ComponentName mTopActivityComponent;
private final HardwareBuffer mSnapshot;
@@ -65,7 +69,7 @@
// Must be one of the named color spaces, otherwise, always use SRGB color space.
private final ColorSpace mColorSpace;
- public TaskSnapshot(long id,
+ public TaskSnapshot(long id, long captureTime,
@NonNull ComponentName topActivityComponent, HardwareBuffer snapshot,
@NonNull ColorSpace colorSpace, int orientation, int rotation, Point taskSize,
Rect contentInsets, Rect letterboxInsets, boolean isLowResolution,
@@ -73,6 +77,7 @@
@WindowInsetsController.Appearance int appearance, boolean isTranslucent,
boolean hasImeSurface) {
mId = id;
+ mCaptureTime = captureTime;
mTopActivityComponent = topActivityComponent;
mSnapshot = snapshot;
mColorSpace = colorSpace.getId() < 0
@@ -92,6 +97,7 @@
private TaskSnapshot(Parcel source) {
mId = source.readLong();
+ mCaptureTime = SystemClock.elapsedRealtimeNanos();
mTopActivityComponent = ComponentName.readFromParcel(source);
mSnapshot = source.readTypedObject(HardwareBuffer.CREATOR);
int colorSpaceId = source.readInt();
@@ -119,6 +125,14 @@
}
/**
+ * @return The elapsed real time (in nanoseconds) when this snapshot was captured. This time is
+ * only valid in the process where this snapshot was taken.
+ */
+ public long getCaptureTime() {
+ return mCaptureTime;
+ }
+
+ /**
* @return The top activity component for the task at the point this snapshot was taken.
*/
public ComponentName getTopActivityComponent() {
@@ -268,6 +282,7 @@
final int height = mSnapshot != null ? mSnapshot.getHeight() : 0;
return "TaskSnapshot{"
+ " mId=" + mId
+ + " mCaptureTime=" + mCaptureTime
+ " mTopActivityComponent=" + mTopActivityComponent.flattenToShortString()
+ " mSnapshot=" + mSnapshot + " (" + width + "x" + height + ")"
+ " mColorSpace=" + mColorSpace.toString()
@@ -296,6 +311,7 @@
/** Builder for a {@link TaskSnapshot} object */
public static final class Builder {
private long mId;
+ private long mCaptureTime;
private ComponentName mTopActivity;
private HardwareBuffer mSnapshot;
private ColorSpace mColorSpace;
@@ -317,6 +333,11 @@
return this;
}
+ public Builder setCaptureTime(long captureTime) {
+ mCaptureTime = captureTime;
+ return this;
+ }
+
public Builder setTopActivityComponent(ComponentName name) {
mTopActivity = name;
return this;
@@ -400,6 +421,7 @@
public TaskSnapshot build() {
return new TaskSnapshot(
mId,
+ mCaptureTime,
mTopActivity,
mSnapshot,
mColorSpace,
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 7ad2a68..8135f9c 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -549,11 +549,6 @@
"task_manager_inform_job_scheduler_of_pending_app_stop";
/**
- * (boolean) Whether to show notification volume control slider separate from ring.
- */
- public static final String VOLUME_SEPARATE_NOTIFICATION = "volume_separate_notification";
-
- /**
* (boolean) Whether widget provider info would be saved to / loaded from system persistence
* layer as opposed to individual manifests in respective apps.
*/
diff --git a/core/java/com/android/internal/util/LatencyTracker.java b/core/java/com/android/internal/util/LatencyTracker.java
index f277635..116c301c 100644
--- a/core/java/com/android/internal/util/LatencyTracker.java
+++ b/core/java/com/android/internal/util/LatencyTracker.java
@@ -367,28 +367,42 @@
* using a single static object.
*/
@VisibleForTesting
+ @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
public void startListeningForLatencyTrackerConfigChanges() {
final Context context = ActivityThread.currentApplication();
- if (context != null
- && context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) == PERMISSION_GRANTED) {
- // Post initialization to the background in case we're running on the main thread.
- BackgroundThread.getHandler().post(() -> this.updateProperties(
- DeviceConfig.getProperties(NAMESPACE_LATENCY_TRACKER)));
- DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_LATENCY_TRACKER,
- BackgroundThread.getExecutor(), mOnPropertiesChangedListener);
- } else {
+ if (context == null) {
if (DEBUG) {
- if (context == null) {
- Log.d(TAG, "No application for " + ActivityThread.currentActivityThread());
- } else {
- synchronized (mLock) {
- Log.d(TAG, "Initialized the LatencyTracker."
- + " (No READ_DEVICE_CONFIG permission to change configs)"
- + " enabled=" + mEnabled + ", package=" + context.getPackageName());
- }
+ Log.d(TAG, "No application for package: " + ActivityThread.currentPackageName());
+ }
+ return;
+ }
+ if (context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG) != PERMISSION_GRANTED) {
+ if (DEBUG) {
+ synchronized (mLock) {
+ Log.d(TAG, "Initialized the LatencyTracker."
+ + " (No READ_DEVICE_CONFIG permission to change configs)"
+ + " enabled=" + mEnabled + ", package=" + context.getPackageName());
}
}
+ return;
}
+
+ // Post initialization to the background in case we're running on the main thread.
+ BackgroundThread.getHandler().post(() -> {
+ try {
+ this.updateProperties(
+ DeviceConfig.getProperties(NAMESPACE_LATENCY_TRACKER));
+ DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_LATENCY_TRACKER,
+ BackgroundThread.getExecutor(), mOnPropertiesChangedListener);
+ } catch (SecurityException ex) {
+ // In case of running tests that the main thread passes the check,
+ // but the background thread doesn't have necessary permissions.
+ // Swallow it since it's ok to ignore device config changes in the tests.
+ Log.d(TAG, "Can't get properties: READ_DEVICE_CONFIG granted="
+ + context.checkCallingOrSelfPermission(READ_DEVICE_CONFIG)
+ + ", package=" + context.getPackageName());
+ }
+ });
}
/**
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 91fbf6b..fb3acbe 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5410,6 +5410,9 @@
<!-- Title for button to see application detail in app store which it came from - it may allow user to update to newer version. [CHAR LIMIT=50] -->
<string name="deprecated_target_sdk_app_store">Check for update</string>
+ <!-- Message displayed in dialog when app is 32 bit on a 64 bit system. [CHAR LIMIT=NONE] -->
+ <string name="deprecated_abi_message">This app isn\'t compatible with the latest version of Android. Check for an update or contact the app\'s developer.</string>
+
<!-- Notification title shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
<string name="new_sms_notification_title">You have new messages</string>
<!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f75bcdd..6ab671a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3156,6 +3156,8 @@
<java-symbol type="string" name="deprecated_target_sdk_message" />
<java-symbol type="string" name="deprecated_target_sdk_app_store" />
+ <java-symbol type="string" name="deprecated_abi_message" />
+
<!-- New SMS notification while phone is locked. -->
<java-symbol type="string" name="new_sms_notification_title" />
<java-symbol type="string" name="new_sms_notification_content" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index c5b00c9..eba7f58 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -33,6 +33,8 @@
import static android.app.Notification.EXTRA_PEOPLE_LIST;
import static android.app.Notification.EXTRA_PICTURE;
import static android.app.Notification.EXTRA_PICTURE_ICON;
+import static android.app.Notification.EXTRA_SUMMARY_TEXT;
+import static android.app.Notification.EXTRA_TITLE;
import static android.app.Notification.MessagingStyle.Message.KEY_DATA_URI;
import static android.app.Notification.MessagingStyle.Message.KEY_SENDER_PERSON;
import static android.app.Notification.MessagingStyle.Message.KEY_TEXT;
@@ -76,6 +78,7 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
@@ -111,6 +114,9 @@
@Before
public void setUp() {
mContext = InstrumentationRegistry.getContext();
+ // TODO(b/169435530): remove this flag set once resolved.
+ SystemProperties.set("persist.sysui.notification.builder_extras_override",
+ Boolean.toString(false));
}
@Test
@@ -1481,6 +1487,107 @@
Assert.assertEquals(actionWithFreeformRemoteInput, remoteInputActionPair.second);
}
+ // Ensures that extras in a Notification Builder can be updated.
+ @Test
+ public void testExtras_cachedExtrasOverwrittenByUserProvided() {
+ // Sets the flag to new state.
+ // TODO(b/169435530): remove this set value once resolved.
+ SystemProperties.set("persist.sysui.notification.builder_extras_override",
+ Boolean.toString(true));
+ Bundle extras = new Bundle();
+ extras.putCharSequence(EXTRA_TITLE, "test title");
+ extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text");
+
+ Notification.Builder builder = new Notification.Builder(mContext, "test id")
+ .addExtras(extras);
+
+ Notification notification = builder.build();
+ assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
+ "test title");
+ assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
+ "summary text");
+
+ extras.putCharSequence(EXTRA_TITLE, "new title");
+ builder.addExtras(extras);
+ notification = builder.build();
+ assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
+ "new title");
+ assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
+ "summary text");
+ }
+
+ // Ensures that extras in a Notification Builder can be updated by an extender.
+ @Test
+ public void testExtras_cachedExtrasOverwrittenByExtender() {
+ // Sets the flag to new state.
+ // TODO(b/169435530): remove this set value once resolved.
+ SystemProperties.set("persist.sysui.notification.builder_extras_override",
+ Boolean.toString(true));
+ Notification.CarExtender extender = new Notification.CarExtender().setColor(1234);
+
+ Notification notification = new Notification.Builder(mContext, "test id")
+ .extend(extender).build();
+
+ extender.setColor(5678);
+
+ Notification.Builder.recoverBuilder(mContext, notification).extend(extender).build();
+
+ Notification.CarExtender recoveredExtender = new Notification.CarExtender(notification);
+ assertThat(recoveredExtender.getColor()).isEqualTo(5678);
+ }
+
+ // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated.
+ // TODO(b/169435530): remove this test once resolved.
+ @Test
+ public void testExtras_cachedExtrasOverwrittenByUserProvidedOld() {
+ // Sets the flag to old state.
+ SystemProperties.set("persist.sysui.notification.builder_extras_override",
+ Boolean.toString(false));
+
+ Bundle extras = new Bundle();
+ extras.putCharSequence(EXTRA_TITLE, "test title");
+ extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text");
+
+ Notification.Builder builder = new Notification.Builder(mContext, "test id")
+ .addExtras(extras);
+
+ Notification notification = builder.build();
+ assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
+ "test title");
+ assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
+ "summary text");
+
+ extras.putCharSequence(EXTRA_TITLE, "new title");
+ builder.addExtras(extras);
+ notification = builder.build();
+ assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo(
+ "test title");
+ assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo(
+ "summary text");
+ }
+
+ // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated
+ // by an extender.
+ // TODO(b/169435530): remove this test once resolved.
+ @Test
+ public void testExtras_cachedExtrasOverwrittenByExtenderOld() {
+ // Sets the flag to old state.
+ SystemProperties.set("persist.sysui.notification.builder_extras_override",
+ Boolean.toString(false));
+
+ Notification.CarExtender extender = new Notification.CarExtender().setColor(1234);
+
+ Notification notification = new Notification.Builder(mContext, "test id")
+ .extend(extender).build();
+
+ extender.setColor(5678);
+
+ Notification.Builder.recoverBuilder(mContext, notification).extend(extender).build();
+
+ Notification.CarExtender recoveredExtender = new Notification.CarExtender(notification);
+ assertThat(recoveredExtender.getColor()).isEqualTo(1234);
+ }
+
private void assertValid(Notification.Colors c) {
// Assert that all colors are populated
assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
diff --git a/core/tests/coretests/src/android/content/res/TEST_MAPPING b/core/tests/coretests/src/android/content/res/TEST_MAPPING
index ab14950..4ea6e40 100644
--- a/core/tests/coretests/src/android/content/res/TEST_MAPPING
+++ b/core/tests/coretests/src/android/content/res/TEST_MAPPING
@@ -39,18 +39,5 @@
}
]
}
- ],
- "ironwood-postsubmit": [
- {
- "name": "FrameworksCoreTests",
- "options":[
- {
- "include-annotation": "android.platform.test.annotations.IwTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
]
}
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 4672226..7879801 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -716,6 +716,30 @@
}
@Test
+ public void visitUris_nestedViews() {
+ final RemoteViews outer = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+ final RemoteViews inner = new RemoteViews(mPackage, 33);
+ final Uri imageUriI = Uri.parse("content://inner/image");
+ final Icon icon1 = Icon.createWithContentUri("content://inner/icon1");
+ final Icon icon2 = Icon.createWithContentUri("content://inner/icon2");
+ final Icon icon3 = Icon.createWithContentUri("content://inner/icon3");
+ final Icon icon4 = Icon.createWithContentUri("content://inner/icon4");
+ inner.setImageViewUri(R.id.image, imageUriI);
+ inner.setTextViewCompoundDrawables(R.id.text, icon1, icon2, icon3, icon4);
+
+ outer.addView(R.id.layout, inner);
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ outer.visitUris(visitor);
+ verify(visitor, times(1)).accept(eq(imageUriI));
+ verify(visitor, times(1)).accept(eq(icon1.getUri()));
+ verify(visitor, times(1)).accept(eq(icon2.getUri()));
+ verify(visitor, times(1)).accept(eq(icon3.getUri()));
+ verify(visitor, times(1)).accept(eq(icon4.getUri()));
+ }
+
+ @Test
public void visitUris_separateOrientation() {
final RemoteViews landscape = new RemoteViews(mPackage, R.layout.remote_views_test);
final Uri imageUriL = Uri.parse("content://landscape/image");
diff --git a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
index 281d677..6764ac8 100644
--- a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
+++ b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
@@ -88,6 +88,7 @@
1, HardwareBuffer.USAGE_CPU_READ_RARELY);
return new TaskSnapshot(
System.currentTimeMillis(),
+ 0 /* captureTime */,
new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, taskSize, contentInsets, new Rect() /* letterboxInsets */,
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 4b4e722..e4defcf 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1135,6 +1135,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "-1060529098": {
+ "message": " Skipping post-transition snapshot for task %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/Transition.java"
+ },
"-1060365734": {
"message": "Attempted to add QS dialog window with bad token %s. Aborting.",
"level": "WARN",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/TEST_MAPPING b/libs/WindowManager/Shell/src/com/android/wm/shell/TEST_MAPPING
deleted file mode 100644
index 8dd1369..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "ironwood-postsubmit": [
- {
- "name": "WMShellFlickerTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.IwTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
- ]
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 91c7cc0..68fea41 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -2518,6 +2518,7 @@
mExpandedAnimationController.expandFromStack(() -> {
updatePointerPosition(false /* forIme */);
afterExpandedViewAnimation();
+ mExpandedViewContainer.setVisibility(VISIBLE);
mExpandedViewAnimationController.animateForImeVisibilityChange(visible);
} /* after */);
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
index ac6e4c2..53683c6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/TabletopModeController.java
@@ -54,14 +54,6 @@
DevicePostureController.OnDevicePostureChangedListener,
DisplayController.OnDisplaysChangedListener {
/**
- * When {@code true}, floating windows like PiP would auto move to the position
- * specified by {@link #PREFER_TOP_HALF_IN_TABLETOP} when in tabletop mode.
- */
- private static final boolean ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP =
- SystemProperties.getBoolean(
- "persist.wm.debug.enable_move_floating_window_in_tabletop", true);
-
- /**
* Prefer the {@link #PREFERRED_TABLETOP_HALF_TOP} if this flag is enabled,
* {@link #PREFERRED_TABLETOP_HALF_BOTTOM} otherwise.
* See also {@link #getPreferredHalfInTabletopMode()}.
@@ -162,14 +154,6 @@
}
}
- /**
- * @return {@code true} if floating windows like PiP would auto move to the position
- * specified by {@link #getPreferredHalfInTabletopMode()} when in tabletop mode.
- */
- public boolean enableMoveFloatingWindowInTabletop() {
- return ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP;
- }
-
/** @return Preferred half for floating windows like PiP when in tabletop mode. */
@PreferredTabletopHalf
public int getPreferredHalfInTabletopMode() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index 753dfa7..a9ccdf6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -293,6 +293,9 @@
}
if (mResizingIconView == null) {
+ if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
+ animFinishedCallback.accept(false);
+ }
return;
}
@@ -311,6 +314,9 @@
releaseDecor(finishT);
finishT.apply();
finishT.close();
+ if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
+ animFinishedCallback.accept(true);
+ }
}
});
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
index 65a12d6..2590cab 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMediaController.java
@@ -252,13 +252,16 @@
// It can be removed when min_sdk of the app is set to 31 or greater.
@SuppressLint("NewApi")
private List<RemoteAction> getMediaActions() {
- if (mMediaController == null || mMediaController.getPlaybackState() == null) {
+ // Cache the PlaybackState since it's a Binder call.
+ final PlaybackState playbackState;
+ if (mMediaController == null
+ || (playbackState = mMediaController.getPlaybackState()) == null) {
return Collections.emptyList();
}
ArrayList<RemoteAction> mediaActions = new ArrayList<>();
- boolean isPlaying = mMediaController.getPlaybackState().isActive();
- long actions = mMediaController.getPlaybackState().getActions();
+ boolean isPlaying = playbackState.isActive();
+ long actions = playbackState.getActions();
// Prev action
mPrevAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index bfc1fb9..3c7ce3c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -249,11 +249,6 @@
finishTransaction);
}
- // Fade in the fadeout PIP when the fixed rotation is finished.
- if (mPipTransitionState.isInPip() && !mInFixedRotation && mHasFadeOut) {
- fadeExistingPip(true /* show */);
- }
-
return false;
}
@@ -1056,6 +1051,12 @@
.crop(finishTransaction, leash, destBounds)
.round(finishTransaction, leash, isInPip)
.shadow(finishTransaction, leash, isInPip);
+ // Make sure the PiP keeps invisible if it was faded out. If it needs to fade in, that will
+ // be handled by onFixedRotationFinished().
+ if (isInPip && mHasFadeOut) {
+ startTransaction.setAlpha(leash, 0f);
+ finishTransaction.setAlpha(leash, 0f);
+ }
}
/** Hides and shows the existing PIP during fixed rotation transition of other activities. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 63181da..6a861ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -677,7 +677,6 @@
});
mTabletopModeController.registerOnTabletopModeChangedListener((isInTabletopMode) -> {
- if (!mTabletopModeController.enableMoveFloatingWindowInTabletop()) return;
final String tag = "tabletop-mode";
if (!isInTabletopMode) {
mPipBoundsState.removeNamedUnrestrictedKeepClearArea(tag);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 5c9709c..f35eda6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -371,7 +371,8 @@
* Find the background task that match the given component.
*/
@Nullable
- public ActivityManager.RecentTaskInfo findTaskInBackground(ComponentName componentName) {
+ public ActivityManager.RecentTaskInfo findTaskInBackground(ComponentName componentName,
+ int userId) {
if (componentName == null) {
return null;
}
@@ -383,7 +384,7 @@
if (task.isVisible) {
continue;
}
- if (componentName.equals(task.baseIntent.getComponent())) {
+ if (componentName.equals(task.baseIntent.getComponent()) && userId == task.userId) {
return task;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index a9ad3c9..c286959 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -264,21 +264,18 @@
void cancel(String reason) {
// restoring (to-home = false) involves submitting more WM changes, so by default, use
// toHome = true when canceling.
- cancel(true /* toHome */, reason);
+ cancel(true /* toHome */, false /* withScreenshots */, reason);
}
- void cancel(boolean toHome, String reason) {
+ void cancel(boolean toHome, boolean withScreenshots, String reason) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.cancel: toHome=%b reason=%s",
mInstanceId, toHome, reason);
if (mListener != null) {
- try {
- ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- "[%d] RecentsController.cancel: calling onAnimationCanceled",
- mInstanceId);
- mListener.onAnimationCanceled(null, null);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error canceling recents animation", e);
+ if (withScreenshots) {
+ sendCancelWithSnapshots();
+ } else {
+ sendCancel(null, null);
}
}
if (mFinishCB != null) {
@@ -300,24 +297,34 @@
snapshots = new TaskSnapshot[mPausingTasks.size()];
try {
for (int i = 0; i < mPausingTasks.size(); ++i) {
+ TaskState state = mPausingTasks.get(0);
snapshots[i] = ActivityTaskManager.getService().takeTaskSnapshot(
- mPausingTasks.get(0).mTaskInfo.taskId, false /* updateCache */);
+ state.mTaskInfo.taskId, true /* updateCache */);
}
} catch (RemoteException e) {
taskIds = null;
snapshots = null;
}
}
+ return sendCancel(taskIds, snapshots);
+ }
+
+ /**
+ * Sends a cancel message to the recents animation.
+ */
+ private boolean sendCancel(@Nullable int[] taskIds,
+ @Nullable TaskSnapshot[] taskSnapshots) {
try {
+ final String cancelDetails = taskSnapshots != null ? " with snapshots" : "";
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
- "[%d] RecentsController.cancel: calling onAnimationCanceled with snapshots",
- mInstanceId);
- mListener.onAnimationCanceled(taskIds, snapshots);
+ "[%d] RecentsController.cancel: calling onAnimationCanceled %s",
+ mInstanceId, cancelDetails);
+ mListener.onAnimationCanceled(taskIds, taskSnapshots);
+ return true;
} catch (RemoteException e) {
Slog.e(TAG, "Error canceling recents animation", e);
return false;
}
- return true;
}
void cleanUp() {
@@ -519,7 +526,7 @@
// Finish recents animation if the display is changed, so the default
// transition handler can play the animation such as rotation effect.
if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) {
- cancel(mWillFinishToHome, "display change");
+ cancel(mWillFinishToHome, true /* withScreenshots */, "display change");
return;
}
// Don't consider order-only changes as changing apps.
@@ -633,7 +640,7 @@
+ foundRecentsClosing);
if (foundRecentsClosing) {
mWillFinishToHome = false;
- cancel(false /* toHome */, "didn't merge");
+ cancel(false /* toHome */, false /* withScreenshots */, "didn't merge");
}
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 34701f1..ea33a1f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -723,7 +723,7 @@
// in the background with priority.
final ActivityManager.RecentTaskInfo taskInfo = mRecentTasksOptional
.map(recentTasks -> recentTasks.findTaskInBackground(
- intent.getIntent().getComponent()))
+ intent.getIntent().getComponent(), userId1))
.orElse(null);
if (taskInfo != null) {
startTask(taskInfo.taskId, position, options);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 14ea86a..d2b0e28 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -87,6 +87,14 @@
mStageCoordinator = stageCoordinator;
}
+ private void initTransition(@NonNull IBinder transition,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ mAnimatingTransition = transition;
+ mFinishTransaction = finishTransaction;
+ mFinishCallback = finishCallback;
+ }
+
/** Play animation for enter transition or dismiss transition. */
void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -94,9 +102,7 @@
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
@NonNull WindowContainerToken topRoot) {
- mFinishCallback = finishCallback;
- mAnimatingTransition = transition;
- mFinishTransaction = finishTransaction;
+ initTransition(transition, finishTransaction, finishCallback);
final TransitSession pendingTransition = getPendingTransition(transition);
if (pendingTransition != null) {
@@ -220,6 +226,45 @@
onFinish(null /* wct */, null /* wctCB */);
}
+ /** Play animation for drag divider dismiss transition. */
+ void playDragDismissAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback,
+ @NonNull WindowContainerToken toTopRoot, @NonNull SplitDecorManager toTopDecor,
+ @NonNull WindowContainerToken topRoot) {
+ initTransition(transition, finishTransaction, finishCallback);
+
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final SurfaceControl leash = change.getLeash();
+
+ if (toTopRoot.equals(change.getContainer())) {
+ startTransaction.setAlpha(leash, 1.f);
+ startTransaction.show(leash);
+
+ ValueAnimator va = new ValueAnimator();
+ mAnimations.add(va);
+
+ toTopDecor.onResized(startTransaction, animated -> {
+ mAnimations.remove(va);
+ if (animated) {
+ mTransitions.getMainExecutor().execute(() -> {
+ onFinish(null /* wct */, null /* wctCB */);
+ });
+ }
+ });
+ } else if (topRoot.equals(change.getContainer())) {
+ // Ensure it on top of all changes in transition.
+ startTransaction.setLayer(leash, Integer.MAX_VALUE);
+ startTransaction.setAlpha(leash, 1.f);
+ startTransaction.show(leash);
+ }
+ }
+ startTransaction.apply();
+ onFinish(null /* wct */, null /* wctCB */);
+ }
+
/** Play animation for resize transition. */
void playResizeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -227,9 +272,7 @@
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
@NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
- mFinishCallback = finishCallback;
- mAnimatingTransition = transition;
- mFinishTransaction = finishTransaction;
+ initTransition(transition, finishTransaction, finishCallback);
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index bf20567..e0fffff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -1328,8 +1328,6 @@
mIsExiting = true;
childrenToTop.resetBounds(wct);
wct.reorder(childrenToTop.mRootTaskInfo.token, true);
- wct.setSmallestScreenWidthDp(childrenToTop.mRootTaskInfo.token,
- SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
}
wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
false /* reparentLeafTaskIfRelaunch */);
@@ -1517,6 +1515,10 @@
void finishEnterSplitScreen(SurfaceControl.Transaction t) {
mSplitLayout.update(t);
+ mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash,
+ getMainStageBounds());
+ mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash,
+ getSideStageBounds());
setDividerVisibility(true, t);
// Ensure divider surface are re-parented back into the hierarchy at the end of the
// transition. See Transition#buildFinishTransaction for more detail.
@@ -1989,13 +1991,15 @@
final boolean mainStageToTop =
bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
: mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
+ final StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage;
if (!ENABLE_SHELL_TRANSITIONS) {
- exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, reason);
+ exitSplitScreen(toTopStage, reason);
return;
}
final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ toTopStage.resetBounds(wct);
prepareExitSplitScreen(dismissTop, wct);
if (mRootTaskInfo != null) {
wct.setDoNotPip(mRootTaskInfo.token);
@@ -2531,8 +2535,17 @@
shouldAnimate = startPendingEnterAnimation(
mSplitTransitions.mPendingEnter, info, startTransaction, finishTransaction);
} else if (mSplitTransitions.isPendingDismiss(transition)) {
+ final SplitScreenTransitions.DismissSession dismiss = mSplitTransitions.mPendingDismiss;
shouldAnimate = startPendingDismissAnimation(
- mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
+ dismiss, info, startTransaction, finishTransaction);
+ if (shouldAnimate && dismiss.mReason == EXIT_REASON_DRAG_DIVIDER) {
+ final StageTaskListener toTopStage =
+ dismiss.mDismissTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage;
+ mSplitTransitions.playDragDismissAnimation(transition, info, startTransaction,
+ finishTransaction, finishCallback, toTopStage.mRootTaskInfo.token,
+ toTopStage.getSplitDecorManager(), mRootTaskInfo.token);
+ return true;
+ }
} else if (mSplitTransitions.isPendingResize(transition)) {
mSplitTransitions.playResizeAnimation(transition, info, startTransaction,
finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token,
@@ -2787,6 +2800,10 @@
mSplitTransitions.mPendingDismiss = null;
return false;
}
+ dismissTransition.setFinishedCallback((callbackWct, callbackT) -> {
+ mMainStage.getSplitDecorManager().release(callbackT);
+ mSideStage.getSplitDecorManager().release(callbackT);
+ });
addDividerBarToTransition(info, false /* show */);
return true;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index e2e9270..da7d186 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -19,6 +19,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
@@ -201,7 +202,7 @@
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
if (mRootTaskInfo.taskId == taskInfo.taskId) {
// Inflates split decor view only when the root task is visible.
- if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
+ if (!ENABLE_SHELL_TRANSITIONS && mRootTaskInfo.isVisible != taskInfo.isVisible) {
if (taskInfo.isVisible) {
mSplitDecorManager.inflate(mContext, mRootLeash,
taskInfo.configuration.windowConfiguration.getBounds());
@@ -385,6 +386,7 @@
void resetBounds(WindowContainerTransaction wct) {
wct.setBounds(mRootTaskInfo.token, null);
wct.setAppBounds(mRootTaskInfo.token, null);
+ wct.setSmallestScreenWidthDp(mRootTaskInfo.token, SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
}
void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index d16b497..3b306e7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -191,6 +191,12 @@
*/
private static final int SYNC_ALLOWANCE_MS = 120;
+ /**
+ * Keyguard gets a more generous timeout to finish its animations, because we are always holding
+ * a sleep token during occlude/unocclude transitions and we want them to finish playing cleanly
+ */
+ private static final int SYNC_ALLOWANCE_KEYGUARD_MS = 2000;
+
/** For testing only. Disables the force-finish timeout on sync. */
private boolean mDisableForceSync = false;
@@ -673,7 +679,7 @@
// Sleep starts a process of forcing all prior transitions to finish immediately
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
"Start finish-for-sync track %d", i);
- finishForSync(i, null /* forceFinish */);
+ finishForSync(active, i, null /* forceFinish */);
}
if (hadPreceding) {
return false;
@@ -1021,6 +1027,9 @@
for (int i = 0; i < mPendingTransitions.size(); ++i) {
if (mPendingTransitions.get(i).mToken == token) return true;
}
+ for (int i = 0; i < mReadyDuringSync.size(); ++i) {
+ if (mReadyDuringSync.get(i).mToken == token) return true;
+ }
for (int t = 0; t < mTracks.size(); ++t) {
final Track tr = mTracks.get(t);
for (int i = 0; i < tr.mReadyTransitions.size(); ++i) {
@@ -1107,10 +1116,17 @@
*
* This is then repeated until there are no more pending sleep transitions.
*
+ * @param reason The SLEEP transition that triggered this round of finishes. We will continue
+ * looping round finishing transitions as long as this is still waiting.
* @param forceFinish When non-null, this is the transition that we last sent the SLEEP merge
* signal to -- so it will be force-finished if it's still running.
*/
- private void finishForSync(int trackIdx, @Nullable ActiveTransition forceFinish) {
+ private void finishForSync(ActiveTransition reason,
+ int trackIdx, @Nullable ActiveTransition forceFinish) {
+ if (!isTransitionKnown(reason.mToken)) {
+ Log.d(TAG, "finishForSleep: already played sync transition " + reason);
+ return;
+ }
final Track track = mTracks.get(trackIdx);
if (forceFinish != null) {
final Track trk = mTracks.get(forceFinish.getTrack());
@@ -1154,8 +1170,11 @@
if (track.mActiveTransition == playing) {
if (!mDisableForceSync) {
// Give it a short amount of time to process it before forcing.
- mMainExecutor.executeDelayed(() -> finishForSync(trackIdx, playing),
- SYNC_ALLOWANCE_MS);
+ final int tolerance = KeyguardTransitionHandler.handles(playing.mInfo)
+ ? SYNC_ALLOWANCE_KEYGUARD_MS
+ : SYNC_ALLOWANCE_MS;
+ mMainExecutor.executeDelayed(
+ () -> finishForSync(reason, trackIdx, playing), tolerance);
}
break;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 9189d3d..fb17d87 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -223,7 +223,7 @@
doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask();
// Put the same component into a task in the background
ActivityManager.RecentTaskInfo sameTaskInfo = new ActivityManager.RecentTaskInfo();
- doReturn(sameTaskInfo).when(mRecentTasks).findTaskInBackground(any());
+ doReturn(sameTaskInfo).when(mRecentTasks).findTaskInBackground(any(), anyInt());
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
SPLIT_POSITION_TOP_OR_LEFT, null);
@@ -247,7 +247,7 @@
SPLIT_POSITION_BOTTOM_OR_RIGHT);
// Put the same component into a task in the background
doReturn(new ActivityManager.RecentTaskInfo()).when(mRecentTasks)
- .findTaskInBackground(any());
+ .findTaskInBackground(any(), anyInt());
mSplitScreenController.startIntent(pendingIntent, mContext.getUserId(), null,
SPLIT_POSITION_TOP_OR_LEFT, null);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index ae69b3d..4e446c6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -44,11 +44,15 @@
static SplitLayout createMockSplitLayout() {
final Rect dividerBounds = new Rect(48, 0, 52, 100);
+ final Rect bounds1 = new Rect(0, 0, 40, 100);
+ final Rect bounds2 = new Rect(60, 0, 100, 100);
final SurfaceControl leash = createMockSurface();
SplitLayout out = mock(SplitLayout.class);
doReturn(dividerBounds).when(out).getDividerBounds();
doReturn(dividerBounds).when(out).getRefDividerBounds();
doReturn(leash).when(out).getDividerLeash();
+ doReturn(bounds1).when(out).getBounds1();
+ doReturn(bounds2).when(out).getBounds2();
return out;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 8038453..60c0e55 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -42,6 +42,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -72,6 +73,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.transition.Transitions;
@@ -117,13 +119,13 @@
doReturn(mockExecutor).when(mTransitions).getAnimExecutor();
doReturn(mock(SurfaceControl.Transaction.class)).when(mTransactionPool).acquire();
mSplitLayout = SplitTestUtils.createMockSplitLayout();
- mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
+ mMainStage = spy(new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
- mIconProvider);
+ mIconProvider));
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
- mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
+ mSideStage = spy(new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
- mIconProvider);
+ mIconProvider));
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
@@ -137,6 +139,8 @@
.setParentTaskId(mMainStage.mRootTaskInfo.taskId).build();
mSideChild = new TestRunningTaskInfoBuilder()
.setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
+ doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager();
+ doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager();
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 6621ab8..66b6c62 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -68,6 +68,7 @@
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.splitscreen.SplitScreen.SplitScreenListener;
import com.android.wm.shell.sysui.ShellController;
@@ -145,6 +146,8 @@
mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
+ doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager();
+ doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager();
}
@Test
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 8115a5d..ee9f886 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
@@ -364,6 +364,7 @@
1, HardwareBuffer.USAGE_CPU_READ_RARELY);
return new TaskSnapshot(
System.currentTimeMillis(),
+ 0 /* captureTime */,
new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, taskSize, contentInsets, new Rect() /* letterboxInsets */,
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index c4f09ce..f911d35 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -111,6 +111,9 @@
public static final int COMPLICATION_TYPE_SMARTSPACE = 7;
public static final int COMPLICATION_TYPE_MEDIA_ENTRY = 8;
+ private static final int SCREENSAVER_HOME_CONTROLS_ENABLED_DEFAULT = 1;
+ private static final int LOCKSCREEN_SHOW_CONTROLS_DEFAULT = 0;
+
private final Context mContext;
private final IDreamManager mDreamManager;
private final DreamInfoComparator mComparator;
@@ -311,8 +314,14 @@
/** Gets whether home controls button is enabled on the dream */
private boolean getHomeControlsEnabled() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED, 1) == 1;
+ return Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCKSCREEN_SHOW_CONTROLS,
+ LOCKSCREEN_SHOW_CONTROLS_DEFAULT) == 1
+ && Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED,
+ SCREENSAVER_HOME_CONTROLS_ENABLED_DEFAULT) == 1;
}
/**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
index 22ec12d..2edf403 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/dream/DreamBackendTest.java
@@ -28,6 +28,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.provider.Settings;
import org.junit.After;
import org.junit.Before;
@@ -84,6 +85,7 @@
@Test
public void testComplicationsEnabledByDefault() {
+ setControlsEnabledOnLockscreen(true);
assertThat(mBackend.getComplicationsEnabled()).isTrue();
assertThat(mBackend.getEnabledComplications()).containsExactlyElementsIn(
SUPPORTED_DREAM_COMPLICATIONS_LIST);
@@ -91,6 +93,7 @@
@Test
public void testEnableComplicationExplicitly() {
+ setControlsEnabledOnLockscreen(true);
mBackend.setComplicationsEnabled(true);
assertThat(mBackend.getEnabledComplications()).containsExactlyElementsIn(
SUPPORTED_DREAM_COMPLICATIONS_LIST);
@@ -99,6 +102,7 @@
@Test
public void testDisableComplications() {
+ setControlsEnabledOnLockscreen(true);
mBackend.setComplicationsEnabled(false);
assertThat(mBackend.getEnabledComplications())
.containsExactly(COMPLICATION_TYPE_HOME_CONTROLS);
@@ -107,6 +111,7 @@
@Test
public void testHomeControlsDisabled_ComplicationsEnabled() {
+ setControlsEnabledOnLockscreen(true);
mBackend.setComplicationsEnabled(true);
mBackend.setHomeControlsEnabled(false);
// Home controls should not be enabled, only date and time.
@@ -118,6 +123,7 @@
@Test
public void testHomeControlsDisabled_ComplicationsDisabled() {
+ setControlsEnabledOnLockscreen(true);
mBackend.setComplicationsEnabled(false);
mBackend.setHomeControlsEnabled(false);
assertThat(mBackend.getEnabledComplications()).isEmpty();
@@ -125,9 +131,9 @@
@Test
public void testHomeControlsEnabled_ComplicationsDisabled() {
+ setControlsEnabledOnLockscreen(true);
mBackend.setComplicationsEnabled(false);
mBackend.setHomeControlsEnabled(true);
- // Home controls should not be enabled, only date and time.
final List<Integer> enabledComplications =
Collections.singletonList(COMPLICATION_TYPE_HOME_CONTROLS);
assertThat(mBackend.getEnabledComplications())
@@ -136,9 +142,9 @@
@Test
public void testHomeControlsEnabled_ComplicationsEnabled() {
+ setControlsEnabledOnLockscreen(true);
mBackend.setComplicationsEnabled(true);
mBackend.setHomeControlsEnabled(true);
- // Home controls should not be enabled, only date and time.
final List<Integer> enabledComplications =
Arrays.asList(
COMPLICATION_TYPE_HOME_CONTROLS,
@@ -148,4 +154,26 @@
assertThat(mBackend.getEnabledComplications())
.containsExactlyElementsIn(enabledComplications);
}
+
+ @Test
+ public void testHomeControlsEnabled_lockscreenDisabled() {
+ setControlsEnabledOnLockscreen(false);
+ mBackend.setComplicationsEnabled(true);
+ mBackend.setHomeControlsEnabled(true);
+ // Home controls should not be enabled, only date and time.
+ final List<Integer> enabledComplications =
+ Arrays.asList(
+ COMPLICATION_TYPE_DATE,
+ COMPLICATION_TYPE_TIME
+ );
+ assertThat(mBackend.getEnabledComplications())
+ .containsExactlyElementsIn(enabledComplications);
+ }
+
+ private void setControlsEnabledOnLockscreen(boolean enabled) {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCKSCREEN_SHOW_CONTROLS,
+ enabled ? 1 : 0);
+ }
}
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index bdd941d..aee829d 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -90,63 +90,6 @@
//
// If you don't use @Postsubmit, your new test will immediately
// block presubmit, which is probably not what you want!
- "sysui-platinum-postsubmit": [
- {
- "name": "PlatformScenarioTests",
- "options": [
- {
- "include-filter": "android.platform.test.scenario.sysui"
- },
- {
- "include-annotation": "android.platform.test.scenario.annotation.Scenario"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "exclude-annotation": "androidx.test.filters.FlakyTest"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- }
- ]
- }
- ],
- "sysui-staged-platinum-postsubmit": [
- {
- "name": "PlatformScenarioTests",
- "options": [
- {
- "include-filter": "android.platform.test.scenario.sysui"
- },
- {
- "include-annotation": "android.platform.test.scenario.annotation.Scenario"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
- ],
- "ironwood-postsubmit": [
- {
- "name": "PlatformScenarioTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.IwTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.platform.test.scenario.sysui"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- }
- ]
- }
- ],
"auto-end-to-end-postsubmit": [
{
"name": "AndroidAutomotiveHomeTests",
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 8dd2c39..465b73e 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -272,6 +272,7 @@
color = lockScreenColor,
animate = isAnimationEnabled,
duration = APPEAR_ANIM_DURATION,
+ interpolator = Interpolators.EMPHASIZED_DECELERATE,
delay = 0,
onAnimationEnd = null
)
@@ -562,7 +563,7 @@
private const val DOUBLE_LINE_FORMAT_12_HOUR = "hh\nmm"
private const val DOUBLE_LINE_FORMAT_24_HOUR = "HH\nmm"
private const val DOZE_ANIM_DURATION: Long = 300
- private const val APPEAR_ANIM_DURATION: Long = 350
+ private const val APPEAR_ANIM_DURATION: Long = 833
private const val CHARGE_ANIM_DURATION_PHASE_0: Long = 500
private const val CHARGE_ANIM_DURATION_PHASE_1: Long = 1000
private const val COLOR_ANIM_DURATION: Long = 400
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 330676b..01c5443 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -82,7 +82,7 @@
androidprv:layout_constraintGuide_percent="0"
android:orientation="horizontal" />
- <androidx.constraintlayout.helper.widget.Flow
+ <com.android.keyguard.KeyguardPinFlowView
android:id="@+id/flow1"
android:layout_width="0dp"
android:layout_height="0dp"
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index cad2c16..4b79689 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -96,6 +96,7 @@
<!-- additional offset for clock switch area items -->
<dimen name="small_clock_height">114dp</dimen>
+ <dimen name="small_clock_padding_top">28dp</dimen>
<dimen name="clock_padding_start">28dp</dimen>
<dimen name="below_clock_padding_start">32dp</dimen>
<dimen name="below_clock_padding_end">16dp</dimen>
diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
index 1112bcd..9b1fa23 100644
--- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml
+++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml
@@ -85,7 +85,7 @@
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/ic_volume_ringer_mute" />
+ android:src="@drawable/ic_speaker_mute" />
</FrameLayout>
@@ -102,7 +102,7 @@
android:layout_height="@dimen/volume_ringer_drawer_icon_size"
android:layout_gravity="center"
android:tint="?android:attr/textColorPrimary"
- android:src="@drawable/ic_volume_ringer" />
+ android:src="@drawable/ic_speaker_on" />
</FrameLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a62dead..8d3ba36 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -716,7 +716,7 @@
<!-- Minimum margin between clock and status bar -->
<dimen name="keyguard_clock_top_margin">18dp</dimen>
<!-- The amount to shift the clocks during a small/large transition -->
- <dimen name="keyguard_clock_switch_y_shift">10dp</dimen>
+ <dimen name="keyguard_clock_switch_y_shift">14dp</dimen>
<!-- When large clock is showing, offset the smartspace by this amount -->
<dimen name="keyguard_smartspace_top_offset">12dp</dimen>
<!-- With the large clock, move up slightly from the center -->
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index e54d473..d9d64ad 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,5 +1,8 @@
package com.android.keyguard;
+import static android.view.View.ALPHA;
+import static android.view.View.TRANSLATION_Y;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -35,11 +38,12 @@
private static final String TAG = "KeyguardClockSwitch";
- private static final long CLOCK_OUT_MILLIS = 150;
- private static final long CLOCK_IN_MILLIS = 200;
- public static final long CLOCK_IN_START_DELAY_MILLIS = CLOCK_OUT_MILLIS / 2;
- private static final long STATUS_AREA_START_DELAY_MILLIS = 50;
- private static final long STATUS_AREA_MOVE_MILLIS = 350;
+ private static final long CLOCK_OUT_MILLIS = 133;
+ private static final long CLOCK_IN_MILLIS = 167;
+ public static final long CLOCK_IN_START_DELAY_MILLIS = 133;
+ private static final long STATUS_AREA_START_DELAY_MILLIS = 0;
+ private static final long STATUS_AREA_MOVE_UP_MILLIS = 967;
+ private static final long STATUS_AREA_MOVE_DOWN_MILLIS = 467;
@IntDef({LARGE, SMALL})
@Retention(RetentionPolicy.SOURCE)
@@ -66,6 +70,17 @@
top + targetHeight);
}
+ /** Returns a region for the small clock to position itself, based on the given parent. */
+ public static Rect getSmallClockRegion(ViewGroup parent) {
+ int targetHeight = parent.getResources()
+ .getDimensionPixelSize(R.dimen.small_clock_text_size);
+ return new Rect(
+ parent.getLeft(),
+ parent.getTop(),
+ parent.getRight(),
+ parent.getTop() + targetHeight);
+ }
+
/**
* Frame for small/large clocks
*/
@@ -90,7 +105,7 @@
@VisibleForTesting AnimatorSet mClockInAnim = null;
@VisibleForTesting AnimatorSet mClockOutAnim = null;
- private ObjectAnimator mStatusAreaAnim = null;
+ private AnimatorSet mStatusAreaAnim = null;
private int mClockSwitchYAmount;
@VisibleForTesting boolean mChildrenAreLaidOut = false;
@@ -172,13 +187,8 @@
void updateClockTargetRegions() {
if (mClock != null) {
if (mSmallClockFrame.isLaidOut()) {
- int targetHeight = getResources()
- .getDimensionPixelSize(R.dimen.small_clock_text_size);
- mClock.getSmallClock().getEvents().onTargetRegionChanged(new Rect(
- mSmallClockFrame.getLeft(),
- mSmallClockFrame.getTop(),
- mSmallClockFrame.getRight(),
- mSmallClockFrame.getTop() + targetHeight));
+ Rect targetRegion = getSmallClockRegion(mSmallClockFrame);
+ mClock.getSmallClock().getEvents().onTargetRegionChanged(targetRegion);
}
if (mLargeClockFrame.isLaidOut()) {
@@ -220,39 +230,44 @@
mStatusAreaAnim = null;
View in, out;
- int direction = 1;
- float statusAreaYTranslation;
+ float statusAreaYTranslation, clockInYTranslation, clockOutYTranslation;
if (useLargeClock) {
out = mSmallClockFrame;
in = mLargeClockFrame;
if (indexOfChild(in) == -1) addView(in, 0);
- direction = -1;
statusAreaYTranslation = mSmallClockFrame.getTop() - mStatusArea.getTop()
+ mSmartspaceTopOffset;
+ clockInYTranslation = 0;
+ clockOutYTranslation = 0; // Small clock translation is handled with statusArea
} else {
in = mSmallClockFrame;
out = mLargeClockFrame;
statusAreaYTranslation = 0f;
+ clockInYTranslation = 0f;
+ clockOutYTranslation = mClockSwitchYAmount * -1f;
- // Must remove in order for notifications to appear in the proper place
+ // Must remove in order for notifications to appear in the proper place, ideally this
+ // would happen after the out animation runs, but we can't guarantee that the
+ // nofications won't enter only after the out animation runs.
removeView(out);
}
if (!animate) {
out.setAlpha(0f);
+ out.setTranslationY(clockOutYTranslation);
in.setAlpha(1f);
- in.setVisibility(VISIBLE);
+ in.setTranslationY(clockInYTranslation);
+ in.setVisibility(View.VISIBLE);
mStatusArea.setTranslationY(statusAreaYTranslation);
return;
}
mClockOutAnim = new AnimatorSet();
mClockOutAnim.setDuration(CLOCK_OUT_MILLIS);
- mClockOutAnim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+ mClockOutAnim.setInterpolator(Interpolators.LINEAR);
mClockOutAnim.playTogether(
- ObjectAnimator.ofFloat(out, View.ALPHA, 0f),
- ObjectAnimator.ofFloat(out, View.TRANSLATION_Y, 0,
- direction * -mClockSwitchYAmount));
+ ObjectAnimator.ofFloat(out, ALPHA, 0f),
+ ObjectAnimator.ofFloat(out, TRANSLATION_Y, clockOutYTranslation));
mClockOutAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
mClockOutAnim = null;
@@ -264,8 +279,9 @@
mClockInAnim = new AnimatorSet();
mClockInAnim.setDuration(CLOCK_IN_MILLIS);
mClockInAnim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- mClockInAnim.playTogether(ObjectAnimator.ofFloat(in, View.ALPHA, 1f),
- ObjectAnimator.ofFloat(in, View.TRANSLATION_Y, direction * mClockSwitchYAmount, 0));
+ mClockInAnim.playTogether(
+ ObjectAnimator.ofFloat(in, ALPHA, 1f),
+ ObjectAnimator.ofFloat(in, TRANSLATION_Y, clockInYTranslation));
mClockInAnim.setStartDelay(CLOCK_IN_START_DELAY_MILLIS);
mClockInAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
@@ -273,19 +289,22 @@
}
});
- mClockInAnim.start();
- mClockOutAnim.start();
-
- mStatusAreaAnim = ObjectAnimator.ofFloat(mStatusArea, View.TRANSLATION_Y,
- statusAreaYTranslation);
- mStatusAreaAnim.setStartDelay(useLargeClock ? STATUS_AREA_START_DELAY_MILLIS : 0L);
- mStatusAreaAnim.setDuration(STATUS_AREA_MOVE_MILLIS);
- mStatusAreaAnim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mStatusAreaAnim = new AnimatorSet();
+ mStatusAreaAnim.setStartDelay(STATUS_AREA_START_DELAY_MILLIS);
+ mStatusAreaAnim.setDuration(
+ useLargeClock ? STATUS_AREA_MOVE_UP_MILLIS : STATUS_AREA_MOVE_DOWN_MILLIS);
+ mStatusAreaAnim.setInterpolator(Interpolators.EMPHASIZED);
+ mStatusAreaAnim.playTogether(
+ ObjectAnimator.ofFloat(mStatusArea, TRANSLATION_Y, statusAreaYTranslation),
+ ObjectAnimator.ofFloat(mSmallClockFrame, TRANSLATION_Y, statusAreaYTranslation));
mStatusAreaAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
mStatusAreaAnim = null;
}
});
+
+ mClockInAnim.start();
+ mClockOutAnim.start();
mStatusAreaAnim.start();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinFlowView.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardPinFlowView.kt
new file mode 100644
index 0000000..5c66b82
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinFlowView.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 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.keyguard
+
+import android.content.Context
+import android.util.AttributeSet
+import androidx.constraintlayout.helper.widget.Flow
+import androidx.constraintlayout.widget.ConstraintLayout
+
+class KeyguardPinFlowView(context: Context, attrs: AttributeSet?) : Flow(context, attrs) {
+ // Overriding this so that visibilities of child views do not get updated.
+ override fun applyLayoutFeatures(container: ConstraintLayout?) {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index f04fdfff..9807b9e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -122,7 +122,9 @@
if (shouldAnimateIconViewForTransition(lastState, newState)) {
iconView.playAnimation()
}
- LottieColorUtils.applyDynamicColors(context, iconView)
+ if (isSideFps) {
+ LottieColorUtils.applyDynamicColors(context, iconView)
+ }
}
override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
index ede62ac..a3f34ce 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt
@@ -68,15 +68,15 @@
var inputTopBound: Int
var headerRightBound = right
var headerTopBounds = top
+ var headerBottomBounds = bottom
val subTitleBottom: Int = if (subtitleView.isGone) titleView.bottom else subtitleView.bottom
val descBottom = if (descriptionView.isGone) subTitleBottom else descriptionView.bottom
if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) {
inputTopBound = (bottom - credentialInput.height) / 2
inputLeftBound = (right - left) / 2
headerRightBound = inputLeftBound
- headerTopBounds -= iconView.bottom.coerceAtMost(bottomInset)
-
- if (descriptionView.bottom > bottomInset) {
+ if (descriptionView.bottom > headerBottomBounds) {
+ headerTopBounds -= iconView.bottom.coerceAtMost(bottomInset)
credentialHeader.layout(left, headerTopBounds, headerRightBound, bottom)
}
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/complication/ComplicationTypesUpdater.java b/packages/SystemUI/src/com/android/systemui/complication/ComplicationTypesUpdater.java
index a334c1e..0bdc7f1 100644
--- a/packages/SystemUI/src/com/android/systemui/complication/ComplicationTypesUpdater.java
+++ b/packages/SystemUI/src/com/android/systemui/complication/ComplicationTypesUpdater.java
@@ -77,6 +77,10 @@
Settings.Secure.SCREENSAVER_HOME_CONTROLS_ENABLED,
settingsObserver,
UserHandle.myUserId());
+ mSecureSettings.registerContentObserverForUser(
+ Settings.Secure.LOCKSCREEN_SHOW_CONTROLS,
+ settingsObserver,
+ UserHandle.myUserId());
settingsObserver.onChange(false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 27cebc6..19810b3 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -104,6 +104,16 @@
val SENSITIVE_REVEAL_ANIM =
unreleasedFlag(268005230, "sensitive_reveal_anim", teamfood = true)
+ // TODO(b/280783617): Tracking Bug
+ @Keep
+ @JvmField
+ val BUILDER_EXTRAS_OVERRIDE =
+ sysPropBooleanFlag(
+ 128,
+ "persist.sysui.notification.builder_extras_override",
+ default = false
+ )
+
// 200 - keyguard/lockscreen
// ** Flag retired **
// public static final BooleanFlag KEYGUARD_LAYOUT =
@@ -136,7 +146,7 @@
* the digits when the clock moves.
*/
@JvmField
- val STEP_CLOCK_ANIMATION = unreleasedFlag(212, "step_clock_animation", teamfood = true)
+ val STEP_CLOCK_ANIMATION = releasedFlag(212, "step_clock_animation")
/**
* Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
@@ -167,7 +177,7 @@
*/
// TODO(b/281655028): Tracking bug
@JvmField
- val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = true)
+ val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = false)
/** Flag to control the migration of face auth to modern architecture. */
// TODO(b/262838215): Tracking bug
@@ -525,13 +535,6 @@
val ENABLE_PIP_APP_ICON_OVERLAY =
sysPropBooleanFlag(1115, "persist.wm.debug.enable_pip_app_icon_overlay", default = true)
- // TODO(b/272110828): Tracking bug
- @Keep
- @JvmField
- val ENABLE_MOVE_FLOATING_WINDOW_IN_TABLETOP =
- sysPropBooleanFlag(
- 1116, "persist.wm.debug.enable_move_floating_window_in_tabletop", default = true)
-
// TODO(b/273443374): Tracking Bug
@Keep
@JvmField val LOCKSCREEN_LIVE_WALLPAPER =
@@ -615,8 +618,6 @@
unreleasedFlag(1401, "quick_tap_flow_framework", teamfood = false)
// 1500 - chooser aka sharesheet
- // TODO(b/254512507): Tracking Bug
- val CHOOSER_UNBUNDLED = releasedFlag(1500, "chooser_unbundled")
// 1700 - clipboard
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 5d3f5f2..b8d3121 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -19,7 +19,6 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
-import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
@@ -30,13 +29,11 @@
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.view.WindowManager.TransitionFlags;
import static android.view.WindowManager.TransitionOldType;
import static android.view.WindowManager.TransitionType;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.Service;
@@ -65,6 +62,7 @@
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
@@ -116,6 +114,14 @@
final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
final int taskId = taskInfo != null ? change.getTaskInfo().taskId : -1;
+ if (taskId != -1 && change.getParent() != null) {
+ final TransitionInfo.Change parentChange = info.getChange(change.getParent());
+ if (parentChange != null && parentChange.getTaskInfo() != null) {
+ // Only adding the root task as the animation target.
+ continue;
+ }
+ }
+
final RemoteAnimationTarget target = TransitionUtil.newTarget(change,
// wallpapers go into the "below" layer space
info.getChanges().size() - i,
@@ -123,13 +129,6 @@
(change.getFlags() & TransitionInfo.FLAG_SHOW_WALLPAPER) != 0,
info, t, leashMap);
- // Use hasAnimatingParent to mark the anything below root task
- if (taskId != -1 && change.getParent() != null) {
- final TransitionInfo.Change parentChange = info.getChange(change.getParent());
- if (parentChange != null && parentChange.getTaskInfo() != null) {
- target.hasAnimatingParent = true;
- }
- }
out.add(target);
}
return out.toArray(new RemoteAnimationTarget[out.size()]);
@@ -158,71 +157,83 @@
// Note: Also used for wrapping occlude by Dream animation. It works (with some redundancy).
public static IRemoteTransition wrap(IRemoteAnimationRunner runner) {
return new IRemoteTransition.Stub() {
- final ArrayMap<IBinder, IRemoteTransitionFinishedCallback> mFinishCallbacks =
- new ArrayMap<>();
+
private final ArrayMap<SurfaceControl, SurfaceControl> mLeashMap = new ArrayMap<>();
+ @GuardedBy("mLeashMap")
+ private IRemoteTransitionFinishedCallback mFinishCallback = null;
+
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t, IRemoteTransitionFinishedCallback finishCallback)
throws RemoteException {
Slog.d(TAG, "Starts IRemoteAnimationRunner: info=" + info);
- final RemoteAnimationTarget[] apps =
- wrap(info, false /* wallpapers */, t, mLeashMap);
- final RemoteAnimationTarget[] wallpapers =
- wrap(info, true /* wallpapers */, t, mLeashMap);
- final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
- // Sets the alpha to 0 for the opening root task for fade in animation. And since
- // the fade in animation can only apply on the first opening app, so set alpha to 1
- // for anything else.
- for (RemoteAnimationTarget target : apps) {
- if (target.taskId != -1
- && target.mode == RemoteAnimationTarget.MODE_OPENING
- && !target.hasAnimatingParent) {
- t.setAlpha(target.leash, 0.0f);
- } else {
- t.setAlpha(target.leash, 1.0f);
- }
- }
- t.apply();
- synchronized (mFinishCallbacks) {
- mFinishCallbacks.put(transition, finishCallback);
- }
- runner.onAnimationStart(getTransitionOldType(info.getType(), info.getFlags(), apps),
- apps, wallpapers, nonApps,
- new IRemoteAnimationFinishedCallback.Stub() {
- @Override
- public void onAnimationFinished() throws RemoteException {
- synchronized (mFinishCallbacks) {
- if (mFinishCallbacks.remove(transition) == null) return;
- }
- info.releaseAllSurfaces();
- Slog.d(TAG, "Finish IRemoteAnimationRunner.");
- finishCallback.onTransitionFinished(null /* wct */, null /* t */);
- }
+ synchronized (mLeashMap) {
+ final RemoteAnimationTarget[] apps =
+ wrap(info, false /* wallpapers */, t, mLeashMap);
+ final RemoteAnimationTarget[] wallpapers =
+ wrap(info, true /* wallpapers */, t, mLeashMap);
+ final RemoteAnimationTarget[] nonApps = new RemoteAnimationTarget[0];
+
+ // Set alpha back to 1 for the independent changes because we will be animating
+ // children instead.
+ for (TransitionInfo.Change chg : info.getChanges()) {
+ if (TransitionInfo.isIndependent(chg, info)) {
+ t.setAlpha(chg.getLeash(), 1.f);
}
- );
+ }
+ initAlphaForAnimationTargets(t, apps);
+ initAlphaForAnimationTargets(t, wallpapers);
+ t.apply();
+ mFinishCallback = finishCallback;
+ runner.onAnimationStart(
+ getTransitionOldType(info.getType(), info.getFlags(), apps),
+ apps, wallpapers, nonApps,
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ synchronized (mLeashMap) {
+ Slog.d(TAG, "Finish IRemoteAnimationRunner.");
+ finish();
+ }
+ }
+ }
+ );
+ }
}
public void mergeAnimation(IBinder candidateTransition, TransitionInfo candidateInfo,
SurfaceControl.Transaction candidateT, IBinder currentTransition,
- IRemoteTransitionFinishedCallback candidateFinishCallback) {
+ IRemoteTransitionFinishedCallback candidateFinishCallback)
+ throws RemoteException {
try {
- final IRemoteTransitionFinishedCallback currentFinishCB;
- synchronized (mFinishCallbacks) {
- currentFinishCB = mFinishCallbacks.remove(currentTransition);
+ synchronized (mLeashMap) {
+ runner.onAnimationCancelled();
+ finish();
}
- if (currentFinishCB == null) {
- Slog.e(TAG, "Called mergeAnimation, but finish callback is missing");
- return;
- }
- runner.onAnimationCancelled();
- currentFinishCB.onTransitionFinished(null /* wct */, null /* t */);
} catch (RemoteException e) {
// nothing, we'll just let it finish on its own I guess.
}
}
+
+ private static void initAlphaForAnimationTargets(@NonNull SurfaceControl.Transaction t,
+ @NonNull RemoteAnimationTarget[] targets) {
+ for (RemoteAnimationTarget target : targets) {
+ if (target.mode != MODE_OPENING) continue;
+ t.setAlpha(target.leash, 0.f);
+ }
+ }
+
+ @GuardedBy("mLeashMap")
+ private void finish() throws RemoteException {
+ mLeashMap.clear();
+ final IRemoteTransitionFinishedCallback finishCallback = mFinishCallback;
+ if (finishCallback != null) {
+ mFinishCallback = null;
+ finishCallback.onTransitionFinished(null /* wct */, null /* t */);
+ }
+ }
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index f96f337..122e259 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -812,8 +812,8 @@
// Translate up from the bottom.
surfaceBehindMatrix.setTranslate(
- surfaceBehindRemoteAnimationTarget.localBounds.left.toFloat(),
- surfaceBehindRemoteAnimationTarget.localBounds.top.toFloat() +
+ surfaceBehindRemoteAnimationTarget.screenSpaceBounds.left.toFloat(),
+ surfaceBehindRemoteAnimationTarget.screenSpaceBounds.top.toFloat() +
surfaceHeight * SURFACE_BEHIND_START_TRANSLATION_Y * (1f - amount)
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt
index d8affa4..1978b3d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ResourceTrimmer.kt
@@ -139,7 +139,8 @@
if (dozeDisabledAndScreenOff || dozeEnabledAndDozeAnimationCompleted) {
Trace.beginSection("ResourceTrimmer#trimMemory")
Log.d(LOG_TAG, "SysUI asleep, trimming memory.")
- globalWindowManager.trimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND)
+ globalWindowManager.trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
+ globalWindowManager.trimCaches(HardwareRenderer.CACHE_TRIM_ALL)
Trace.endSection()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
new file mode 100644
index 0000000..641e20b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2023 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.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.keyguard.shared.model.SettingsClockSize
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+class KeyguardClockRepository
+@Inject
+constructor(
+ private val secureSettings: SecureSettings,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
+
+ val selectedClockSize: Flow<SettingsClockSize> =
+ secureSettings
+ .observerFlow(
+ names = arrayOf(Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK),
+ userId = UserHandle.USER_SYSTEM,
+ )
+ .onStart { emit(Unit) } // Forces an initial update.
+ .map { getClockSize() }
+
+ private suspend fun getClockSize(): SettingsClockSize {
+ return withContext(backgroundDispatcher) {
+ if (
+ secureSettings.getIntForUser(
+ Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK,
+ 1,
+ UserHandle.USER_CURRENT
+ ) == 1
+ ) {
+ SettingsClockSize.DYNAMIC
+ } else {
+ SettingsClockSize.SMALL
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
new file mode 100644
index 0000000..98f445c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardClockInteractor.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 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.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardClockRepository
+import com.android.systemui.keyguard.shared.model.SettingsClockSize
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Encapsulates business-logic related to the keyguard clock. */
+@SysUISingleton
+class KeyguardClockInteractor
+@Inject
+constructor(
+ repository: KeyguardClockRepository,
+) {
+ val selectedClockSize: Flow<SettingsClockSize> = repository.selectedClockSize
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/SettingsClockSize.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/SettingsClockSize.kt
new file mode 100644
index 0000000..c6b0f58
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/SettingsClockSize.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 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.shared.model
+
+enum class SettingsClockSize {
+ DYNAMIC,
+ SMALL,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockSmartspaceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockSmartspaceViewBinder.kt
new file mode 100644
index 0000000..57c32b3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockSmartspaceViewBinder.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 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.ui.binder
+
+import android.view.View
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockSmartspaceViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import kotlinx.coroutines.flow.collect
+
+/** Binder for the small clock view, large clock view and smartspace. */
+object KeyguardPreviewClockSmartspaceViewBinder {
+
+ @JvmStatic
+ fun bind(
+ largeClockHostView: View,
+ smallClockHostView: View,
+ smartspace: View?,
+ viewModel: KeyguardPreviewClockSmartspaceViewModel,
+ ) {
+ largeClockHostView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.isLargeClockVisible.collect { largeClockHostView.isVisible = it }
+ }
+ }
+
+ smallClockHostView.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.isSmallClockVisible.collect { smallClockHostView.isVisible = it }
+ }
+ }
+
+ smartspace?.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ viewModel.smartSpaceTopPadding.collect { smartspace.setTopPadding(it) }
+ }
+ }
+ }
+
+ private fun View.setTopPadding(padding: Int) {
+ setPaddingRelative(paddingStart, padding, paddingEnd, paddingBottom)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 555a09b..4308d84 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -22,6 +22,7 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.res.Resources
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.os.Bundle
@@ -33,6 +34,7 @@
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
+import androidx.core.view.isInvisible
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
import com.android.systemui.R
@@ -40,7 +42,10 @@
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockSmartspaceViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockSmartspaceViewModel
+import com.android.systemui.plugins.ClockController
import com.android.systemui.shared.clocks.ClockRegistry
import com.android.systemui.shared.clocks.DefaultClockController
import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants
@@ -60,6 +65,7 @@
@Application private val context: Context,
@Main private val mainDispatcher: CoroutineDispatcher,
@Main private val mainHandler: Handler,
+ private val clockSmartspaceViewModel: KeyguardPreviewClockSmartspaceViewModel,
private val bottomAreaViewModel: KeyguardBottomAreaViewModel,
displayManager: DisplayManager,
private val windowManager: WindowManager,
@@ -79,6 +85,7 @@
KeyguardPreviewConstants.KEY_HIGHLIGHT_QUICK_AFFORDANCES,
false,
)
+ /** [shouldHideClock] here means that we never create and bind the clock views */
private val shouldHideClock: Boolean =
bundle.getBoolean(ClockPreviewConstants.KEY_HIDE_CLOCK, false)
@@ -87,7 +94,8 @@
val surfacePackage: SurfaceControlViewHost.SurfacePackage
get() = host.surfacePackage
- private var clockView: View? = null
+ private lateinit var largeClockHostView: FrameLayout
+ private lateinit var smallClockHostView: FrameLayout
private var smartSpaceView: View? = null
private var colorOverride: Int? = null
@@ -126,6 +134,12 @@
if (!shouldHideClock) {
setUpClock(rootView)
+ KeyguardPreviewClockSmartspaceViewBinder.bind(
+ largeClockHostView,
+ smallClockHostView,
+ smartSpaceView,
+ clockSmartspaceViewModel,
+ )
}
rootView.measure(
@@ -205,11 +219,9 @@
smartSpaceView = lockscreenSmartspaceController.buildAndConnectDateView(parentView)
val topPadding: Int =
- with(context.resources) {
- getDimensionPixelSize(R.dimen.status_bar_header_height_keyguard) +
- getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) +
- getDimensionPixelSize(R.dimen.keyguard_clock_top_margin)
- }
+ KeyguardPreviewClockSmartspaceViewModel.getLargeClockSmartspaceTopPadding(
+ context.resources
+ )
val startPadding: Int =
with(context.resources) {
@@ -284,10 +296,19 @@
}
private fun setUpClock(parentView: ViewGroup) {
+ largeClockHostView = createLargeClockHostView()
+ largeClockHostView.isInvisible = true
+ parentView.addView(largeClockHostView)
+
+ smallClockHostView = createSmallClockHostView(parentView.resources)
+ smallClockHostView.isInvisible = true
+ parentView.addView(smallClockHostView)
+
+ // TODO (b/283465254): Move the listeners to KeyguardClockRepository
val clockChangeListener =
object : ClockRegistry.ClockChangeListener {
override fun onCurrentClockChanged() {
- onClockChanged(parentView)
+ onClockChanged()
}
}
clockRegistry.registerClockChangeListener(clockChangeListener)
@@ -317,62 +338,89 @@
disposables.add(DisposableHandle { broadcastDispatcher.unregisterReceiver(receiver) })
val layoutChangeListener =
- object : View.OnLayoutChangeListener {
- override fun onLayoutChange(
- v: View,
- left: Int,
- top: Int,
- right: Int,
- bottom: Int,
- oldLeft: Int,
- oldTop: Int,
- oldRight: Int,
- oldBottom: Int
- ) {
- if (clockController.clock !is DefaultClockController) {
- clockController.clock
- ?.largeClock
- ?.events
- ?.onTargetRegionChanged(
- KeyguardClockSwitch.getLargeClockRegion(parentView)
- )
- }
+ View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
+ if (clockController.clock !is DefaultClockController) {
+ clockController.clock
+ ?.largeClock
+ ?.events
+ ?.onTargetRegionChanged(KeyguardClockSwitch.getLargeClockRegion(parentView))
}
}
-
parentView.addOnLayoutChangeListener(layoutChangeListener)
-
disposables.add(
DisposableHandle { parentView.removeOnLayoutChangeListener(layoutChangeListener) }
)
- onClockChanged(parentView)
+ onClockChanged()
}
- private fun onClockChanged(parentView: ViewGroup) {
+ private fun createLargeClockHostView(): FrameLayout {
+ val hostView = FrameLayout(context)
+ hostView.layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ )
+ return hostView
+ }
+
+ private fun createSmallClockHostView(resources: Resources): FrameLayout {
+ val hostView = FrameLayout(context)
+ val layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ resources.getDimensionPixelSize(R.dimen.small_clock_height)
+ )
+ layoutParams.topMargin =
+ KeyguardPreviewClockSmartspaceViewModel.getStatusBarHeight(resources) +
+ resources.getDimensionPixelSize(R.dimen.small_clock_padding_top)
+ hostView.layoutParams = layoutParams
+
+ hostView.setPaddingRelative(
+ resources.getDimensionPixelSize(R.dimen.clock_padding_start),
+ 0,
+ 0,
+ 0
+ )
+ hostView.clipChildren = false
+ return hostView
+ }
+
+ private fun onClockChanged() {
val clock = clockRegistry.createCurrentClock()
clockController.clock = clock
colorOverride?.let { clock.events.onSeedColorChanged(it) }
- clock.largeClock.events.onTargetRegionChanged(
- KeyguardClockSwitch.getLargeClockRegion(parentView)
- )
-
- clockView?.let { parentView.removeView(it) }
- clockView =
- clock.largeClock.view.apply {
- if (shouldHighlightSelectedAffordance) {
- alpha = DIM_ALPHA
- }
- parentView.addView(this)
- visibility = View.VISIBLE
- }
+ updateLargeClock(clock)
+ updateSmallClock(clock)
// Hide smart space if the clock has weather display; otherwise show it
hideSmartspace(clock.largeClock.config.hasCustomWeatherDataDisplay)
}
+ private fun updateLargeClock(clock: ClockController) {
+ clock.largeClock.events.onTargetRegionChanged(
+ KeyguardClockSwitch.getLargeClockRegion(largeClockHostView)
+ )
+ if (shouldHighlightSelectedAffordance) {
+ clock.largeClock.view.alpha = DIM_ALPHA
+ }
+ largeClockHostView.removeAllViews()
+ largeClockHostView.addView(clock.largeClock.view)
+ }
+
+ private fun updateSmallClock(clock: ClockController) {
+ clock.smallClock.events.onTargetRegionChanged(
+ KeyguardClockSwitch.getSmallClockRegion(smallClockHostView)
+ )
+ if (shouldHighlightSelectedAffordance) {
+ clock.smallClock.view.alpha = DIM_ALPHA
+ }
+ smallClockHostView.removeAllViews()
+ smallClockHostView.addView(clock.smallClock.view)
+ }
+
companion object {
private const val KEY_HOST_TOKEN = "host_token"
private const val KEY_VIEW_WIDTH = "width"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockSmartspaceViewModel.kt
new file mode 100644
index 0000000..00c603b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardPreviewClockSmartspaceViewModel.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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.ui.viewmodel
+
+import android.content.Context
+import android.content.res.Resources
+import com.android.systemui.R
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.shared.model.SettingsClockSize
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/** View model for the small clock view, large clock view and smartspace. */
+class KeyguardPreviewClockSmartspaceViewModel
+@Inject
+constructor(
+ @Application private val context: Context,
+ interactor: KeyguardClockInteractor,
+) {
+
+ val isLargeClockVisible: Flow<Boolean> =
+ interactor.selectedClockSize.map { it == SettingsClockSize.DYNAMIC }
+
+ val isSmallClockVisible: Flow<Boolean> =
+ interactor.selectedClockSize.map { it == SettingsClockSize.SMALL }
+
+ val smartSpaceTopPadding: Flow<Int> =
+ interactor.selectedClockSize.map {
+ when (it) {
+ SettingsClockSize.DYNAMIC -> getLargeClockSmartspaceTopPadding(context.resources)
+ SettingsClockSize.SMALL -> getSmallClockSmartspaceTopPadding(context.resources)
+ }
+ }
+
+ companion object {
+ fun getLargeClockSmartspaceTopPadding(resources: Resources): Int {
+ return with(resources) {
+ getDimensionPixelSize(R.dimen.status_bar_header_height_keyguard) +
+ getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) +
+ getDimensionPixelSize(R.dimen.keyguard_clock_top_margin)
+ }
+ }
+
+ fun getSmallClockSmartspaceTopPadding(resources: Resources): Int {
+ return with(resources) {
+ getStatusBarHeight(this) +
+ getDimensionPixelSize(R.dimen.small_clock_padding_top) +
+ getDimensionPixelSize(R.dimen.small_clock_height)
+ }
+ }
+
+ fun getStatusBarHeight(resource: Resources): Int {
+ var result = 0
+ val resourceId: Int = resource.getIdentifier("status_bar_height", "dimen", "android")
+ if (resourceId > 0) {
+ result = resource.getDimensionPixelSize(resourceId)
+ }
+ return result
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 1469d96..bce3346 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -16,10 +16,12 @@
package com.android.systemui.media.controls.pipeline
+import android.annotation.SuppressLint
import android.app.BroadcastOptions
import android.app.Notification
import android.app.Notification.EXTRA_SUBSTITUTE_APP_NAME
import android.app.PendingIntent
+import android.app.StatusBarManager
import android.app.smartspace.SmartspaceConfig
import android.app.smartspace.SmartspaceManager
import android.app.smartspace.SmartspaceSession
@@ -43,7 +45,6 @@
import android.net.Uri
import android.os.Parcelable
import android.os.Process
-import android.os.RemoteException
import android.os.UserHandle
import android.provider.Settings
import android.service.notification.StatusBarNotification
@@ -53,7 +54,6 @@
import android.util.Pair as APair
import androidx.media.utils.MediaConstants
import com.android.internal.logging.InstanceId
-import com.android.internal.statusbar.IStatusBarService
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.Dumpable
import com.android.systemui.R
@@ -185,7 +185,6 @@
private val logger: MediaUiEventLogger,
private val smartspaceManager: SmartspaceManager,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
- private val statusBarService: IStatusBarService,
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
companion object {
@@ -230,6 +229,10 @@
private val artworkHeight =
context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded)
+ @SuppressLint("WrongConstant") // sysui allowed to call STATUS_BAR_SERVICE
+ private val statusBarManager =
+ context.getSystemService(Context.STATUS_BAR_SERVICE) as StatusBarManager
+
/** Check whether this notification is an RCN */
private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean {
return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)
@@ -257,7 +260,6 @@
mediaFlags: MediaFlags,
logger: MediaUiEventLogger,
smartspaceManager: SmartspaceManager,
- statusBarService: IStatusBarService,
keyguardUpdateMonitor: KeyguardUpdateMonitor,
) : this(
context,
@@ -283,7 +285,6 @@
logger,
smartspaceManager,
keyguardUpdateMonitor,
- statusBarService,
)
private val appChangeReceiver =
@@ -793,27 +794,12 @@
song = HybridGroupManager.resolveTitle(notif)
}
if (song.isNullOrBlank()) {
- if (mediaFlags.isMediaTitleRequired(sbn.packageName, sbn.user)) {
- // App is required to provide a title: cancel the underlying notification
- try {
- statusBarService.onNotificationError(
- sbn.packageName,
- sbn.tag,
- sbn.id,
- sbn.uid,
- sbn.initialPid,
- MEDIA_TITLE_ERROR_MESSAGE,
- sbn.user.identifier
- )
- } catch (e: RemoteException) {
- Log.e(TAG, "cancelNotification failed: $e")
- }
- // Only add log for media removed if active media is updated with invalid title.
- foregroundExecutor.execute { removeEntry(key, !isNewlyActiveEntry) }
- return
- } else {
- // For apps that don't have the title requirement yet, add a placeholder
- song = context.getString(R.string.controls_media_empty_title, appName)
+ // For apps that don't include a title, log and add a placeholder
+ song = context.getString(R.string.controls_media_empty_title, appName)
+ try {
+ statusBarManager.logBlankMediaTitle(sbn.packageName, sbn.user.identifier)
+ } catch (e: RuntimeException) {
+ Log.e(TAG, "Error reporting blank media title for package ${sbn.packageName}")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 3751c60..9bc66f6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -64,9 +64,4 @@
/** Check whether we allow remote media to generate resume controls */
fun isRemoteResumeAllowed() = featureFlags.isEnabled(Flags.MEDIA_REMOTE_RESUME)
-
- /** Check whether app is required to provide a non-empty media title */
- fun isMediaTitleRequired(packageName: String, user: UserHandle): Boolean {
- return StatusBarManager.isMediaTitleRequiredForApp(packageName, user)
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 993c3801..b956207 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -354,7 +354,11 @@
@Override
protected void snapChild(final View animView, final float targetLeft, float velocity) {
- superSnapChild(animView, targetLeft, velocity);
+ if (animView instanceof SwipeableView) {
+ // only perform the snapback animation on views that are swipeable inside the shade.
+ superSnapChild(animView, targetLeft, velocity);
+ }
+
mCallback.onDragCancelled(animView);
if (targetLeft == 0) {
handleMenuCoveredOrDismissed();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index a6b2bd8..f26a84b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -30,6 +30,8 @@
import android.view.ViewDebug;
import android.view.WindowInsetsController.Appearance;
+import androidx.annotation.NonNull;
+
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.Dumpable;
@@ -46,7 +48,6 @@
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Date;
import javax.inject.Inject;
@@ -57,7 +58,8 @@
public class LightBarController implements BatteryController.BatteryStateChangeCallback, Dumpable {
private static final String TAG = "LightBarController";
- private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean DEBUG_NAVBAR = Compile.IS_DEBUG;
+ private static final boolean DEBUG_LOGS = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
@@ -113,6 +115,7 @@
private String mLastSetScrimStateLog;
private String mLastNavigationBarAppearanceChangedLog;
+ private StringBuilder mLogStringBuilder = null;
@Inject
public LightBarController(
@@ -193,35 +196,43 @@
final boolean darkForTop = darkForQs || mGlobalActionsVisible;
mNavigationLight =
((mHasLightNavigationBar && !darkForScrim) || lightForScrim) && !darkForTop;
- mLastNavigationBarAppearanceChangedLog = "onNavigationBarAppearanceChanged()"
- + " appearance=" + appearance
- + " nbModeChanged=" + nbModeChanged
- + " navigationBarMode=" + navigationBarMode
- + " navbarColorManagedByIme=" + navbarColorManagedByIme
- + " mHasLightNavigationBar=" + mHasLightNavigationBar
- + " ignoreScrimForce=" + ignoreScrimForce
- + " darkForScrim=" + darkForScrim
- + " lightForScrim=" + lightForScrim
- + " darkForQs=" + darkForQs
- + " darkForTop=" + darkForTop
- + " mNavigationLight=" + mNavigationLight
- + " last=" + last
- + " timestamp=" + new Date();
- if (DEBUG) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
+ if (DEBUG_NAVBAR) {
+ mLastNavigationBarAppearanceChangedLog = getLogStringBuilder()
+ .append("onNavigationBarAppearanceChanged()")
+ .append(" appearance=").append(appearance)
+ .append(" nbModeChanged=").append(nbModeChanged)
+ .append(" navigationBarMode=").append(navigationBarMode)
+ .append(" navbarColorManagedByIme=").append(navbarColorManagedByIme)
+ .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
+ .append(" ignoreScrimForce=").append(ignoreScrimForce)
+ .append(" darkForScrim=").append(darkForScrim)
+ .append(" lightForScrim=").append(lightForScrim)
+ .append(" darkForQs=").append(darkForQs)
+ .append(" darkForTop=").append(darkForTop)
+ .append(" mNavigationLight=").append(mNavigationLight)
+ .append(" last=").append(last)
+ .append(" timestamp=").append(System.currentTimeMillis())
+ .toString();
+ if (DEBUG_LOGS) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
+ }
} else {
mNavigationLight = mHasLightNavigationBar
&& (mDirectReplying && mNavbarColorManagedByIme || !mForceDarkForScrim)
&& !mQsCustomizing;
- mLastNavigationBarAppearanceChangedLog = "onNavigationBarAppearanceChanged()"
- + " appearance=" + appearance
- + " nbModeChanged=" + nbModeChanged
- + " navigationBarMode=" + navigationBarMode
- + " navbarColorManagedByIme=" + navbarColorManagedByIme
- + " mHasLightNavigationBar=" + mHasLightNavigationBar
- + " mNavigationLight=" + mNavigationLight
- + " last=" + last
- + " timestamp=" + new Date();
- if (DEBUG) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
+ if (DEBUG_NAVBAR) {
+ mLastNavigationBarAppearanceChangedLog = getLogStringBuilder()
+ .append("onNavigationBarAppearanceChanged()")
+ .append(" appearance=").append(appearance)
+ .append(" nbModeChanged=").append(nbModeChanged)
+ .append(" navigationBarMode=").append(navigationBarMode)
+ .append(" navbarColorManagedByIme=").append(navbarColorManagedByIme)
+ .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
+ .append(" mNavigationLight=").append(mNavigationLight)
+ .append(" last=").append(last)
+ .append(" timestamp=").append(System.currentTimeMillis())
+ .toString();
+ if (DEBUG_LOGS) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
+ }
}
if (mNavigationLight != last) {
updateNavigation();
@@ -319,18 +330,22 @@
} else {
if (mForceLightForScrim != forceLightForScrimLast) reevaluate();
}
- mLastSetScrimStateLog = "setScrimState()"
- + " scrimState=" + scrimState
- + " scrimBehindAlpha=" + scrimBehindAlpha
- + " scrimInFrontColor=" + scrimInFrontColor
- + " forceForScrim=" + forceForScrim
- + " scrimColorIsLight=" + scrimColorIsLight
- + " mHasLightNavigationBar=" + mHasLightNavigationBar
- + " mBouncerVisible=" + mBouncerVisible
- + " mForceDarkForScrim=" + mForceDarkForScrim
- + " mForceLightForScrim=" + mForceLightForScrim
- + " timestamp=" + new Date();
- if (DEBUG) Log.d(TAG, mLastSetScrimStateLog);
+ if (DEBUG_NAVBAR) {
+ mLastSetScrimStateLog = getLogStringBuilder()
+ .append("setScrimState()")
+ .append(" scrimState=").append(scrimState)
+ .append(" scrimBehindAlpha=").append(scrimBehindAlpha)
+ .append(" scrimInFrontColor=").append(scrimInFrontColor)
+ .append(" forceForScrim=").append(forceForScrim)
+ .append(" scrimColorIsLight=").append(scrimColorIsLight)
+ .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
+ .append(" mBouncerVisible=").append(mBouncerVisible)
+ .append(" mForceDarkForScrim=").append(mForceDarkForScrim)
+ .append(" mForceLightForScrim=").append(mForceLightForScrim)
+ .append(" timestamp=").append(System.currentTimeMillis())
+ .toString();
+ if (DEBUG_LOGS) Log.d(TAG, mLastSetScrimStateLog);
+ }
} else {
boolean forceDarkForScrimLast = mForceDarkForScrim;
// For BOUNCER/BOUNCER_SCRIMMED cases, we assume that alpha is always below threshold.
@@ -344,17 +359,30 @@
if (mHasLightNavigationBar && (mForceDarkForScrim != forceDarkForScrimLast)) {
reevaluate();
}
- mLastSetScrimStateLog = "setScrimState()"
- + " scrimState=" + scrimState
- + " scrimBehindAlpha=" + scrimBehindAlpha
- + " scrimInFrontColor=" + scrimInFrontColor
- + " mHasLightNavigationBar=" + mHasLightNavigationBar
- + " mForceDarkForScrim=" + mForceDarkForScrim
- + " timestamp=" + new Date();
- if (DEBUG) Log.d(TAG, mLastSetScrimStateLog);
+ if (DEBUG_NAVBAR) {
+ mLastSetScrimStateLog = getLogStringBuilder()
+ .append("setScrimState()")
+ .append(" scrimState=").append(scrimState)
+ .append(" scrimBehindAlpha=").append(scrimBehindAlpha)
+ .append(" scrimInFrontColor=").append(scrimInFrontColor)
+ .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
+ .append(" mForceDarkForScrim=").append(mForceDarkForScrim)
+ .append(" timestamp=").append(System.currentTimeMillis())
+ .toString();
+ if (DEBUG_LOGS) Log.d(TAG, mLastSetScrimStateLog);
+ }
}
}
+ @NonNull
+ private StringBuilder getLogStringBuilder() {
+ if (mLogStringBuilder == null) {
+ mLogStringBuilder = new StringBuilder();
+ }
+ mLogStringBuilder.setLength(0);
+ return mLogStringBuilder;
+ }
+
private static boolean isLight(int appearance, int barMode, int flag) {
final boolean isTransparentBar = (barMode == MODE_TRANSPARENT
|| barMode == MODE_LIGHTS_OUT_TRANSPARENT);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 5ba02fa..b24a692 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -73,7 +73,6 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.VibrationEffect;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.text.InputFilter;
@@ -113,7 +112,6 @@
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.view.RotationPolicy;
@@ -133,15 +131,11 @@
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.AlphaTintDrawableWrapper;
-import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.RoundedCornerProgressDrawable;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
@@ -198,9 +192,6 @@
private ViewGroup mDialogRowsView;
private ViewGroup mRinger;
- private DeviceConfigProxy mDeviceConfigProxy;
- private Executor mExecutor;
-
/**
* Container for the top part of the dialog, which contains the ringer, the ringer drawer, the
* volume rows, and the ellipsis button. This does not include the live caption button.
@@ -290,14 +281,12 @@
private BackgroundBlurDrawable mDialogRowsViewBackground;
private final InteractionJankMonitor mInteractionJankMonitor;
- private boolean mSeparateNotification;
-
private int mWindowGravity;
@VisibleForTesting
- int mVolumeRingerIconDrawableId;
+ final int mVolumeRingerIconDrawableId = R.drawable.ic_speaker_on;
@VisibleForTesting
- int mVolumeRingerMuteIconDrawableId;
+ final int mVolumeRingerMuteIconDrawableId = R.drawable.ic_speaker_mute;
private int mOriginalGravity;
private final DevicePostureController.Callback mDevicePostureControllerCallback;
@@ -315,8 +304,6 @@
VolumePanelFactory volumePanelFactory,
ActivityStarter activityStarter,
InteractionJankMonitor interactionJankMonitor,
- DeviceConfigProxy deviceConfigProxy,
- Executor executor,
CsdWarningDialog.Factory csdWarningDialogFactory,
DevicePostureController devicePostureController,
Looper looper,
@@ -374,12 +361,6 @@
} else {
mDevicePostureControllerCallback = null;
}
-
- mDeviceConfigProxy = deviceConfigProxy;
- mExecutor = executor;
- mSeparateNotification = mDeviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false);
- updateRingerModeIconSet();
}
/**
@@ -401,44 +382,6 @@
return mWindowGravity;
}
- /**
- * If ringer and notification are the same stream (T and earlier), use notification-like bell
- * icon set.
- * If ringer and notification are separated, then use generic speaker icons.
- */
- private void updateRingerModeIconSet() {
- if (mSeparateNotification) {
- mVolumeRingerIconDrawableId = R.drawable.ic_speaker_on;
- mVolumeRingerMuteIconDrawableId = R.drawable.ic_speaker_mute;
- } else {
- mVolumeRingerIconDrawableId = R.drawable.ic_volume_ringer;
- mVolumeRingerMuteIconDrawableId = R.drawable.ic_volume_ringer_mute;
- }
-
- if (mRingerDrawerMuteIcon != null) {
- mRingerDrawerMuteIcon.setImageResource(mVolumeRingerMuteIconDrawableId);
- }
- if (mRingerDrawerNormalIcon != null) {
- mRingerDrawerNormalIcon.setImageResource(mVolumeRingerIconDrawableId);
- }
- }
-
- /**
- * Change icon for ring stream (not ringer mode icon)
- */
- private void updateRingRowIcon() {
- Optional<VolumeRow> volumeRow = mRows.stream().filter(row -> row.stream == STREAM_RING)
- .findFirst();
- if (volumeRow.isPresent()) {
- VolumeRow volRow = volumeRow.get();
- volRow.iconRes = mSeparateNotification ? R.drawable.ic_ring_volume
- : R.drawable.ic_volume_ringer;
- volRow.iconMuteRes = mSeparateNotification ? R.drawable.ic_ring_volume_off
- : R.drawable.ic_volume_ringer_mute;
- volRow.setIcon(volRow.iconRes, mContext.getTheme());
- }
- }
-
@Override
public void onUiModeChanged() {
mContext.getTheme().applyStyle(mContext.getThemeResId(), true);
@@ -454,9 +397,6 @@
mConfigurationController.addCallback(this);
- mDeviceConfigProxy.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
- mExecutor, this::onDeviceConfigChange);
-
if (mDevicePostureController != null) {
mDevicePostureController.addCallback(mDevicePostureControllerCallback);
}
@@ -464,31 +404,15 @@
@Override
public void destroy() {
+ Log.d(TAG, "destroy() called");
mController.removeCallback(mControllerCallbackH);
mHandler.removeCallbacksAndMessages(null);
mConfigurationController.removeCallback(this);
- mDeviceConfigProxy.removeOnPropertiesChangedListener(this::onDeviceConfigChange);
if (mDevicePostureController != null) {
mDevicePostureController.removeCallback(mDevicePostureControllerCallback);
}
}
- /**
- * Update ringer mode icon based on the config
- */
- private void onDeviceConfigChange(DeviceConfig.Properties properties) {
- Set<String> changeSet = properties.getKeyset();
- if (changeSet.contains(SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION)) {
- boolean newVal = properties.getBoolean(
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false);
- if (newVal != mSeparateNotification) {
- mSeparateNotification = newVal;
- updateRingerModeIconSet();
- updateRingRowIcon();
- }
- }
- }
-
@Override
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo internalInsetsInfo) {
// Set touchable region insets on the root dialog view. This tells WindowManager that
@@ -542,6 +466,7 @@
}
private void initDialog(int lockTaskModeState) {
+ Log.d(TAG, "initDialog: called!");
mDialog = new CustomDialog(mContext);
initDimens();
@@ -699,7 +624,12 @@
mRingerDrawerNormalIcon = mDialog.findViewById(R.id.volume_drawer_normal_icon);
mRingerDrawerNewSelectionBg = mDialog.findViewById(R.id.volume_drawer_selection_background);
- updateRingerModeIconSet();
+ if (mRingerDrawerMuteIcon != null) {
+ mRingerDrawerMuteIcon.setImageResource(mVolumeRingerMuteIconDrawableId);
+ }
+ if (mRingerDrawerNormalIcon != null) {
+ mRingerDrawerNormalIcon.setImageResource(mVolumeRingerIconDrawableId);
+ }
setupRingerDrawer();
@@ -724,13 +654,10 @@
addRow(AudioManager.STREAM_MUSIC,
R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true, true);
if (!AudioSystem.isSingleVolume(mContext)) {
- if (mSeparateNotification) {
- addRow(AudioManager.STREAM_RING, R.drawable.ic_ring_volume,
- R.drawable.ic_ring_volume_off, true, false);
- } else {
- addRow(AudioManager.STREAM_RING, R.drawable.ic_volume_ringer,
- R.drawable.ic_volume_ringer, true, false);
- }
+
+ addRow(AudioManager.STREAM_RING, R.drawable.ic_ring_volume,
+ R.drawable.ic_ring_volume_off, true, false);
+
addRow(STREAM_ALARM,
R.drawable.ic_alarm, R.drawable.ic_volume_alarm_mute, true, false);
@@ -1344,7 +1271,7 @@
}
protected void tryToRemoveCaptionsTooltip() {
- if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null) {
+ if (mHasSeenODICaptionsTooltip && mODICaptionsTooltipView != null && mDialog != null) {
ViewGroup container = mDialog.findViewById(R.id.volume_dialog_container);
container.removeView(mODICaptionsTooltipView);
mODICaptionsTooltipView = null;
@@ -1551,8 +1478,16 @@
mHandler.removeMessages(H.DISMISS);
mHandler.removeMessages(H.SHOW);
- if (mIsAnimatingDismiss) {
- Log.d(TAG, "dismissH: isAnimatingDismiss");
+
+ boolean showingStateInconsistent = !mShowing && mDialog != null && mDialog.isShowing();
+ // If incorrectly assuming dialog is not showing, continue and make the state consistent.
+ if (showingStateInconsistent) {
+ Log.d(TAG, "dismissH: volume dialog possible in inconsistent state:"
+ + "mShowing=" + mShowing + ", mDialog==null?" + (mDialog == null));
+ }
+ if (mIsAnimatingDismiss && !showingStateInconsistent) {
+ Log.d(TAG, "dismissH: skipping dismiss because isAnimatingDismiss is true"
+ + " and showingStateInconsistent is false");
Trace.endSection();
return;
}
@@ -1570,8 +1505,12 @@
.setDuration(mDialogHideAnimationDurationMs)
.setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
.withEndAction(() -> mHandler.postDelayed(() -> {
- mController.notifyVisible(false);
- mDialog.dismiss();
+ if (mController != null) {
+ mController.notifyVisible(false);
+ }
+ if (mDialog != null) {
+ mDialog.dismiss();
+ }
tryToRemoveCaptionsTooltip();
mIsAnimatingDismiss = false;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index bb04f82..aa4ee54 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -21,7 +21,6 @@
import android.os.Looper;
import com.android.internal.jank.InteractionJankMonitor;
-import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.dialog.MediaOutputDialogFactory;
import com.android.systemui.plugins.ActivityStarter;
@@ -31,7 +30,6 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.volume.CsdWarningDialog;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.volume.VolumeDialogComponent;
@@ -42,8 +40,6 @@
import dagger.Module;
import dagger.Provides;
-import java.util.concurrent.Executor;
-
/** Dagger Module for code in the volume package. */
@Module
public interface VolumeModule {
@@ -63,8 +59,6 @@
VolumePanelFactory volumePanelFactory,
ActivityStarter activityStarter,
InteractionJankMonitor interactionJankMonitor,
- DeviceConfigProxy deviceConfigProxy,
- @Main Executor executor,
CsdWarningDialog.Factory csdFactory,
DevicePostureController devicePostureController,
DumpManager dumpManager) {
@@ -78,8 +72,6 @@
volumePanelFactory,
activityStarter,
interactionJankMonitor,
- deviceConfigProxy,
- executor,
csdFactory,
devicePostureController,
Looper.getMainLooper(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
index 548d26f..78a65a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ResourceTrimmerTest.kt
@@ -98,7 +98,8 @@
)
testScope.runCurrent()
verify(globalWindowManager, times(1))
- .trimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND)
+ .trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
+ verify(globalWindowManager, times(1)).trimCaches(HardwareRenderer.CACHE_TRIM_ALL)
}
@Test
@@ -115,7 +116,8 @@
)
testScope.runCurrent()
verify(globalWindowManager, times(1))
- .trimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND)
+ .trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
+ verify(globalWindowManager, times(1)).trimCaches(HardwareRenderer.CACHE_TRIM_ALL)
}
@Test
@@ -161,7 +163,8 @@
keyguardRepository.setDozeAmount(1f)
testScope.runCurrent()
verify(globalWindowManager, times(1))
- .trimMemory(ComponentCallbacks2.TRIM_MEMORY_BACKGROUND)
+ .trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN)
+ verify(globalWindowManager, times(1)).trimCaches(HardwareRenderer.CACHE_TRIM_ALL)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index 3bcefcf..56698e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -41,7 +41,6 @@
import androidx.media.utils.MediaConstants
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
-import com.android.internal.statusbar.IStatusBarService
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.R
@@ -133,7 +132,6 @@
@Mock lateinit var activityStarter: ActivityStarter
@Mock lateinit var smartspaceManager: SmartspaceManager
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
- @Mock lateinit var statusBarService: IStatusBarService
lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
@@ -197,7 +195,6 @@
logger = logger,
smartspaceManager = smartspaceManager,
keyguardUpdateMonitor = keyguardUpdateMonitor,
- statusBarService = statusBarService,
)
verify(tunerService)
.addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
@@ -522,143 +519,12 @@
}
@Test
- fun testOnNotificationAdded_emptyTitle_isRequired_notLoaded() {
- // When the manager has a notification with an empty title, and the app is required
- // to include a non-empty title
- whenever(mediaFlags.isMediaTitleRequired(any(), any())).thenReturn(true)
- whenever(controller.metadata)
- .thenReturn(
- metadataBuilder
- .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE)
- .build()
- )
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
-
- // Then the media control is not added and we report a notification error
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(statusBarService)
- .onNotificationError(
- eq(PACKAGE_NAME),
- eq(mediaNotification.tag),
- eq(mediaNotification.id),
- eq(mediaNotification.uid),
- eq(mediaNotification.initialPid),
- eq(MEDIA_TITLE_ERROR_MESSAGE),
- eq(mediaNotification.user.identifier)
- )
- verify(listener, never())
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
- verify(logger, never()).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), any())
- verify(logger, never()).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), any())
- }
-
- @Test
- fun testOnNotificationAdded_blankTitle_isRequired_notLoaded() {
- // When the manager has a notification with a blank title, and the app is required
- // to include a non-empty title
- whenever(mediaFlags.isMediaTitleRequired(any(), any())).thenReturn(true)
- whenever(controller.metadata)
- .thenReturn(
- metadataBuilder
- .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE)
- .build()
- )
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
-
- // Then the media control is not added and we report a notification error
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(statusBarService)
- .onNotificationError(
- eq(PACKAGE_NAME),
- eq(mediaNotification.tag),
- eq(mediaNotification.id),
- eq(mediaNotification.uid),
- eq(mediaNotification.initialPid),
- eq(MEDIA_TITLE_ERROR_MESSAGE),
- eq(mediaNotification.user.identifier)
- )
- verify(listener, never())
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
- verify(logger, never()).logResumeMediaAdded(anyInt(), eq(PACKAGE_NAME), any())
- verify(logger, never()).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), any())
- }
-
- @Test
- fun testOnNotificationUpdated_invalidTitle_isRequired_logMediaRemoved() {
- // When the app is required to provide a non-blank title, and updates a previously valid
- // title to an empty one
- whenever(mediaFlags.isMediaTitleRequired(any(), any())).thenReturn(true)
- addNotificationAndLoad()
- val data = mediaDataCaptor.value
-
- verify(listener)
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
-
- reset(listener)
- whenever(controller.metadata)
- .thenReturn(
- metadataBuilder
- .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE)
- .build()
- )
- mediaDataManager.onNotificationAdded(KEY, mediaNotification)
-
- // Then the media control is removed
- assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
- assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(statusBarService)
- .onNotificationError(
- eq(PACKAGE_NAME),
- eq(mediaNotification.tag),
- eq(mediaNotification.id),
- eq(mediaNotification.uid),
- eq(mediaNotification.initialPid),
- eq(MEDIA_TITLE_ERROR_MESSAGE),
- eq(mediaNotification.user.identifier)
- )
- verify(listener, never())
- .onMediaDataLoaded(
- eq(KEY),
- eq(null),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
- verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
- }
-
- @Test
- fun testOnNotificationAdded_emptyTitle_notRequired_hasPlaceholder() {
+ fun testOnNotificationAdded_emptyTitle_hasPlaceholder() {
// When the manager has a notification with an empty title, and the app is not
// required to include a non-empty title
val mockPackageManager = mock(PackageManager::class.java)
context.setMockPackageManager(mockPackageManager)
whenever(mockPackageManager.getApplicationLabel(any())).thenReturn(APP_NAME)
- whenever(mediaFlags.isMediaTitleRequired(any(), any())).thenReturn(false)
whenever(controller.metadata)
.thenReturn(
metadataBuilder
@@ -684,13 +550,12 @@
}
@Test
- fun testOnNotificationAdded_blankTitle_notRequired_hasPlaceholder() {
+ fun testOnNotificationAdded_blankTitle_hasPlaceholder() {
// GIVEN that the manager has a notification with a blank title, and the app is not
// required to include a non-empty title
val mockPackageManager = mock(PackageManager::class.java)
context.setMockPackageManager(mockPackageManager)
whenever(mockPackageManager.getApplicationLabel(any())).thenReturn(APP_NAME)
- whenever(mediaFlags.isMediaTitleRequired(any(), any())).thenReturn(false)
whenever(controller.metadata)
.thenReturn(
metadataBuilder
@@ -722,7 +587,6 @@
val mockPackageManager = mock(PackageManager::class.java)
context.setMockPackageManager(mockPackageManager)
whenever(mockPackageManager.getApplicationLabel(any())).thenReturn(APP_NAME)
- whenever(mediaFlags.isMediaTitleRequired(any(), any())).thenReturn(true)
whenever(controller.metadata)
.thenReturn(
metadataBuilder
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
index 2eca78a..e92368d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/AnimatableClockViewTest.kt
@@ -19,6 +19,7 @@
import android.testing.AndroidTestingRunner
import android.view.LayoutInflater
import androidx.test.filters.SmallTest
+import com.android.app.animation.Interpolators
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.TextAnimator
@@ -64,8 +65,8 @@
color = 200,
strokeWidth = -1F,
animate = false,
- duration = 350L,
- interpolator = null,
+ duration = 833L,
+ interpolator = Interpolators.EMPHASIZED_DECELERATE,
delay = 0L,
onAnimationEnd = null
)
@@ -98,8 +99,8 @@
color = 200,
strokeWidth = -1F,
animate = true,
- duration = 350L,
- interpolator = null,
+ duration = 833L,
+ interpolator = Interpolators.EMPHASIZED_DECELERATE,
delay = 0L,
onAnimationEnd = null
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 551499e..7632d01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -392,23 +392,32 @@
@Test
public void testSnapchild_targetIsZero() {
- doNothing().when(mSwipeHelper).superSnapChild(mView, 0, 0);
- mSwipeHelper.snapChild(mView, 0, 0);
+ doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 0, 0);
+ mSwipeHelper.snapChild(mNotificationRow, 0, 0);
- verify(mCallback, times(1)).onDragCancelled(mView);
- verify(mSwipeHelper, times(1)).superSnapChild(mView, 0, 0);
+ verify(mCallback, times(1)).onDragCancelled(mNotificationRow);
+ verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 0, 0);
verify(mSwipeHelper, times(1)).handleMenuCoveredOrDismissed();
}
@Test
public void testSnapchild_targetNotZero() {
+ doNothing().when(mSwipeHelper).superSnapChild(mNotificationRow, 10, 0);
+ mSwipeHelper.snapChild(mNotificationRow, 10, 0);
+
+ verify(mCallback, times(1)).onDragCancelled(mNotificationRow);
+ verify(mSwipeHelper, times(1)).superSnapChild(mNotificationRow, 10, 0);
+ verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
+ }
+
+ @Test
+ public void testSnapchild_targetNotSwipeable() {
doNothing().when(mSwipeHelper).superSnapChild(mView, 10, 0);
mSwipeHelper.snapChild(mView, 10, 0);
- verify(mCallback, times(1)).onDragCancelled(mView);
- verify(mSwipeHelper, times(1)).superSnapChild(mView, 10, 0);
- verify(mSwipeHelper, times(0)).handleMenuCoveredOrDismissed();
+ verify(mCallback).onDragCancelled(mView);
+ verify(mSwipeHelper, never()).superSnapChild(mView, 10, 0);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 45a37cf..8f725be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -35,7 +35,6 @@
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.SystemClock;
-import android.provider.DeviceConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Gravity;
@@ -47,7 +46,6 @@
import androidx.test.filters.SmallTest;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.Prefs;
import com.android.systemui.R;
@@ -62,9 +60,6 @@
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.FakeConfigurationController;
-import com.android.systemui.util.DeviceConfigProxyFake;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
import org.junit.After;
import org.junit.Before;
@@ -88,8 +83,6 @@
View mDrawerVibrate;
View mDrawerMute;
View mDrawerNormal;
- private DeviceConfigProxyFake mDeviceConfigProxy;
- private FakeExecutor mExecutor;
private TestableLooper mTestableLooper;
private ConfigurationController mConfigurationController;
private int mOriginalOrientation;
@@ -131,8 +124,6 @@
getContext().addMockSystemService(KeyguardManager.class, mKeyguard);
mTestableLooper = TestableLooper.get(this);
- mDeviceConfigProxy = new DeviceConfigProxyFake();
- mExecutor = new FakeExecutor(new FakeSystemClock());
when(mPostureController.getDevicePosture())
.thenReturn(DevicePostureController.DEVICE_POSTURE_CLOSED);
@@ -151,8 +142,6 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
- mDeviceConfigProxy,
- mExecutor,
mCsdWarningDialogFactory,
mPostureController,
mTestableLooper.getLooper(),
@@ -173,9 +162,6 @@
VolumePrefs.SHOW_RINGER_TOAST_COUNT + 1);
Prefs.putBoolean(mContext, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false);
-
- mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false);
}
private State createShellState() {
@@ -351,13 +337,8 @@
* API does not exist. So we do the next best thing; we check the cached icon id.
*/
@Test
- public void notificationVolumeSeparated_theRingerIconChanges() {
- mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "true", false);
-
- mExecutor.runAllReady(); // for the config change to take effect
-
- // assert icon is new based on res id
+ public void notificationVolumeSeparated_theRingerIconChangesToSpeakerIcon() {
+ // already separated. assert icon is new based on res id
assertEquals(mDialog.mVolumeRingerIconDrawableId,
R.drawable.ic_speaker_on);
assertEquals(mDialog.mVolumeRingerMuteIconDrawableId,
@@ -365,17 +346,6 @@
}
@Test
- public void notificationVolumeNotSeparated_theRingerIconRemainsTheSame() {
- mDeviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false);
-
- mExecutor.runAllReady();
-
- assertEquals(mDialog.mVolumeRingerIconDrawableId, R.drawable.ic_volume_ringer);
- assertEquals(mDialog.mVolumeRingerMuteIconDrawableId, R.drawable.ic_volume_ringer_mute);
- }
-
- @Test
public void testDialogDismissAnimation_notifyVisibleIsNotCalledBeforeAnimation() {
mDialog.dismissH(DISMISS_REASON_UNKNOWN);
// notifyVisible(false) should not be called immediately but only after the dismiss
@@ -408,8 +378,6 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
- mDeviceConfigProxy,
- mExecutor,
mCsdWarningDialogFactory,
devicePostureController,
mTestableLooper.getLooper(),
@@ -447,8 +415,6 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
- mDeviceConfigProxy,
- mExecutor,
mCsdWarningDialogFactory,
devicePostureController,
mTestableLooper.getLooper(),
@@ -485,8 +451,6 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
- mDeviceConfigProxy,
- mExecutor,
mCsdWarningDialogFactory,
devicePostureController,
mTestableLooper.getLooper(),
@@ -525,8 +489,6 @@
mVolumePanelFactory,
mActivityStarter,
mInteractionJankMonitor,
- mDeviceConfigProxy,
- mExecutor,
mCsdWarningDialogFactory,
mPostureController,
mTestableLooper.getLooper(),
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 1e5f187..85a0185 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -837,7 +837,7 @@
*/
@GuardedBy("mService")
void enqueueOomAdjTargetLocked(ProcessRecord app) {
- if (app != null) {
+ if (app != null && app.mState.getMaxAdj() > FOREGROUND_APP_ADJ) {
mPendingProcessSet.add(app);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 355981a..d0b6cdc 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -45,7 +45,6 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
@@ -167,7 +166,6 @@
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.System;
import android.service.notification.ZenModeConfig;
@@ -187,10 +185,8 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -252,7 +248,6 @@
AudioSystemAdapter.OnVolRangeInitRequestListener {
private static final String TAG = "AS.AudioService";
- private static final boolean CONFIG_DEFAULT_VAL = false;
private final AudioSystemAdapter mAudioSystem;
private final SystemServerAdapter mSystemServer;
@@ -309,7 +304,7 @@
* indicates whether STREAM_NOTIFICATION is aliased to STREAM_RING
* not final due to test method, see {@link #setNotifAliasRingForTest(boolean)}.
*/
- private boolean mNotifAliasRing;
+ private boolean mNotifAliasRing = false;
/**
* Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING,
@@ -1057,13 +1052,6 @@
mUseVolumeGroupAliases = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_handleVolumeAliasesUsingVolumeGroups);
- mNotifAliasRing = !DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, false);
-
- DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
- ActivityThread.currentApplication().getMainExecutor(),
- this::onDeviceConfigChange);
-
// Initialize volume
// Priority 1 - Android Property
// Priority 2 - Audio Policy Service
@@ -1157,6 +1145,11 @@
MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
}
+ int minAssistantVolume = SystemProperties.getInt("ro.config.assistant_vol_min", -1);
+ if (minAssistantVolume != -1) {
+ MIN_STREAM_VOLUME[AudioSystem.STREAM_ASSISTANT] = minAssistantVolume;
+ }
+
// Read following properties to configure max volume (number of steps) and default volume
// for STREAM_NOTIFICATION and STREAM_RING:
// config_audio_notif_vol_default
@@ -1277,22 +1270,6 @@
}
/**
- * Separating notification volume from ring is NOT of aliasing the corresponding streams
- * @param properties
- */
- private void onDeviceConfigChange(DeviceConfig.Properties properties) {
- Set<String> changeSet = properties.getKeyset();
- if (changeSet.contains(SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION)) {
- boolean newNotifAliasRing = !properties.getBoolean(
- SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, CONFIG_DEFAULT_VAL);
- if (mNotifAliasRing != newNotifAliasRing) {
- mNotifAliasRing = newNotifAliasRing;
- updateStreamVolumeAlias(true, TAG);
- }
- }
- }
-
- /**
* Called by handling of MSG_INIT_STREAMS_VOLUMES
*/
private void onInitStreamsAndVolumes() {
diff --git a/services/core/java/com/android/server/biometrics/TEST_MAPPING b/services/core/java/com/android/server/biometrics/TEST_MAPPING
index daca00b..9e60ba8 100644
--- a/services/core/java/com/android/server/biometrics/TEST_MAPPING
+++ b/services/core/java/com/android/server/biometrics/TEST_MAPPING
@@ -6,24 +6,5 @@
{
"name": "CtsBiometricsHostTestCases"
}
- ],
- "ironwood-postsubmit": [
- {
- "name": "BiometricsE2eTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.IwTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- },
- {
- "include-filter": "android.platform.test.scenario.biometrics"
- },
- {
- "exclude-annotation": "android.platform.test.annotations.FlakyTest"
- }
- ]
- }
- ]
+ ]
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index a486d16..694dfd2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -70,9 +70,11 @@
// Set mStopUserClient to null when StopUserClient fails. Otherwise it's possible
// for that the queue will wait indefinitely until the field is cleared.
- if (clientMonitor instanceof StopUserClient<?> && !success) {
- Slog.w(getTag(),
- "StopUserClient failed(), is the HAL stuck? Clearing mStopUserClient");
+ if (clientMonitor instanceof StopUserClient<?>) {
+ if (!success) {
+ Slog.w(getTag(), "StopUserClient failed(), is the HAL stuck? "
+ + "Clearing mStopUserClient");
+ }
mStopUserClient = null;
}
if (mCurrentOperation != null && mCurrentOperation.isFor(mOwner)) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index ffbf4e1..2ad41c2 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -89,7 +89,7 @@
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@NonNull private final Supplier<AidlSession> mLazySession;
- @Nullable private AidlSession mCurrentSession;
+ @Nullable AidlSession mCurrentSession;
@VisibleForTesting
public static class HalSessionCallback extends ISessionCallback.Stub {
@@ -486,7 +486,7 @@
Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
@NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
- @NonNull BiometricContext biometricContext) {
+ @NonNull BiometricContext biometricContext, AidlSession session) {
mTag = tag;
mProvider = provider;
mContext = context;
@@ -549,6 +549,14 @@
mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
}
+ Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
+ @NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull BiometricContext biometricContext) {
+ this(tag, provider, context, handler, sensorProperties, lockoutResetDispatcher,
+ biometricContext, null);
+ }
+
@NonNull Supplier<AidlSession> getLazySession() {
return mLazySession;
}
@@ -557,7 +565,7 @@
return mSensorProperties;
}
- @Nullable AidlSession getSessionForUser(int userId) {
+ @VisibleForTesting @Nullable AidlSession getSessionForUser(int userId) {
if (mCurrentSession != null && mCurrentSession.getUserId() == userId) {
return mCurrentSession;
} else {
@@ -641,6 +649,8 @@
BiometricsProtoEnums.MODALITY_FACE,
BiometricsProtoEnums.ISSUE_HAL_DEATH,
-1 /* sensorId */);
+ } else if (client != null) {
+ client.cancel();
}
mScheduler.recordCrashState();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
index c0dde72..56b85ce 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java
@@ -90,7 +90,7 @@
@NonNull private final LockoutCache mLockoutCache;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
- @Nullable private AidlSession mCurrentSession;
+ @Nullable AidlSession mCurrentSession;
@NonNull private final Supplier<AidlSession> mLazySession;
@VisibleForTesting
@@ -439,7 +439,7 @@
@NonNull Handler handler, @NonNull FingerprintSensorPropertiesInternal sensorProperties,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
- @NonNull BiometricContext biometricContext) {
+ @NonNull BiometricContext biometricContext, AidlSession session) {
mTag = tag;
mProvider = provider;
mContext = context;
@@ -501,6 +501,16 @@
});
mAuthenticatorIds = new HashMap<>();
mLazySession = () -> mCurrentSession != null ? mCurrentSession : null;
+ mCurrentSession = session;
+ }
+
+ Sensor(@NonNull String tag, @NonNull FingerprintProvider provider, @NonNull Context context,
+ @NonNull Handler handler, @NonNull FingerprintSensorPropertiesInternal sensorProperties,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
+ @NonNull BiometricContext biometricContext) {
+ this(tag, provider, context, handler, sensorProperties, lockoutResetDispatcher,
+ gestureAvailabilityDispatcher, biometricContext, null);
}
@NonNull Supplier<AidlSession> getLazySession() {
@@ -599,6 +609,8 @@
BiometricsProtoEnums.MODALITY_FINGERPRINT,
BiometricsProtoEnums.ISSUE_HAL_DEATH,
-1 /* sensorId */);
+ } else if (client != null) {
+ client.cancel();
}
mScheduler.recordCrashState();
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index e8c65ef..d550650 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -796,6 +796,7 @@
pw.print(", isUserSetBrightness=" + events[i].isUserSetBrightness);
pw.print(", powerBrightnessFactor=" + events[i].powerBrightnessFactor);
pw.print(", isDefaultBrightnessConfig=" + events[i].isDefaultBrightnessConfig);
+ pw.print(", recent lux values=");
pw.print(" {");
for (int j = 0; j < events[i].luxValues.length; ++j){
if (j != 0) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 1674141..41e4671d 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -157,6 +157,7 @@
private static final int REPORTED_TO_POLICY_SCREEN_TURNING_OFF = 3;
private static final int RINGBUFFER_MAX = 100;
+ private static final int RINGBUFFER_RBC_MAX = 20;
private static final float[] BRIGHTNESS_RANGE_BOUNDARIES = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80,
@@ -390,6 +391,10 @@
// Keeps a record of brightness changes for dumpsys.
private RingBuffer<BrightnessEvent> mBrightnessEventRingBuffer;
+ // Keeps a record of rbc changes for dumpsys.
+ private final RingBuffer<BrightnessEvent> mRbcEventRingBuffer =
+ new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_RBC_MAX);
+
// Controls and tracks all the wakelocks that are acquired/released by the system. Also acts as
// a medium of communication between this class and the PowerManagerService.
private final WakelockController mWakelockController;
@@ -1593,6 +1598,10 @@
mTempBrightnessEvent.getReason().getReason() == BrightnessReason.REASON_TEMPORARY
&& mLastBrightnessEvent.getReason().getReason()
== BrightnessReason.REASON_TEMPORARY;
+ // Purely for dumpsys;
+ final boolean isRbcEvent =
+ mLastBrightnessEvent.isRbcEnabled() != mTempBrightnessEvent.isRbcEnabled();
+
if ((!mTempBrightnessEvent.equalsMainData(mLastBrightnessEvent) && !tempToTempTransition)
|| brightnessAdjustmentFlags != 0) {
mTempBrightnessEvent.setInitialBrightness(mLastBrightnessEvent.getBrightness());
@@ -1612,6 +1621,10 @@
if (mBrightnessEventRingBuffer != null) {
mBrightnessEventRingBuffer.append(newEvent);
}
+ if (isRbcEvent) {
+ mRbcEventRingBuffer.append(newEvent);
+ }
+
}
// Update display white-balance.
@@ -2359,6 +2372,8 @@
dumpBrightnessEvents(pw);
}
+ dumpRbcEvents(pw);
+
if (mHbmController != null) {
mHbmController.dump(pw);
}
@@ -2431,6 +2446,20 @@
}
}
+ private void dumpRbcEvents(PrintWriter pw) {
+ int size = mRbcEventRingBuffer.size();
+ if (size < 1) {
+ pw.println("No Reduce Bright Colors Adjustments");
+ return;
+ }
+
+ pw.println("Reduce Bright Colors Adjustments Last " + size + " Events: ");
+ BrightnessEvent[] eventArray = mRbcEventRingBuffer.toArray();
+ for (int i = 0; i < mRbcEventRingBuffer.size(); i++) {
+ pw.println(" " + eventArray[i]);
+ }
+ }
+
private void noteScreenState(int screenState) {
// Log screen state change with display id
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index cede273..be9df4a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -63,10 +63,12 @@
import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioAttributes;
+import android.media.AudioDescriptor;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioDeviceVolumeManager;
import android.media.AudioManager;
+import android.media.AudioProfile;
import android.media.VolumeInfo;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
@@ -4727,9 +4729,22 @@
// reported connection state changes, but even if it did, it won't take effect.
if (mEarcLocalDevice != null) {
mEarcLocalDevice.handleEarcStateChange(status);
+ } else if (status == HDMI_EARC_STATUS_ARC_PENDING) {
+ // If the local device is null we notify the Audio Service that eARC connection
+ // is disabled.
+ notifyEarcStatusToAudioService(false, new ArrayList<>());
+ startArcAction(true, null);
}
}
+ protected void notifyEarcStatusToAudioService(
+ boolean enabled, List<AudioDescriptor> audioDescriptors) {
+ AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_EARC, "", "",
+ new ArrayList<AudioProfile>(), audioDescriptors);
+ getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
+ }
+
@ServiceThreadOnly
void handleEarcCapabilitiesReported(byte[] rawCapabilities, int portId) {
assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java
index 9058c98..873d5fc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java
+++ b/services/core/java/com/android/server/hdmi/HdmiEarcLocalDeviceTx.java
@@ -23,8 +23,6 @@
import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.AudioDescriptor;
-import android.media.AudioDeviceAttributes;
-import android.media.AudioDeviceInfo;
import android.media.AudioProfile;
import android.os.Handler;
import android.util.IndentingPrintWriter;
@@ -88,10 +86,10 @@
mReportCapsHandler.removeCallbacksAndMessages(null);
if (status == HDMI_EARC_STATUS_IDLE) {
- notifyEarcStatusToAudioService(false, new ArrayList<>());
+ mService.notifyEarcStatusToAudioService(false, new ArrayList<>());
mService.startArcAction(false, null);
} else if (status == HDMI_EARC_STATUS_ARC_PENDING) {
- notifyEarcStatusToAudioService(false, new ArrayList<>());
+ mService.notifyEarcStatusToAudioService(false, new ArrayList<>());
mService.startArcAction(true, null);
} else if (status == HDMI_EARC_STATUS_EARC_PENDING
&& oldEarcStatus == HDMI_EARC_STATUS_ARC_PENDING) {
@@ -110,19 +108,11 @@
&& mReportCapsHandler.hasCallbacks(mReportCapsRunnable)) {
mReportCapsHandler.removeCallbacksAndMessages(null);
List<AudioDescriptor> audioDescriptors = parseCapabilities(rawCapabilities);
- notifyEarcStatusToAudioService(true, audioDescriptors);
+ mService.notifyEarcStatusToAudioService(true, audioDescriptors);
}
}
}
- private void notifyEarcStatusToAudioService(
- boolean enabled, List<AudioDescriptor> audioDescriptors) {
- AudioDeviceAttributes attributes = new AudioDeviceAttributes(
- AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_EARC, "", "",
- new ArrayList<AudioProfile>(), audioDescriptors);
- mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
- }
-
/**
* Runnable for waiting for a certain amount of time for the audio system to report its
* capabilities after eARC was connected. If the audio system doesn´t report its capabilities in
@@ -134,7 +124,7 @@
public void run() {
synchronized (mLock) {
if (mEarcStatus == HDMI_EARC_STATUS_EARC_CONNECTED) {
- notifyEarcStatusToAudioService(true, new ArrayList<>());
+ mService.notifyEarcStatusToAudioService(true, new ArrayList<>());
}
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 20f0697..2e62ef4 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -889,22 +889,31 @@
}
- private void migrateOldDataAfterSystemReady() {
- // Migrate the FRP credential to the persistent data block
+ @VisibleForTesting
+ void migrateOldDataAfterSystemReady() {
+ // Write the FRP persistent data block if needed.
+ //
+ // The original purpose of this code was to write the FRP block for the first time, when
+ // upgrading from Android 8.1 or earlier which didn't use the FRP block. This code has
+ // since been repurposed to also fix the "bad" (non-forwards-compatible) FRP block written
+ // by Android 14 Beta 2. For this reason, the database key used here has been renamed from
+ // "migrated_frp" to "migrated_frp2" to cause migrateFrpCredential() to run again on devices
+ // where it had run before.
if (LockPatternUtils.frpCredentialEnabled(mContext)
- && !getBoolean("migrated_frp", false, 0)) {
+ && !getBoolean("migrated_frp2", false, 0)) {
migrateFrpCredential();
- setBoolean("migrated_frp", true, 0);
+ setBoolean("migrated_frp2", true, 0);
}
}
/**
- * Migrate the credential for the FRP credential owner user if the following are satisfied:
- * - the user has a secure credential
- * - the FRP credential is not set up
+ * Write the FRP persistent data block if the following are satisfied:
+ * - the user who owns the FRP credential has a nonempty credential
+ * - the FRP persistent data block doesn't exist or uses the "bad" format from Android 14 Beta 2
*/
private void migrateFrpCredential() {
- if (mStorage.readPersistentDataBlock() != PersistentData.NONE) {
+ PersistentData data = mStorage.readPersistentDataBlock();
+ if (data != PersistentData.NONE && !data.isBadFormatFromAndroid14Beta()) {
return;
}
for (UserInfo userInfo : mUserManager.getUsers()) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 731ecad..2fa637e 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -606,6 +606,11 @@
this.payload = payload;
}
+ public boolean isBadFormatFromAndroid14Beta() {
+ return (this.type == TYPE_SP_GATEKEEPER || this.type == TYPE_SP_WEAVER)
+ && SyntheticPasswordManager.PasswordData.isBadFormatFromAndroid14Beta(this.payload);
+ }
+
public static PersistentData fromBytes(byte[] frpData) {
if (frpData == null || frpData.length == 0) {
return NONE;
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 65e7a00..66f862a 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -370,6 +370,15 @@
return result;
}
+ /**
+ * Returns true if the given serialized PasswordData begins with the value 2 as a short.
+ * This detects the "bad" (non-forwards-compatible) PasswordData format that was temporarily
+ * used during development of Android 14. For more details, see fromBytes() below.
+ */
+ public static boolean isBadFormatFromAndroid14Beta(byte[] data) {
+ return data != null && data.length >= 2 && data[0] == 0 && data[1] == 2;
+ }
+
public static PasswordData fromBytes(byte[] data) {
PasswordData result = new PasswordData();
ByteBuffer buffer = ByteBuffer.allocate(data.length);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9add537..a079875 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -82,6 +82,7 @@
import android.os.IInterface;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -2514,6 +2515,7 @@
* Propagate a wake event to the wallpaper engine(s).
*/
public void notifyWakingUp(int x, int y, @NonNull Bundle extras) {
+ checkCallerIsSystemOrSystemUi();
synchronized (mLock) {
if (mIsLockscreenLiveWallpaperEnabled) {
for (WallpaperData data : getActiveWallpapers()) {
@@ -2551,6 +2553,7 @@
* Propagate a sleep event to the wallpaper engine(s).
*/
public void notifyGoingToSleep(int x, int y, @NonNull Bundle extras) {
+ checkCallerIsSystemOrSystemUi();
synchronized (mLock) {
if (mIsLockscreenLiveWallpaperEnabled) {
for (WallpaperData data : getActiveWallpapers()) {
@@ -3684,6 +3687,14 @@
mActivityManager.getPackageImportance(callingPackage) == IMPORTANCE_FOREGROUND);
}
+ /** Check that the caller is either system_server or systemui */
+ private void checkCallerIsSystemOrSystemUi() {
+ if (Binder.getCallingUid() != Process.myUid() && mContext.checkCallingPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE) != PERMISSION_GRANTED) {
+ throw new SecurityException("Access denied: only system processes can call this");
+ }
+ }
+
/**
* Certain user types do not support wallpapers (e.g. managed profiles). The check is
* implemented through through the OP_WRITE_WALLPAPER AppOp.
diff --git a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
index 5c929a9..bd07622 100644
--- a/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
+++ b/services/core/java/com/android/server/wm/AbsAppSnapshotController.java
@@ -30,6 +30,7 @@
import android.graphics.Rect;
import android.graphics.RenderNode;
import android.hardware.HardwareBuffer;
+import android.os.SystemClock;
import android.os.Trace;
import android.util.Pair;
import android.util.Slog;
@@ -213,6 +214,7 @@
// Failed to acquire image. Has been logged.
return null;
}
+ builder.setCaptureTime(SystemClock.elapsedRealtimeNanos());
builder.setSnapshot(screenshotBuffer.getHardwareBuffer());
builder.setColorSpace(screenshotBuffer.getColorSpace());
return builder.build();
@@ -432,6 +434,7 @@
// color above
return new TaskSnapshot(
System.currentTimeMillis() /* id */,
+ SystemClock.elapsedRealtimeNanos() /* captureTime */,
topActivity.mActivityComponent, hwBitmap.getHardwareBuffer(),
hwBitmap.getColorSpace(), mainWindow.getConfiguration().orientation,
mainWindow.getWindowConfiguration().getRotation(), new Point(taskWidth, taskHeight),
diff --git a/services/core/java/com/android/server/wm/AppSnapshotLoader.java b/services/core/java/com/android/server/wm/AppSnapshotLoader.java
index 88c4752..ed65a2b 100644
--- a/services/core/java/com/android/server/wm/AppSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/AppSnapshotLoader.java
@@ -28,6 +28,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
+import android.os.SystemClock;
import android.util.Slog;
import android.window.TaskSnapshot;
@@ -195,8 +196,9 @@
taskSize = new Point(proto.taskWidth, proto.taskHeight);
}
- return new TaskSnapshot(proto.id, topActivityComponent, buffer,
- hwBitmap.getColorSpace(), proto.orientation, proto.rotation, taskSize,
+ return new TaskSnapshot(proto.id, SystemClock.elapsedRealtimeNanos(),
+ topActivityComponent, buffer, hwBitmap.getColorSpace(),
+ proto.orientation, proto.rotation, taskSize,
new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
new Rect(proto.letterboxInsetLeft, proto.letterboxInsetTop,
proto.letterboxInsetRight, proto.letterboxInsetBottom),
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index d22c38e..123a74d 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -28,11 +28,13 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.util.AtomicFile;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.util.ArrayUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
@@ -56,6 +58,7 @@
public static final int FLAG_HIDE_DISPLAY_SIZE = 0x01;
public static final int FLAG_HIDE_COMPILE_SDK = 0x02;
public static final int FLAG_HIDE_DEPRECATED_SDK = 0x04;
+ public static final int FLAG_HIDE_DEPRECATED_ABI = 0x08;
private final HashMap<String, Integer> mPackageFlags = new HashMap<>();
@@ -68,6 +71,7 @@
private UnsupportedDisplaySizeDialog mUnsupportedDisplaySizeDialog;
private UnsupportedCompileSdkDialog mUnsupportedCompileSdkDialog;
private DeprecatedTargetSdkVersionDialog mDeprecatedTargetSdkVersionDialog;
+ private DeprecatedAbiDialog mDeprecatedAbiDialog;
/** @see android.app.ActivityManager#alwaysShowUnsupportedCompileSdkWarning */
private HashSet<ComponentName> mAlwaysShowUnsupportedCompileSdkWarningActivities =
@@ -166,6 +170,31 @@
}
/**
+ * Shows the "deprecated abi" warning, if necessary. This can only happen is the device
+ * supports both 64-bit and 32-bit ABIs, and the app only contains 32-bit libraries. The app
+ * cannot be installed if the device only supports 64-bit ABI while the app contains only 32-bit
+ * libraries.
+ *
+ * @param r activity record for which the warning may be displayed
+ */
+ public void showDeprecatedAbiDialogIfNeeded(ActivityRecord r) {
+ final boolean disableDeprecatedAbiDialog = SystemProperties.getBoolean(
+ "debug.wm.disable_deprecated_abi_dialog", false);
+ if (disableDeprecatedAbiDialog) {
+ return;
+ }
+ final String appPrimaryAbi = r.info.applicationInfo.primaryCpuAbi;
+ final String appSecondaryAbi = r.info.applicationInfo.secondaryCpuAbi;
+ final boolean appContainsOnly32bitLibraries =
+ (appPrimaryAbi != null && appSecondaryAbi == null && !appPrimaryAbi.contains("64"));
+ final boolean is64BitDevice =
+ ArrayUtils.find(Build.SUPPORTED_ABIS, abi -> abi.contains("64")) != null;
+ if (is64BitDevice && appContainsOnly32bitLibraries) {
+ mUiHandler.showDeprecatedAbiDialog(r);
+ }
+ }
+
+ /**
* Called when an activity is being started.
*
* @param r record for the activity being started
@@ -174,6 +203,7 @@
showUnsupportedCompileSdkDialogIfNeeded(r);
showUnsupportedDisplaySizeDialogIfNeeded(r);
showDeprecatedTargetDialogIfNeeded(r);
+ showDeprecatedAbiDialogIfNeeded(r);
}
/**
@@ -299,6 +329,27 @@
}
/**
+ * Shows the "deprecated abi" warning for the given application.
+ * <p>
+ * <strong>Note:</strong> Must be called on the UI thread.
+ *
+ * @param ar record for the activity that triggered the warning
+ */
+ @UiThread
+ private void showDeprecatedAbiDialogUiThread(ActivityRecord ar) {
+ if (mDeprecatedAbiDialog != null) {
+ mDeprecatedAbiDialog.dismiss();
+ mDeprecatedAbiDialog = null;
+ }
+ if (ar != null && !hasPackageFlag(
+ ar.packageName, FLAG_HIDE_DEPRECATED_ABI)) {
+ mDeprecatedAbiDialog = new DeprecatedAbiDialog(
+ AppWarnings.this, mUiContext, ar.info.applicationInfo);
+ mDeprecatedAbiDialog.show();
+ }
+ }
+
+ /**
* Dismisses all warnings for the given package.
* <p>
* <strong>Note:</strong> Must be called on the UI thread.
@@ -328,6 +379,13 @@
mDeprecatedTargetSdkVersionDialog.dismiss();
mDeprecatedTargetSdkVersionDialog = null;
}
+
+ // Hides the "deprecated abi" dialog if necessary.
+ if (mDeprecatedAbiDialog != null && (name == null || name.equals(
+ mDeprecatedAbiDialog.mPackageName))) {
+ mDeprecatedAbiDialog.dismiss();
+ mDeprecatedAbiDialog = null;
+ }
}
/**
@@ -381,6 +439,7 @@
private static final int MSG_SHOW_UNSUPPORTED_COMPILE_SDK_DIALOG = 3;
private static final int MSG_HIDE_DIALOGS_FOR_PACKAGE = 4;
private static final int MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG = 5;
+ private static final int MSG_SHOW_DEPRECATED_ABI_DIALOG = 6;
public UiHandler(Looper looper) {
super(looper, null, true);
@@ -408,6 +467,10 @@
final ActivityRecord ar = (ActivityRecord) msg.obj;
showDeprecatedTargetSdkDialogUiThread(ar);
} break;
+ case MSG_SHOW_DEPRECATED_ABI_DIALOG: {
+ final ActivityRecord ar = (ActivityRecord) msg.obj;
+ showDeprecatedAbiDialogUiThread(ar);
+ } break;
}
}
@@ -431,6 +494,11 @@
obtainMessage(MSG_SHOW_DEPRECATED_TARGET_SDK_DIALOG, r).sendToTarget();
}
+ public void showDeprecatedAbiDialog(ActivityRecord r) {
+ removeMessages(MSG_SHOW_DEPRECATED_ABI_DIALOG);
+ obtainMessage(MSG_SHOW_DEPRECATED_ABI_DIALOG, r).sendToTarget();
+ }
+
public void hideDialogsForPackage(String name) {
obtainMessage(MSG_HIDE_DIALOGS_FOR_PACKAGE, name).sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/DeprecatedAbiDialog.java b/services/core/java/com/android/server/wm/DeprecatedAbiDialog.java
new file mode 100644
index 0000000..e96208d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DeprecatedAbiDialog.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 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.server.wm;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+
+class DeprecatedAbiDialog extends AppWarnings.BaseDialog {
+ DeprecatedAbiDialog(final AppWarnings manager, Context context,
+ ApplicationInfo appInfo) {
+ super(manager, appInfo.packageName);
+
+ final PackageManager pm = context.getPackageManager();
+ final CharSequence label = appInfo.loadSafeLabel(pm,
+ PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
+ PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE
+ | PackageItemInfo.SAFE_LABEL_FLAG_TRIM);
+ final CharSequence message = context.getString(R.string.deprecated_abi_message);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context)
+ .setPositiveButton(R.string.ok, (dialog, which) ->
+ manager.setPackageFlag(
+ mPackageName, AppWarnings.FLAG_HIDE_DEPRECATED_ABI, true))
+ .setMessage(message)
+ .setTitle(label);
+
+ // Ensure the content view is prepared.
+ mDialog = builder.create();
+ mDialog.create();
+
+ final Window window = mDialog.getWindow();
+ window.setType(WindowManager.LayoutParams.TYPE_PHONE);
+
+ // DO NOT MODIFY. Used by CTS to verify the dialog is displayed.
+ window.getAttributes().setTitle("DeprecatedAbiDialog");
+ }
+}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 7e20b3b..c747c09 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -180,6 +180,18 @@
}
/**
+ * Returns the elapsed real time (in nanoseconds) at which a snapshot for the given task was
+ * last taken, or -1 if no such snapshot exists for that task.
+ */
+ long getSnapshotCaptureTime(int taskId) {
+ final TaskSnapshot snapshot = mCache.getSnapshot(taskId);
+ if (snapshot != null) {
+ return snapshot.getCaptureTime();
+ }
+ return -1;
+ }
+
+ /**
* @see WindowManagerInternal#clearSnapshotCache
*/
public void clearSnapshotCache() {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index c763cfa..663db86 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -382,11 +382,7 @@
// Add FLAG_ABOVE_TRANSIENT_LAUNCH to the tree of transient-hide tasks,
// so ChangeInfo#hasChanged() can return true to report the transition info.
for (int i = mChanges.size() - 1; i >= 0; --i) {
- final WindowContainer<?> wc = mChanges.keyAt(i);
- if (wc.asTaskFragment() == null && wc.asActivityRecord() == null) continue;
- if (isInTransientHide(wc)) {
- mChanges.valueAt(i).mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH;
- }
+ updateTransientFlags(mChanges.valueAt(i));
}
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Transition %d: Set %s as "
@@ -581,7 +577,9 @@
for (WindowContainer<?> curr = getAnimatableParent(wc);
curr != null && !mChanges.containsKey(curr);
curr = getAnimatableParent(curr)) {
- mChanges.put(curr, new ChangeInfo(curr));
+ final ChangeInfo info = new ChangeInfo(curr);
+ updateTransientFlags(info);
+ mChanges.put(curr, info);
if (isReadyGroup(curr)) {
mReadyTracker.addGroup(curr);
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, " Creating Ready-group for"
@@ -600,6 +598,7 @@
ChangeInfo info = mChanges.get(wc);
if (info == null) {
info = new ChangeInfo(wc);
+ updateTransientFlags(info);
mChanges.put(wc, info);
}
mParticipants.add(wc);
@@ -615,6 +614,14 @@
}
}
+ private void updateTransientFlags(@NonNull ChangeInfo info) {
+ final WindowContainer<?> wc = info.mContainer;
+ // Only look at tasks, taskfragments, or activities
+ if (wc.asTaskFragment() == null && wc.asActivityRecord() == null) return;
+ if (!isInTransientHide(wc)) return;
+ info.mFlags |= ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH;
+ }
+
private void recordDisplay(DisplayContent dc) {
if (dc == null || mTargetDisplays.contains(dc)) return;
mTargetDisplays.add(dc);
@@ -1079,12 +1086,23 @@
if (commitVisibility) {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
" Commit activity becoming invisible: %s", ar);
+ final SnapshotController snapController = mController.mSnapshotController;
if (mTransientLaunches != null && !task.isVisibleRequested()) {
+ final long startTimeNs = mLogger.mSendTimeNs;
+ final long lastSnapshotTimeNs = snapController.mTaskSnapshotController
+ .getSnapshotCaptureTime(task.mTaskId);
// If transition is transient, then snapshots are taken at end of
- // transition.
- mController.mSnapshotController.mTaskSnapshotController
- .recordSnapshot(task, false /* allowSnapshotHome */);
- mController.mSnapshotController.mActivitySnapshotController
+ // transition only if a snapshot was not already captured by request
+ // during the transition
+ if (lastSnapshotTimeNs < startTimeNs) {
+ snapController.mTaskSnapshotController
+ .recordSnapshot(task, false /* allowSnapshotHome */);
+ } else {
+ ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+ " Skipping post-transition snapshot for task %d",
+ task.mTaskId);
+ }
+ snapController.mActivitySnapshotController
.notifyAppVisibilityChanged(ar, false /* visible */);
}
ar.commitVisibility(false /* visible */, false /* performLayout */,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index 25bd9bc..be9f52e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -17,12 +17,14 @@
package com.android.server.biometrics.sensors.face.aidl;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -41,6 +43,7 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -82,6 +85,10 @@
private AuthSessionCoordinator mAuthSessionCoordinator;
@Mock
FaceProvider mFaceProvider;
+ @Mock
+ BaseClientMonitor mClientMonitor;
+ @Mock
+ AidlSession mCurrentSession;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
@@ -161,6 +168,39 @@
assertNull(sensor.getSessionForUser(USER_ID));
}
+ @Test
+ public void onBinderDied_cancelNonInterruptableClient() {
+ mLooper.dispatchAll();
+
+ when(mCurrentSession.getUserId()).thenReturn(USER_ID);
+ when(mClientMonitor.getTargetUserId()).thenReturn(USER_ID);
+ when(mClientMonitor.isInterruptable()).thenReturn(false);
+
+ final SensorProps sensorProps = new SensorProps();
+ sensorProps.commonProps = new CommonProps();
+ sensorProps.commonProps.sensorId = 1;
+ final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
+ sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
+ sensorProps.commonProps.maxEnrollmentsPerUser, null,
+ sensorProps.sensorType, sensorProps.supportsDetectInteraction,
+ sensorProps.halControlsPreview, false /* resetLockoutRequiresChallenge */);
+ final Sensor sensor = new Sensor("SensorTest", mFaceProvider, mContext, null,
+ internalProp, mLockoutResetDispatcher, mBiometricContext, mCurrentSession);
+ mScheduler = (UserAwareBiometricScheduler) sensor.getScheduler();
+ sensor.mCurrentSession = new AidlSession(0, mock(ISession.class),
+ USER_ID, mHalCallback);
+
+ mScheduler.scheduleClientMonitor(mClientMonitor);
+
+ assertNotNull(mScheduler.getCurrentClient());
+
+ sensor.onBinderDied();
+
+ verify(mClientMonitor).cancel();
+ assertNull(sensor.getSessionForUser(USER_ID));
+ assertNull(mScheduler.getCurrentClient());
+ }
+
private void verifyNotLocked() {
assertEquals(LockoutTracker.LOCKOUT_NONE, mLockoutCache.getLockoutModeForUser(USER_ID));
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
index 0c13466..15d7601 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
@@ -17,17 +17,23 @@
package com.android.server.biometrics.sensors.fingerprint.aidl;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.biometrics.IBiometricService;
+import android.hardware.biometrics.common.CommonProps;
+import android.hardware.biometrics.face.SensorProps;
import android.hardware.biometrics.fingerprint.ISession;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
@@ -37,11 +43,13 @@
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.AuthSessionCoordinator;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.LockoutTracker;
import com.android.server.biometrics.sensors.UserAwareBiometricScheduler;
+import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import org.junit.Before;
import org.junit.Test;
@@ -76,6 +84,14 @@
private BiometricContext mBiometricContext;
@Mock
private AuthSessionCoordinator mAuthSessionCoordinator;
+ @Mock
+ FingerprintProvider mFingerprintProvider;
+ @Mock
+ GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
+ @Mock
+ private AidlSession mCurrentSession;
+ @Mock
+ private BaseClientMonitor mClientMonitor;
private final TestLooper mLooper = new TestLooper();
private final LockoutCache mLockoutCache = new LockoutCache();
@@ -130,6 +146,40 @@
verifyNotLocked();
}
+ @Test
+ public void onBinderDied_cancelNonInterruptableClient() {
+ mLooper.dispatchAll();
+
+ when(mCurrentSession.getUserId()).thenReturn(USER_ID);
+ when(mClientMonitor.getTargetUserId()).thenReturn(USER_ID);
+ when(mClientMonitor.isInterruptable()).thenReturn(false);
+
+ final SensorProps sensorProps = new SensorProps();
+ sensorProps.commonProps = new CommonProps();
+ sensorProps.commonProps.sensorId = 1;
+ final FingerprintSensorPropertiesInternal internalProp = new
+ FingerprintSensorPropertiesInternal(
+ sensorProps.commonProps.sensorId, sensorProps.commonProps.sensorStrength,
+ sensorProps.commonProps.maxEnrollmentsPerUser, null,
+ sensorProps.sensorType, false /* resetLockoutRequiresHardwareAuthToken */);
+ final Sensor sensor = new Sensor("SensorTest", mFingerprintProvider, mContext,
+ null /* handler */, internalProp, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher, mBiometricContext, mCurrentSession);
+ mScheduler = (UserAwareBiometricScheduler) sensor.getScheduler();
+ sensor.mCurrentSession = new AidlSession(0, mock(ISession.class),
+ USER_ID, mHalCallback);
+
+ mScheduler.scheduleClientMonitor(mClientMonitor);
+
+ assertNotNull(mScheduler.getCurrentClient());
+
+ sensor.onBinderDied();
+
+ verify(mClientMonitor).cancel();
+ assertNull(sensor.getSessionForUser(USER_ID));
+ assertNull(mScheduler.getCurrentClient());
+ }
+
private void verifyNotLocked() {
assertEquals(LockoutTracker.LOCKOUT_NONE, mLockoutCache.getLockoutModeForUser(USER_ID));
verify(mLockoutResetDispatcher).notifyLockoutResetCallbacks(eq(SENSOR_ID));
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 0e6b412..39930bc 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -92,6 +92,7 @@
private ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();
private HdmiPortInfo[] mHdmiPortInfo;
private ArrayList<Integer> mLocalDeviceTypes = new ArrayList<>();
+ private static final int PORT_ID_EARC_SUPPORTED = 3;
@Before
public void setUp() throws Exception {
@@ -148,7 +149,7 @@
.setEarcSupported(false)
.build();
mHdmiPortInfo[2] =
- new HdmiPortInfo.Builder(3, HdmiPortInfo.PORT_INPUT, 0x2000)
+ new HdmiPortInfo.Builder(PORT_ID_EARC_SUPPORTED, HdmiPortInfo.PORT_INPUT, 0x2000)
.setCecSupported(true)
.setMhlSupported(false)
.setArcSupported(true)
@@ -1129,6 +1130,23 @@
}
@Test
+ public void disableEarc_noEarcLocalDevice_enableArc() {
+ mHdmiControlServiceSpy.clearEarcLocalDevice();
+ mHdmiControlServiceSpy.addEarcLocalDevice(
+ new HdmiEarcLocalDeviceTx(mHdmiControlServiceSpy));
+ mHdmiControlServiceSpy.setEarcEnabled(HdmiControlManager.EARC_FEATURE_DISABLED);
+ mTestLooper.dispatchAll();
+ assertThat(mHdmiControlServiceSpy.getEarcLocalDevice()).isNull();
+
+ Mockito.clearInvocations(mHdmiControlServiceSpy);
+ mHdmiControlServiceSpy.handleEarcStateChange(Constants.HDMI_EARC_STATUS_ARC_PENDING,
+ PORT_ID_EARC_SUPPORTED);
+ verify(mHdmiControlServiceSpy, times(1))
+ .notifyEarcStatusToAudioService(eq(false), eq(new ArrayList<>()));
+ verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(true), any());
+ }
+
+ @Test
public void disableCec_doNotClearEarcLocalDevice() {
mHdmiControlServiceSpy.clearEarcLocalDevice();
mHdmiControlServiceSpy.addEarcLocalDevice(
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
index 2b49b8a..a242cde 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
@@ -23,6 +23,8 @@
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManager;
@@ -38,8 +40,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.nio.ByteBuffer;
-/** Test setting a lockscreen credential and then verify it under USER_FRP */
+/** Tests that involve the Factory Reset Protection (FRP) credential. */
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -148,4 +151,68 @@
mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */)
.getResponseCode());
}
+
+ // The FRP block that gets written by the current version of Android must still be accepted by
+ // old versions of Android. This test tries to detect non-forward-compatible changes in
+ // PasswordData#toBytes(), which would break that.
+ @Test
+ public void testFrpBlock_isForwardsCompatible() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ PersistentData data = mStorage.readPersistentDataBlock();
+ ByteBuffer buffer = ByteBuffer.wrap(data.payload);
+
+ final int credentialType = buffer.getInt();
+ assertEquals(CREDENTIAL_TYPE_PIN, credentialType);
+
+ final byte scryptLogN = buffer.get();
+ assertTrue(scryptLogN >= 0);
+
+ final byte scryptLogR = buffer.get();
+ assertTrue(scryptLogR >= 0);
+
+ final byte scryptLogP = buffer.get();
+ assertTrue(scryptLogP >= 0);
+
+ final int saltLength = buffer.getInt();
+ assertTrue(saltLength > 0);
+ final byte[] salt = new byte[saltLength];
+ buffer.get(salt);
+
+ final int passwordHandleLength = buffer.getInt();
+ assertTrue(passwordHandleLength > 0);
+ final byte[] passwordHandle = new byte[passwordHandleLength];
+ buffer.get(passwordHandle);
+ }
+
+ @Test
+ public void testFrpBlock_inBadAndroid14FormatIsAutomaticallyFixed() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+
+ // Write a "bad" FRP block with PasswordData beginning with the bytes [0, 2].
+ byte[] badPasswordData = new byte[] {
+ 0, 2, /* version 2 */
+ 0, 3, /* CREDENTIAL_TYPE_PIN */
+ 11, /* scryptLogN */
+ 22, /* scryptLogR */
+ 33, /* scryptLogP */
+ 0, 0, 0, 5, /* salt.length */
+ 1, 2, -1, -2, 55, /* salt */
+ 0, 0, 0, 6, /* passwordHandle.length */
+ 2, 3, -2, -3, 44, 1, /* passwordHandle */
+ 0, 0, 0, 6, /* pinLength */
+ };
+ mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_GATEKEEPER, PRIMARY_USER_ID, 0,
+ badPasswordData);
+
+ // Execute the code that should fix the FRP block.
+ assertFalse(mStorage.getBoolean("migrated_frp2", false, 0));
+ mService.migrateOldDataAfterSystemReady();
+ assertTrue(mStorage.getBoolean("migrated_frp2", false, 0));
+
+ // Verify that the FRP block has been fixed.
+ PersistentData data = mStorage.readPersistentDataBlock();
+ assertEquals(PersistentData.TYPE_SP_GATEKEEPER, data.type);
+ ByteBuffer buffer = ByteBuffer.wrap(data.payload);
+ assertEquals(CREDENTIAL_TYPE_PIN, buffer.getInt());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 067feae..ce0347d 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -638,6 +638,7 @@
2, 3, -2, -3, 44, 1, /* passwordHandle */
0, 0, 0, 6, /* pinLength */
};
+ assertFalse(PasswordData.isBadFormatFromAndroid14Beta(serialized));
PasswordData deserialized = PasswordData.fromBytes(serialized);
assertEquals(11, deserialized.scryptLogN);
@@ -690,6 +691,7 @@
2, 3, -2, -3, 44, 1, /* passwordHandle */
0, 0, 0, 6, /* pinLength */
};
+ assertTrue(PasswordData.isBadFormatFromAndroid14Beta(serialized));
PasswordData deserialized = PasswordData.fromBytes(serialized);
assertEquals(11, deserialized.scryptLogN);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index 27677e1..0e627b2 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -88,7 +88,6 @@
private static final Multimap<Class<?>, String> KNOWN_BAD =
ImmutableMultimap.<Class<?>, String>builder()
.put(Notification.Builder.class, "setPublicVersion") // b/276294099
- .putAll(RemoteViews.class, "addView", "addStableView") // b/277740082
.put(RemoteViews.class, "setIcon") // b/281018094
.put(Notification.WearableExtender.class, "addAction") // TODO: b/281044385
.put(Person.Builder.class, "setUri") // TODO: b/281044385
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 10f4158..0ccb0d0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -1286,7 +1286,7 @@
doReturn(bufferSize.x).when(buffer).getWidth();
doReturn(bufferSize.y).when(buffer).getHeight();
}
- return new TaskSnapshot(1, new ComponentName("", ""), buffer,
+ return new TaskSnapshot(1, 0 /* captureTime */, new ComponentName("", ""), buffer,
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
Surface.ROTATION_0, taskSize, new Rect() /* contentInsets */,
new Rect() /* letterboxInsets*/, false /* isLowResolution */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index b69874a..84c0696 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -218,7 +218,7 @@
Canvas c = buffer.lockCanvas();
c.drawColor(Color.RED);
buffer.unlockCanvasAndPost(c);
- return new TaskSnapshot(MOCK_SNAPSHOT_ID, mTopActivityComponent,
+ return new TaskSnapshot(MOCK_SNAPSHOT_ID, 0 /* captureTime */, mTopActivityComponent,
HardwareBuffer.createFromGraphicBuffer(buffer),
ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
mRotation, taskSize, TEST_CONTENT_INSETS, TEST_LETTERBOX_INSETS,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/TEST_MAPPING b/tests/FlickerTests/src/com/android/server/wm/flicker/TEST_MAPPING
deleted file mode 100644
index 945de33..0000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "ironwood-postsubmit": [
- {
- "name": "FlickerTests",
- "options": [
- {
- "include-annotation": "android.platform.test.annotations.IwTest"
- },
- {
- "exclude-annotation": "org.junit.Ignore"
- }
- ]
- }
- ]
-}
\ No newline at end of file