From 92170abdea4ce95cb236471750ca166125dbb617 Mon Sep 17 00:00:00 2001 From: Matt Casey Date: Thu, 22 Aug 2024 14:39:51 +0000 Subject: [PATCH 001/466] Remove FLAG_ENABLE_CHOOSER_RESULT Launched in V. Bug: 263474465 Test: atest IntentTest Flag: EXEMPT flag removal Change-Id: Ibeaff8f6b323de17a7f2b7bb16ae22853a4513e7 --- core/api/current.txt | 6 +++--- core/api/test-current.txt | 2 +- core/java/android/content/Intent.java | 8 +------- core/java/android/service/chooser/ChooserResult.java | 2 -- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index c1366a155aed..16012284906e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -11390,8 +11390,8 @@ package android.content { field @FlaggedApi("android.service.chooser.chooser_payload_toggling") public static final String EXTRA_CHOOSER_FOCUSED_ITEM_POSITION = "android.intent.extra.CHOOSER_FOCUSED_ITEM_POSITION"; field public static final String EXTRA_CHOOSER_MODIFY_SHARE_ACTION = "android.intent.extra.CHOOSER_MODIFY_SHARE_ACTION"; field public static final String EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER = "android.intent.extra.CHOOSER_REFINEMENT_INTENT_SENDER"; - field @FlaggedApi("android.service.chooser.enable_chooser_result") public static final String EXTRA_CHOOSER_RESULT = "android.intent.extra.CHOOSER_RESULT"; - field @FlaggedApi("android.service.chooser.enable_chooser_result") public static final String EXTRA_CHOOSER_RESULT_INTENT_SENDER = "android.intent.extra.CHOOSER_RESULT_INTENT_SENDER"; + field public static final String EXTRA_CHOOSER_RESULT = "android.intent.extra.CHOOSER_RESULT"; + field public static final String EXTRA_CHOOSER_RESULT_INTENT_SENDER = "android.intent.extra.CHOOSER_RESULT_INTENT_SENDER"; field public static final String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS"; field public static final String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT"; field public static final String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER"; @@ -40542,7 +40542,7 @@ package android.service.chooser { method @NonNull public android.service.chooser.ChooserAction build(); } - @FlaggedApi("android.service.chooser.enable_chooser_result") public final class ChooserResult implements android.os.Parcelable { + public final class ChooserResult implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.content.ComponentName getSelectedComponent(); method public int getType(); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 177b859da0ad..3337cea83fc1 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -3123,7 +3123,7 @@ package android.service.autofill.augmented { package android.service.chooser { - @FlaggedApi("android.service.chooser.enable_chooser_result") public final class ChooserResult implements android.os.Parcelable { + public final class ChooserResult implements android.os.Parcelable { ctor public ChooserResult(int, @Nullable android.content.ComponentName, boolean); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index cb57c7bd565d..b7d94769c3eb 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1062,11 +1062,7 @@ public class Intent implements Parcelable, Cloneable { } if (sender != null) { - if (android.service.chooser.Flags.enableChooserResult()) { - intent.putExtra(EXTRA_CHOOSER_RESULT_INTENT_SENDER, sender); - } else { - intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender); - } + intent.putExtra(EXTRA_CHOOSER_RESULT_INTENT_SENDER, sender); } // Migrate any clip data and flags from target. @@ -6415,7 +6411,6 @@ public class Intent implements Parcelable, Cloneable { * activity. The IntentSender will have the extra {@link #EXTRA_CHOOSER_RESULT} describing * the result. */ - @FlaggedApi(android.service.chooser.Flags.FLAG_ENABLE_CHOOSER_RESULT) public static final String EXTRA_CHOOSER_RESULT_INTENT_SENDER = "android.intent.extra.CHOOSER_RESULT_INTENT_SENDER"; @@ -6425,7 +6420,6 @@ public class Intent implements Parcelable, Cloneable { * An instance is supplied to the optional IntentSender provided to * {@link #createChooser(Intent, CharSequence, IntentSender)} when the session completes. */ - @FlaggedApi(android.service.chooser.Flags.FLAG_ENABLE_CHOOSER_RESULT) public static final String EXTRA_CHOOSER_RESULT = "android.intent.extra.CHOOSER_RESULT"; /** diff --git a/core/java/android/service/chooser/ChooserResult.java b/core/java/android/service/chooser/ChooserResult.java index 2d56ec730836..9e6c4ff5d24e 100644 --- a/core/java/android/service/chooser/ChooserResult.java +++ b/core/java/android/service/chooser/ChooserResult.java @@ -16,7 +16,6 @@ package android.service.chooser; -import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -41,7 +40,6 @@ import java.util.Objects; * * @see Intent#EXTRA_CHOOSER_RESULT_INTENT_SENDER */ -@FlaggedApi(android.service.chooser.Flags.FLAG_ENABLE_CHOOSER_RESULT) public final class ChooserResult implements Parcelable { /** -- GitLab From 972848bab11bd5814f876c0d62b2a1ebb04720b9 Mon Sep 17 00:00:00 2001 From: Jared Herdlevar Date: Thu, 22 Aug 2024 23:29:38 +0000 Subject: [PATCH 002/466] If the FINE_LOCATION permission is granted to voice search on wear, and it is not user set, revoke it in the DefaultPermissionGrantPolicy Bug: 226204212 Flag: NONE request from legal to match assistant on the phone Change-Id: I7c4029aa1e4e51d0482241ea7d5ea3e46bead388 --- .../pm/permission/DefaultPermissionGrantPolicy.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 6c78b3c85e18..371b70bdbaed 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -884,10 +884,13 @@ final class DefaultPermissionGrantPolicy { } // Allow voice search on wear - grantPermissionsToSystemPackage(pm, - getDefaultSystemHandlerActivityPackage(pm, - SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId), - userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS); + String voiceSearchPackage = getDefaultSystemHandlerActivityPackage(pm, + SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId); + grantPermissionsToSystemPackage(pm, voiceSearchPackage, + userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS, + COARSE_BACKGROUND_LOCATION_PERMISSIONS); + revokeRuntimePermissions(pm, voiceSearchPackage, + FINE_LOCATION_PERMISSIONS, false, userId); } // Print Spooler -- GitLab From 255ee52dd9254ba8bbe68bef0c1182aae91dbf41 Mon Sep 17 00:00:00 2001 From: "Penghui.Liu" Date: Mon, 26 Aug 2024 20:43:49 +0800 Subject: [PATCH 003/466] HWUI: Make releaseQueueOwnership thread-safety We encountered a Skia Resource Cache SIGTRAP NE Issue, caused by deleting DeferredLayerUpdater on the wrong thread, FinalizerDaemon. Make AutoBackendTextureRelease::releaseQueueOwnership thread-safety. Avoid multi-thread access to the Skia Resource Cache. Bug: Test:Manual 1.Install and Launch APK 2.Run Monkey Test adb shell monkey -v -p com.ss.android.article.news --throttle 3000 99999 Change-Id: Icb5098e9460ce4be799db8575d9916a9910d61a1 --- libs/hwui/AutoBackendTextureRelease.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp index 5f5ffe97e953..86fede5eb98c 100644 --- a/libs/hwui/AutoBackendTextureRelease.cpp +++ b/libs/hwui/AutoBackendTextureRelease.cpp @@ -140,6 +140,13 @@ void AutoBackendTextureRelease::releaseQueueOwnership(GrDirectContext* context) return; } + if (!RenderThread::isCurrent()) { + // releaseQueueOwnership needs to run on RenderThread to prevent multithread calling + // setBackendTextureState will operate skia resource cache which need single owner + RenderThread::getInstance().queue().post([this, context]() { releaseQueueOwnership(context); }); + return; + } + LOG_ALWAYS_FATAL_IF(Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan); if (mBackendTexture.isValid()) { // Passing in VK_IMAGE_LAYOUT_UNDEFINED means we keep the old layout. -- GitLab From a79e9e542a1d071efa9b453247358834d3104222 Mon Sep 17 00:00:00 2001 From: Miranda Kephart Date: Fri, 16 Feb 2024 10:14:15 -0500 Subject: [PATCH 004/466] Block clipboard UI when device is locked In some situations (see bug for details) it's possible to enter the clipboard even while the device is locked, and from there access the provided intents. Users should not be able to access intents from this state; this change adds an additional check before showing the interactive UI. The behavior is identical to what we do when user setup is not complete (b/251778420): we show a toast to note that content has been copied, but no interactive UI. Interactive UI is only blocked when device is locked (i.e. requiring pin entry/password/biometric/etc), not if the keyguard is up but trivially dismissable. Bug: 317048495 Test: atest ClipboardListenerTest; verification using steps in linked bug as well as forcing text content to appear client-side, to verify that even if text content is received in the ClipboardListener, no interactive UI appears. Change-Id: I1a48cbe64852dce3fba69915ca11dad8878f66eb Merged-In: I1a48cbe64852dce3fba69915ca11dad8878f66eb (cherry picked from commit 2976ca86d5c5be558191a1fe706d4cd0d7ccdecb) --- .../clipboardoverlay/ClipboardListener.java | 8 +++++++- .../ClipboardListenerTest.java | 18 +++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java index 63b4288ce055..f0a980e0a30c 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java @@ -24,6 +24,7 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE; +import android.app.KeyguardManager; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -57,6 +58,7 @@ public class ClipboardListener implements private final Provider mOverlayProvider; private final ClipboardToast mClipboardToast; private final ClipboardManager mClipboardManager; + private final KeyguardManager mKeyguardManager; private final UiEventLogger mUiEventLogger; private ClipboardOverlay mClipboardOverlay; @@ -65,11 +67,13 @@ public class ClipboardListener implements Provider clipboardOverlayControllerProvider, ClipboardToast clipboardToast, ClipboardManager clipboardManager, + KeyguardManager keyguardManager, UiEventLogger uiEventLogger) { mContext = context; mOverlayProvider = clipboardOverlayControllerProvider; mClipboardToast = clipboardToast; mClipboardManager = clipboardManager; + mKeyguardManager = keyguardManager; mUiEventLogger = uiEventLogger; } @@ -92,7 +96,9 @@ public class ClipboardListener implements return; } - if (!isUserSetupComplete() // user should not access intents from this state + // user should not access intents before setup or while device is locked + if (mKeyguardManager.isDeviceLocked() + || !isUserSetupComplete() || clipData == null // shouldn't happen, but just in case || clipData.getItemCount() == 0) { if (shouldShowToast(clipData)) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java index 18515825967f..9d02c86cfa7a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import android.app.KeyguardManager; import android.content.ClipData; import android.content.ClipDescription; import android.content.ClipboardManager; @@ -59,6 +60,8 @@ public class ClipboardListenerTest extends SysuiTestCase { @Mock private ClipboardManager mClipboardManager; @Mock + private KeyguardManager mKeyguardManager; + @Mock private ClipboardOverlayController mOverlayController; @Mock private ClipboardToast mClipboardToast; @@ -96,7 +99,7 @@ public class ClipboardListenerTest extends SysuiTestCase { when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource); mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider, - mClipboardToast, mClipboardManager, mUiEventLogger); + mClipboardToast, mClipboardManager, mKeyguardManager, mUiEventLogger); } @@ -190,6 +193,19 @@ public class ClipboardListenerTest extends SysuiTestCase { verifyZeroInteractions(mOverlayControllerProvider); } + @Test + public void test_deviceLocked_showsToast() { + when(mKeyguardManager.isDeviceLocked()).thenReturn(true); + + mClipboardListener.start(); + mClipboardListener.onPrimaryClipChanged(); + + verify(mUiEventLogger, times(1)).log( + ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource); + verify(mClipboardToast, times(1)).showCopiedToast(); + verifyZeroInteractions(mOverlayControllerProvider); + } + @Test public void test_nullClipData_showsNothing() { when(mClipboardManager.getPrimaryClip()).thenReturn(null); -- GitLab From b156c582347ad55a592eb364c8c86aee915195bf Mon Sep 17 00:00:00 2001 From: Miranda Kephart Date: Fri, 16 Feb 2024 10:14:15 -0500 Subject: [PATCH 005/466] Block clipboard UI when device is locked In some situations (see bug for details) it's possible to enter the clipboard even while the device is locked, and from there access the provided intents. Users should not be able to access intents from this state; this change adds an additional check before showing the interactive UI. The behavior is identical to what we do when user setup is not complete (b/251778420): we show a toast to note that content has been copied, but no interactive UI. Interactive UI is only blocked when device is locked (i.e. requiring pin entry/password/biometric/etc), not if the keyguard is up but trivially dismissable. Bug: 317048495 Test: atest ClipboardListenerTest; verification using steps in linked bug as well as forcing text content to appear client-side, to verify that even if text content is received in the ClipboardListener, no interactive UI appears. Change-Id: I1a48cbe64852dce3fba69915ca11dad8878f66eb Merged-In: I1a48cbe64852dce3fba69915ca11dad8878f66eb (cherry picked from commit 2976ca86d5c5be558191a1fe706d4cd0d7ccdecb) --- .../clipboardoverlay/ClipboardListener.java | 8 +++++++- .../ClipboardListenerTest.java | 18 +++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java index 63b4288ce055..f0a980e0a30c 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java @@ -24,6 +24,7 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE; +import android.app.KeyguardManager; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -57,6 +58,7 @@ public class ClipboardListener implements private final Provider mOverlayProvider; private final ClipboardToast mClipboardToast; private final ClipboardManager mClipboardManager; + private final KeyguardManager mKeyguardManager; private final UiEventLogger mUiEventLogger; private ClipboardOverlay mClipboardOverlay; @@ -65,11 +67,13 @@ public class ClipboardListener implements Provider clipboardOverlayControllerProvider, ClipboardToast clipboardToast, ClipboardManager clipboardManager, + KeyguardManager keyguardManager, UiEventLogger uiEventLogger) { mContext = context; mOverlayProvider = clipboardOverlayControllerProvider; mClipboardToast = clipboardToast; mClipboardManager = clipboardManager; + mKeyguardManager = keyguardManager; mUiEventLogger = uiEventLogger; } @@ -92,7 +96,9 @@ public class ClipboardListener implements return; } - if (!isUserSetupComplete() // user should not access intents from this state + // user should not access intents before setup or while device is locked + if (mKeyguardManager.isDeviceLocked() + || !isUserSetupComplete() || clipData == null // shouldn't happen, but just in case || clipData.getItemCount() == 0) { if (shouldShowToast(clipData)) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java index 18515825967f..9d02c86cfa7a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import android.app.KeyguardManager; import android.content.ClipData; import android.content.ClipDescription; import android.content.ClipboardManager; @@ -59,6 +60,8 @@ public class ClipboardListenerTest extends SysuiTestCase { @Mock private ClipboardManager mClipboardManager; @Mock + private KeyguardManager mKeyguardManager; + @Mock private ClipboardOverlayController mOverlayController; @Mock private ClipboardToast mClipboardToast; @@ -96,7 +99,7 @@ public class ClipboardListenerTest extends SysuiTestCase { when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource); mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider, - mClipboardToast, mClipboardManager, mUiEventLogger); + mClipboardToast, mClipboardManager, mKeyguardManager, mUiEventLogger); } @@ -190,6 +193,19 @@ public class ClipboardListenerTest extends SysuiTestCase { verifyZeroInteractions(mOverlayControllerProvider); } + @Test + public void test_deviceLocked_showsToast() { + when(mKeyguardManager.isDeviceLocked()).thenReturn(true); + + mClipboardListener.start(); + mClipboardListener.onPrimaryClipChanged(); + + verify(mUiEventLogger, times(1)).log( + ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource); + verify(mClipboardToast, times(1)).showCopiedToast(); + verifyZeroInteractions(mOverlayControllerProvider); + } + @Test public void test_nullClipData_showsNothing() { when(mClipboardManager.getPrimaryClip()).thenReturn(null); -- GitLab From 01a842822adc467beb972e9e3c37a0244dbd105a Mon Sep 17 00:00:00 2001 From: Miranda Kephart Date: Fri, 16 Feb 2024 10:14:15 -0500 Subject: [PATCH 006/466] Block clipboard UI when device is locked In some situations (see bug for details) it's possible to enter the clipboard even while the device is locked, and from there access the provided intents. Users should not be able to access intents from this state; this change adds an additional check before showing the interactive UI. The behavior is identical to what we do when user setup is not complete (b/251778420): we show a toast to note that content has been copied, but no interactive UI. Interactive UI is only blocked when device is locked (i.e. requiring pin entry/password/biometric/etc), not if the keyguard is up but trivially dismissable. Bug: 317048495 Test: atest ClipboardListenerTest; verification using steps in linked bug as well as forcing text content to appear client-side, to verify that even if text content is received in the ClipboardListener, no interactive UI appears. Change-Id: I1a48cbe64852dce3fba69915ca11dad8878f66eb Merged-In: I1a48cbe64852dce3fba69915ca11dad8878f66eb (cherry picked from commit 2976ca86d5c5be558191a1fe706d4cd0d7ccdecb) --- .../clipboardoverlay/ClipboardListener.java | 8 +++++++- .../ClipboardListenerTest.java | 19 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java index edda87527b1d..f512d58a13a0 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java @@ -25,6 +25,7 @@ import static com.android.systemui.flags.Flags.CLIPBOARD_MINIMIZED_LAYOUT; import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE; +import android.app.KeyguardManager; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -60,6 +61,7 @@ public class ClipboardListener implements private final ClipboardToast mClipboardToast; private final ClipboardManager mClipboardManager; private final FeatureFlags mFeatureFlags; + private final KeyguardManager mKeyguardManager; private final UiEventLogger mUiEventLogger; private ClipboardOverlay mClipboardOverlay; @@ -69,12 +71,14 @@ public class ClipboardListener implements ClipboardToast clipboardToast, ClipboardManager clipboardManager, FeatureFlags featureFlags, + KeyguardManager keyguardManager, UiEventLogger uiEventLogger) { mContext = context; mOverlayProvider = clipboardOverlayControllerProvider; mClipboardToast = clipboardToast; mClipboardManager = clipboardManager; mFeatureFlags = featureFlags; + mKeyguardManager = keyguardManager; mUiEventLogger = uiEventLogger; } @@ -97,7 +101,9 @@ public class ClipboardListener implements return; } - if (!isUserSetupComplete() // user should not access intents from this state + // user should not access intents before setup or while device is locked + if (mKeyguardManager.isDeviceLocked() + || !isUserSetupComplete() || clipData == null // shouldn't happen, but just in case || clipData.getItemCount() == 0) { if (shouldShowToast(clipData)) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java index fd6e31ba3bee..cb73d4296c49 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java @@ -29,6 +29,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import android.app.KeyguardManager; import android.content.ClipData; import android.content.ClipDescription; import android.content.ClipboardManager; @@ -62,6 +63,8 @@ public class ClipboardListenerTest extends SysuiTestCase { @Mock private ClipboardManager mClipboardManager; @Mock + private KeyguardManager mKeyguardManager; + @Mock private ClipboardOverlayController mOverlayController; @Mock private ClipboardToast mClipboardToast; @@ -102,7 +105,8 @@ public class ClipboardListenerTest extends SysuiTestCase { mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, true); mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider, - mClipboardToast, mClipboardManager, mFeatureFlags, mUiEventLogger); + mClipboardToast, mClipboardManager, mFeatureFlags, mKeyguardManager, + mUiEventLogger); } @@ -196,6 +200,19 @@ public class ClipboardListenerTest extends SysuiTestCase { verifyZeroInteractions(mOverlayControllerProvider); } + @Test + public void test_deviceLocked_showsToast() { + when(mKeyguardManager.isDeviceLocked()).thenReturn(true); + + mClipboardListener.start(); + mClipboardListener.onPrimaryClipChanged(); + + verify(mUiEventLogger, times(1)).log( + ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource); + verify(mClipboardToast, times(1)).showCopiedToast(); + verifyZeroInteractions(mOverlayControllerProvider); + } + @Test public void test_nullClipData_showsNothing() { when(mClipboardManager.getPrimaryClip()).thenReturn(null); -- GitLab From a9b535f8a9f9cb46861585168543bb67660a6d1d Mon Sep 17 00:00:00 2001 From: "Torne (Richard Coles)" Date: Mon, 9 Sep 2024 13:57:17 -0400 Subject: [PATCH 007/466] Fix inconsistent behavior of killPackageDependents. ActivityManagerService.killPackageDependents behaved inconsistently when used with USER_ALL vs a specific user id. In both cases, processes that have added a dependency on the specified package via addPackageDependency were killed as expected, but processes owned by the specified package were only being killed when a specific user id was used, and were left alone when USER_ALL was specified. Fix this by looping over all the users as other similar process-killing methods do, instead of relying on a single call to killPackageProcessesLSP. This also adds proper usage of UserController.handleIncomingUser, making it possible to use the API with USER_CURRENT. Killing dependents for all users now requires INTERACT_ACROSS_USERS_FULL to be consistent with other similar APIs - previously no permission other than KILL_UID was required. Bug: 310653407 Test: atest CtsAppTestCases:PackageDependencyTest Flag: EXEMPT bugfix Change-Id: I7a95758bab4fa2c8b33d5c6748a614848c9d8d9a --- .../server/am/ActivityManagerService.java | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3c574769eaec..a3792180c510 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -418,7 +418,6 @@ import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; -import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.AlarmManagerInternal; import com.android.server.BootReceiver; import com.android.server.DeviceIdleInternal; @@ -438,6 +437,7 @@ import com.android.server.am.LowMemDetector.MemFactor; import com.android.server.appop.AppOpsService; import com.android.server.compat.PlatformCompat; import com.android.server.contentcapture.ContentCaptureManagerInternal; +import com.android.server.crashrecovery.CrashRecoveryHelper; import com.android.server.criticalevents.CriticalEventLog; import com.android.server.firewall.IntentFirewall; import com.android.server.graphics.fonts.FontManagerInternal; @@ -18376,25 +18376,34 @@ public class ActivityManagerService extends IActivityManager.Stub "Cannot kill the dependents of a package without its name."); } + userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), + userId, true, ALLOW_FULL_ONLY, "killPackageDependents", null); + final int[] userIds = mUserController.expandUserId(userId); + final long callingId = Binder.clearCallingIdentity(); IPackageManager pm = AppGlobals.getPackageManager(); - int pkgUid = -1; try { - pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId); - } catch (RemoteException e) { - } - if (userId != UserHandle.USER_ALL && pkgUid == -1) { - throw new IllegalArgumentException( - "Cannot kill dependents of non-existing package " + packageName); - } - try { - synchronized(this) { - synchronized (mProcLock) { - mProcessList.killPackageProcessesLSP(packageName, UserHandle.getAppId(pkgUid), - userId, ProcessList.FOREGROUND_APP_ADJ, - ApplicationExitInfo.REASON_DEPENDENCY_DIED, - ApplicationExitInfo.SUBREASON_UNKNOWN, - "dep: " + packageName); + for (int targetUserId : userIds) { + int pkgUid = -1; + try { + pkgUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, + targetUserId); + } catch (RemoteException e) { + } + if (userId != UserHandle.USER_ALL && pkgUid == -1) { + throw new IllegalArgumentException( + "Cannot kill dependents of non-existing package " + packageName); + } + synchronized (this) { + synchronized (mProcLock) { + mProcessList.killPackageProcessesLSP(packageName, + UserHandle.getAppId(pkgUid), + targetUserId, + ProcessList.FOREGROUND_APP_ADJ, + ApplicationExitInfo.REASON_DEPENDENCY_DIED, + ApplicationExitInfo.SUBREASON_UNKNOWN, + "dep: " + packageName); + } } } } finally { -- GitLab From 31db47319937f234c8eae3d6c1b6ab6bfc2b9ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= Date: Thu, 12 Sep 2024 09:49:16 +0200 Subject: [PATCH 008/466] Rework SDK_MINOR_INT -> SDK_INT_FULL Change how minor release codes are encoded in Build.java. Instead of a new int representing the minor version, which always needs to be combined with SDK_INT, change SDK_MINOR_INT to become SDK_INT_FULL which encodes both major and minor versions. This reduces the risk of confusing the integers, simplifies version checks and is better for Lint and the docs. Bug: 350458259 Test: atest 'CtsOsTestCases:BuildTest#testSdkIntFull' Flag: android.sdk.major_minor_versioning_scheme Change-Id: I4373e846f572aedd2f48af17c8d60aea80c42b2e --- core/api/current.txt | 5 ++- core/java/android/os/Build.java | 63 ++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 1865e8c55d80..11030f7c6ce0 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -32771,7 +32771,7 @@ package android.os { field @NonNull public static final String RELEASE_OR_PREVIEW_DISPLAY; field @Deprecated public static final String SDK; field public static final int SDK_INT; - field @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static final int SDK_MINOR_INT; + field @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static final int SDK_INT_FULL; field public static final String SECURITY_PATCH; } @@ -32815,6 +32815,9 @@ package android.os { field public static final int VANILLA_ICE_CREAM = 35; // 0x23 } + @FlaggedApi("android.sdk.major_minor_versioning_scheme") public static class Build.VERSION_CODES_FULL { + } + public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { ctor public Bundle(); ctor public Bundle(ClassLoader); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index a8267d1c9d8c..479aa98f80de 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.app.ActivityThread; @@ -401,33 +402,42 @@ public class Build { * device. This value never changes while a device is booted, but it may * increase when the hardware manufacturer provides an OTA update. *

- * Together with {@link SDK_MINOR_INT}, this constant defines the - *

major.minor
version of Android.
SDK_INT
is - * increased and
SDK_MINOR_INT
is set to 0 on new Android - * dessert releases. Between these, Android may also release so called - * minor releases where
SDK_INT
remains unchanged and - *
SDK_MINOR_INT
is increased. Minor releases can add new - * APIs, and have stricter guarantees around backwards compatibility - * (e.g. no changes gated by
targetSdkVersion
) compared to - * major releases. + * This constant records the major version of Android. Use {@link + * SDK_INT_FULL} if you need to consider the minor version of Android + * as well. *

* Possible values are defined in {@link Build.VERSION_CODES}. + * @see #SDK_INT_FULL */ public static final int SDK_INT = SystemProperties.getInt( "ro.build.version.sdk", 0); /** - * The minor SDK version of the software currently running on this hardware - * device. This value never changes while a device is booted, but it may - * increase when the hardware manufacturer provides an OTA update. + * The major and minor SDK version of the software currently running on + * this hardware device. This value never changes while a device is + * booted, but it may increase when the hardware manufacturer provides + * an OTA update. + *

+ * SDK_INT is increased on new Android dessert releases, + * also called major releases. Between these, Android may also release + * minor releases where SDK_INT remains unchanged. Minor + * releases can add new APIs, and have stricter guarantees around + * backwards compatibility (e.g. no changes gated by + * targetSdkVersion) compared to major releases. *

- * Together with {@link SDK_INT}, this constant defines the - *

major.minor
version of Android. See {@link SDK_INT} for - * more information. + * SDK_INT_FULL is increased on every release. + *

+ * Possible values are defined in {@link + * android.os.Build.VERSION_CODES_FULL}. */ @FlaggedApi(Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME) - public static final int SDK_MINOR_INT = SystemProperties.getInt( - "ro.build.version.sdk_minor", 0); + public static final int SDK_INT_FULL; + + static { + SDK_INT_FULL = VERSION_CODES_FULL.SDK_INT_MULTIPLIER + * SystemProperties.getInt("ro.build.version.sdk", 0) + + SystemProperties.getInt("ro.build.version.sdk_minor", 0); + } /** * The SDK version of the software that initially shipped on @@ -1263,6 +1273,25 @@ public class Build { public static final int VANILLA_ICE_CREAM = 35; } + /** + * Enumeration of the currently known SDK major and minor version codes. + * The numbers increase for every release, and are guaranteed to be ordered + * by the release date of each release. The actual values should be + * considered an implementation detail, and the current encoding scheme may + * change in the future. + * + * @see android.os.Build.VERSION#SDK_INT_FULL + */ + @FlaggedApi(Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME) + @SuppressLint("AcronymName") + public static class VERSION_CODES_FULL { + private VERSION_CODES_FULL() {} + + // Use the last 5 digits for the minor version. This allows the + // minor version to be set to CUR_DEVELOPMENT. + private static final int SDK_INT_MULTIPLIER = 100000; + } + /** * The vendor API for 2024 Q2 * -- GitLab From ad6599eac4ebc6cb481658304bb78035e7cfeeba Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 16 Sep 2024 11:09:01 -0700 Subject: [PATCH 009/466] Drop FEATURE_TELEPHONY_GSM from interface requirements Bug: 367363970 Test: m Flag: NONE removing exception Change-Id: Id11dfbf02277f6dafac421bb68ffd75aed006c2a --- .../android/telephony/TelephonyManager.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 3e226ccf2737..9c259208fb4d 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2298,13 +2298,9 @@ public class TelephonyManager { * * See {@link #getImei(int)} for details on the required permissions and behavior * when the caller does not hold sufficient permissions. - * - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELEPHONY_GSM}. */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) public String getImei() { return getImei(getSlotIndex()); } @@ -2343,13 +2339,9 @@ public class TelephonyManager { * * * @param slotIndex of which IMEI is returned - * - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELEPHONY_GSM}. */ @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) public String getImei(int slotIndex) { ITelephony telephony = getITelephony(); if (telephony == null) return null; @@ -2366,11 +2358,7 @@ public class TelephonyManager { /** * Returns the Type Allocation Code from the IMEI. Return null if Type Allocation Code is not * available. - * - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELEPHONY_GSM}. */ - @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) @Nullable public String getTypeAllocationCode() { return getTypeAllocationCode(getSlotIndex()); @@ -2381,11 +2369,7 @@ public class TelephonyManager { * available. * * @param slotIndex of which Type Allocation Code is returned - * - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELEPHONY_GSM}. */ - @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) @Nullable public String getTypeAllocationCode(int slotIndex) { ITelephony telephony = getITelephony(); @@ -19367,12 +19351,9 @@ public class TelephonyManager { * * * @return Primary IMEI of type string - * @throws UnsupportedOperationException If the device does not have - * {@link PackageManager#FEATURE_TELEPHONY_GSM}. * @throws SecurityException if the caller does not have the required permission/privileges */ @NonNull - @RequiresFeature(PackageManager.FEATURE_TELEPHONY_GSM) public String getPrimaryImei() { try { ITelephony telephony = getITelephony(); -- GitLab From 1573f5d7b44d58b3dd2b0c8503c5e4b22d16c32d Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Tue, 17 Sep 2024 13:36:29 -0700 Subject: [PATCH 010/466] Turn off smart idle maint service for ZUFS Since ZUFS devices already have more aggressive GC, we don't need the smart idle maint service for them. Bug: 325517147 Test: run smart idle maint service for ZUFS devices Change-Id: I1ae1a3733222de5caec7f7c25764b605cdcf4e10 Signed-off-by: Daeho Jeong --- .../core/java/com/android/server/StorageManagerService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index b35959f1a6e8..0c7840c0d5c2 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2738,7 +2738,8 @@ class StorageManagerService extends IStorageManager.Stub boolean smartIdleMaintEnabled = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, "smart_idle_maint_enabled", - DEFAULT_SMART_IDLE_MAINT_ENABLED); + DEFAULT_SMART_IDLE_MAINT_ENABLED) + && !SystemProperties.getBoolean("ro.boot.zufs_provisioned", false); if (smartIdleMaintEnabled) { mLifetimePercentThreshold = DeviceConfig.getInt( DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT, -- GitLab From 88cbe44bde56a2df4ef48ba211536f7d8c2db319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cosmin=20B=C4=83ie=C8=99?= Date: Thu, 19 Sep 2024 12:23:22 +0200 Subject: [PATCH 011/466] Check relayoutCalled in updateSourceFrame In some cases a WindowState could try to update its InsetsSourceProviders sourceFrame before relayout was called. Even though it does check that we don't given insets pending, this could pass when the window is just being added. In this case each source provider would update the frame on the server side only, and try to apply the frame provider logic to potentially inset the result. However, we wouldn't have any given content insets to apply to this frame before the window is laid out, so the provider would be using the whole app frame as its sourceFrame. This would only remain on the server side initially, but will be sent to the InsetsSource on the client side whenever the provider would become serverVisible, which can happen before we get another updateSourceFrame call to trigger applying the content insets after layout, when they wouldn't be empty anymore. In the IME source provider case, this could lead to the app receiving full height IME insets, which will trigger a flicker as the app will re-measure its contents with zero height. Additionally, this leads to the app losing focus on the actual view, and focusing the DecorView instead. If the window focus switches to a different app in this case, while the IME is shown, and then back to the original app, we would hide the IME as the focused view (DecorView) is not an EditText. This fixes the case described above by ensuring the WindowState source frame update also considers whether relayout was called before setting the new frame. Flag: EXEMPT bugfix Test: atest WindowStateTests#testUpdateSourceFrameBeforeRelayout InsetsStateControllerTest#testImeForDispatch DisplayPolicyTests#testImeInsetsGivenContentFrame DisplayPolicyLayoutTests#addingWindow_withInsetsTypes DisplayPolicyLayoutTests#testFixedRotationInsetsSourceFrame DisplayPolicyLayoutTests#testSimulateLayoutDisplay Bug: 359387875 Change-Id: I0c94f7bf7604d55b23e568cfa1a16433537395b7 --- .../server/wm/InsetsSourceProvider.java | 6 +++++ .../com/android/server/wm/WindowState.java | 5 ++++ .../server/wm/DisplayPolicyLayoutTests.java | 2 ++ .../android/server/wm/DisplayPolicyTests.java | 1 + .../server/wm/InsetsStateControllerTest.java | 2 ++ .../android/server/wm/WindowStateTests.java | 26 +++++++++++++++++++ 6 files changed, 42 insertions(+) diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 8f90b2d183e8..95e0d8c81b9b 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -147,6 +147,12 @@ class InsetsSourceProvider { return mSource; } + @VisibleForTesting + @NonNull + Rect getSourceFrame() { + return mSourceFrame; + } + /** * @return Whether the current flag configuration allows to control this source. */ diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 1640ad3f1958..8a5a80ff1a40 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1378,6 +1378,11 @@ class WindowState extends WindowContainer implements WindowManagerP // should be updated after the new given insets are sent to window manager. return; } + if (!mRelayoutCalled) { + // The window was not laid out yet. The source frame should be updated after the window + // is laid out. + return; + } final SparseArray providers = getInsetsSourceProviders(); for (int i = providers.size() - 1; i >= 0; i--) { providers.valueAt(i).updateSourceFrame(winFrame); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 7a0961d8c306..1015651438c3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -84,6 +84,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { // Disabling this call for most tests since it can override the systemUiFlags when called. doNothing().when(mDisplayPolicy).updateSystemBarAttributes(); + makeWindowVisible(mStatusBarWindow, mNavBarWindow); updateDisplayFrames(); } @@ -154,6 +155,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { }; addWindow(win); win.getFrame().set(0, 0, 500, 100); + makeWindowVisible(win); win.updateSourceFrame(win.getFrame()); mDisplayContent.getInsetsStateController().onPostLayout(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index f32a234f3e40..63b51002b411 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -530,6 +530,7 @@ public class DisplayPolicyTests extends WindowTestsBase { final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); mDisplayContent.setInputMethodWindowLocked(mImeWindow); + makeWindowVisible(mImeWindow); mImeWindow.getControllableInsetProvider().setServerVisible(true); mImeWindow.mGivenContentInsets.set(0, 10, 0, 0); diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index d0d7c06bd706..66a66a1e358b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -291,6 +291,8 @@ public class InsetsStateControllerTest extends WindowTestsBase { final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar"); final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, "ime"); + makeWindowVisible(statusBar); + // IME cannot be the IME target. ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE; diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 2d5e5dacc217..e7e184c537f7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -483,6 +483,32 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(statusBar.isVisible()); } + /** + * Verifies that the InsetsSourceProvider frame cannot be updated by WindowState before + * relayout is called. + */ + @SetupWindows(addWindows = { W_STATUS_BAR }) + @Test + public void testUpdateSourceFrameBeforeRelayout() { + final WindowState statusBar = mStatusBarWindow; + statusBar.mHasSurface = true; + assertTrue(statusBar.isVisible()); + final int statusBarId = InsetsSource.createId(null, 0, statusBars()); + final var statusBarProvider = mDisplayContent.getInsetsStateController() + .getOrCreateSourceProvider(statusBarId, statusBars()); + statusBarProvider.setWindowContainer(statusBar, null /* frameProvider */, + null /* imeFrameProvider */); + + statusBar.updateSourceFrame(new Rect(0, 0, 500, 200)); + assertTrue("InsetsSourceProvider frame should not be updated before relayout", + statusBarProvider.getSourceFrame().isEmpty()); + + makeWindowVisible(statusBar); + statusBar.updateSourceFrame(new Rect(0, 0, 500, 100)); + assertEquals("InsetsSourceProvider frame should be updated after relayout", + new Rect(0, 0, 500, 100), statusBarProvider.getSourceFrame()); + } + @Test public void testIsSelfOrAncestorWindowAnimating() { final WindowState root = createWindow(null, TYPE_APPLICATION, "root"); -- GitLab From cf3d3fc31be8a1d497e4f029d541c4a15c14eb34 Mon Sep 17 00:00:00 2001 From: Christopher Cameron Date: Wed, 11 Sep 2024 14:18:44 +0000 Subject: [PATCH 012/466] SkAndroidCodec: Use getGainmapAndroidCodec Bug: 349357636 Flag: EXEMPT refactor Test: courage Test: Viewing UltraHDR images in Photos Change-Id: Ifc467d930fe1dc96989751d0a9be30284d292175 --- libs/hwui/hwui/ImageDecoder.cpp | 11 +++-------- libs/hwui/jni/BitmapFactory.cpp | 14 ++++---------- libs/hwui/jni/BitmapRegionDecoder.cpp | 27 +++++++-------------------- 3 files changed, 14 insertions(+), 38 deletions(-) diff --git a/libs/hwui/hwui/ImageDecoder.cpp b/libs/hwui/hwui/ImageDecoder.cpp index 588463c49497..e074a27db38f 100644 --- a/libs/hwui/hwui/ImageDecoder.cpp +++ b/libs/hwui/hwui/ImageDecoder.cpp @@ -501,18 +501,13 @@ SkCodec::Result ImageDecoder::decode(void* pixels, size_t rowBytes) { SkCodec::Result ImageDecoder::extractGainmap(Bitmap* destination, bool isShared) { ATRACE_CALL(); SkGainmapInfo gainmapInfo; - std::unique_ptr gainmapStream; + std::unique_ptr gainmapCodec; { - ATRACE_NAME("getAndroidGainmap"); - if (!mCodec->getAndroidGainmap(&gainmapInfo, &gainmapStream)) { + ATRACE_NAME("getGainmapAndroidCodec"); + if (!mCodec->getGainmapAndroidCodec(&gainmapInfo, &gainmapCodec)) { return SkCodec::kSuccess; } } - auto gainmapCodec = SkAndroidCodec::MakeFromStream(std::move(gainmapStream)); - if (!gainmapCodec) { - ALOGW("Failed to create codec for gainmap stream"); - return SkCodec::kInvalidInput; - } ImageDecoder decoder{std::move(gainmapCodec)}; // Gainmap inherits the origin of the containing image decoder.mOverrideOrigin.emplace(getOrigin()); diff --git a/libs/hwui/jni/BitmapFactory.cpp b/libs/hwui/jni/BitmapFactory.cpp index 785aef312072..49a7f73fb3a3 100644 --- a/libs/hwui/jni/BitmapFactory.cpp +++ b/libs/hwui/jni/BitmapFactory.cpp @@ -183,14 +183,8 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize, needsFineScale(fullSize.height(), decodedSize.height(), sampleSize); } -static bool decodeGainmap(std::unique_ptr gainmapStream, const SkGainmapInfo& gainmapInfo, +static bool decodeGainmap(std::unique_ptr codec, const SkGainmapInfo& gainmapInfo, sp* outGainmap, const int sampleSize, float scale) { - std::unique_ptr codec; - codec = SkAndroidCodec::MakeFromStream(std::move(gainmapStream), nullptr); - if (!codec) { - ALOGE("Can not create a codec for Gainmap."); - return false; - } SkColorType decodeColorType = kN32_SkColorType; if (codec->getInfo().colorType() == kGray_8_SkColorType) { decodeColorType = kGray_8_SkColorType; @@ -613,15 +607,15 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr stream, bool hasGainmap = false; SkGainmapInfo gainmapInfo; - std::unique_ptr gainmapStream = nullptr; + std::unique_ptr gainmapCodec; sp gainmap = nullptr; if (result == SkCodec::kSuccess) { - hasGainmap = codec->getAndroidGainmap(&gainmapInfo, &gainmapStream); + hasGainmap = codec->getGainmapAndroidCodec(&gainmapInfo, &gainmapCodec); } if (hasGainmap) { hasGainmap = - decodeGainmap(std::move(gainmapStream), gainmapInfo, &gainmap, sampleSize, scale); + decodeGainmap(std::move(gainmapCodec), gainmapInfo, &gainmap, sampleSize, scale); } if (!isMutable && javaBitmap == NULL) { diff --git a/libs/hwui/jni/BitmapRegionDecoder.cpp b/libs/hwui/jni/BitmapRegionDecoder.cpp index 6a65b8273194..f7e8e073a272 100644 --- a/libs/hwui/jni/BitmapRegionDecoder.cpp +++ b/libs/hwui/jni/BitmapRegionDecoder.cpp @@ -48,25 +48,14 @@ public: } SkGainmapInfo gainmapInfo; - std::unique_ptr gainmapStream; + std::unique_ptr gainmapCodec; std::unique_ptr gainmapBRD = nullptr; - if (mainImageBRD->getAndroidGainmap(&gainmapInfo, &gainmapStream)) { - sk_sp data = nullptr; - if (gainmapStream->getMemoryBase()) { - // It is safe to make without copy because we'll hold onto the stream. - data = SkData::MakeWithoutCopy(gainmapStream->getMemoryBase(), - gainmapStream->getLength()); - } else { - data = SkCopyStreamToData(gainmapStream.get()); - // We don't need to hold the stream anymore - gainmapStream = nullptr; - } - gainmapBRD = skia::BitmapRegionDecoder::Make(std::move(data)); + if (!mainImageBRD->getGainmapBitmapRegionDecoder(&gainmapInfo, &gainmapBRD)) { + gainmapBRD = nullptr; } - return std::unique_ptr( - new BitmapRegionDecoderWrapper(std::move(mainImageBRD), std::move(gainmapBRD), - gainmapInfo, std::move(gainmapStream))); + return std::unique_ptr(new BitmapRegionDecoderWrapper( + std::move(mainImageBRD), std::move(gainmapBRD), gainmapInfo)); } SkEncodedImageFormat getEncodedFormat() { return mMainImageBRD->getEncodedFormat(); } @@ -191,16 +180,14 @@ public: private: BitmapRegionDecoderWrapper(std::unique_ptr mainImageBRD, std::unique_ptr gainmapBRD, - SkGainmapInfo info, std::unique_ptr stream) + SkGainmapInfo info) : mMainImageBRD(std::move(mainImageBRD)) , mGainmapBRD(std::move(gainmapBRD)) - , mGainmapInfo(info) - , mGainmapStream(std::move(stream)) {} + , mGainmapInfo(info) {} std::unique_ptr mMainImageBRD; std::unique_ptr mGainmapBRD; SkGainmapInfo mGainmapInfo; - std::unique_ptr mGainmapStream; }; } // namespace android -- GitLab From aebcc469d28cf6f148a837ce32c53e68d3d280d9 Mon Sep 17 00:00:00 2001 From: ziyiw Date: Fri, 20 Sep 2024 20:56:25 +0000 Subject: [PATCH 013/466] [framework] Add more oem extension APIs Bug: 338255533 Test: atest CtsNfcTestCases Change-Id: I1a63f1cff59fc099f07f318d7e520429463c36bc --- nfc/api/system-current.txt | 5 +++ nfc/java/android/nfc/INfcAdapter.aidl | 3 ++ nfc/java/android/nfc/NfcOemExtension.java | 52 +++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index d17a9b62d02d..94231b0facdb 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -58,10 +58,15 @@ package android.nfc { @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension { method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference(); method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List getActiveNfceeList(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean hasUserEnabledNfc(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagPresent(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void pausePolling(int); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void resumePolling(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOnMode(int); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void triggerInitialization(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback); field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int DISABLE = 0; // 0x0 field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_DEFAULT = 1; // 0x1 diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl index 246efc7ca557..a166b283f55b 100644 --- a/nfc/java/android/nfc/INfcAdapter.aidl +++ b/nfc/java/android/nfc/INfcAdapter.aidl @@ -114,4 +114,7 @@ interface INfcAdapter void setScreenState(); void checkFirmware(); List fetchActiveNfceeList(); + void triggerInitialization(); + boolean getSettingStatus(); + boolean isTagPresent(); } diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index 011c60b080f8..6d5c069bca3a 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -471,6 +471,58 @@ public final class NfcOemExtension { NfcAdapter.callService(() -> NfcAdapter.sService.setControllerAlwaysOn(mode)); } + /** + * Triggers NFC initialization. If OEM extension is registered + * (indicated via `enable_oem_extension` NFC overlay), the NFC stack initialization at bootup + * is delayed until the OEM extension app triggers the initialization via this call. + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public void triggerInitialization() { + NfcAdapter.callService(() -> NfcAdapter.sService.triggerInitialization()); + } + + /** + * Gets the last user toggle status. + * @return true if NFC is set to ON, false otherwise + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public boolean hasUserEnabledNfc() { + return NfcAdapter.callServiceReturn(() -> NfcAdapter.sService.getSettingStatus(), false); + } + + /** + * Checks if the tag is present or not. + * @return true if the tag is present, false otherwise + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public boolean isTagPresent() { + return NfcAdapter.callServiceReturn(() -> NfcAdapter.sService.isTagPresent(), false); + } + + /** + * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond. If polling must be + * resumed before timeout, use {@link #resumePolling()}. + * @param timeoutInMs the pause polling duration in millisecond + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public void pausePolling(int timeoutInMs) { + NfcAdapter.callService(() -> NfcAdapter.sService.pausePolling(timeoutInMs)); + } + + /** + * Resumes default NFC tag reader mode polling for the current device state if polling is + * paused. Calling this while polling is not paused is a no-op. + */ + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public void resumePolling() { + NfcAdapter.callService(() -> NfcAdapter.sService.resumePolling()); + } + private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub { @Override -- GitLab From 771b570ddc9ab4e087ca9470a8e4f86f6ea5e564 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Wed, 18 Sep 2024 21:43:24 +0000 Subject: [PATCH 014/466] Also support setJniMethodFormat in hwui. Idfb9e0900957e3a13bde10ba9626dd9b6ff4ac99 added support for binding to a native methods that have been renamed by a fixed pattern to jni_wrappers.h. This commit copies the identical logic to graphics_jni_helpers.h And also refactors the existing logic to avoid a memory leak. Flag: EXEMPT: Only changes the behavior on host-side test. Bug: 323057854 Test: m libandroid_runtime Merged-In: I1a25389f7c6eb3270a32d858ee114ddadbc72a65 Change-Id: I232e1ca8ecf2faff2af692624a51188ed317e297 --- core/jni/jni_wrappers.h | 21 ++++++++----- libs/hwui/jni/graphics_jni_helpers.h | 45 +++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 9 deletions(-) diff --git a/core/jni/jni_wrappers.h b/core/jni/jni_wrappers.h index 21b5b1308fcf..e3e17eed54d5 100644 --- a/core/jni/jni_wrappers.h +++ b/core/jni/jni_wrappers.h @@ -79,13 +79,14 @@ inline static void setJniMethodFormat(std::string value) { jniMethodFormat = value; } -// Potentially translates the given JNINativeMethods if setJniMethodFormat has been set. -// Has no effect otherwise -inline const JNINativeMethod* maybeRenameJniMethods(const JNINativeMethod* gMethods, - int numMethods) { +// Register the native methods, potenially applying the jniMethodFormat if it has been set. +static inline int jniRegisterMaybeRenamedNativeMethods(JNIEnv* env, const char* className, + const JNINativeMethod* gMethods, + int numMethods) { if (jniMethodFormat.empty()) { - return gMethods; + return jniRegisterNativeMethods(env, className, gMethods, numMethods); } + // Make a copy of gMethods with reformatted method names. JNINativeMethod* modifiedMethods = new JNINativeMethod[numMethods]; LOG_ALWAYS_FATAL_IF(!modifiedMethods, "Failed to allocate a copy of the JNI methods"); @@ -103,13 +104,17 @@ inline const JNINativeMethod* maybeRenameJniMethods(const JNINativeMethod* gMeth std::strcpy(modifiedNameChars, modifiedName.c_str()); modifiedMethods[i].name = modifiedNameChars; } - return modifiedMethods; + int res = jniRegisterNativeMethods(env, className, modifiedMethods, numMethods); + for (int i = 0; i < numMethods; i++) { + delete[] modifiedMethods[i].name; + } + delete[] modifiedMethods; + return res; } static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { - const JNINativeMethod* modifiedMethods = maybeRenameJniMethods(gMethods, numMethods); - int res = jniRegisterNativeMethods(env, className, modifiedMethods, numMethods); + int res = jniRegisterMaybeRenamedNativeMethods(env, className, gMethods, numMethods); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); return res; } diff --git a/libs/hwui/jni/graphics_jni_helpers.h b/libs/hwui/jni/graphics_jni_helpers.h index 78db54acc9e5..91db134af18f 100644 --- a/libs/hwui/jni/graphics_jni_helpers.h +++ b/libs/hwui/jni/graphics_jni_helpers.h @@ -80,9 +80,52 @@ static inline T MakeGlobalRefOrDie(JNIEnv* env, T in) { return static_cast(res); } +// Inline variable that specifies the method binding format. +// The expected format is 'XX${method}XX', where ${method} represents the original method name. +// This variable is shared across all translation units. This is treated as a global variable as +// per C++ 17. +inline std::string jniMethodFormat; + +inline static void setJniMethodFormat(std::string value) { + jniMethodFormat = value; +} + +// Register the native methods, potenially applying the jniMethodFormat if it has been set. +static inline int jniRegisterMaybeRenamedNativeMethods(JNIEnv* env, const char* className, + const JNINativeMethod* gMethods, + int numMethods) { + if (jniMethodFormat.empty()) { + return jniRegisterNativeMethods(env, className, gMethods, numMethods); + } + + // Make a copy of gMethods with reformatted method names. + JNINativeMethod* modifiedMethods = new JNINativeMethod[numMethods]; + LOG_ALWAYS_FATAL_IF(!modifiedMethods, "Failed to allocate a copy of the JNI methods"); + + size_t methodNamePos = jniMethodFormat.find("${method}"); + LOG_ALWAYS_FATAL_IF(methodNamePos == std::string::npos, + "Invalid jniMethodFormat: could not find '${method}' in pattern"); + + for (int i = 0; i < numMethods; i++) { + modifiedMethods[i] = gMethods[i]; + std::string modifiedName = jniMethodFormat; + modifiedName.replace(methodNamePos, 9, gMethods[i].name); + char* modifiedNameChars = new char[modifiedName.length() + 1]; + LOG_ALWAYS_FATAL_IF(!modifiedNameChars, "Failed to allocate the new method name"); + std::strcpy(modifiedNameChars, modifiedName.c_str()); + modifiedMethods[i].name = modifiedNameChars; + } + int res = jniRegisterNativeMethods(env, className, modifiedMethods, numMethods); + for (int i = 0; i < numMethods; i++) { + delete[] modifiedMethods[i].name; + } + delete[] modifiedMethods; + return res; +} + static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods) { - int res = jniRegisterNativeMethods(env, className, gMethods, numMethods); + int res = jniRegisterMaybeRenamedNativeMethods(env, className, gMethods, numMethods); LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods."); return res; } -- GitLab From 36ed35e30511d045d815aa271c3806b1f32d5271 Mon Sep 17 00:00:00 2001 From: qinyige1 Date: Wed, 14 Aug 2024 16:15:53 +0800 Subject: [PATCH 015/466] [Binder][XIAOMI][Bugfix] Skip appops header in native parcel. [1/2] The same way as strict mode header. Bug: 359692915 Test: atest binderUnitTest Change-Id: Id4d20ecd5b3445ebe59519472fe99bf84a1faf44 --- core/java/android/app/AppOpsManager.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 2afc78cb90e6..11e464f5c07c 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -10119,6 +10119,9 @@ public class AppOpsManager { } p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER); + final int sizePosition = p.dataPosition(); + // Write size placeholder. With this size we can easily skip it in native. + p.writeInt(0); int numAttributionWithNotesAppOps = notedAppOps.size(); p.writeInt(numAttributionWithNotesAppOps); @@ -10135,6 +10138,12 @@ public class AppOpsManager { } } } + + final int payloadPosition = p.dataPosition(); + p.setDataPosition(sizePosition); + // Total header size including 4 bytes size itself. + p.writeInt(payloadPosition - sizePosition); + p.setDataPosition(payloadPosition); } /** @@ -10148,6 +10157,8 @@ public class AppOpsManager { * @hide */ public static void readAndLogNotedAppops(@NonNull Parcel p) { + // Skip size. + p.readInt(); int numAttributionsWithNotedAppOps = p.readInt(); for (int i = 0; i < numAttributionsWithNotedAppOps; i++) { -- GitLab From f518e04a7d998ec238a385c5049878a99e880a5d Mon Sep 17 00:00:00 2001 From: Matt Casey Date: Wed, 14 Aug 2024 19:34:48 +0000 Subject: [PATCH 016/466] Screenshot a single display per invocation Actual per-source display determination left as TODOs, but this puts the structure in place under a flag. Bug: 362720389 Test: atest TakeScreenshotExecutorTest Flag: com.android.systemui.screenshot_multidisplay_focus_change Change-Id: I4f0b4f21b1f93e02ccb14546157c79ffad685397 --- packages/SystemUI/aconfig/systemui.aconfig | 7 ++ .../screenshot/TakeScreenshotExecutor.kt | 104 ++++++++++++------ .../screenshot/TakeScreenshotExecutorTest.kt | 78 ++++++++++++- 3 files changed, 151 insertions(+), 38 deletions(-) diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index f8383d94b1ab..5942ff366c4c 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -632,6 +632,13 @@ flag { bug: "354711957" } +flag { + name: "screenshot_multidisplay_focus_change" + namespace: "systemui" + description: "Only capture a single display when screenshotting" + bug: "362720389" +} + flag { name: "run_fingerprint_detect_on_dismissible_keyguard" namespace: "systemui" diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt index 448f7c4d7e95..38608d0e793a 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotExecutor.kt @@ -20,9 +20,11 @@ import android.net.Uri import android.os.Trace import android.util.Log import android.view.Display +import android.view.WindowManager.ScreenshotSource import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE import com.android.internal.logging.UiEventLogger import com.android.internal.util.ScreenshotRequest +import com.android.systemui.Flags.screenshotMultidisplayFocusChange import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.display.data.repository.DisplayRepository @@ -40,7 +42,7 @@ interface TakeScreenshotExecutor { suspend fun executeScreenshots( screenshotRequest: ScreenshotRequest, onSaved: (Uri?) -> Unit, - requestCallback: RequestCallback + requestCallback: RequestCallback, ) fun onCloseSystemDialogsReceived() @@ -52,7 +54,7 @@ interface TakeScreenshotExecutor { fun executeScreenshotsAsync( screenshotRequest: ScreenshotRequest, onSaved: Consumer, - requestCallback: RequestCallback + requestCallback: RequestCallback, ) } @@ -60,7 +62,7 @@ interface ScreenshotHandler { fun handleScreenshot( screenshot: ScreenshotData, finisher: Consumer, - requestCallback: RequestCallback + requestCallback: RequestCallback, ) } @@ -75,7 +77,7 @@ class TakeScreenshotExecutorImpl @Inject constructor( private val interactiveScreenshotHandlerFactory: InteractiveScreenshotHandler.Factory, - displayRepository: DisplayRepository, + private val displayRepository: DisplayRepository, @Application private val mainScope: CoroutineScope, private val screenshotRequestProcessor: ScreenshotRequestProcessor, private val uiEventLogger: UiEventLogger, @@ -95,31 +97,44 @@ constructor( override suspend fun executeScreenshots( screenshotRequest: ScreenshotRequest, onSaved: (Uri?) -> Unit, - requestCallback: RequestCallback + requestCallback: RequestCallback, ) { - val displays = getDisplaysToScreenshot(screenshotRequest.type) - val resultCallbackWrapper = MultiResultCallbackWrapper(requestCallback) - if (displays.isEmpty()) { - Log.wtf(TAG, "No displays found for screenshot.") - } - displays.forEach { display -> - val displayId = display.displayId - var screenshotHandler: ScreenshotHandler = - if (displayId == Display.DEFAULT_DISPLAY) { - getScreenshotController(display) - } else { - headlessScreenshotHandler - } - Log.d(TAG, "Executing screenshot for display $displayId") + if (screenshotMultidisplayFocusChange()) { + val display = getDisplayToScreenshot(screenshotRequest) + val screenshotHandler = getScreenshotController(display) dispatchToController( screenshotHandler, - rawScreenshotData = ScreenshotData.fromRequest(screenshotRequest, displayId), - onSaved = - if (displayId == Display.DEFAULT_DISPLAY) { - onSaved - } else { _ -> }, - callback = resultCallbackWrapper.createCallbackForId(displayId) + ScreenshotData.fromRequest(screenshotRequest, display.displayId), + onSaved, + requestCallback, ) + } else { + val displays = getDisplaysToScreenshot(screenshotRequest.type) + val resultCallbackWrapper = MultiResultCallbackWrapper(requestCallback) + if (displays.isEmpty()) { + Log.e(TAG, "No displays found for screenshot.") + } + + displays.forEach { display -> + val displayId = display.displayId + var screenshotHandler: ScreenshotHandler = + if (displayId == Display.DEFAULT_DISPLAY) { + getScreenshotController(display) + } else { + headlessScreenshotHandler + } + + Log.d(TAG, "Executing screenshot for display $displayId") + dispatchToController( + screenshotHandler, + rawScreenshotData = ScreenshotData.fromRequest(screenshotRequest, displayId), + onSaved = + if (displayId == Display.DEFAULT_DISPLAY) { + onSaved + } else { _ -> }, + callback = resultCallbackWrapper.createCallbackForId(displayId), + ) + } } } @@ -128,7 +143,7 @@ constructor( screenshotHandler: ScreenshotHandler, rawScreenshotData: ScreenshotData, onSaved: (Uri?) -> Unit, - callback: RequestCallback + callback: RequestCallback, ) { // Let's wait before logging "screenshot requested", as we should log the processed // ScreenshotData. @@ -160,13 +175,13 @@ constructor( uiEventLogger.log( ScreenshotEvent.getScreenshotSource(screenshotData.source), 0, - screenshotData.packageNameString + screenshotData.packageNameString, ) } private fun onFailedScreenshotRequest( screenshotData: ScreenshotData, - callback: RequestCallback + callback: RequestCallback, ) { uiEventLogger.log(SCREENSHOT_CAPTURE_FAILED, 0, screenshotData.packageNameString) getNotificationController(screenshotData.displayId) @@ -184,6 +199,31 @@ constructor( } } + // Return the single display to be screenshot based upon the request. + private suspend fun getDisplayToScreenshot(screenshotRequest: ScreenshotRequest): Display { + return when (screenshotRequest.source) { + // TODO(b/367394043): Overview requests should use a display ID provided in + // ScreenshotRequest. + ScreenshotSource.SCREENSHOT_OVERVIEW -> + displayRepository.getDisplay(Display.DEFAULT_DISPLAY) + ?: error("Can't find default display") + + // Key chord and vendor gesture occur on the device itself, so screenshot the device's + // display + ScreenshotSource.SCREENSHOT_KEY_CHORD, + ScreenshotSource.SCREENSHOT_VENDOR_GESTURE -> + displayRepository.getDisplay(Display.DEFAULT_DISPLAY) + ?: error("Can't find default display") + + // All other invocations use the focused display + else -> focusedDisplay() + } + } + + // TODO(b/367394043): Determine the focused display here. + private suspend fun focusedDisplay() = + displayRepository.getDisplay(Display.DEFAULT_DISPLAY) ?: error("Can't find default display") + /** Propagates the close system dialog signal to the ScreenshotController. */ override fun onCloseSystemDialogsReceived() { if (screenshotController?.isPendingSharedTransition() == false) { @@ -214,7 +254,7 @@ constructor( override fun executeScreenshotsAsync( screenshotRequest: ScreenshotRequest, onSaved: Consumer, - requestCallback: RequestCallback + requestCallback: RequestCallback, ) { mainScope.launch { executeScreenshots(screenshotRequest, { uri -> onSaved.accept(uri) }, requestCallback) @@ -235,9 +275,7 @@ constructor( * - If any finished with an error, [reportError] of [originalCallback] is called * - Otherwise, [onFinish] is called. */ - private class MultiResultCallbackWrapper( - private val originalCallback: RequestCallback, - ) { + private class MultiResultCallbackWrapper(private val originalCallback: RequestCallback) { private val idsPending = mutableSetOf() private val idsWithErrors = mutableSetOf() @@ -290,7 +328,7 @@ constructor( Display.TYPE_EXTERNAL, Display.TYPE_INTERNAL, Display.TYPE_OVERLAY, - Display.TYPE_WIFI + Display.TYPE_WIFI, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt index a2959811cd0a..15705fbfec33 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotExecutorTest.kt @@ -3,6 +3,8 @@ package com.android.systemui.screenshot import android.content.ComponentName import android.graphics.Bitmap import android.net.Uri +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags import android.view.Display import android.view.Display.TYPE_EXTERNAL import android.view.Display.TYPE_INTERNAL @@ -15,6 +17,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.logging.testing.UiEventLoggerFake import com.android.internal.util.ScreenshotRequest +import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.display.data.repository.FakeDisplayRepository import com.android.systemui.display.data.repository.display @@ -75,6 +78,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_severalDisplays_callsControllerForEachOne() = testScope.runTest { val internalDisplay = display(TYPE_INTERNAL, id = 0) @@ -106,6 +110,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_providedImageType_callsOnlyDefaultDisplayController() = testScope.runTest { val internalDisplay = display(TYPE_INTERNAL, id = 0) @@ -115,7 +120,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { screenshotExecutor.executeScreenshots( createScreenshotRequest(TAKE_SCREENSHOT_PROVIDED_IMAGE), onSaved, - callback + callback, ) verify(controllerFactory).create(eq(internalDisplay)) @@ -137,6 +142,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_onlyVirtualDisplays_noInteractionsWithControllers() = testScope.runTest { setDisplays(display(TYPE_VIRTUAL, id = 0), display(TYPE_VIRTUAL, id = 1)) @@ -149,6 +155,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_allowedTypes_allCaptured() = testScope.runTest { whenever(controllerFactory.create(any())).thenReturn(controller) @@ -157,7 +164,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1), display(TYPE_OVERLAY, id = 2), - display(TYPE_WIFI, id = 3) + display(TYPE_WIFI, id = 3), ) val onSaved = { _: Uri? -> } screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) @@ -168,6 +175,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_reportsOnFinishedOnlyWhenBothFinished() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) @@ -193,6 +201,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_oneFinishesOtherFails_reportFailsOnlyAtTheEnd() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) @@ -220,6 +229,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_allDisplaysFail_reportsFail() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) @@ -319,6 +329,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromProcessor_logsScreenshotRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) @@ -336,6 +347,7 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) fun executeScreenshots_errorFromProcessor_logsUiError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) @@ -379,7 +391,8 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test - fun executeScreenshots_errorFromScreenshotController_reportsRequested() = + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) + fun executeScreenshots_errorFromScreenshotController_multidisplay_reportsRequested() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } @@ -399,7 +412,27 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test - fun executeScreenshots_errorFromScreenshotController_reportsError() = + @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) + fun executeScreenshots_errorFromScreenshotController_reportsRequested() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri? -> } + whenever(controller.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + val screenshotRequested = + eventLogger.logs.filter { + it.eventId == ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_OTHER.id + } + assertThat(screenshotRequested).hasSize(1) + screenshotExecutor.onDestroy() + } + + @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) + fun executeScreenshots_errorFromScreenshotController_multidisplay_reportsError() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } @@ -419,7 +452,27 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { } @Test - fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() = + @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) + fun executeScreenshots_errorFromScreenshotController_reportsError() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri? -> } + whenever(controller.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + val screenshotRequested = + eventLogger.logs.filter { + it.eventId == ScreenshotEvent.SCREENSHOT_CAPTURE_FAILED.id + } + assertThat(screenshotRequested).hasSize(1) + screenshotExecutor.onDestroy() + } + + @Test + @DisableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) + fun executeScreenshots_errorFromScreenshotController_multidisplay_showsErrorNotification() = testScope.runTest { setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) val onSaved = { _: Uri? -> } @@ -435,6 +488,21 @@ class TakeScreenshotExecutorTest : SysuiTestCase() { screenshotExecutor.onDestroy() } + @Test + @EnableFlags(Flags.FLAG_SCREENSHOT_MULTIDISPLAY_FOCUS_CHANGE) + fun executeScreenshots_errorFromScreenshotController_showsErrorNotification() = + testScope.runTest { + setDisplays(display(TYPE_INTERNAL, id = 0), display(TYPE_EXTERNAL, id = 1)) + val onSaved = { _: Uri? -> } + whenever(controller.handleScreenshot(any(), any(), any())) + .thenThrow(IllegalStateException::class.java) + + screenshotExecutor.executeScreenshots(createScreenshotRequest(), onSaved, callback) + + verify(notificationsController0).notifyScreenshotError(any()) + screenshotExecutor.onDestroy() + } + @Test fun executeScreenshots_finisherCalledWithNullUri_succeeds() = testScope.runTest { -- GitLab From 32a9155ad1fe6e9da0edb1a2bf621ea7dba9d252 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 25 Sep 2024 03:13:24 +0000 Subject: [PATCH 017/466] Update layer of rotation leash when restoring pip to original task This is similar to I6172e69400a258d9fdbc66044b459d65af622d14 Just the original task contains more than 1 activity. E.g. after reparenting: layer=0 activityZ=0 layer=1 activityZ=1 layer=2 activityZ=2 <- pip But if the pip has a rotation leash, its layer is not synced with activityZ, then it becomes layer=2 leashZ=0{activityZ=2}. That causes the top activity becomes invisible awhile before the leash is removed. Bug: 369006473 Flag: EXEMPT bugfix Test: Expand a pip which will reparent to a top task with 2 activities with orientation change. The previous fullscreen activity should not flicker on top. Change-Id: I2810646bb9b1be1782dcb5ec06d86d21125778c4 --- services/core/java/com/android/server/wm/Task.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 86bb75ab3f8c..a6fdbcb67bbf 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -4706,8 +4706,13 @@ class Task extends TaskFragment { // If the moveToFront is a part of finishing transition, then make sure // the z-order of tasks are up-to-date. if (topActivity.mTransitionController.inFinishingTransition(topActivity)) { - Transition.assignLayers(taskDisplayArea, - taskDisplayArea.getPendingTransaction()); + final SurfaceControl.Transaction tx = + taskDisplayArea.getPendingTransaction(); + Transition.assignLayers(taskDisplayArea, tx); + final SurfaceControl leash = topActivity.getFixedRotationLeash(); + if (leash != null) { + tx.setLayer(leash, topActivity.getLastLayer()); + } } } } -- GitLab From dc6e0ff9d5ad5fa1be6b4ec37891793dd448d387 Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Thu, 12 Sep 2024 08:01:15 +0000 Subject: [PATCH 018/466] Abort AE saved state restoration if it is too late Abort the AE saved state restoration if it is not yet able to be restored before any Activity#onCreate to be called. And start the Task root activity as a fresh restart as a fallback approach. Note that this may not always be correct (for example, an new Activity was expected to be started on the reused Task, but is now showing the Task root activity), but it should be a minimum fallback in case the app is not following the best practice to set up the embedding rules in Application#onCreate. Bug: 289875940 Test: verified on demo app Flag: com.android.window.flags.ae_back_stack_restore Change-Id: If7d33ec66a2476adf24892e54a4856db9b3d020a --- .../extensions/embedding/BackupHelper.java | 14 ++++++++ .../extensions/embedding/SplitController.java | 33 ++++++++++++++++++- .../extensions/embedding/SplitPresenter.java | 6 +++- .../extensions/embedding/TaskContainer.java | 2 +- 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java index bfccb29bc952..e3a1d8ac48e2 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java @@ -142,6 +142,19 @@ class BackupHelper { } } + void abortTaskContainerRebuilding(@NonNull WindowContainerTransaction wct) { + // Clean-up the legacy states in the system + for (int i = mTaskFragmentInfos.size() - 1; i >= 0; i--) { + final TaskFragmentInfo info = mTaskFragmentInfos.valueAt(i); + mPresenter.deleteTaskFragment(wct, info.getFragmentToken()); + } + mPresenter.setSavedState(new Bundle()); + + mParcelableTaskContainerDataList.clear(); + mTaskFragmentInfos.clear(); + mTaskFragmentParentInfos.clear(); + } + boolean hasPendingStateToRestore() { return !mParcelableTaskContainerDataList.isEmpty(); } @@ -196,6 +209,7 @@ class BackupHelper { mController.onTaskFragmentParentRestored(wct, taskContainer.getTaskId(), mTaskFragmentParentInfos.get(taskContainer.getTaskId())); + mTaskFragmentParentInfos.remove(taskContainer.getTaskId()); restoredAny = true; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java index db4bb0e5e75e..8345b409ae52 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java @@ -56,6 +56,7 @@ import static androidx.window.extensions.embedding.TaskFragmentContainer.Overlay import android.annotation.CallbackExecutor; import android.app.Activity; import android.app.ActivityClient; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.AppGlobals; @@ -280,7 +281,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen mSplitRules.clear(); mSplitRules.addAll(rules); - if (!Flags.aeBackStackRestore() || !mPresenter.isRebuildTaskContainersNeeded()) { + if (!Flags.aeBackStackRestore() || !mPresenter.isWaitingToRebuildTaskContainers()) { return; } @@ -2893,6 +2894,36 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen return; } synchronized (mLock) { + if (mPresenter.isWaitingToRebuildTaskContainers()) { + Log.w(TAG, "Rebuilding aborted, clean up and restart"); + + // Retrieve the Task intent. + final int taskId = getTaskId(activity); + Intent taskIntent = null; + final ActivityManager am = activity.getSystemService(ActivityManager.class); + final List appTasks = am.getAppTasks(); + for (ActivityManager.AppTask appTask : appTasks) { + if (appTask.getTaskInfo().taskId == taskId) { + taskIntent = appTask.getTaskInfo().baseIntent.cloneFilter(); + break; + } + } + + // Clean up and abort the restoration + // TODO(b/369488857): also to remove the non-organized activities in the Task? + final TransactionRecord transactionRecord = + mTransactionManager.startNewTransaction(); + final WindowContainerTransaction wct = transactionRecord.getTransaction(); + mPresenter.abortTaskContainerRebuilding(wct); + transactionRecord.apply(false /* shouldApplyIndependently */); + + // Start the Task root activity. + if (taskIntent != null) { + activity.startActivity(taskIntent); + } + return; + } + final IBinder activityToken = activity.getActivityToken(); final IBinder initialTaskFragmentToken = getTaskFragmentTokenFromActivityClientRecord(activity); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java index 0c0ded9bad74..b498ee2ff438 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java @@ -187,10 +187,14 @@ class SplitPresenter extends JetpackTaskFragmentOrganizer { mBackupHelper.scheduleBackup(); } - boolean isRebuildTaskContainersNeeded() { + boolean isWaitingToRebuildTaskContainers() { return mBackupHelper.hasPendingStateToRestore(); } + void abortTaskContainerRebuilding(@NonNull WindowContainerTransaction wct) { + mBackupHelper.abortTaskContainerRebuilding(wct); + } + boolean rebuildTaskContainers(@NonNull WindowContainerTransaction wct, @NonNull Set rules) { return mBackupHelper.rebuildTaskContainers(wct, rules); diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java index 74cce68f270b..e45b0961770d 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java @@ -156,7 +156,7 @@ class TaskContainer { mSplitController = splitController; for (ParcelableTaskFragmentContainerData tfData : data.getParcelableTaskFragmentContainerDataList()) { - final TaskFragmentInfo info = taskFragmentInfoMap.get(tfData.mToken); + final TaskFragmentInfo info = taskFragmentInfoMap.remove(tfData.mToken); if (info != null && !info.isEmpty()) { final TaskFragmentContainer container = new TaskFragmentContainer(tfData, splitController, this); -- GitLab From ed587d406d0fbd985faa924d67dd2daeb341f20e Mon Sep 17 00:00:00 2001 From: yumeichen Date: Mon, 26 Aug 2024 10:46:51 +0000 Subject: [PATCH 019/466] Add an extra condition to check whether it is the default notification uri There is a valid case that the default notification uri with `vibration_uri` as the parameter like: ``` content://settings/system/notification_sound?vibration_uri=file%3A%2Fproduct%252Fmedia%252Fvibration%2Fnotification%2FRumble.xml ``` This CL is to enable this case. Flag: android.media.audio.enable_ringtone_haptics_customization Bug: 351975435 Test: atest RingtoneManagerTest Change-Id: If14de08c6e3c84167df19a8adfc06892f2b5667d --- media/java/android/media/RingtoneManager.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index f0ab6ecc5cda..0f24654879cd 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -1089,7 +1089,24 @@ public class RingtoneManager { defaultRingtoneUri = ContentProvider.getUriWithoutUserId(defaultRingtoneUri); if (defaultRingtoneUri == null) { return -1; - } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) { + } + + if (Flags.enableRingtoneHapticsCustomization() + && Utils.hasVibration(defaultRingtoneUri)) { + // skip to check TYPE_ALARM because the customized haptic hasn't enabled in alarm + if (defaultRingtoneUri.toString() + .contains(Settings.System.DEFAULT_RINGTONE_URI.toString())) { + return TYPE_RINGTONE; + } else if (defaultRingtoneUri.toString() + .contains(Settings.System.DEFAULT_NOTIFICATION_URI.toString())) { + return TYPE_NOTIFICATION; + } else if (defaultRingtoneUri.toString() + .contains(Settings.System.DEFAULT_ALARM_ALERT_URI.toString())) { + return TYPE_ALARM; + } + } + + if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) { return TYPE_RINGTONE; } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) { return TYPE_NOTIFICATION; -- GitLab From c75c0875da89a56357fd863257340cd029792baa Mon Sep 17 00:00:00 2001 From: Miranda Kephart Date: Mon, 23 Sep 2024 12:16:43 -0400 Subject: [PATCH 020/466] Only run clipboard shared transition for images There's no available shared transition for text, so trying to run a shared transition looks bad. Switch to only running the shared transition for images, otherwise regular dismiss + share intent. Bug: 369132381 Fix: 369132381 Test: manual (invoke share for text content) Flag: com.android.systemui.clipboard_shared_transitions Change-Id: Iecaa3d86a512cc85d7af845403f352381dd14b0a --- .../ClipboardOverlayController.java | 13 ++++++++--- .../ClipboardOverlayControllerTest.java | 22 ++++++++++++------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index aabfbd11b70e..65c01ed9eecd 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -710,9 +710,16 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv @Override public void onShareButtonTapped() { if (clipboardSharedTransitions()) { - if (mClipboardModel.getType() != ClipboardModel.Type.OTHER) { - finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED, - IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext)); + switch (mClipboardModel.getType()) { + case TEXT: + case URI: + finish(CLIPBOARD_OVERLAY_SHARE_TAPPED, + IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext)); + break; + case IMAGE: + finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED, + IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext)); + break; } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java index 5fc19711a26c..8075d117a58a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java @@ -104,6 +104,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { @Mock private Animator mAnimator; + @Mock + private Animator mEndAnimator; private ArgumentCaptor mAnimatorListenerCaptor = ArgumentCaptor.forClass(Animator.AnimatorListener.class); @@ -123,7 +125,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); when(mClipboardOverlayView.getEnterAnimation()).thenReturn(mAnimator); - when(mClipboardOverlayView.getExitAnimation()).thenReturn(mAnimator); + when(mClipboardOverlayView.getExitAnimation()).thenReturn(mEndAnimator); when(mClipboardOverlayView.getFadeOutAnimation()).thenReturn(mAnimator); when(mClipboardOverlayWindow.getWindowInsets()).thenReturn( getImeInsets(new Rect(0, 0, 0, 0))); @@ -318,11 +320,11 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { mOverlayController.setClipData(mSampleClipData, ""); mCallbacks.onShareButtonTapped(); - verify(mAnimator).addListener(mAnimatorListenerCaptor.capture()); - mAnimatorListenerCaptor.getValue().onAnimationEnd(mAnimator); + verify(mEndAnimator).addListener(mAnimatorListenerCaptor.capture()); + mAnimatorListenerCaptor.getValue().onAnimationEnd(mEndAnimator); verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, ""); - verify(mClipboardOverlayView, times(1)).getFadeOutAnimation(); + verify(mClipboardOverlayView, times(1)).getExitAnimation(); } @Test @@ -343,8 +345,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { initController(); mCallbacks.onDismissButtonTapped(); - verify(mAnimator).addListener(mAnimatorListenerCaptor.capture()); - mAnimatorListenerCaptor.getValue().onAnimationEnd(mAnimator); + verify(mEndAnimator).addListener(mAnimatorListenerCaptor.capture()); + mAnimatorListenerCaptor.getValue().onAnimationEnd(mEndAnimator); // package name is null since we haven't actually set a source for this test verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, null); @@ -403,14 +405,18 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { mOverlayController.setClipData(mSampleClipData, "first.package"); mCallbacks.onShareButtonTapped(); + verify(mEndAnimator).addListener(mAnimatorListenerCaptor.capture()); + mAnimatorListenerCaptor.getValue().onAnimationEnd(mEndAnimator); mOverlayController.setClipData(mSampleClipData, "second.package"); mCallbacks.onShareButtonTapped(); + verify(mEndAnimator, times(2)).addListener(mAnimatorListenerCaptor.capture()); + mAnimatorListenerCaptor.getValue().onAnimationEnd(mEndAnimator); - verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "first.package"); - verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "second.package"); verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "first.package"); + verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "first.package"); verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "second.package"); + verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "second.package"); verifyNoMoreInteractions(mUiEventLogger); } -- GitLab From 5083e5833c94bbaba7bb9e4bdfc722085ab498f8 Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Wed, 25 Sep 2024 15:48:44 +0000 Subject: [PATCH 021/466] AudioService: remove SA state sync between BT profiles Remove the synchronization of Spatial Audio Settings (SA enabled, head tracking available/enabled) between Bluetooth A2DP and LE profiles for the same headset. It is not helpful for the user, does not match the BT headset market realility and was implemented with bugs. Bug: 365014132 Flag: EXEMPT bug fix Test: repro steps in bug with dual mode Bluetooth headset Change-Id: I6b013f73c4f18f7bb000203d1561306226c88cea --- .../java/com/android/server/audio/AudioDeviceInventory.java | 5 ----- .../core/java/com/android/server/audio/AudioService.java | 3 --- 2 files changed, 8 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index a9bff8bf4bc3..eacd62a99cf2 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -385,11 +385,6 @@ public class AudioDeviceInventory { || !updatedDevice.getDeviceAddress().equals(ads.getDeviceAddress())) { continue; } - if (mDeviceBroker.isSADevice(updatedDevice) == mDeviceBroker.isSADevice(ads)) { - ads.setHasHeadTracker(updatedDevice.hasHeadTracker()); - ads.setHeadTrackerEnabled(updatedDevice.isHeadTrackerEnabled()); - ads.setSAEnabled(updatedDevice.isSAEnabled()); - } ads.setAudioDeviceCategory(updatedDevice.getAudioDeviceCategory()); mDeviceBroker.postUpdatedAdiDeviceState(ads, false /*initSA*/); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index df69afe6ed79..e32ad638de15 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -10040,9 +10040,6 @@ public class AudioService extends IAudioService.Stub case MSG_INIT_SPATIALIZER: onInitSpatializer(); - // the device inventory can only be synchronized after the - // spatializer has been initialized - mDeviceBroker.postSynchronizeAdiDevicesInInventory(null); mAudioEventWakeLock.release(); break; -- GitLab From cff6f5a2caa3248480ee15f0fbb81eaa4413f007 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Mon, 9 Sep 2024 18:07:48 +0100 Subject: [PATCH 022/466] Cleanup dont_read_policy_definition flag It is a low risk bugfix and it has been in trunkfood for 4 weeks, entered trunkfood partial on 29 Aug 2024. Bug: 335663055 Test: TH Flag: EXEMPT flag cleanup Change-Id: I958de41bf6020f2ba240ac1c1562371038989007 --- core/java/android/app/admin/flags/flags.aconfig | 10 ---------- .../server/devicepolicy/DevicePolicyEngine.java | 13 ++++--------- .../android/server/devicepolicy/PolicyState.java | 13 ------------- 3 files changed, 4 insertions(+), 32 deletions(-) diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig index d9f886d41aa8..12f96e184a95 100644 --- a/core/java/android/app/admin/flags/flags.aconfig +++ b/core/java/android/app/admin/flags/flags.aconfig @@ -322,16 +322,6 @@ flag { } } -flag { - name: "dont_read_policy_definition" - namespace: "enterprise" - description: "Rely on to determine policy definition and ignore " - bug: "335663055" - metadata { - purpose: PURPOSE_BUGFIX - } -} - flag { name: "user_provisioning_same_state" namespace: "enterprise" diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java index 4beb6a8a3480..a58da81c6396 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java @@ -42,7 +42,6 @@ import android.app.admin.PolicyUpdateReceiver; import android.app.admin.PolicyValue; import android.app.admin.TargetUser; import android.app.admin.UserRestrictionPolicyKey; -import android.app.admin.flags.Flags; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -2100,17 +2099,13 @@ final class DevicePolicyEngine { String tag = parser.getName(); switch (tag) { case TAG_POLICY_KEY_ENTRY: - if (Flags.dontReadPolicyDefinition()) { - policyDefinition = PolicyDefinition.readFromXml(parser); - if (policyDefinition != null) { - policyKey = policyDefinition.getPolicyKey(); - } - } else { - policyKey = PolicyDefinition.readPolicyKeyFromXml(parser); + policyDefinition = PolicyDefinition.readFromXml(parser); + if (policyDefinition != null) { + policyKey = policyDefinition.getPolicyKey(); } break; case TAG_POLICY_STATE_ENTRY: - if (Flags.dontReadPolicyDefinition() && policyDefinition == null) { + if (policyDefinition == null) { Slogf.w(TAG, "Skipping policy state - unknown policy definition"); } else { policyState = PolicyState.readFromXml(policyDefinition, parser); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java index b81348969f7d..2277d684aa3f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java @@ -19,7 +19,6 @@ package com.android.server.devicepolicy; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.admin.PolicyValue; -import android.app.admin.flags.Flags; import android.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; @@ -298,18 +297,6 @@ final class PolicyState { + (value == null ? "null" : value)); } break; - case TAG_POLICY_DEFINITION_ENTRY: - if (Flags.dontReadPolicyDefinition()) { - // Should be passed by the caller. - Objects.requireNonNull(policyDefinition); - } else { - policyDefinition = PolicyDefinition.readFromXml(parser); - if (policyDefinition == null) { - Slogf.wtf(TAG, "Error Parsing TAG_POLICY_DEFINITION_ENTRY, " - + "PolicyDefinition is null"); - } - } - break; case TAG_RESOLVED_VALUE_ENTRY: if (policyDefinition == null) { -- GitLab From ba21f2518604c152f2bed61e89355e435f15cbc6 Mon Sep 17 00:00:00 2001 From: Alex Stetson Date: Wed, 25 Sep 2024 16:54:59 +0000 Subject: [PATCH 023/466] Use explicit user id for sensor privacy manager Recent changes to the SensorPrivacyManager will cause it to default to using the context user for these interactions, which will always be user 0 for SysUI. Therefore, the explicit user id needs to be specified. Bug: 366660154 Test: atest CtsSensorPrivacyTestCases:android.sensorprivacy.cts.SensorPrivacyMicrophoneTest Flag: NONE bugfix Change-Id: I725b2fda806020bd21075364fa52fc302a841249 --- .../systemui/dagger/ReferenceSystemUIModule.java | 5 +++-- .../IndividualSensorPrivacyControllerImpl.java | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 5c075c240caf..8261e5083a63 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -55,6 +55,7 @@ import com.android.systemui.rotationlock.RotationLockNewModule; import com.android.systemui.scene.SceneContainerFrameworkModule; import com.android.systemui.screenshot.ReferenceScreenshotModule; import com.android.systemui.settings.MultiUserUtilsModule; +import com.android.systemui.settings.UserTracker; import com.android.systemui.shade.NotificationShadeWindowControllerImpl; import com.android.systemui.shade.ShadeModule; import com.android.systemui.startable.Dependencies; @@ -176,9 +177,9 @@ public abstract class ReferenceSystemUIModule { @Provides @SysUISingleton static IndividualSensorPrivacyController provideIndividualSensorPrivacyController( - SensorPrivacyManager sensorPrivacyManager) { + SensorPrivacyManager sensorPrivacyManager, UserTracker userTracker) { IndividualSensorPrivacyController spC = new IndividualSensorPrivacyControllerImpl( - sensorPrivacyManager); + sensorPrivacyManager, userTracker); spC.init(); return spC; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java index da928a364984..3cf206643207 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/IndividualSensorPrivacyControllerImpl.java @@ -32,6 +32,7 @@ import android.util.SparseBooleanArray; import androidx.annotation.NonNull; import com.android.internal.camera.flags.Flags; +import com.android.systemui.settings.UserTracker; import com.android.systemui.util.ListenerSet; import java.util.Set; @@ -41,14 +42,17 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr private static final int[] SENSORS = new int[] {CAMERA, MICROPHONE}; private final @NonNull SensorPrivacyManager mSensorPrivacyManager; + private final @NonNull UserTracker mUserTracker; private final SparseBooleanArray mSoftwareToggleState = new SparseBooleanArray(); private final SparseBooleanArray mHardwareToggleState = new SparseBooleanArray(); private Boolean mRequiresAuthentication; private final ListenerSet mCallbacks = new ListenerSet<>(); public IndividualSensorPrivacyControllerImpl( - @NonNull SensorPrivacyManager sensorPrivacyManager) { + @NonNull SensorPrivacyManager sensorPrivacyManager, + @NonNull UserTracker userTracker) { mSensorPrivacyManager = sensorPrivacyManager; + mUserTracker = userTracker; } @Override @@ -94,12 +98,14 @@ public class IndividualSensorPrivacyControllerImpl implements IndividualSensorPr @Override public void setSensorBlocked(@Source int source, @Sensor int sensor, boolean blocked) { - mSensorPrivacyManager.setSensorPrivacyForProfileGroup(source, sensor, blocked); + mSensorPrivacyManager.setSensorPrivacyForProfileGroup(source, sensor, blocked, + mUserTracker.getUserId()); } @Override public void suppressSensorPrivacyReminders(int sensor, boolean suppress) { - mSensorPrivacyManager.suppressSensorPrivacyReminders(sensor, suppress); + mSensorPrivacyManager.suppressSensorPrivacyReminders(sensor, suppress, + mUserTracker.getUserId()); } @Override -- GitLab From 3f4da6bf735a159d1b48603a8f0661d0dcae5313 Mon Sep 17 00:00:00 2001 From: Shubang Lu Date: Wed, 25 Sep 2024 17:24:46 -0700 Subject: [PATCH 024/466] [TIAF] Fix ClassCastException of content rating Test: mmm Bug: 366132585 Flag: EXEMPT bugfix Change-Id: Iedc9decc4cb2516fd534ef62a26dd78af430155d --- .../media/tv/interactive/ITvInteractiveAppSessionWrapper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java index ec6c2bfab576..8e6297c3899d 100644 --- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java +++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionWrapper.java @@ -267,7 +267,9 @@ public class ITvInteractiveAppSessionWrapper break; } case DO_NOTIFY_CONTENT_BLOCKED: { - mSessionImpl.notifyContentBlocked((TvContentRating) msg.obj); + String contentRating = (String) msg.obj; + mSessionImpl.notifyContentBlocked( + TvContentRating.unflattenFromString(contentRating)); break; } case DO_NOTIFY_SIGNAL_STRENGTH: { -- GitLab From acc651b746c8e2e05131a3dc2fdcea05976e7e24 Mon Sep 17 00:00:00 2001 From: mattsziklay Date: Wed, 25 Sep 2024 18:09:41 -0700 Subject: [PATCH 025/466] Dismiss exclusion region when task is hidden. Previously we only dismissed gesture exclusion regions when a decor was closed. This meant the regions persisted when hiding the task or exiting desktop windowing, interfering with back gestures. Fix: 368697694 Test: Manual; line up 4 app headers on the left edge of the screen. Exit desktop and confirm back gesture still works in the previously occupied region. Flag: EXEMPT, bug fix Change-Id: I27afd66108121986bbe53e5d8cf5afdb1d506627 --- .../wm/shell/windowdecor/DesktopModeWindowDecoration.java | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 8a53f5ba4a51..99457d8436ff 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -461,6 +461,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration Date: Wed, 25 Sep 2024 11:24:51 +0800 Subject: [PATCH 026/466] Add notes comment for isBinderAlive API, to warn developers who use this should know the limit of this API. Change-Id: I365af33834cd2bf79487a185c7db743510abfe6c --- core/java/android/os/BinderProxy.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java index 80546cd6770f..3b5a99ed089a 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -493,6 +493,11 @@ public final class BinderProxy implements IBinder { public native boolean pingBinder(); /** + * Check to see if the process that the binder is in is still alive. + * + * Note, this only reflects the last known death state, if the object + * is linked to death or has made a transactions since the death occurs. + * * @return false if the hosting process is gone */ public native boolean isBinderAlive(); -- GitLab From fb1fc421bdfb5012f66f4d831c9e0521dac8fab0 Mon Sep 17 00:00:00 2001 From: Yuchen Date: Tue, 24 Sep 2024 08:19:58 +0000 Subject: [PATCH 027/466] [expressive design] Update Category layout. Also update style of preference. Test: visual Bug: 360916599 Flag: EXEMPT bug fix Change-Id: I2118bcb7359dabf19b0ed685c42b094cc005c392 --- .../spa/gallery/home/HomePageProvider.kt | 2 +- ...ategoryPage.kt => CategoryPageProvider.kt} | 26 +++---- .../spa/framework/theme/SettingsDimension.kt | 5 +- .../spa/framework/theme/SettingsShape.kt | 2 + .../spa/widget/preference/BaseLayout.kt | 37 +++++----- .../settingslib/spa/widget/ui/Category.kt | 74 +++++++++++++++---- 6 files changed, 95 insertions(+), 51 deletions(-) rename packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/{CategoryPage.kt => CategoryPageProvider.kt} (88%) diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt index b1558cce718a..c4058a02952c 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt @@ -27,8 +27,8 @@ import com.android.settingslib.spa.framework.common.createSettingsPage import com.android.settingslib.spa.framework.theme.SettingsTheme import com.android.settingslib.spa.gallery.R import com.android.settingslib.spa.gallery.SettingsPageProviderEnum -import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider import com.android.settingslib.spa.gallery.banner.BannerPageProvider +import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider import com.android.settingslib.spa.gallery.chart.ChartPageProvider import com.android.settingslib.spa.gallery.dialog.DialogMainPageProvider import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt similarity index 88% rename from packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt rename to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt index 7a1fad016d0e..aaeb22e33fe9 100644 --- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt +++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPageProvider.kt @@ -31,7 +31,6 @@ import com.android.settingslib.spa.widget.preference.PreferenceModel import com.android.settingslib.spa.widget.preference.SimplePreferenceMacro import com.android.settingslib.spa.widget.scaffold.RegularScaffold import com.android.settingslib.spa.widget.ui.Category -import com.android.settingslib.spa.widget.ui.CategoryTitle private const val TITLE = "Sample Category" @@ -42,10 +41,12 @@ object CategoryPageProvider : SettingsPageProvider { fun buildInjectEntry(): SettingsEntryBuilder { return SettingsEntryBuilder.createInject(owner) .setUiLayoutFn { - Preference(object : PreferenceModel { - override val title = TITLE - override val onClick = navigator(name) - }) + Preference( + object : PreferenceModel { + override val title = TITLE + override val onClick = navigator(name) + } + ) } .setSearchDataFn { EntrySearchData(title = TITLE) } } @@ -70,7 +71,6 @@ object CategoryPageProvider : SettingsPageProvider { SettingsEntryBuilder.create("Preference 3", owner) .setMacro { SimplePreferenceMacro(title = "Preference 2", summary = "Summary 3") } .build() - ) entryList.add( SettingsEntryBuilder.create("Preference 4", owner) @@ -84,11 +84,11 @@ object CategoryPageProvider : SettingsPageProvider { override fun Page(arguments: Bundle?) { val entries = buildEntry(arguments) RegularScaffold(title = getTitle(arguments)) { - CategoryTitle("Category A") - entries[0].UiLayout() - entries[1].UiLayout() - - Category("Category B") { + Category("Category A") { + entries[0].UiLayout() + entries[1].UiLayout() + } + Category { entries[2].UiLayout() entries[3].UiLayout() } @@ -99,7 +99,5 @@ object CategoryPageProvider : SettingsPageProvider { @Preview(showBackground = true) @Composable private fun SpinnerPagePreview() { - SettingsTheme { - SpinnerPageProvider.Page(null) - } + SettingsTheme { CategoryPageProvider.Page(null) } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt index f8c791aab0d0..ab95162fb142 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt @@ -24,6 +24,7 @@ object SettingsDimension { val paddingExtraSmall = 4.dp val paddingSmall = if (isSpaExpressiveEnabled) 8.dp else 4.dp val paddingExtraSmall5 = 10.dp + val paddingExtraSmall6 = 12.dp val paddingLarge = 16.dp val paddingExtraLarge = 24.dp @@ -36,9 +37,9 @@ object SettingsDimension { val itemIconSize = 24.dp val itemIconContainerSize = 72.dp - val itemPaddingStart = paddingExtraLarge + val itemPaddingStart = if (isSpaExpressiveEnabled) paddingLarge else paddingExtraLarge val itemPaddingEnd = paddingLarge - val itemPaddingVertical = paddingLarge + val itemPaddingVertical = if (isSpaExpressiveEnabled) paddingExtraSmall6 else paddingLarge val itemPadding = PaddingValues( start = itemPaddingStart, top = itemPaddingVertical, diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt index f7c5414a420c..c78771566f64 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt @@ -24,5 +24,7 @@ object SettingsShape { val CornerMedium = RoundedCornerShape(12.dp) + val categoryCorner = RoundedCornerShape(20.dp) + val CornerExtraLarge = RoundedCornerShape(28.dp) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt index 23a8e78e6c4a..c68ec78b1ba6 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/BaseLayout.kt @@ -16,6 +16,7 @@ package com.android.settingslib.spa.widget.preference +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -25,16 +26,20 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsOpacity.alphaForEnabled +import com.android.settingslib.spa.framework.theme.SettingsShape import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled import com.android.settingslib.spa.widget.ui.SettingsTitle @Composable @@ -51,10 +56,17 @@ internal fun BaseLayout( widget: @Composable () -> Unit = {}, ) { Row( - modifier = modifier - .fillMaxWidth() - .semantics(mergeDescendants = true) {} - .padding(end = paddingEnd), + modifier = + modifier + .fillMaxWidth() + .semantics(mergeDescendants = true) {} + .then( + if (isSpaExpressiveEnabled) + Modifier.clip(SettingsShape.CornerExtraSmall) + .background(MaterialTheme.colorScheme.surfaceBright) + else Modifier + ) + .padding(end = paddingEnd), verticalAlignment = Alignment.CenterVertically, ) { val alphaModifier = Modifier.alphaForEnabled(enabled()) @@ -63,20 +75,14 @@ internal fun BaseLayout( title = title, titleContentDescription = titleContentDescription, subTitle = subTitle, - modifier = alphaModifier - .weight(1f) - .padding(vertical = paddingVertical), + modifier = alphaModifier.weight(1f).padding(vertical = paddingVertical), ) widget() } } @Composable -internal fun BaseIcon( - icon: @Composable (() -> Unit)?, - modifier: Modifier, - paddingStart: Dp, -) { +internal fun BaseIcon(icon: @Composable (() -> Unit)?, modifier: Modifier, paddingStart: Dp) { if (icon != null) { Box( modifier = modifier.size(SettingsDimension.itemIconContainerSize), @@ -107,11 +113,6 @@ private fun Titles( @Composable private fun BaseLayoutPreview() { SettingsTheme { - BaseLayout( - title = "Title", - subTitle = { - HorizontalDivider(thickness = 10.dp) - } - ) + BaseLayout(title = "Title", subTitle = { HorizontalDivider(thickness = 10.dp) }) } } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt index 48cd145da124..6c5581fb4b50 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Category.kt @@ -16,9 +16,13 @@ package com.android.settingslib.spa.widget.ui +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.TouchApp import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -27,25 +31,31 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.android.settingslib.spa.framework.theme.SettingsDimension +import com.android.settingslib.spa.framework.theme.SettingsShape import com.android.settingslib.spa.framework.theme.SettingsTheme +import com.android.settingslib.spa.framework.theme.isSpaExpressiveEnabled +import com.android.settingslib.spa.widget.preference.Preference +import com.android.settingslib.spa.widget.preference.PreferenceModel -/** - * A category title that is placed before a group of similar items. - */ +/** A category title that is placed before a group of similar items. */ @Composable fun CategoryTitle(title: String) { Text( text = title, - modifier = Modifier.padding( - start = SettingsDimension.itemPaddingStart, - top = 20.dp, - end = SettingsDimension.itemPaddingEnd, - bottom = 8.dp, - ), + modifier = + Modifier.padding( + start = SettingsDimension.itemPaddingStart, + top = 20.dp, + end = + if (isSpaExpressiveEnabled) SettingsDimension.paddingSmall + else SettingsDimension.itemPaddingEnd, + bottom = 8.dp, + ), color = MaterialTheme.colorScheme.primary, style = MaterialTheme.typography.labelMedium, ) @@ -56,14 +66,31 @@ fun CategoryTitle(title: String) { * visually separates groups of items. */ @Composable -fun Category(title: String, content: @Composable ColumnScope.() -> Unit) { - Column { +fun Category(title: String? = null, content: @Composable ColumnScope.() -> Unit) { + Column( + modifier = + if (isSpaExpressiveEnabled) + Modifier.padding( + horizontal = SettingsDimension.paddingLarge, + vertical = SettingsDimension.paddingSmall, + ) + else Modifier + ) { var displayTitle by remember { mutableStateOf(false) } - if (displayTitle) CategoryTitle(title = title) + if (title != null && displayTitle) CategoryTitle(title = title) Column( - modifier = Modifier.onGloballyPositioned { coordinates -> - displayTitle = coordinates.size.height > 0 - }, + modifier = + Modifier.onGloballyPositioned { coordinates -> + displayTitle = coordinates.size.height > 0 + } + .then( + if (isSpaExpressiveEnabled) + Modifier.fillMaxWidth().clip(SettingsShape.categoryCorner) + else Modifier + ), + verticalArrangement = + if (isSpaExpressiveEnabled) Arrangement.spacedBy(SettingsDimension.paddingTiny) + else Arrangement.Top, content = content, ) } @@ -73,6 +100,21 @@ fun Category(title: String, content: @Composable ColumnScope.() -> Unit) { @Composable private fun CategoryPreview() { SettingsTheme { - CategoryTitle("Appearance") + Category("Appearance") { + Preference( + object : PreferenceModel { + override val title = "Title" + override val summary = { "Summary" } + } + ) + Preference( + object : PreferenceModel { + override val title = "Title" + override val summary = { "Summary" } + override val icon = + @Composable { SettingsIcon(imageVector = Icons.Outlined.TouchApp) } + } + ) + } } } -- GitLab From 091882d75e206e97b9277541a85c28f0c1565dc6 Mon Sep 17 00:00:00 2001 From: Ioana Alexandru Date: Wed, 25 Sep 2024 18:24:09 +0200 Subject: [PATCH 028/466] Verify that params passed to NotifActivityStarter are not null Bug: 369599778 Test: builds, existing tests pass Flag: EXEMPT logging only (but could crash development) Change-Id: I1bd051d114a955f11e26cf70a80c4c3b96378024 --- .../phone/StatusBarNotificationActivityStarter.java | 9 +++++++++ .../util/kotlin/{nullability.kt => Nullability.kt} | 12 ++++++++++++ 2 files changed, 21 insertions(+) rename packages/SystemUI/src/com/android/systemui/util/kotlin/{nullability.kt => Nullability.kt} (67%) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index ee961955df39..93db2db918b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -20,6 +20,7 @@ import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED import static android.service.notification.NotificationListenerService.REASON_CLICK; import static com.android.systemui.statusbar.phone.CentralSurfaces.getActivityOptions; +import static com.android.systemui.util.kotlin.NullabilityKt.expectNotNull; import android.app.ActivityManager; import android.app.ActivityOptions; @@ -112,6 +113,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit boolean showOverTheLockScreen); } + private final static String TAG = "StatusBarNotificationActivityStarter"; + private final Context mContext; private final int mDisplayId; @@ -229,6 +232,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit */ @Override public void onNotificationBubbleIconClicked(NotificationEntry entry) { + expectNotNull(TAG, "entry", entry); Runnable action = () -> { mBubblesManagerOptional.ifPresent(bubblesManager -> bubblesManager.onUserChangedBubble(entry, !entry.isBubble())); @@ -255,6 +259,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit */ @Override public void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row) { + expectNotNull(TAG, "entry", entry); + expectNotNull(TAG, "row", row); mLogger.logStartingActivityFromClick(entry, row.isHeadsUpState(), mKeyguardStateController.isVisible(), mNotificationShadeWindowController.getPanelExpanded()); @@ -437,6 +443,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit */ @Override public void onDragSuccess(NotificationEntry entry) { + expectNotNull(TAG, "entry", entry); // this method is not responsible for intent sending. // will focus follow operation only after drag-and-drop that notification. final NotificationVisibility nv = mVisibilityProvider.obtain(entry, true); @@ -529,6 +536,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit @Override public void startNotificationGutsIntent(final Intent intent, final int appUid, ExpandableNotificationRow row) { + expectNotNull(TAG, "intent", intent); + expectNotNull(TAG, "row", row); boolean animate = mActivityStarter.shouldAnimateLaunch(true /* isActivityIntent */); ActivityStarter.OnDismissAction onDismissAction = new ActivityStarter.OnDismissAction() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Nullability.kt similarity index 67% rename from packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt rename to packages/SystemUI/src/com/android/systemui/util/kotlin/Nullability.kt index 298dacde8128..1c760bedff58 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Nullability.kt @@ -16,6 +16,7 @@ package com.android.systemui.util.kotlin +import android.util.Log import java.util.Optional /** @@ -28,3 +29,14 @@ inline fun transform(value: T?, block: (T) -> R): R? = value?.let(b */ @Suppress("NOTHING_TO_INLINE") inline fun Optional.getOrNull(): T? = orElse(null) + +/** + * Utility method to check if a value that is technically nullable is actually null. If it is null, + * this will crash development builds (but just log on production/droidfood builds). It can be used + * as a first step to verify if a nullable value can be made non-nullable instead. + */ +fun expectNotNull(logTag: String, name: String, nullable: T?) { + if (nullable == null) { + Log.wtf(logTag, "Expected value of $name to not be null.") + } +} -- GitLab From 93ce895530cd0917865d1ebc607e32cc1284685b Mon Sep 17 00:00:00 2001 From: Garvita Jain Date: Thu, 26 Sep 2024 11:58:28 +0000 Subject: [PATCH 029/466] Update documentation for non-visible downloads. All downloads which have set non-visible destination URIs are cleaned up if they are not touched in the last 7 days. Change-Id: If973b814b8a22f3a01eb571fa3a00e249f74f2a9 BUG: 259023742 Flag: EXEMPT docs only --- core/java/android/app/DownloadManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index b781ce50c4db..f21c3e8d44d6 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -493,6 +493,9 @@ public class DownloadManager { * {@link Environment#getExternalStoragePublicDirectory(String)} with * {@link Environment#DIRECTORY_DOWNLOADS}). * + * All non-visible downloads that are not modified in the last 7 days will be deleted during + * idle runs. + * * @param uri a file {@link Uri} indicating the destination for the downloaded file. * @return this object */ @@ -796,7 +799,9 @@ public class DownloadManager { * public Downloads directory (as returned by * {@link Environment#getExternalStoragePublicDirectory(String)} with * {@link Environment#DIRECTORY_DOWNLOADS}) will be visible in system's Downloads UI - * and the rest will not be visible. + * and the rest will not be visible. All non-visible downloads that are not modified + * in the last 7 days will be deleted during idle runs. + * * (e.g. {@link Context#getExternalFilesDir(String)}) will not be visible. */ @Deprecated -- GitLab From b9625b33c2c4b29991bfef88a9e97d75c06f07c0 Mon Sep 17 00:00:00 2001 From: tanxiaoyan Date: Thu, 26 Sep 2024 17:47:26 +0800 Subject: [PATCH 030/466] Don't associate starting data with task when the fixed rotation started for AE Bug:369522908 If the launching activity has the fixed rotation transform. Even if isEmbedded Activity, the surface of starting window should remain in activity to follow the rotation transform from activity. Otherwise the starting window will show in different orientation. Change-Id: I0ec67a7eea905b8fa7e4cdd2bf12005c5fa91b16 Signed-off-by: tanxiaoyan --- services/core/java/com/android/server/wm/Task.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index eee282122792..49086af0d513 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1469,7 +1469,7 @@ class Task extends TaskFragment { // The starting window should keep covering its task when a pure TaskFragment is added // because its bounds may not fill the task. final ActivityRecord top = getTopMostActivity(); - if (top != null) { + if (top != null && !top.hasFixedRotationTransform()) { top.associateStartingWindowWithTaskIfNeeded(); } } -- GitLab From bdb5053443f7e0407d86f807d734f372c37a7a0e Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Thu, 26 Sep 2024 15:33:22 +0000 Subject: [PATCH 031/466] Cleanup backup_service_security_log_event_enabled Flag was rolled out in V. Keeping flag definition since it is exported Bug: 335663055 Test: TH Flag: EXEMPT flag cleanup (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1143776ca208c9ff843b17ea48c0da6f383963da) Merged-In: I0d8074d3fb82cbcbe68b2436261a1741f77f9d9f Change-Id: I0d8074d3fb82cbcbe68b2436261a1741f77f9d9f --- core/api/current.txt | 2 +- core/java/android/app/admin/SecurityLog.java | 4 ---- core/java/android/app/admin/flags/flags.aconfig | 2 ++ .../server/devicepolicy/DevicePolicyManagerService.java | 8 +++----- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 9881a90ff003..d798a7497d5e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8596,7 +8596,7 @@ package android.app.admin { field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452 field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451 field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455 - field @FlaggedApi("android.app.admin.flags.backup_service_security_log_event_enabled") public static final int TAG_BACKUP_SERVICE_TOGGLED = 210044; // 0x3347c + field public static final int TAG_BACKUP_SERVICE_TOGGLED = 210044; // 0x3347c field public static final int TAG_BLUETOOTH_CONNECTION = 210039; // 0x33477 field public static final int TAG_BLUETOOTH_DISCONNECTION = 210040; // 0x33478 field public static final int TAG_CAMERA_POLICY_SET = 210034; // 0x33472 diff --git a/core/java/android/app/admin/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java index 477f2e007b33..beb93fd079d9 100644 --- a/core/java/android/app/admin/SecurityLog.java +++ b/core/java/android/app/admin/SecurityLog.java @@ -16,10 +16,7 @@ package android.app.admin; -import static android.app.admin.flags.Flags.FLAG_BACKUP_SERVICE_SECURITY_LOG_EVENT_ENABLED; - import android.Manifest; -import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -611,7 +608,6 @@ public class SecurityLog { *

  • [2] backup service state ({@code Integer}, 1 for enabled, 0 for disabled) * @see DevicePolicyManager#setBackupServiceEnabled(ComponentName, boolean) */ - @FlaggedApi(FLAG_BACKUP_SERVICE_SECURITY_LOG_EVENT_ENABLED) public static final int TAG_BACKUP_SERVICE_TOGGLED = SecurityLogTags.SECURITY_BACKUP_SERVICE_TOGGLED; /** diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig index ff66e0fbc76d..7a615b27686a 100644 --- a/core/java/android/app/admin/flags/flags.aconfig +++ b/core/java/android/app/admin/flags/flags.aconfig @@ -146,6 +146,7 @@ flag { bug: "293441361" } +# Fully rolled out and must not be used. flag { name: "assist_content_user_restriction_enabled" is_exported: true @@ -164,6 +165,7 @@ flag { } } +# Fully rolled out and must not be used. flag { name: "backup_service_security_log_event_enabled" is_exported: true diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f1d858fa1f6c..cc780132e0f5 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -18578,11 +18578,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { toggleBackupServiceActive(caller.getUserId(), enabled); - if (Flags.backupServiceSecurityLogEventEnabled()) { - if (SecurityLog.isLoggingEnabled()) { - SecurityLog.writeEvent(SecurityLog.TAG_BACKUP_SERVICE_TOGGLED, - caller.getPackageName(), caller.getUserId(), enabled ? 1 : 0); - } + if (SecurityLog.isLoggingEnabled()) { + SecurityLog.writeEvent(SecurityLog.TAG_BACKUP_SERVICE_TOGGLED, + caller.getPackageName(), caller.getUserId(), enabled ? 1 : 0); } } -- GitLab From 13d38508552588d4796981509d995542963b31a2 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Fri, 20 Sep 2024 11:08:56 -0700 Subject: [PATCH 032/466] Move config-at-end seamless-flip to activity-level The current setup was made to sorta match pip1 in the sense that the config-at-end task and activity surfaces remain untouched and shell does a "forward" animation (ie. it animates from identity to a transformed state) and then WM flips the content and the surface transform together at the *end* of the animation. The issue, here, is that it means there is a period of time where WM is manipulating surfaces (Task-level) that Shell technically "owns" and without any synchronization mechanism: this means shell can't synchronize updates to it's overlay and also must somehow prevent user interaction with the surface while WM is messing with it; however, WM never tells Shell when it is done. Instead of making the sync/communication more complicated (and error-prone), we move the content/transform-flipping to the Activity-level (which WM "owns"). This changes the dynamics such that shell is now responsible for a "catch-up" animation (ie. animating from a "reverse transformed" state into the current state). The benefits are: * Works like other transitions now (which also do catch-up). * WM only manipulates surfaces that it "owns" * Synchronization is now only on start (like other transitions). * No need to bubble-up CONFIG_AT_END flag. We still keep the old behavior for activity-level because there's really no other way to do it -- but activity-level doesn't have the same issues as task because it is only loaned to shell for the animation. Bug: 202201326 Test: atest TransitionTests#testConfigAtEnd Flag: com.android.wm.shell.enable_pip2 Change-Id: Ice26e2414772555fae577ce517a8892634e716da --- .../android/wm/shell/common/pip/PipUtils.kt | 84 +++++++++++- .../com/android/server/wm/Transition.java | 122 +++++++++++------- .../android/server/wm/TransitionTests.java | 10 +- 3 files changed, 158 insertions(+), 58 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt index 7070ce99b24c..b3491baa629d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipUtils.kt @@ -22,6 +22,7 @@ import android.app.WindowConfiguration import android.content.ComponentName import android.content.Context import android.content.pm.PackageManager +import android.graphics.PointF import android.graphics.Rect import android.os.RemoteException import android.util.DisplayMetrics @@ -29,10 +30,13 @@ import android.util.Log import android.util.Pair import android.util.TypedValue import android.window.TaskSnapshot +import android.window.TransitionInfo import com.android.internal.protolog.ProtoLog import com.android.wm.shell.Flags import com.android.wm.shell.protolog.ShellProtoLogGroup import kotlin.math.abs +import kotlin.math.ceil +import kotlin.math.floor import kotlin.math.roundToInt /** A class that includes convenience methods. */ @@ -163,6 +167,84 @@ object PipUtils { return Rect(left, top, left + width, top + height) } + /** + * Temporary rounding "outward" (ie. -1.2 -> -2) used for crop since it is an int. We lean + * outward since, usually, child surfaces are, themselves, cropped, so we'd prefer to avoid + * inadvertently cutting out content that would otherwise be visible. + */ + private fun roundOut(`val`: Float): Int { + return (if (`val` >= 0f) ceil(`val`) else floor(`val`)).toInt() + } + + /** + * Calculates the transform and crop to apply on a Task surface in order for the config-at-end + * activity inside it (original-size activity transformed to match it's hint rect to the final + * Task bounds) to occupy the same world-space position/dimensions as it had before the + * transition. + * + * Usage example: + * calcStartTransform(pipChange, scale, pos, crop); + * t.setScale(pipChange.getLeash(), scale.x, scale.y); + * t.setPosition(pipChange.getLeash(), pos.x, pos.y); + * t.setCrop(pipChange.getLeash(), crop); + */ + @JvmStatic + fun calcStartTransform(pipChange: TransitionInfo.Change, outScale: PointF, + outPos: PointF, outCrop: Rect) { + val startBounds = pipChange.startAbsBounds + val taskEndBounds = pipChange.endAbsBounds + // For now, pip activity bounds always matches task bounds. If this ever changes, we'll + // need to get the activity offset. + val endBounds = taskEndBounds + var hintRect = pipChange.taskInfo?.pictureInPictureParams?.sourceRectHint + if (hintRect == null) { + hintRect = Rect(startBounds) + hintRect.offsetTo(0, 0) + } + + // FA = final activity bounds (absolute) + // FT = final task bounds (absolute) + // SA = start activity bounds (absolute) + // H = source hint (relative to start activity bounds) + // We want to transform the activity so that when the task is at FT, H overlaps with FA + + // The scaling which takes the hint rect (H) in SA and matches it to FA + val hintToEndScaleX = (endBounds.width().toFloat()) / (hintRect.width().toFloat()) + val hintToEndScaleY = (endBounds.height().toFloat()) / (hintRect.height().toFloat()) + + // We want to set the transform on the END TASK surface to put the start activity + // back to where it was. + // First do backwards scale (which takes FA back to H) + val endToHintScaleX = 1f / hintToEndScaleX + val endToHintScaleY = 1f / hintToEndScaleY + // Then top-left needs to place FA (relative to the FT) at H (relative to SA): + // so -(FA.tl - FT.tl) + SA.tl + H.tl + // but we have scaled up the task, so anything that was "within" the task needs to + // be scaled: + // so -(FA.tl - FT.tl)*endToHint + SA.tl + H.tl + val endTaskPosForStartX = (-(endBounds.left - taskEndBounds.left) * endToHintScaleX + + startBounds.left + hintRect.left) + val endTaskPosForStartY = (-(endBounds.top - taskEndBounds.top) * endToHintScaleY + + startBounds.top + hintRect.top) + outScale[endToHintScaleX] = endToHintScaleY + outPos[endTaskPosForStartX] = endTaskPosForStartY + + // now need to set crop to reveal the non-hint stuff. Again, hintrect is relative, so + // we must apply outsets to reveal the *activity* content which is *inside* the task + // and thus is scaled (ie. if activity is scaled down, each task-level pixel exposes + // >1 activity-level pixels) + // For example, the topleft crop would be: + // (FA.tl - FT.tl) - H.tl * hintToEnd + // ^ activity within task + // bottomright can just use scaled activity size + // tl + scale(SA.size, hintToEnd) + outCrop.left = roundOut((endBounds.left - taskEndBounds.left) + - hintRect.left * hintToEndScaleX) + outCrop.top = roundOut((endBounds.top - taskEndBounds.top) - hintRect.top * hintToEndScaleY) + outCrop.right = roundOut(outCrop.left + startBounds.width() * hintToEndScaleX) + outCrop.bottom = roundOut(outCrop.top + startBounds.height() * hintToEndScaleY) + } + private var isPip2ExperimentEnabled: Boolean? = null /** @@ -181,4 +263,4 @@ object PipUtils { } return isPip2ExperimentEnabled as Boolean } -} \ No newline at end of file +} diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java index 2451ca87c3c7..d4d6e659498f 100644 --- a/services/core/java/com/android/server/wm/Transition.java +++ b/services/core/java/com/android/server/wm/Transition.java @@ -556,8 +556,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { snapshotStartState(ar); mChanges.get(ar).mFlags |= ChangeInfo.FLAG_CHANGE_CONFIG_AT_END; }); - snapshotStartState(wc); - mChanges.get(wc).mFlags |= ChangeInfo.FLAG_CHANGE_CONFIG_AT_END; } /** Set a transition to be a seamless-rotation. */ @@ -1083,7 +1081,8 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // For config-at-end, the end-transform will be reset after the config is actually // applied in the client (since the transform depends on config). The other properties // remain here because shell might want to persistently override them. - if ((mTargets.get(i).mFlags & ChangeInfo.FLAG_CHANGE_CONFIG_AT_END) == 0) { + if (target.asActivityRecord() == null + || (mTargets.get(i).mFlags & ChangeInfo.FLAG_CHANGE_CONFIG_AT_END) == 0) { resetSurfaceTransform(t, target, targetLeash); } } @@ -1564,46 +1563,33 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { if (mConfigAtEndActivities == null || mConfigAtEndActivities.isEmpty()) { return; } - final SurfaceControl.Transaction t = - mController.mAtm.mWindowManager.mTransactionFactory.get(); - for (int i = 0; i < mTargets.size(); ++i) { - final WindowContainer target = mTargets.get(i).mContainer; - if (target.getParent() == null || (mTargets.get(i).mFlags - & ChangeInfo.FLAG_CHANGE_CONFIG_AT_END) == 0) { - continue; + // Now resume the configuration dispatch, wait until the now resumed configs have been + // drawn, and then apply everything together. Any activities that are already in an + // active sync will remain on that sync instead of the new one. + int syncId = -1; + for (int i = 0; i < mConfigAtEndActivities.size(); ++i) { + final ActivityRecord target = mConfigAtEndActivities.get(i); + final SurfaceControl targetLeash = target.getSurfaceControl(); + if (target.getSyncGroup() == null || target.getSyncGroup().isIgnoring(target)) { + if (syncId < 0) { + final BLASTSyncEngine.SyncGroup sg = mSyncEngine.prepareSyncSet( + (mSyncId, transaction) -> transaction.apply(), + "ConfigAtTransitEnd"); + syncId = sg.mSyncId; + mSyncEngine.startSyncSet(sg, BLAST_TIMEOUT_DURATION, true /* parallel */); + mSyncEngine.setSyncMethod(syncId, BLASTSyncEngine.METHOD_BLAST); + } + mSyncEngine.addToSyncSet(syncId, target); } - final SurfaceControl targetLeash = getLeashSurface(target, null /* t */); // Reset surface state here (since it was skipped in buildFinishTransaction). Since // we are resuming config to the "current" state, we have to calculate the matching // surface state now (rather than snapshotting it at animation start). - resetSurfaceTransform(t, target, targetLeash); - } - - // Now we resume the configuration dispatch, wait until the now resumed configs have been - // drawn, and then apply everything together. - final BLASTSyncEngine.SyncGroup sg = mSyncEngine.prepareSyncSet( - new BLASTSyncEngine.TransactionReadyListener() { - @Override - public void onTransactionReady(int mSyncId, - SurfaceControl.Transaction transaction) { - t.merge(transaction); - t.apply(); - } - - @Override - public void onTransactionCommitTimeout() { - t.apply(); - } - }, "ConfigAtTransitEnd"); - final int syncId = sg.mSyncId; - mSyncEngine.startSyncSet(sg, BLAST_TIMEOUT_DURATION, true /* parallel */); - mSyncEngine.setSyncMethod(syncId, BLASTSyncEngine.METHOD_BLAST); - for (int i = 0; i < mConfigAtEndActivities.size(); ++i) { - final ActivityRecord ar = mConfigAtEndActivities.get(i); - mSyncEngine.addToSyncSet(syncId, ar); - ar.resumeConfigurationDispatch(); + resetSurfaceTransform(target.getSyncTransaction(), target, targetLeash); + target.resumeConfigurationDispatch(); + } + if (syncId >= 0) { + mSyncEngine.setReady(syncId); } - mSyncEngine.setReady(syncId); } @Nullable @@ -1718,6 +1704,54 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { change.mFlags |= ChangeInfo.FLAG_CHANGE_NO_ANIMATION; } + void prepareConfigAtEnd(SurfaceControl.Transaction transact, ArrayList targets) { + if (mConfigAtEndActivities == null) return; + for (int i = 0; i < mConfigAtEndActivities.size(); ++i) { + final ActivityRecord ar = mConfigAtEndActivities.get(i); + if (!ar.isVisibleRequested()) continue; + final SurfaceControl sc = ar.getSurfaceControl(); + if (sc == null) continue; + final Task task = ar.getTask(); + if (task == null) continue; + // If task isn't animating, then it means shell is animating activity directly (within + // task), so don't do any setup. + if (!containsChangeFor(task, targets)) continue; + final ChangeInfo change = mChanges.get(ar); + final Rect startBounds = change.mAbsoluteBounds; + Rect hintRect = null; + if (ar.getWindowingMode() == WINDOWING_MODE_PINNED && ar.pictureInPictureArgs != null + && ar.pictureInPictureArgs.getSourceRectHint() != null) { + hintRect = ar.pictureInPictureArgs.getSourceRectHint(); + } + if (hintRect == null) { + hintRect = new Rect(startBounds); + hintRect.offsetTo(0, 0); + } + final Rect endBounds = ar.getBounds(); + final Rect taskEndBounds = task.getBounds(); + // FA = final activity bounds (absolute) + // FT = final task bounds (absolute) + // SA = start activity bounds (absolute) + // H = source hint (relative to start activity bounds) + // We want to transform the activity so that when the task is at FT, H overlaps with FA + + // This scales the activity such that the hint rect has the same dimensions + // as the final activity bounds. + float hintToEndScaleX = ((float) endBounds.width()) / ((float) hintRect.width()); + float hintToEndScaleY = ((float) endBounds.height()) / ((float) hintRect.height()); + // top-left needs to be (FA.tl - FT.tl) - H.tl * hintToEnd . H is relative to the + // activity; so, for example, if shrinking H to FA (hintToEnd < 1), then the tl of the + // shrunk SA is closer to H than expected, so we need to reduce how much we offset SA + // to get H.tl to match. + float startActPosInTaskEndX = + (endBounds.left - taskEndBounds.left) - hintRect.left * hintToEndScaleX; + float startActPosInTaskEndY = + (endBounds.top - taskEndBounds.top) - hintRect.top * hintToEndScaleY; + transact.setScale(sc, hintToEndScaleX, hintToEndScaleY); + transact.setPosition(sc, startActPosInTaskEndX, startActPosInTaskEndY); + } + } + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) static boolean containsChangeFor(WindowContainer wc, ArrayList list) { for (int i = list.size() - 1; i >= 0; --i) { @@ -1799,6 +1833,7 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { // Resolve the animating targets from the participants. mTargets = calculateTargets(mParticipants, mChanges); + prepareConfigAtEnd(transaction, mTargets); // Check whether the participants were animated from back navigation. mController.mAtm.mBackNavigationController.onTransactionReady(this, mTargets, @@ -2648,9 +2683,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } else { parentChange.mFlags |= ChangeInfo.FLAG_CHANGE_YES_ANIMATION; } - if ((targetChange.mFlags & ChangeInfo.FLAG_CHANGE_CONFIG_AT_END) != 0) { - parentChange.mFlags |= ChangeInfo.FLAG_CHANGE_CONFIG_AT_END; - } } } @@ -2742,14 +2774,6 @@ class Transition implements BLASTSyncEngine.TransactionReadyListener { } else { intermediates.add(parentChange); } - // for config-at-end, we want to promote the flag based on the end-state even - // if the activity was reparented because it operates after the animation. So, - // check that here since the promote code skips reparents. - if ((targetChange.mFlags & ChangeInfo.FLAG_CHANGE_CONFIG_AT_END) != 0 - && targetChange.mContainer.asActivityRecord() != null - && targetChange.mContainer.getParent() == p) { - parentChange.mFlags |= ChangeInfo.FLAG_CHANGE_CONFIG_AT_END; - } foundParentInTargets = true; break; } else if (reportIfNotTop(p) && !skipIntermediateReports) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java index 064b434e1a6b..5b3fd53b197c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java @@ -34,7 +34,6 @@ import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_BACK; -import static android.window.TransitionInfo.FLAG_CONFIG_AT_END; import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL; import static android.window.TransitionInfo.FLAG_FILLS_TASK; import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY; @@ -2935,9 +2934,6 @@ public class TransitionTests extends WindowTestsBase { controller.requestStartTransition(transit, task, null, null); player.start(); assertTrue(activity.isConfigurationDispatchPaused()); - // config-at-end flag must propagate up to task if activity was promoted. - assertTrue(player.mLastReady.getChange( - task.mRemoteToken.toWindowContainerToken()).hasFlags(FLAG_CONFIG_AT_END)); player.finish(); assertFalse(activity.isConfigurationDispatchPaused()); } @@ -2966,11 +2962,9 @@ public class TransitionTests extends WindowTestsBase { controller.requestStartTransition(transit, task, null, null); player.start(); - // config-at-end flag must propagate up to task even when reparented (since config-at-end - // only cares about after-end state). - assertTrue(player.mLastReady.getChange( - task.mRemoteToken.toWindowContainerToken()).hasFlags(FLAG_CONFIG_AT_END)); + assertTrue(activity.isConfigurationDispatchPaused()); player.finish(); + assertFalse(activity.isConfigurationDispatchPaused()); } @Test -- GitLab From 73c182037e115e2a4c7b5216edb98522943447f0 Mon Sep 17 00:00:00 2001 From: Ikram Gabiyev Date: Tue, 24 Sep 2024 14:43:14 -0700 Subject: [PATCH 033/466] Refactor swipe-pip-to-home transition With the defer config dispatch till transition end redesign applying transforms on activities instead of task leashes in Core, we can drastically simplify Shell code for handling TRANSIT_PIP jumpcut transition at the end of swipe PiP to home CUJ. We can also re-enable PiP interaction earlier since there is no need to wait for app draws through TransactionCommittedListener. Bug: 202201326 Flag: com.android.wm.shell.enable_pip2 Test: atest PinnedStackTests Change-Id: I147fbf7d0878a9fbec28fcbc9dd3051a5cd7558f --- .../wm/shell/pip2/phone/PipTransition.java | 58 +++++-------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index f93233ec7461..a78cb7e2e39a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -303,54 +303,28 @@ public class PipTransition extends PipTransitionController implements if (pipChange == null) { return false; } - WindowContainerToken pipTaskToken = pipChange.getContainer(); SurfaceControl pipLeash = pipChange.getLeash(); + Preconditions.checkNotNull(pipLeash, "Leash is null for swipe-up transition."); - if (pipTaskToken == null || pipLeash == null) { - return false; - } - - SurfaceControl overlayLeash = mPipTransitionState.getSwipePipToHomeOverlay(); - PictureInPictureParams params = pipChange.getTaskInfo().pictureInPictureParams; - - Rect appBounds = mPipTransitionState.getSwipePipToHomeAppBounds(); - Rect destinationBounds = pipChange.getEndAbsBounds(); - - float aspectRatio = pipChange.getTaskInfo().pictureInPictureParams.getAspectRatioFloat(); - - // We fake the source rect hint when the one prvided by the app is invalid for - // the animation with an app icon overlay. - Rect animationSrcRectHint = overlayLeash == null ? params.getSourceRectHint() - : PipUtils.getEnterPipWithOverlaySrcRectHint(appBounds, aspectRatio); - - WindowContainerTransaction finishWct = new WindowContainerTransaction(); - SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); - - final float scale = (float) destinationBounds.width() / animationSrcRectHint.width(); - startTransaction.setWindowCrop(pipLeash, animationSrcRectHint); - startTransaction.setPosition(pipLeash, - destinationBounds.left - animationSrcRectHint.left * scale, - destinationBounds.top - animationSrcRectHint.top * scale); - startTransaction.setScale(pipLeash, scale, scale); - - if (overlayLeash != null) { + final Rect destinationBounds = pipChange.getEndAbsBounds(); + final SurfaceControl swipePipToHomeOverlay = mPipTransitionState.getSwipePipToHomeOverlay(); + if (swipePipToHomeOverlay != null) { final int overlaySize = PipContentOverlay.PipAppIconOverlay.getOverlaySize( mPipTransitionState.getSwipePipToHomeAppBounds(), destinationBounds); - - // Overlay needs to be adjusted once a new draw comes in resetting surface transform. - tx.setScale(overlayLeash, 1f, 1f); - tx.setPosition(overlayLeash, (destinationBounds.width() - overlaySize) / 2f, - (destinationBounds.height() - overlaySize) / 2f); + // It is possible we reparent the PIP activity to a new PIP task (in multi-activity + // apps), so we should also reparent the overlay to the final PIP task. + startTransaction.reparent(swipePipToHomeOverlay, pipLeash) + .setLayer(swipePipToHomeOverlay, Integer.MAX_VALUE) + .setScale(swipePipToHomeOverlay, 1f, 1f) + .setPosition(swipePipToHomeOverlay, + (destinationBounds.width() - overlaySize) / 2f, + (destinationBounds.height() - overlaySize) / 2f); } - startTransaction.apply(); - tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(), - this::onClientDrawAtTransitionEnd); - finishWct.setBoundsChangeTransaction(pipTaskToken, tx); - - // Note that finishWct should be free of any actual WM state changes; we are using - // it for syncing with the client draw after delayed configuration changes are dispatched. - finishCallback.onTransitionFinished(finishWct.isEmpty() ? null : finishWct); + startTransaction.merge(finishTransaction); + startTransaction.apply(); + finishCallback.onTransitionFinished(null /* finishWct */); + onClientDrawAtTransitionEnd(); return true; } -- GitLab From 8691bd4d422da01670f733a121b35c893ee7a884 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 24 Sep 2024 08:36:22 -0700 Subject: [PATCH 034/466] Add flagging libraries for trade-in mode. This is needed to start adding tradeinmode APIs. The flags are getting split out separately so they can also be used in AOSP for adbd. Bug: 307713521 Test: builds Flag: com.android.tradeinmode.flags.enable_trade_in_mode Change-Id: Ie6db1e093ee4fc0aa4b01bd4e0639a0ceac50e5a --- AconfigFlags.bp | 27 +++++++++++++++++++ .../image/flags/trade_in_mode_flags.aconfig | 11 ++++++++ 2 files changed, 38 insertions(+) create mode 100644 core/java/android/os/image/flags/trade_in_mode_flags.aconfig diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 0ca97898e936..27d7783ae2e3 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -15,6 +15,7 @@ aconfig_declarations_group { name: "framework-minus-apex-aconfig-declarations", aconfig_declarations_groups: [ + "aconfig_trade_in_mode_flags", "audio-framework-aconfig", ], java_aconfig_libraries: [ @@ -1630,3 +1631,29 @@ java_aconfig_library { aconfig_declarations: "android.app.jank.flags-aconfig", defaults: ["framework-minus-apex-aconfig-java-defaults"], } + +// Trade in mode +aconfig_declarations { + name: "aconfig_trade_in_mode_flags", + package: "com.android.tradeinmode.flags", + container: "system", + srcs: [ + "core/java/android/os/image/flags/trade_in_mode_flags.aconfig", + ], +} + +java_aconfig_library { + name: "aconfig_trade_in_mode_flags_java_lib", + aconfig_declarations: "aconfig_trade_in_mode_flags", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + +cc_aconfig_library { + name: "android_trade_in_mode_flags_cc_lib", + aconfig_declarations: "aconfig_trade_in_mode_flags", + apex_available: [ + "//apex_available:platform", + "com.android.adbd", + ], + min_sdk_version: "apex_inherit", +} diff --git a/core/java/android/os/image/flags/trade_in_mode_flags.aconfig b/core/java/android/os/image/flags/trade_in_mode_flags.aconfig new file mode 100644 index 000000000000..e2e56ef70d62 --- /dev/null +++ b/core/java/android/os/image/flags/trade_in_mode_flags.aconfig @@ -0,0 +1,11 @@ +package: "com.android.tradeinmode.flags" +container: "system" + +flag { + name: "enable_trade_in_mode" + is_exported: true + namespace: "phoenix" + description: "Enable Trade-in Mode" + bug: "332683751" + is_fixed_read_only: true +} -- GitLab From 4235ddb0ef0a07cfe21bba65d39b8cd1c5bee39a Mon Sep 17 00:00:00 2001 From: Atneya Nair Date: Thu, 26 Sep 2024 00:25:20 +0000 Subject: [PATCH 035/466] Add binder unhandled exception notification Exceptions which are not parcelled by binder are dropped on the service side. For oneway txns, all exceptions are dropped. Add an extension point to Java binder interface implementations to generically handle an exception which will be dropped, by logging/crashing or some other facility. Bug: 150808347 Test: atest BinderUncaughtExceptionHandlerTest Test: Manual (handled vs unhandled exception in subsequent CL) Flag: EXEMPT safe addition, no api Merged-In: I6aa97c363ccf21af262ad95efc20611c78796e32 Change-Id: I6aa97c363ccf21af262ad95efc20611c78796e32 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:38e04d4ee890cb87e2a5952fd2cb928638bdf8b3) Change-Id: Ic7696dcb7fee6b1f69ade78e5b496c0b3a0015f6 --- core/java/android/os/Binder.java | 20 ++ core/tests/coretests/Android.bp | 2 + core/tests/coretests/AndroidTest.xml | 1 + .../AppThatCallsBinderMethods/Android.bp | 20 ++ .../AndroidManifest.xml | 26 ++ .../CallMethodsReceiver.kt | 57 ++++ .../methodcallerhelperapp/Constants.kt | 23 ++ .../coretests/aidl/ITestInterface.aidl | 27 ++ .../os/BinderUncaughtExceptionHandlerTest.kt | 247 ++++++++++++++++++ 9 files changed, 423 insertions(+) create mode 100644 core/tests/coretests/AppThatCallsBinderMethods/Android.bp create mode 100644 core/tests/coretests/AppThatCallsBinderMethods/AndroidManifest.xml create mode 100644 core/tests/coretests/AppThatCallsBinderMethods/src/com/android/frameworks/coretests/methodcallerhelperapp/CallMethodsReceiver.kt create mode 100644 core/tests/coretests/AppThatCallsBinderMethods/src/com/android/frameworks/coretests/methodcallerhelperapp/Constants.kt create mode 100644 core/tests/coretests/aidl/com/android/frameworks/coretests/aidl/ITestInterface.aidl create mode 100644 core/tests/coretests/src/android/os/BinderUncaughtExceptionHandlerTest.kt diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index b7556dfb51af..5b05cb54ed54 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -1212,6 +1212,21 @@ public class Binder implements IBinder { @Nullable String[] args) { } + /** + * Called whenever the stub implementation throws an exception which isn't propagated to the + * remote caller by the binder. If this method isn't overridden, this exception is swallowed, + * and some default return values are propagated to the caller. + * + *
    This should not throw. Doing so would defeat the purpose of this handler, and + * suppress the exception it is handling. + * + * @param code The transaction code being handled + * @param e The exception which was thrown. + * @hide + */ + protected void onUnhandledException(int code, int flags, Exception e) { + } + /** * @param in The raw file descriptor that an input data stream can be read from. * @param out The raw file descriptor that normal command messages should be written to. @@ -1517,10 +1532,15 @@ public class Binder implements IBinder { } else { Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e); } + onUnhandledException(code, flags, e); } else { // Clear the parcel before writing the exception. reply.setDataSize(0); reply.setDataPosition(0); + // The writeException below won't do anything useful if this is the case. + if (Parcel.getExceptionCode(e) == 0) { + onUnhandledException(code, flags, e); + } reply.writeException(e); } res = true; diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 23203f029992..a9ac67db2cbc 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -25,6 +25,7 @@ filegroup { "BinderProxyCountingTestApp/src/**/*.java", "BinderProxyCountingTestService/src/**/*.java", "BinderDeathRecipientHelperApp/src/**/*.java", + "AppThatCallsBinderMethods/src/**/*.kt", ], visibility: ["//visibility:private"], } @@ -141,6 +142,7 @@ android_test { ":BinderFrozenStateChangeCallbackTestApp", ":BinderProxyCountingTestApp", ":BinderProxyCountingTestService", + ":AppThatCallsBinderMethods", ], } diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml index 3fdd72935217..dbe0b49f2c32 100644 --- a/core/tests/coretests/AndroidTest.xml +++ b/core/tests/coretests/AndroidTest.xml @@ -25,6 +25,7 @@