*/
@FlaggedApi(android.service.chooser.Flags.FLAG_CHOOSER_PAYLOAD_TOGGLING)
--
GitLab
From 03028555d279a156575dd7f8147f84bb6ce544db Mon Sep 17 00:00:00 2001
From: Vlad Popa
Date: Tue, 24 Sep 2024 18:06:14 -0700
Subject: [PATCH 002/652] Add some improvements in abs vol sync with audio
server
Also improve logging in AudioService
Flag: EXEMPT bugfix
Test: manual
Bug: 350103953
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:efb3a1fc184f27242cbb09d0c96cb7c673a89f58)
Merged-In: Ic3a9f2a9d7aea6cb82892d9943d19dc9ec8fd5c5
Change-Id: Ic3a9f2a9d7aea6cb82892d9943d19dc9ec8fd5c5
---
.../android/server/audio/AudioService.java | 23 +++++++++++++------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index f64a16359028..e1909d91a77d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1583,8 +1583,11 @@ public class AudioService extends IAudioService.Stub
synchronized (mCachedAbsVolDrivingStreamsLock) {
mCachedAbsVolDrivingStreams.forEach((dev, stream) -> {
- mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", /*enabled=*/true,
- stream);
+ boolean enabled = true;
+ if (dev == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
+ enabled = mAvrcpAbsVolSupported;
+ }
+ mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", enabled, stream);
});
}
}
@@ -4848,7 +4851,7 @@ public class AudioService extends IAudioService.Stub
if (absDev == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
enabled = mAvrcpAbsVolSupported;
}
- if (stream != streamType) {
+ if (stream != streamType || !enabled) {
mAudioSystem.setDeviceAbsoluteVolumeEnabled(absDev, /*address=*/"",
enabled, streamType);
}
@@ -10354,10 +10357,10 @@ public class AudioService extends IAudioService.Stub
}
/*package*/ void setAvrcpAbsoluteVolumeSupported(boolean support) {
- mAvrcpAbsVolSupported = support;
- if (absVolumeIndexFix()) {
- int a2dpDev = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
- synchronized (mCachedAbsVolDrivingStreamsLock) {
+ synchronized (mCachedAbsVolDrivingStreamsLock) {
+ mAvrcpAbsVolSupported = support;
+ if (absVolumeIndexFix()) {
+ int a2dpDev = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
mCachedAbsVolDrivingStreams.compute(a2dpDev, (dev, stream) -> {
if (!mAvrcpAbsVolSupported) {
mAudioSystem.setDeviceAbsoluteVolumeEnabled(a2dpDev, /*address=*/
@@ -12420,6 +12423,12 @@ public class AudioService extends IAudioService.Stub
pw.println("\nLoudness alignment:");
mLoudnessCodecHelper.dump(pw);
+ pw.println("\nAbsolute voume devices:");
+ synchronized (mCachedAbsVolDrivingStreamsLock) {
+ mCachedAbsVolDrivingStreams.forEach((dev, stream) -> pw.println(
+ "Device type: 0x" + Integer.toHexString(dev) + ", driving stream " + stream));
+ }
+
mAudioSystem.dump(pw);
}
--
GitLab
From 94bbc6a937ea3a1f96b1c2e06572437f9e8dc852 Mon Sep 17 00:00:00 2001
From: Sherry Zhou
Date: Wed, 2 Oct 2024 20:51:15 +0000
Subject: [PATCH 003/652] Fix clock position is too high in lockscreen preview
in tablet portrait mode
Bug: 369937183
Flag: com.android.systemui.migrate_clocks_to_blueprint
Test: manual test, attach screenshots in comment#6
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:efa861ac8951da4c6c82d849c64b29c06df68299)
Merged-In: I4455798e3de7bb4b597a232926041311ce382b47
Change-Id: I4455798e3de7bb4b597a232926041311ce382b47
---
.../ui/binder/KeyguardPreviewClockViewBinder.kt | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
index 8386628f4c83..57cb10ff9367 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt
@@ -121,7 +121,10 @@ object KeyguardPreviewClockViewBinder {
private fun applyClockDefaultConstraints(context: Context, constraints: ConstraintSet) {
constraints.apply {
constrainWidth(R.id.lockscreen_clock_view_large, ConstraintSet.WRAP_CONTENT)
- constrainHeight(R.id.lockscreen_clock_view_large, ConstraintSet.MATCH_CONSTRAINT)
+ // The following two lines make lockscreen_clock_view_large is constrained to available
+ // height when it goes beyond constraints; otherwise, it use WRAP_CONTENT
+ constrainHeight(R.id.lockscreen_clock_view_large, WRAP_CONTENT)
+ constrainMaxHeight(R.id.lockscreen_clock_view_large, 0)
val largeClockTopMargin =
SystemBarUtils.getStatusBarHeight(context) +
context.resources.getDimensionPixelSize(
@@ -138,7 +141,7 @@ object KeyguardPreviewClockViewBinder {
R.id.lockscreen_clock_view_large,
ConstraintSet.END,
PARENT_ID,
- ConstraintSet.END
+ ConstraintSet.END,
)
// In preview, we'll show UDFPS icon for UDFPS devices
@@ -160,14 +163,14 @@ object KeyguardPreviewClockViewBinder {
BOTTOM,
PARENT_ID,
BOTTOM,
- clockBottomMargin
+ clockBottomMargin,
)
}
constrainWidth(R.id.lockscreen_clock_view, WRAP_CONTENT)
constrainHeight(
R.id.lockscreen_clock_view,
- context.resources.getDimensionPixelSize(customizationR.dimen.small_clock_height)
+ context.resources.getDimensionPixelSize(customizationR.dimen.small_clock_height),
)
connect(
R.id.lockscreen_clock_view,
@@ -175,7 +178,7 @@ object KeyguardPreviewClockViewBinder {
PARENT_ID,
START,
context.resources.getDimensionPixelSize(customizationR.dimen.clock_padding_start) +
- context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
+ context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal),
)
val smallClockTopMargin =
context.resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin) +
@@ -188,7 +191,7 @@ object KeyguardPreviewClockViewBinder {
context: Context,
rootView: ConstraintLayout,
previewClock: ClockController,
- viewModel: KeyguardPreviewClockViewModel
+ viewModel: KeyguardPreviewClockViewModel,
) {
val cs = ConstraintSet().apply { clone(rootView) }
applyClockDefaultConstraints(context, cs)
--
GitLab
From ade2c89f3d3a43c8636b96d270289eb80e0e09a0 Mon Sep 17 00:00:00 2001
From: Yining Liu
Date: Tue, 1 Oct 2024 21:59:51 +0000
Subject: [PATCH 004/652] Fix java crash by inconsistent single-line view and
view model
Fix the java crash when a conversation notification entry has null
MessagingStyle.
Fix: 368441586
Flag: com.android.systemui.notification_async_hybrid_view_inflation
Test: SingleLineViewBinderTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8702b2246c3282abe105d2e60ca4f74d57d11e09)
Merged-In: If47e3f0ccfcc5e7079189288a6f3820691abd3e8
Change-Id: If47e3f0ccfcc5e7079189288a6f3820691abd3e8
---
.../row/NotificationContentInflater.java | 5 +-
.../row/ui/viewbinder/SingleLineViewBinder.kt | 12 ++--
.../row/SingleLineViewBinderTest.kt | 65 +++++++++++++++----
3 files changed, 64 insertions(+), 18 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 8c80fd400360..36e3e92e4063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -203,13 +203,16 @@ public class NotificationContentInflater implements NotificationRowContentBinder
messagingStyle = mConversationProcessor
.processNotification(entry, builder, mLogger);
}
- result.mInflatedSingleLineViewModel = SingleLineViewInflater
+ SingleLineViewModel viewModel = SingleLineViewInflater
.inflateSingleLineViewModel(
entry.getSbn().getNotification(),
messagingStyle,
builder,
row.getContext()
);
+ // If the messagingStyle is null, we want to inflate the normal view
+ isConversation = viewModel.isConversation();
+ result.mInflatedSingleLineViewModel = viewModel;
result.mInflatedSingleLineView =
SingleLineViewInflater.inflatePrivateSingleLineView(
isConversation,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
index 3b0f1ee22be3..a17197c1f8ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/SingleLineViewBinder.kt
@@ -24,14 +24,14 @@ import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineVi
object SingleLineViewBinder {
@JvmStatic
fun bind(viewModel: SingleLineViewModel?, view: HybridNotificationView?) {
- if (viewModel?.isConversation() == true && view is HybridConversationNotificationView) {
+ if (view is HybridConversationNotificationView) {
if (AsyncHybridViewInflation.isUnexpectedlyInLegacyMode()) return
- viewModel.conversationData?.avatar?.let { view.setAvatar(it) }
+ viewModel?.conversationData?.avatar?.let { view.setAvatar(it) }
view.setText(
- viewModel.titleText,
- viewModel.contentText,
- viewModel.conversationData?.conversationSenderName
+ viewModel?.titleText,
+ viewModel?.contentText,
+ viewModel?.conversationData?.conversationSenderName,
)
} else {
// bind the title and content text views
@@ -39,7 +39,7 @@ object SingleLineViewBinder {
bind(
/* title = */ viewModel?.titleText,
/* text = */ viewModel?.contentText,
- /* contentView = */ null
+ /* contentView = */ null,
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
index 6b3fb5b4a2eb..503fa789cb80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/SingleLineViewBinderTest.kt
@@ -29,12 +29,13 @@ import com.android.systemui.statusbar.notification.row.SingleLineViewInflater.in
import com.android.systemui.statusbar.notification.row.SingleLineViewInflater.inflatePublicSingleLineView
import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation
import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder
-import com.android.systemui.util.mockito.mock
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
+import kotlin.test.assertNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -69,7 +70,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE,
entry = row.entry,
context = context,
- logger = mock()
+ logger = mock(),
)
val publicView =
@@ -78,7 +79,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
reinflateFlags = FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE,
entry = row.entry,
context = context,
- logger = mock()
+ logger = mock(),
)
assertNotNull(publicView)
@@ -114,7 +115,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
.addMessage(
"How about lunch?",
System.currentTimeMillis(),
- Person.Builder().setName("user2").build()
+ Person.Builder().setName("user2").build(),
)
.setGroupConversation(true)
notificationBuilder.setStyle(style).setShortcutId(SHORTCUT_ID)
@@ -127,7 +128,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE,
entry = row.entry,
context = context,
- logger = mock()
+ logger = mock(),
)
as HybridConversationNotificationView
@@ -137,7 +138,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
reinflateFlags = FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE,
entry = row.entry,
context = context,
- logger = mock()
+ logger = mock(),
)
as HybridConversationNotificationView
assertNotNull(publicView)
@@ -150,10 +151,7 @@ class SingleLineViewBinderTest : SysuiTestCase() {
systemUiContext = context,
)
// WHEN: binds the view
- SingleLineViewBinder.bind(
- viewModel,
- view,
- )
+ SingleLineViewBinder.bind(viewModel, view)
// THEN: the single-line conversation view should be bound with view model's corresponding
// fields
@@ -161,10 +159,55 @@ class SingleLineViewBinderTest : SysuiTestCase() {
assertEquals(viewModel.contentText, view.textView.text)
assertEquals(
viewModel.conversationData?.conversationSenderName,
- view.conversationSenderNameView.text
+ view.conversationSenderNameView.text,
)
}
+ @Test
+ @EnableFlags(AsyncHybridViewInflation.FLAG_NAME)
+ fun bindConversationSingleLineView_nonConversationViewModel() {
+ // GIVEN: a ConversationSingleLineView, and a nonConversationViewModel
+ val style = Notification.BigTextStyle().bigText(CONTENT_TEXT)
+ notificationBuilder.setStyle(style)
+ val notification = notificationBuilder.build()
+ val row: ExpandableNotificationRow = helper.createRow(notification)
+
+ val view =
+ inflatePrivateSingleLineView(
+ isConversation = true,
+ reinflateFlags = FLAG_CONTENT_VIEW_SINGLE_LINE,
+ entry = row.entry,
+ context = context,
+ logger = mock(),
+ )
+
+ val publicView =
+ inflatePublicSingleLineView(
+ isConversation = true,
+ reinflateFlags = FLAG_CONTENT_VIEW_PUBLIC_SINGLE_LINE,
+ entry = row.entry,
+ context = context,
+ logger = mock(),
+ )
+ assertNotNull(publicView)
+
+ val viewModel =
+ SingleLineViewInflater.inflateSingleLineViewModel(
+ notification = notification,
+ messagingStyle = null,
+ builder = notificationBuilder,
+ systemUiContext = context,
+ )
+ // WHEN: binds the view with the view model
+ SingleLineViewBinder.bind(viewModel, view)
+
+ // THEN: the single-line view should be bound with view model's corresponding
+ // fields as a normal non-conversation single-line view
+ assertEquals(viewModel.titleText, view?.titleView?.text)
+ assertEquals(viewModel.contentText, view?.textView?.text)
+ assertNull(viewModel.conversationData)
+ }
+
private companion object {
const val CHANNEL_ID = "CHANNEL_ID"
const val CONTENT_TITLE = "A Cool New Feature"
--
GitLab
From 276128e3c9c49ae4790607f5867f04462b5948e3 Mon Sep 17 00:00:00 2001
From: Hongwei Wang
Date: Tue, 30 Jul 2024 15:32:43 -0700
Subject: [PATCH 005/652] Separate finishTransaction for leftover transition
When enter PiP from split-screen, the fade-in animation would be picked.
The alpha will be reset to 1 as part of the finishTransaction and from
the MixedTransitionHelper, when we dispatch the leftovers with the same
finishTransaction, there is no guarantee that when finishTransaction is
actually executed, which leads to a race condition.
Fixing this by passing over a fresh finishTransaction to the leftovers
in MixedTransitionHelper, similar to what we do for startTransaction.
This CL covers the enter PiP from split-screen in gesture nav mode.
Flag: EXEMPT bugfix
Video: http://recall/-/aaaaaabFQoRHlzixHdtY/fcSpmPtl7xQUMCkJj0PFUY
Video: http://recall/-/aaaaaabFQoRHlzixHdtY/cxkqthnSiPrK1t5FsbEBQD
Test: Enter PiP from split-screen, make sure no flicker
Test: Enter PiP with non-auto-enter API, make sure no regression there
Test: atest --iteration 5 WMShellFlickerTestsPip1 -- --test-arg \
com.android.tradefed.testtype.AndroidJUnitTest:instrumentation-arg:filter-tests:="com.android.wm.shell.flicker.pip.FromSplitScreenEnterPipOnUserLeaveHintTest#visibleLayersShownMoreThanOneConsecutiveEntry[ROTATION_0_GESTURAL_NAV]"
Test: atest --iteration 5 WMShellFlickerTestsPip1 -- --test-arg \
com.android.tradefed.testtype.AndroidJUnitTest:instrumentation-arg:filter-tests:="com.android.wm.shell.flicker.pip.FromSplitScreenAutoEnterPipOnGoToHomeTest#visibleLayersShownMoreThanOneConsecutiveEntry[ROTATION_0_GESTURAL_NAV]"
Bug: 359667269
Bug: 312446524
Bug: 289943985
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ff188280c713b7ee0bb28a4cb829df85424f212e)
Merged-In: I2f1c2bf9d002639c0e144d2743de9331dcf590c0
Change-Id: I2f1c2bf9d002639c0e144d2743de9331dcf590c0
---
.../android/wm/shell/transition/MixedTransitionHelper.java | 5 ++++-
.../pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt | 6 ------
2 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
index 30d7245436be..e61929fef312 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/MixedTransitionHelper.java
@@ -141,10 +141,13 @@ public class MixedTransitionHelper {
pipHandler.setEnterAnimationType(ANIM_TYPE_ALPHA);
pipHandler.startEnterAnimation(pipChange, startTransaction, finishTransaction,
finishCB);
+ // make a new finishTransaction because pip's startEnterAnimation "consumes" it so
+ // we need a separate one to send over to launcher.
+ SurfaceControl.Transaction otherFinishT = new SurfaceControl.Transaction();
// Dispatch the rest of the transition normally. This will most-likely be taken by
// recents or default handler.
mixed.mLeftoversHandler = player.dispatchTransition(mixed.mTransition, everythingElse,
- otherStartT, finishTransaction, finishCB, mixedHandler);
+ otherStartT, otherFinishT, finishCB, mixedHandler);
} else {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Not leaving split, so just "
+ "forward animation to Pip-Handler.");
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index d03d7799d675..d1bf6acf785d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -182,12 +182,6 @@ class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :
}
}
- /** {@inheritDoc} */
- @FlakyTest(bugId = 312446524)
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
-
/** {@inheritDoc} */
@Test
@FlakyTest(bugId = 336510055)
--
GitLab
From 4ae06726eb3259db1a0667f507f492f96a7aae10 Mon Sep 17 00:00:00 2001
From: Yabin Huang
Date: Wed, 18 Sep 2024 18:06:59 +0000
Subject: [PATCH 006/652] Modify PhoneWindowManager to avoid interfering with
current user's experience
- There are several code locations that assume the operations are for
the current user.
- However, these operations could be executed in reponse to requests
for visible background users in MUMD environment.
- We should handle them to avoid interfering with current user's
experience.
Bug: 358267540
Test: atest WmTests:PhoneWindowManagerTests
Flag: EXEMPT bugfix
(cherry picked from https://partner-android-review.googlesource.com/q/commit:bd7104e0e1abe78201a4adcf6ce3bbc1abc0b93f)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0a332b80a88ec64789afbad7bbc84371b9ecbefb)
Merged-In: I21cff2407937d9de87108529a74d0e9e3f4ca4e8
Change-Id: I21cff2407937d9de87108529a74d0e9e3f4ca4e8
---
.../server/policy/PhoneWindowManager.java | 81 ++++++++++++++++++-
1 file changed, 77 insertions(+), 4 deletions(-)
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 63491e8434bf..ca6051874d78 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -37,6 +37,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.O;
import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID;
+import static android.os.UserManager.isVisibleBackgroundUsersEnabled;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -184,6 +185,7 @@ import android.service.dreams.IDreamManager;
import android.service.vr.IPersistentVrStateCallbacks;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
+import android.util.ArraySet;
import android.util.Log;
import android.util.MathUtils;
import android.util.MutableBoolean;
@@ -256,6 +258,7 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -718,6 +721,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Timeout for showing the keyguard after the screen is on, in case no "ready" is received.
private int mKeyguardDrawnTimeout = 1000;
+ private final boolean mVisibleBackgroundUsersEnabled = isVisibleBackgroundUsersEnabled();
+
+ // Key codes that should be ignored for visible background users in MUMD environment.
+ private static final Set KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS =
+ new ArraySet<>(Arrays.asList(
+ KeyEvent.KEYCODE_POWER,
+ KeyEvent.KEYCODE_SLEEP,
+ KeyEvent.KEYCODE_WAKEUP,
+ KeyEvent.KEYCODE_CALL,
+ KeyEvent.KEYCODE_ENDCALL,
+ KeyEvent.KEYCODE_ASSIST,
+ KeyEvent.KEYCODE_VOICE_ASSIST,
+ KeyEvent.KEYCODE_MUTE,
+ KeyEvent.KEYCODE_VOLUME_MUTE
+ ));
+
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
private static final int MSG_DISPATCH_MEDIA_KEY_REPEAT_WITH_WAKE_LOCK = 4;
private static final int MSG_KEYGUARD_DRAWN_COMPLETE = 5;
@@ -811,7 +830,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
event.recycle();
break;
case MSG_HANDLE_ALL_APPS:
- launchAllAppsAction();
+ KeyEvent keyEvent = (KeyEvent) msg.obj;
+ if (isKeyEventForCurrentUser(keyEvent.getDisplayId(), keyEvent.getKeyCode(),
+ "launchAllAppsViaA11y")) {
+ launchAllAppsAction();
+ }
break;
case MSG_RINGER_TOGGLE_CHORD:
handleRingerChordGesture();
@@ -2082,7 +2105,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
switch (mLongPressOnHomeBehavior) {
case LONG_PRESS_HOME_ALL_APPS:
notifyKeyGestureCompleted(event, KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
- launchAllAppsAction();
+ if (isKeyEventForCurrentUser(event.getDisplayId(), event.getKeyCode(),
+ "launchAllAppsViaA11y")) {
+ launchAllAppsAction();
+ }
break;
case LONG_PRESS_HOME_ASSIST:
notifyKeyGestureCompleted(event,
@@ -3763,7 +3789,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_CAPS_LOCK);
} else if (mPendingMetaAction) {
if (!canceled) {
- launchAllAppsAction();
+ if (isKeyEventForCurrentUser(event.getDisplayId(), event.getKeyCode(),
+ "launchAllAppsViaA11y")) {
+ launchAllAppsAction();
+ }
notifyKeyGestureCompleted(event,
KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS);
}
@@ -4030,7 +4059,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return true;
case KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS:
case KeyGestureEvent.KEY_GESTURE_TYPE_ACCESSIBILITY_ALL_APPS:
- if (complete) {
+ if (complete && isKeyEventForCurrentUser(event.getDisplayId(),
+ event.getKeycodes()[0], "launchAllAppsViaA11y")) {
launchAllAppsAction();
}
return true;
@@ -4859,6 +4889,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean isWakeKey = (policyFlags & WindowManagerPolicy.FLAG_WAKE) != 0
|| event.isWakeKey();
+ // There are key events that perform the operation as the current user,
+ // and these should be ignored for visible background users.
+ if (mVisibleBackgroundUsersEnabled
+ && KEY_CODES_IGNORED_FOR_VISIBLE_BACKGROUND_USERS.contains(keyCode)
+ && !isKeyEventForCurrentUser(event.getDisplayId(), keyCode, null)) {
+ return 0;
+ }
+
if (!mSystemBooted) {
// If we have not yet booted, don't let key events do anything.
// Exception: Wake and power key events are forwarded to PowerManager to allow it to
@@ -5866,6 +5904,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
private void wakeUpFromWakeKey(KeyEvent event) {
+ if (!isKeyEventForCurrentUser(
+ event.getDisplayId(), event.getKeyCode(), "wakeUpFromWakeKey")) {
+ return;
+ }
wakeUpFromWakeKey(
event.getEventTime(),
event.getKeyCode(),
@@ -6445,6 +6487,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// TODO (b/113840485): Move this logic to DisplayPolicy when lockscreen supports multi-display.
@Override
public void setAllowLockscreenWhenOn(int displayId, boolean allow) {
+ // We should ignore this operation for visible background users
+ // until lockscreen supports multi-display.
+ if (mVisibleBackgroundUsersEnabled
+ && mUserManagerInternal.getUserAssignedToDisplay(displayId) != mCurrentUserId) {
+ return;
+ }
if (allow) {
mAllowLockscreenWhenOnDisplays.add(displayId);
} else {
@@ -7253,4 +7301,29 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
return DEFAULT_DISPLAY;
}
+
+ /**
+ * This method is intended to prevent key events for visible background users
+ * from interfering with the current user's experience in MUMD environment.
+ *
+ * @param displayId the displayId of the key event.
+ * @param keyCode the key code of the event.
+ *
+ * @return false if the key event is for a visible background user.
+ */
+ private boolean isKeyEventForCurrentUser(int displayId, int keyCode, @Nullable String purpose) {
+ if (!mVisibleBackgroundUsersEnabled) {
+ return true;
+ }
+ int assignedUser = mUserManagerInternal.getUserAssignedToDisplay(displayId);
+ if (assignedUser == mCurrentUserId) {
+ return true;
+ }
+ if (DEBUG_INPUT) {
+ Slog.w(TAG, "Cannot handle " + KeyEvent.keyCodeToString(keyCode)
+ + (purpose != null ? " to " + purpose : "")
+ + " for visible background user(u" + assignedUser + ")");
+ }
+ return false;
+ }
}
--
GitLab
From 35aa9f5f4767f44fc20ae950d73ee5fe6514ff5f Mon Sep 17 00:00:00 2001
From: Atneya Nair
Date: Wed, 25 Sep 2024 17:36:15 -0700
Subject: [PATCH 007/652] appop: Finish all when last in chain fail
When starting an op for an attribution chain, if a later attr in the
chain fails to start, we should finish the already started ops to avoid
a split in the op state in the chain.
Test: Manual with mic indicator and recording
Test: CtsMediaAudioRecordPermissionTests
Test: CtsSensorPrivacyTestCases
Fixes: 363915467
Bug: 293603271
Flag: EXEMPT security
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c0bca399b2f809ca9efebb5e9ed492e0c32fa95c)
Merged-In: I92060d44e666fa6725411de5d714ac0d380f42ae
Change-Id: I92060d44e666fa6725411de5d714ac0d380f42ae
---
.../android/server/pm/permission/PermissionManagerService.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index df9f7fb3d6e5..5fc3e332b95c 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1015,8 +1015,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
permission, attributionSource, message, forDataDelivery, startDataDelivery,
fromDatasource, attributedOp);
// Finish any started op if some step in the attribution chain failed.
- if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED
- && result != PermissionChecker.PERMISSION_SOFT_DENIED) {
+ if (startDataDelivery && result != PermissionChecker.PERMISSION_GRANTED) {
if (attributedOp == AppOpsManager.OP_NONE) {
finishDataDelivery(AppOpsManager.permissionToOpCode(permission),
attributionSource.asState(), fromDatasource);
--
GitLab
From e5b081962ab2ab2582b5de27dbf176e1e27d117d Mon Sep 17 00:00:00 2001
From: Josh Tsuji
Date: Thu, 3 Oct 2024 18:23:08 -0400
Subject: [PATCH 008/652] Return to OCCLUDED from canceled swipe if needed.
An edge case of a canceled screen off, followed by a partial swipe up to PRIMARY_BOUNCER, followed by a slightly late call to setOccluded=true resulted in the lockscreen overlapping the occluding app until a screen off.
Tests in a follow-up CL (really!) because there are no existing tests for the dragging transition and it's a fairly large change to add support for that.
Bug: 370177430
Test: manual/shortly
Flag: EXEMPT bugfix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:40aa6d94b61f04c1dc822783447d8e5847dc0ff5)
Merged-In: I6af8b473756e43ebccecbccdd6c97d8d082ef912
Change-Id: I6af8b473756e43ebccecbccdd6c97d8d082ef912
---
.../interactor/FromLockscreenTransitionInteractor.kt | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 1e9541e1923e..6d1d9cbd9aae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -189,6 +189,7 @@ constructor(
internalTransitionInteractor.currentTransitionInfoInternal,
keyguardInteractor.statusBarState,
keyguardInteractor.isKeyguardDismissible,
+ keyguardInteractor.isKeyguardOccluded,
)
.collect {
(
@@ -196,7 +197,8 @@ constructor(
startedStep,
currentTransitionInfo,
statusBarState,
- isKeyguardUnlocked) ->
+ isKeyguardUnlocked,
+ isKeyguardOccluded) ->
val id = transitionId
if (id != null) {
if (startedStep.to == KeyguardState.PRIMARY_BOUNCER) {
@@ -236,9 +238,13 @@ constructor(
if (nextState == TransitionState.CANCELED) {
transitionRepository.startTransition(
TransitionInfo(
- ownerName = name,
+ ownerName =
+ "$name " +
+ "(on behalf of FromPrimaryBouncerInteractor)",
from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.LOCKSCREEN,
+ to =
+ if (isKeyguardOccluded) KeyguardState.OCCLUDED
+ else KeyguardState.LOCKSCREEN,
modeOnCanceled = TransitionModeOnCanceled.REVERSE,
animator =
getDefaultAnimatorForTransitionsToState(
--
GitLab
From 9d704623ae4020782c070a8a17d7497f128d1d9e Mon Sep 17 00:00:00 2001
From: Sandeep Bandaru
Date: Fri, 4 Oct 2024 00:09:38 +0000
Subject: [PATCH 009/652] Extend service permission list only accessible from
SystemUid.
As noted in b/185746653 - for isolated_compute_app, we do not want even the holding app for the isolated-process to be able to bind to it. This was implemented specifically for HOTWORD usecase previously and missed for few other usecases.
Similar to hotword service, we are extending the same permission check
to wearablesensingservice and ondeviceintelligence service which also
run as isolated_compute_app and require this enforcement in framework.
Bug: 369871251
Flag: EXEMPT bugfix
Test: added CTS in topic
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:31ce2795a8fa161920ac4e153fb62a37cb20cf2c)
Merged-In: I6bbe1a48de15243ace803e08c2ab7550c3612eb1
Change-Id: I6bbe1a48de15243ace803e08c2ab7550c3612eb1
---
services/core/java/com/android/server/am/ActiveServices.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 36665240c16b..f9197e3c5c42 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -5077,7 +5077,10 @@ public final class ActiveServices {
+ " requires " + r.permission);
return new ServiceLookupResult(r.permission);
} else if ((Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
- || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission))
+ || Manifest.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE.equals(r.permission)
+ || Manifest.permission.BIND_WEARABLE_SENSING_SERVICE.equals(r.permission)
+ || Manifest.permission.BIND_ON_DEVICE_SANDBOXED_INFERENCE_SERVICE.equals(
+ r.permission))
&& callingUid != Process.SYSTEM_UID) {
// Hotword detection and visual query detection must run in its own sandbox, and we
// don't even trust its enclosing application to bind to it - only the system.
--
GitLab
From 7d723f582b46ca5b296042dbab798584514b0d2f Mon Sep 17 00:00:00 2001
From: Matt Pietal
Date: Tue, 8 Oct 2024 12:27:30 +0000
Subject: [PATCH 010/652] Face auth bypass layout issues
The notification shade height isn't stable on swipe up. Unsure
what regressed this but add a check for bypass only that ensures
a stable height as the user is swiping up. This matches other
checks in the same file. Along with this, the AOD icons in bypass
mode would also adjust while swiping. The existing code already
accounts for bypass so remove the extra checks.
Test: atest KeyguardRootViewModelTest
Flag: EXEMPT bugfix
Fixes: 370656534
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:01b33a743507465fda1f5e004c683579be3a8af2)
Merged-In: I38b8f33bd714143891c27ff67e7b6c0c08226a51
Change-Id: I38b8f33bd714143891c27ff67e7b6c0c08226a51
---
.../ui/viewmodel/KeyguardRootViewModelTest.kt | 26 ++++++-------------
.../ui/viewmodel/KeyguardRootViewModel.kt | 4 ---
.../NotificationPanelViewController.java | 5 ++++
3 files changed, 13 insertions(+), 22 deletions(-)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 5d606c67a4d7..4b1ed3b2354a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -188,17 +188,6 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
assertThat(isVisible?.isAnimating).isFalse()
}
- @Test
- fun iconContainer_isVisible_bypassEnabled() =
- testScope.runTest {
- val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
- runCurrent()
- deviceEntryRepository.setBypassEnabled(true)
- runCurrent()
-
- assertThat(isVisible?.value).isTrue()
- }
-
@Test
fun iconContainer_isNotVisible_pulseExpanding_notBypassing() =
testScope.runTest {
@@ -288,22 +277,23 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
}
@Test
- fun iconContainer_isNotVisible_bypassDisabled_onLockscreen() =
+ fun iconContainer_isNotVisible_notifsFullyHiddenThenVisible_bypassEnabled() =
testScope.runTest {
val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
runCurrent()
- keyguardTransitionRepository.sendTransitionSteps(
- from = KeyguardState.AOD,
- to = KeyguardState.LOCKSCREEN,
- testScope,
- )
notificationsKeyguardInteractor.setPulseExpanding(false)
- deviceEntryRepository.setBypassEnabled(false)
+ deviceEntryRepository.setBypassEnabled(true)
whenever(dozeParameters.alwaysOn).thenReturn(true)
whenever(dozeParameters.displayNeedsBlanking).thenReturn(false)
notificationsKeyguardInteractor.setNotificationsFullyHidden(true)
runCurrent()
+ assertThat(isVisible?.value).isTrue()
+ assertThat(isVisible?.isAnimating).isTrue()
+
+ notificationsKeyguardInteractor.setNotificationsFullyHidden(false)
+ runCurrent()
+
assertThat(isVisible?.value).isFalse()
assertThat(isVisible?.isAnimating).isTrue()
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 0b023d9bfead..630fb99bc70a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -341,12 +341,8 @@ constructor(
when {
// If there are no notification icons to show, then it can be hidden
!hasAodIcons -> false
- // If we're bypassing, then we're visible
- isBypassEnabled -> true
// If we are pulsing (and not bypassing), then we are hidden
isPulseExpanding -> false
- // Besides bypass above, they should not be visible on lockscreen
- isOnLockscreen -> false
// If notifs are fully gone, then we're visible
areNotifsFullyHidden -> true
// Otherwise, we're hidden
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 0c05dbde6117..e197f03b5575 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2710,6 +2710,11 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
private int calculatePanelHeightShade() {
+ // Bypass should always occupy the full height
+ if (mBarState == KEYGUARD && mKeyguardBypassController.getBypassEnabled()) {
+ return mNotificationStackScrollLayoutController.getHeight();
+ }
+
int emptyBottomMargin = mNotificationStackScrollLayoutController.getEmptyBottomMargin();
int maxHeight = mNotificationStackScrollLayoutController.getHeight() - emptyBottomMargin;
--
GitLab
From 9e87948a44c1a27d0ec7fcedb40105da2913bd7b Mon Sep 17 00:00:00 2001
From: Calvin Huang
Date: Tue, 8 Oct 2024 09:53:32 -0700
Subject: [PATCH 011/652] Update PAUSE usage state when activity move from
RESUMED to STOPPING
In some multitasking scenarios, an activity can be scheduled to move
directly from the RESUMED state to the STOPPED state, bypassing the PAUSED state.
But the activity will cycled through to PAUSED state anyway. Need to
update the PAUSED usage state in this case.
Test: atest com.google.android.gts.playstore.UsageStatsHostTest
Test: atest ActivityRecordTests
Bug: 368228446
Flag: EXEMPT bugfix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:292ae8c060b23750422af0f822c0ca297addbfb7)
Merged-In: Ib66e9627d4c7ed857df9d6ae614e2001ad2d97b6
Change-Id: Ib66e9627d4c7ed857df9d6ae614e2001ad2d97b6
---
.../core/java/com/android/server/wm/ActivityRecord.java | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 12d733fc8c1a..8d0639b1e73b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -5863,6 +5863,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return;
}
+ final State prevState = mState;
mState = state;
if (getTaskFragment() != null) {
@@ -5903,6 +5904,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mAtmService.updateBatteryStats(this, false);
mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
break;
+ case STOPPING:
+ // It is possible that an Activity is scheduled to be STOPPED directly from RESUMED
+ // state. Updating the PAUSED usage state in that case, since the Activity will be
+ // STOPPED while cycled through the PAUSED state.
+ if (prevState == RESUMED) {
+ mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED);
+ }
+ break;
case STOPPED:
mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED);
if (mDisplayContent != null) {
--
GitLab
From 85cdb918a065cc029942cc16c61cb088b30ef1ca Mon Sep 17 00:00:00 2001
From: Matt Pietal
Date: Tue, 8 Oct 2024 20:13:14 +0000
Subject: [PATCH 012/652] Process adb shell input keyevent 82 through dismiss
Previously, it would trigger a shade collapse, and eventually get
to keyguard to dismiss. Sending the request to keyguard follows
the path of every other dismiss request.
Bug: 371893850
Test: atest CtsWindowManagerDeviceKeyguard:android.server.wm.keyguard.KeyguardLockedTests
Flag: EXEMPT bugfix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:55017463035c83ebb968f7abc0ca900ac3601533)
Merged-In: I2c9a3ead9540ab473815e06d474d42978ff59cf6
Change-Id: I2c9a3ead9540ab473815e06d474d42978ff59cf6
---
.../interactor/KeyguardKeyEventInteractorTest.kt | 13 ++++++++-----
.../domain/interactor/KeyguardKeyEventInteractor.kt | 11 ++++++++++-
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
index 13f30f560cdf..945e44afa455 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractorTest.kt
@@ -46,6 +46,7 @@ import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.isNull
@ExperimentalCoroutinesApi
@SmallTest
@@ -96,7 +97,7 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
.sendVolumeKeyEvent(
eq(actionDownVolumeDownKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isTrue()
@@ -104,7 +105,7 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
.sendVolumeKeyEvent(
eq(actionDownVolumeUpKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
}
@@ -117,7 +118,7 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
.sendVolumeKeyEvent(
eq(actionDownVolumeDownKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isFalse()
@@ -125,7 +126,7 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
.sendVolumeKeyEvent(
eq(actionDownVolumeUpKeyEvent),
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
- eq(true)
+ eq(true),
)
}
@@ -135,7 +136,9 @@ class KeyguardKeyEventInteractorTest : SysuiTestCase() {
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
- verifyActionUpCollapsesTheShade(KeyEvent.KEYCODE_MENU)
+ val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
+ assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
+ verify(statusBarKeyguardViewManager).dismissWithAction(any(), isNull(), eq(false))
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
index 65b42e657e75..fcf486b5696b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardKeyEventInteractor.kt
@@ -23,6 +23,7 @@ import com.android.systemui.back.domain.interactor.BackActionInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler.Companion.handleAction
import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.shade.ShadeController
@@ -105,7 +106,15 @@ constructor(
(statusBarStateController.state != StatusBarState.SHADE) &&
statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
if (shouldUnlockOnMenuPressed) {
- shadeController.animateCollapseShadeForced()
+ statusBarKeyguardViewManager.dismissWithAction(
+ object : OnDismissAction {
+ override fun onDismiss(): Boolean {
+ return false
+ }
+ },
+ null,
+ false,
+ )
return true
}
return false
--
GitLab
From 7d4d2294d1bcdab1cc2086e4d3e367a4ba090bd4 Mon Sep 17 00:00:00 2001
From: "seokgyun.hong"
Date: Fri, 19 Jul 2024 10:26:21 +0900
Subject: [PATCH 013/652] Prevent calls to StatusBarManagerInternal from
visible background users
Visible background users have access to UI on assigned displays on devices that have config_multiuserVisibleBackgroundUsers enabled. The main use case is Automotive's multi-display Whole Cabin experience where
passengers (modeled as visible background users) can interact with the display in front of them concurrently with the driver (modeled as the the current user) interacting with driver's display.
- Calls to StatusBarManagerInternal trigger callbacks to the registered
IStatusBar for the current user.
- However, StatusBarManagerInternal APIs can be called from not only
the current user but also visible background users.
- We should prevent this to ensure that visible background users do not interfere with the current user's experience.
Bug: 332222893
Flag: EXEMPT bugfix
Test: atest MagnificationConnectionManagerTest
atest WmTests:PhoneWindowManagerTests
(cherry picked from https://partner-android-review.googlesource.com/q/commit:62538ec79f939853bd4ea75e81f4f46204fce72d)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3bf69d6d2a6a0852c149d37304472d82a2f9f961)
Merged-In: Icdc6515e69e8044cf972a9e14e2fdd7f7a4b6958
Change-Id: Icdc6515e69e8044cf972a9e14e2fdd7f7a4b6958
---
.../AccessibilityManagerService.java | 6 ++++
.../MagnificationConnectionManager.java | 10 ++++++
.../server/policy/PhoneWindowManager.java | 36 +++++++++++++++++--
.../server/search/SearchManagerService.java | 12 +++++++
.../MagnificationConnectionManagerTest.java | 7 ++++
5 files changed, 68 insertions(+), 3 deletions(-)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 7580b697b516..49f15e46894d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3653,6 +3653,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
return;
}
+ // Magnification connection should not be requested for visible background users.
+ // (b/332222893)
+ if (mUmi.isVisibleBackgroundFullUser(userState.mUserId)) {
+ return;
+ }
+
final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked()
|| userState.isMagnificationSingleFingerTripleTapEnabledLocked()
|| (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index 19e3e690924e..fe06406e580a 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -19,6 +19,7 @@ package com.android.server.accessibility.magnification;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION;
import static android.accessibilityservice.AccessibilityTrace.FLAGS_MAGNIFICATION_CONNECTION_CALLBACK;
import static android.os.Build.HW_TIMEOUT_MULTIPLIER;
+import static android.os.UserHandle.getCallingUserId;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;
import static com.android.server.accessibility.AccessibilityManagerService.INVALID_SERVICE_ID;
@@ -54,6 +55,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -209,6 +211,7 @@ public class MagnificationConnectionManager implements
private final Callback mCallback;
private final AccessibilityTraceManager mTrace;
private final MagnificationScaleProvider mScaleProvider;
+ private final UserManagerInternal mUserManagerInternal;
public MagnificationConnectionManager(Context context, Object lock, @NonNull Callback callback,
AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) {
@@ -217,6 +220,7 @@ public class MagnificationConnectionManager implements
mCallback = callback;
mTrace = trace;
mScaleProvider = scaleProvider;
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
}
/**
@@ -280,12 +284,18 @@ public class MagnificationConnectionManager implements
* Requests {@link IMagnificationConnection} through
* {@link StatusBarManagerInternal#requestMagnificationConnection(boolean)} and
* destroys all window magnifications if necessary.
+ * NOTE: Currently, this is not allowed to call from visible background users.(b/332222893)
*
* @param connect {@code true} if needs connection, otherwise set the connection to null and
* destroy all window magnifications.
* @return {@code true} if {@link IMagnificationConnection} state is going to change.
*/
public boolean requestConnection(boolean connect) {
+ final int callingUserId = getCallingUserId();
+ if (mUserManagerInternal.isVisibleBackgroundFullUser(callingUserId)) {
+ throw new SecurityException("Visible background user(u" + callingUserId
+ + " is not permitted to request magnification connection.");
+ }
if (DBG) {
Slog.d(TAG, "requestConnection :" + connect);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index ca6051874d78..e0c4ebeb9f89 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -734,7 +734,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
KeyEvent.KEYCODE_ASSIST,
KeyEvent.KEYCODE_VOICE_ASSIST,
KeyEvent.KEYCODE_MUTE,
- KeyEvent.KEYCODE_VOLUME_MUTE
+ KeyEvent.KEYCODE_VOLUME_MUTE,
+ KeyEvent.KEYCODE_RECENT_APPS,
+ KeyEvent.KEYCODE_APP_SWITCH,
+ KeyEvent.KEYCODE_NOTIFICATION
));
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
@@ -2077,12 +2080,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
switch (mDoubleTapOnHomeBehavior) {
case DOUBLE_TAP_HOME_RECENT_SYSTEM_UI:
+ if (!isKeyEventForCurrentUser(
+ event.getDisplayId(), event.getKeyCode(), "toggleRecentApps")) {
+ break;
+ }
notifyKeyGestureCompleted(event,
KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH);
mHomeConsumed = true;
toggleRecentApps();
break;
case DOUBLE_TAP_HOME_PIP_MENU:
+ if (!isKeyEventForCurrentUser(
+ event.getDisplayId(), event.getKeyCode(),
+ "showPictureInPictureMenu")) {
+ break;
+ }
mHomeConsumed = true;
showPictureInPictureMenuInternal();
break;
@@ -2111,12 +2123,20 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
break;
case LONG_PRESS_HOME_ASSIST:
+ if (!isKeyEventForCurrentUser(
+ event.getDisplayId(), event.getKeyCode(), "launchAssistAction")) {
+ break;
+ }
notifyKeyGestureCompleted(event,
KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_ASSISTANT);
launchAssistAction(null, event.getDeviceId(), event.getEventTime(),
AssistUtils.INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
break;
case LONG_PRESS_HOME_NOTIFICATION_PANEL:
+ if (!isKeyEventForCurrentUser(
+ event.getDisplayId(), event.getKeyCode(), "toggleNotificationPanel")) {
+ break;
+ }
notifyKeyGestureCompleted(event,
KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL);
toggleNotificationPanel();
@@ -3477,7 +3497,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (isUserSetupComplete() && !keyguardOn) {
if (mModifierShortcutManager.interceptKey(event)) {
- dismissKeyboardShortcutsMenu();
+ if (isKeyEventForCurrentUser(
+ event.getDisplayId(), event.getKeyCode(),
+ "dismissKeyboardShortcutsMenu")) {
+ dismissKeyboardShortcutsMenu();
+ }
mPendingMetaAction = false;
mPendingCapsLockToggle = false;
return true;
@@ -4733,7 +4757,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
// no keyguard stuff to worry about, just launch home!
- if (mRecentsVisible) {
+ // If Recents is visible and the action is not from visible background users,
+ // hide Recents and notify it to launch Home.
+ if (mRecentsVisible
+ && (!mVisibleBackgroundUsersEnabled || displayId == DEFAULT_DISPLAY)) {
try {
ActivityManager.getService().stopAppSwitches();
} catch (RemoteException e) {}
@@ -5477,6 +5504,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* Notify the StatusBar that a system key was pressed.
*/
private void sendSystemKeyToStatusBar(KeyEvent key) {
+ if (!isKeyEventForCurrentUser(key.getDisplayId(), key.getKeyCode(), "handleSystemKey")) {
+ return;
+ }
IStatusBarService statusBar = getStatusBarService();
if (statusBar != null) {
try {
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index 9b39fa1e177c..a49a9fdf4cca 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -46,6 +46,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService.TargetUser;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.FileDescriptor;
@@ -89,6 +90,8 @@ public class SearchManagerService extends ISearchManager.Stub {
@GuardedBy("mSearchables")
private final SparseArray mSearchables = new SparseArray<>();
+ private final UserManagerInternal mUserManagerInternal;
+
/**
* Initializes the Search Manager service in the provided system context.
* Only one instance of this object should be created!
@@ -101,6 +104,7 @@ public class SearchManagerService extends ISearchManager.Stub {
mMyPackageMonitor.register(context, null, UserHandle.ALL, true);
new GlobalSearchProviderObserver(context.getContentResolver());
mHandler = BackgroundThread.getHandler();
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
}
private Searchables getSearchables(int userId) {
@@ -336,6 +340,14 @@ public class SearchManagerService extends ISearchManager.Stub {
@Override
public void launchAssist(int userHandle, Bundle args) {
+ // Currently, visible background users are not allowed to launch assist.(b/332222893)
+ // TODO(b/368715893): Consider indirect calls from system service when checking the
+ // calling user.
+ final int callingUserId = UserHandle.getCallingUserId();
+ if (mUserManagerInternal.isVisibleBackgroundFullUser(callingUserId)) {
+ throw new SecurityException("Visible background user(u" + callingUserId
+ + ") is not permitted to launch assist.");
+ }
StatusBarManagerInternal statusBarManager =
LocalServices.getService(StatusBarManagerInternal.class);
if (statusBarManager != null) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
index 87fe6cf8f283..6d27dddfc357 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
@@ -62,6 +62,7 @@ import androidx.test.filters.FlakyTest;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.statusbar.StatusBarManagerInternal;
import org.junit.Before;
@@ -92,12 +93,16 @@ public class MagnificationConnectionManagerTest {
private MagnificationConnectionManager.Callback mMockCallback;
private MockContentResolver mResolver;
private MagnificationConnectionManager mMagnificationConnectionManager;
+ @Mock
+ private UserManagerInternal mMockUserManagerInternal;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+ LocalServices.removeServiceForTest(UserManagerInternal.class);
LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal);
+ LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
mResolver = new MockContentResolver();
mMockConnection = new MockMagnificationConnection();
mMagnificationConnectionManager = new MagnificationConnectionManager(mContext, new Object(),
@@ -110,6 +115,8 @@ public class MagnificationConnectionManagerTest {
Settings.Secure.putFloatForUser(mResolver,
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.5f,
CURRENT_USER_ID);
+
+ when(mMockUserManagerInternal.isVisibleBackgroundFullUser(anyInt())).thenReturn(false);
}
private void stubSetConnection(boolean needDelay) {
--
GitLab
From d869c280d408ee185e889bd948a714b5f860cbfb Mon Sep 17 00:00:00 2001
From: William Xiao
Date: Wed, 9 Oct 2024 16:04:21 -0700
Subject: [PATCH 014/652] Call dream overlay callback onWakeUp in dream overlay
reset
The dream overlay may not always receive onWakeUp, which can cause
SysUI state to incorrect and not recognize that the user dream has
exited. This can happen when unlocking from the dream when the wake
redirect is active.
Always attempt to send onWakeUp when the overlay state is reset so that
SysUI state will be correct.
Bug: 370610704
Fixed: 370610704
Test: atest DreamOverlayCallbackControllerTest DreamOverlayServiceTest
Flag: android.service.dreams.dream_wake_redirect
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:899bdd1c81e3e17f0f81b101123a852086c03ddb)
Merged-In: I23716e7c884e41758a093461ec29f487f500bcbb
Change-Id: I23716e7c884e41758a093461ec29f487f500bcbb
---
.../dreams/DreamOverlayCallbackControllerTest.kt | 14 ++++++++++++++
.../systemui/dreams/DreamOverlayServiceTest.kt | 3 +++
.../dreams/DreamOverlayCallbackController.kt | 6 ++++--
.../systemui/dreams/DreamOverlayService.java | 2 ++
4 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
index d9dcfdc7becb..9c6fd4bf71b4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayCallbackControllerTest.kt
@@ -56,6 +56,7 @@ class DreamOverlayCallbackControllerTest : SysuiTestCase() {
// Adding twice should not invoke twice
reset(callback)
+ underTest.onStartDream()
underTest.addCallback(callback)
underTest.onWakeUp()
verify(callback, times(1)).onWakeUp()
@@ -67,6 +68,19 @@ class DreamOverlayCallbackControllerTest : SysuiTestCase() {
verify(callback, never()).onWakeUp()
}
+ @Test
+ fun onWakeUp_multipleCalls() {
+ underTest.onStartDream()
+ assertThat(underTest.isDreaming).isEqualTo(true)
+
+ underTest.addCallback(callback)
+ underTest.onWakeUp()
+ underTest.onWakeUp()
+ underTest.onWakeUp()
+ verify(callback, times(1)).onWakeUp()
+ assertThat(underTest.isDreaming).isEqualTo(false)
+ }
+
@Test
fun onStartDreamInvokesCallback() {
underTest.addCallback(callback)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
index 7dd717470153..30b0aef90489 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt
@@ -712,6 +712,9 @@ class DreamOverlayServiceTest : SysuiTestCase() {
// Verify DreamOverlayContainerViewController is destroyed.
verify(mDreamOverlayContainerViewController).destroy()
+
+ // DreamOverlay callback receives onWakeUp.
+ verify(mDreamOverlayCallbackController).onWakeUp()
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt
index d5ff8f21abb2..2b617525fbcc 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayCallbackController.kt
@@ -39,8 +39,10 @@ class DreamOverlayCallbackController @Inject constructor() :
}
fun onWakeUp() {
- isDreaming = false
- callbacks.forEach { it.onWakeUp() }
+ if (isDreaming) {
+ isDreaming = false
+ callbacks.forEach { it.onWakeUp() }
+ }
}
fun onStartDream() {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 113e0011f5bd..0b465e9ce6db 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -296,6 +296,8 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mStateController.setLowLightActive(false);
mStateController.setEntryAnimationsFinished(false);
+ mDreamOverlayCallbackController.onWakeUp();
+
if (mDreamOverlayContainerViewController != null) {
mDreamOverlayContainerViewController.destroy();
mDreamOverlayContainerViewController = null;
--
GitLab
From a9bd641e90b4503a7251ca776f7330f7b5b94e65 Mon Sep 17 00:00:00 2001
From: Ibrahim Yilmaz
Date: Wed, 9 Oct 2024 19:30:52 +0000
Subject: [PATCH 015/652] Revert "Reset HUN clipping after cancellation of
disappearing animation"
This reverts commit ba2a922fb9cba2c5008006e73972fd7c1c199721.
Reason for revert: b/369608449
Only run without interruptions can clear the clipping rect.
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a03615b3e067dac90f6e1bad4aa3ce8bece26233)
Merged-In: Ide457a83d2eca1ddafa78e6f10d89d62da56f4d4
Change-Id: Ide457a83d2eca1ddafa78e6f10d89d62da56f4d4
---
.../notification/row/ActivatableNotificationView.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 7b6a2cb62b14..560028cb5640 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -444,9 +444,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (onFinishedRunnable != null) {
onFinishedRunnable.run();
}
+ if (mRunWithoutInterruptions) {
+ enableAppearDrawing(false);
+ }
// We need to reset the View state, even if the animation was cancelled
- enableAppearDrawing(false);
onAppearAnimationFinished(isAppearing);
if (mRunWithoutInterruptions) {
--
GitLab
From 3aac99cc775c3b9bcedb7f08dddc7ea0c8ba7060 Mon Sep 17 00:00:00 2001
From: Eric Laurent
Date: Wed, 18 Sep 2024 15:51:26 +0000
Subject: [PATCH 016/652] AudioService: synchronize audio mode and focus for
Telecom
make sure that an audio focus abandon by Telecom is delayed until
the corresponding audio mode reset sequence has been completed
Bug: 339030944
Bug: 346573435
Flag: EXEMPT bug fix
Test: repro steps in bug
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:15f9e56e1f898bd34400db8231f2cda71ca4cc91)
Merged-In: If7249e8276c76df710e0fa363f0aad91c511c14f
Change-Id: If7249e8276c76df710e0fa363f0aad91c511c14f
---
.../server/audio/AudioDeviceBroker.java | 13 +-
.../android/server/audio/AudioService.java | 130 ++++++++++++++----
2 files changed, 111 insertions(+), 32 deletions(-)
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 0fd22c583192..2bbe08d22020 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1321,9 +1321,9 @@ public class AudioDeviceBroker {
sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
}
- /*package*/ void postSetModeOwner(int mode, int pid, int uid) {
- sendLMsgNoDelay(MSG_I_SET_MODE_OWNER, SENDMSG_REPLACE,
- new AudioModeInfo(mode, pid, uid));
+ /*package*/ void postSetModeOwner(int mode, int pid, int uid, boolean signal) {
+ sendILMsgNoDelay(MSG_IL_SET_MODE_OWNER, SENDMSG_REPLACE,
+ signal ? 1 : 0, new AudioModeInfo(mode, pid, uid));
}
/*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) {
@@ -2025,7 +2025,7 @@ public class AudioDeviceBroker {
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
}
break;
- case MSG_I_SET_MODE_OWNER:
+ case MSG_IL_SET_MODE_OWNER:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
int btScoRequesterUid = bluetoothScoRequestOwnerUid();
@@ -2036,6 +2036,9 @@ public class AudioDeviceBroker {
}
}
}
+ if (msg.arg1 == 1 /*signal*/) {
+ mAudioService.decrementAudioModeResetCount();
+ }
break;
case MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT:
@@ -2224,7 +2227,7 @@ public class AudioDeviceBroker {
private static final int MSG_REPORT_NEW_ROUTES = 13;
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
- private static final int MSG_I_SET_MODE_OWNER = 16;
+ private static final int MSG_IL_SET_MODE_OWNER = 16;
private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e1909d91a77d..c37d47149ef5 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1918,7 +1918,7 @@ public class AudioService extends IAudioService.Stub
// Restore call state
synchronized (mDeviceBroker.mSetModeLock) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
- mContext.getPackageName(), true /*force*/);
+ mContext.getPackageName(), true /*force*/, false /*signal*/);
}
final int forSys;
synchronized (mSettingsLock) {
@@ -4746,14 +4746,47 @@ public class AudioService extends IAudioService.Stub
}
}
if (updateAudioMode) {
- sendMsg(mAudioHandler,
- MSG_UPDATE_AUDIO_MODE,
- existingMsgPolicy,
- AudioSystem.MODE_CURRENT,
- android.os.Process.myPid(),
- mContext.getPackageName(),
- delay);
+ postUpdateAudioMode(existingMsgPolicy, AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(), mContext.getPackageName(),
+ false /*signal*/, delay);
+ }
+ }
+ }
+
+ static class UpdateAudioModeInfo {
+ UpdateAudioModeInfo(int mode, int pid, String packageName, boolean signal) {
+ mMode = mode;
+ mPid = pid;
+ mPackageName = packageName;
+ mSignal = signal;
+ }
+ private final int mMode;
+ private final int mPid;
+ private final String mPackageName;
+ private final boolean mSignal;
+
+ int getMode() {
+ return mMode;
+ }
+ int getPid() {
+ return mPid;
+ }
+ String getPackageName() {
+ return mPackageName;
+ }
+ boolean getSignal() {
+ return mSignal;
+ }
+ }
+
+ void postUpdateAudioMode(int msgPolicy, int mode, int pid, String packageName,
+ boolean signal, int delay) {
+ synchronized (mAudioModeResetLock) {
+ if (signal) {
+ mAudioModeResetCount++;
}
+ sendMsg(mAudioHandler, MSG_UPDATE_AUDIO_MODE, msgPolicy, 0, 0,
+ new UpdateAudioModeInfo(mode, pid, packageName, signal), delay);
}
}
@@ -6155,13 +6188,9 @@ public class AudioService extends IAudioService.Stub
} else {
SetModeDeathHandler h = mSetModeDeathHandlers.get(index);
mSetModeDeathHandlers.remove(index);
- sendMsg(mAudioHandler,
- MSG_UPDATE_AUDIO_MODE,
- SENDMSG_QUEUE,
- AudioSystem.MODE_CURRENT,
- android.os.Process.myPid(),
- mContext.getPackageName(),
- 0);
+ postUpdateAudioMode(SENDMSG_QUEUE, AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(), mContext.getPackageName(),
+ false /*signal*/, 0);
}
}
}
@@ -6407,19 +6436,14 @@ public class AudioService extends IAudioService.Stub
}
}
- sendMsg(mAudioHandler,
- MSG_UPDATE_AUDIO_MODE,
- SENDMSG_REPLACE,
- mode,
- pid,
- callingPackage,
- 0);
+ postUpdateAudioMode(SENDMSG_REPLACE, mode, pid, callingPackage,
+ hasModifyPhoneStatePermission && mode == AudioSystem.MODE_NORMAL, 0);
}
}
@GuardedBy("mDeviceBroker.mSetModeLock")
void onUpdateAudioMode(int requestedMode, int requesterPid, String requesterPackage,
- boolean force) {
+ boolean force, boolean signal) {
if (requestedMode == AudioSystem.MODE_CURRENT) {
requestedMode = getMode();
}
@@ -6434,7 +6458,7 @@ public class AudioService extends IAudioService.Stub
}
if (DEBUG_MODE) {
Log.v(TAG, "onUpdateAudioMode() new mode: " + mode + ", current mode: "
- + mMode.get() + " requested mode: " + requestedMode);
+ + mMode.get() + " requested mode: " + requestedMode + " signal: " + signal);
}
if (mode != mMode.get() || force) {
int status = AudioSystem.SUCCESS;
@@ -6480,7 +6504,7 @@ public class AudioService extends IAudioService.Stub
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwner(mode, pid, uid);
+ mDeviceBroker.postSetModeOwner(mode, pid, uid, signal);
} else {
Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
}
@@ -10162,7 +10186,7 @@ public class AudioService extends IAudioService.Stub
h.setRecordingActive(isRecordingActiveForUid(h.getUid()));
if (wasActive != h.isActive()) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
- mContext.getPackageName(), false /*force*/);
+ mContext.getPackageName(), false /*force*/, false /*signal*/);
}
}
break;
@@ -10192,7 +10216,9 @@ public class AudioService extends IAudioService.Stub
case MSG_UPDATE_AUDIO_MODE:
synchronized (mDeviceBroker.mSetModeLock) {
- onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj, false /*force*/);
+ UpdateAudioModeInfo info = (UpdateAudioModeInfo) msg.obj;
+ onUpdateAudioMode(info.getMode(), info.getPid(), info.getPackageName(),
+ false /*force*/, info.getSignal());
}
break;
@@ -10895,9 +10921,59 @@ public class AudioService extends IAudioService.Stub
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
mmi.record();
+ //delay abandon focus requests from Telecom if an audio mode reset from Telecom
+ // is still being processed
+ final boolean abandonFromTelecom = (mContext.checkCallingOrSelfPermission(
+ MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
+ && ((aa != null && aa.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION)
+ || AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId));
+ if (abandonFromTelecom) {
+ synchronized (mAudioModeResetLock) {
+ final long start = java.lang.System.currentTimeMillis();
+ long elapsed = 0;
+ while (mAudioModeResetCount > 0) {
+ if (DEBUG_MODE) {
+ Log.i(TAG, "Abandon focus from Telecom, waiting for mode change");
+ }
+ try {
+ mAudioModeResetLock.wait(
+ AUDIO_MODE_RESET_TIMEOUT_MS - elapsed);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted while waiting for audio mode reset");
+ }
+ elapsed = java.lang.System.currentTimeMillis() - start;
+ if (elapsed >= AUDIO_MODE_RESET_TIMEOUT_MS) {
+ Log.e(TAG, "Timeout waiting for audio mode reset");
+ break;
+ }
+ }
+ if (DEBUG_MODE && elapsed != 0) {
+ Log.i(TAG, "Abandon focus from Telecom done waiting");
+ }
+ }
+ }
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
}
+ /** synchronization between setMode(NORMAL) and abandonAudioFocus() frmo Telecom */
+ private static final long AUDIO_MODE_RESET_TIMEOUT_MS = 3000;
+
+ private final Object mAudioModeResetLock = new Object();
+
+ @GuardedBy("mAudioModeResetLock")
+ private int mAudioModeResetCount = 0;
+
+ void decrementAudioModeResetCount() {
+ synchronized (mAudioModeResetLock) {
+ if (mAudioModeResetCount > 0) {
+ mAudioModeResetCount--;
+ } else {
+ Log.w(TAG, "mAudioModeResetCount already 0");
+ }
+ mAudioModeResetLock.notify();
+ }
+ }
+
/** see {@link AudioManager#abandonAudioFocusForTest(AudioFocusRequest, String)} */
public int abandonAudioFocusForTest(IAudioFocusDispatcher fd, String clientId,
AudioAttributes aa, String callingPackageName) {
--
GitLab
From 6e7c3ccd6a2787af9dbc5c36323522f12343fb88 Mon Sep 17 00:00:00 2001
From: Chandru S
Date: Thu, 10 Oct 2024 02:27:29 +0000
Subject: [PATCH 017/652] Fix persisting SFPS indicator issue.
KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never reset.
This is caused by usages of show()/forceShow() that only read (but not collect) the canShowAlternateBouncer flow to set the alternate bouncer visible state, if there is a race condition between when canShowAlternateBouncer flow changes to false and when the read happens, alternateBouncerVisible state will be set to an incorrect value and not reset on time.
Confirmed with additional logs that this is what is happening.
Flag: EXEMPT bugfix
Fixes: 360737693
Test: verified manually
1. Enable screensaver while charging (on a large screen device with side fingerprint sensor)
2. Go to screensaver
3. Try authenticating with un-enrolled finger 5 times
4. Bouncer should be shown
5. SFPS indicator should not be visible on bouncer
6. unlock the device with PIN/pattern/password
7. SFPS indicator should not be visible after device is entered
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:070817baf2efe665c186e19775c9beda05199a72)
Merged-In: I3bad4783b4283820bcf6473fd87da8cc8173c07f
Change-Id: I3bad4783b4283820bcf6473fd87da8cc8173c07f
---
.../interactor/AlternateBouncerInteractor.kt | 6 ++++++
.../phone/StatusBarKeyguardViewManager.java | 14 ++++++++++++--
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
index 373671d01395..0949ea4d7797 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.bouncer.domain.interactor
+import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
@@ -46,6 +47,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/** Encapsulates business logic for interacting with the lock-screen alternate bouncer. */
@@ -137,6 +139,8 @@ constructor(
flowOf(false)
}
}
+ .distinctUntilChanged()
+ .onEach { Log.d(TAG, "canShowAlternateBouncer changed to $it") }
.stateIn(
scope = scope,
started = WhileSubscribed(),
@@ -234,5 +238,7 @@ constructor(
companion object {
private const val MIN_VISIBILITY_DURATION_UNTIL_TOUCHES_DISMISS_ALTERNATE_BOUNCER_MS = 200L
+
+ private const val TAG = "AlternateBouncerInteractor"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 1ea26e5727ac..6fde603af4c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -528,6 +528,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
this::consumeKeyguardAuthenticatedBiometricsHandled
);
} else {
+ // Collector that keeps the AlternateBouncerInteractor#canShowAlternateBouncer flow hot.
mListenForCanShowAlternateBouncer = mJavaAdapter.alwaysCollectFlow(
mAlternateBouncerInteractor.getCanShowAlternateBouncer(),
this::consumeCanShowAlternateBouncer
@@ -576,8 +577,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
}
private void consumeCanShowAlternateBouncer(boolean canShow) {
- // do nothing, we only are registering for the flow to ensure that there's at least
- // one subscriber that will update AlternateBouncerInteractor.canShowAlternateBouncer.value
+ // Hack: this is required to fix issues where
+ // KeyguardBouncerRepository#alternateBouncerVisible state is incorrectly set and then never
+ // reset. This is caused by usages of show()/forceShow() that only read this flow to set the
+ // alternate bouncer visible state, if there is a race condition between when that flow
+ // changes to false and when the read happens, the flow will be set to an incorrect value
+ // and not reset on time.
+ if (!canShow) {
+ Log.d(TAG, "canShowAlternateBouncer turned false, maybe try hiding the alternate "
+ + "bouncer if it is already visible");
+ mAlternateBouncerInteractor.maybeHide();
+ }
}
/** Register a callback, to be invoked by the Predictive Back system. */
--
GitLab
From 2355d893234e7a0887385be58df1ec84f8da2d8c Mon Sep 17 00:00:00 2001
From: Yunfan Chen
Date: Thu, 10 Oct 2024 15:46:36 +0900
Subject: [PATCH 018/652] Partially revert the decor bounds calculation
Previous change uses the intersection to calculate the non-decor frame
to make sure the insets area is not deducted if the window is not even
overlap with the insets. This causes a zero result when a split screen
task is launched by another fullscreen task with an intent. The initial
bounds of that window is out of the display and hence the overlap is
zero.
Without changing the split screen launch implementation, we have no
better clue of the case. Revert the calculation back to the previous
strategy - deduct the insets from the window regardless of the position
relationship.
Added todo for long term solution. The shell should report to the WM
about the difference between the current window bounds and the final
bounds to let the insets system report a stable bounds to the app.
Bug: 364883053
Test: See reproduce steps in the bug
Test: WindowPolicyTests
Flag: EXEMPT bugfix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:140e0710744d0426295d46863c233da6c1f6e8a6)
Merged-In: I599a000f609c6a9964d6d0bc1bce14b0b9c979e6
Change-Id: I599a000f609c6a9964d6d0bc1bce14b0b9c979e6
---
.../android/server/wm/ConfigurationContainer.java | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 670a61dca5c8..05dcbb7f9af4 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
@@ -268,7 +269,16 @@ public abstract class ConfigurationContainer {
}
final DisplayPolicy.DecorInsets.Info decor =
displayContent.getDisplayPolicy().getDecorInsetsInfo(rotation, dw, dh);
- outAppBounds.intersectUnchecked(decor.mOverrideNonDecorFrame);
+ if (!outAppBounds.intersect(decor.mOverrideNonDecorFrame)) {
+ // TODO (b/364883053): When a split screen is requested from an app intent for a new
+ // task, the bounds is not the final bounds, and this is also not a bounds change
+ // event handled correctly with the offset. Revert back to legacy method for this
+ // case.
+ if (inOutConfig.windowConfiguration.getWindowingMode()
+ == WINDOWING_MODE_MULTI_WINDOW) {
+ outAppBounds.inset(decor.mOverrideNonDecorInsets);
+ }
+ }
if (task != null && (task.mOffsetYForInsets != 0 || task.mOffsetXForInsets != 0)) {
outAppBounds.offset(-task.mOffsetXForInsets, -task.mOffsetYForInsets);
}
--
GitLab
From fb0aea8712289a763b09bf8c9d5b00539312e673 Mon Sep 17 00:00:00 2001
From: Ibrahim Yilmaz
Date: Thu, 10 Oct 2024 21:41:11 +0000
Subject: [PATCH 019/652] [SingleLineView] Fallback to mUser when senderPerson
is null
Bug: 371843309
Test: Send group notification for conversations. Last message sender in one of these conversations should be null. Check SingleLineView and see Messaging#mUser name comes instead of null
Flag: com.android.systemui.notification_async_hybrid_view_inflation
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:29b080800b12dd5b406a1799150bd39d46d75618)
Merged-In: I011378b8f0f0a29557b651fb85273a8cc91db6b8
Change-Id: I011378b8f0f0a29557b651fb85273a8cc91db6b8
---
.../row/SingleLineViewInflater.kt | 24 ++++++++++---------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
index d67947d1fda8..4e26ae85100c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/SingleLineViewInflater.kt
@@ -90,7 +90,7 @@ internal object SingleLineViewInflater {
notification = notification,
isGroupConversation = isGroupConversation,
builder = builder,
- systemUiContext = systemUiContext
+ systemUiContext = systemUiContext,
)
val conversationData =
@@ -98,7 +98,7 @@ internal object SingleLineViewInflater {
// We don't show the sender's name for one-to-one conversation
conversationSenderName =
if (isGroupConversation) conversationTextData?.senderName else null,
- avatar = conversationAvatar
+ avatar = conversationAvatar,
)
return SingleLineViewModel(
@@ -111,7 +111,7 @@ internal object SingleLineViewInflater {
@JvmStatic
fun inflateRedactedSingleLineViewModel(
context: Context,
- isConversation: Boolean = false
+ isConversation: Boolean = false,
): SingleLineViewModel {
val conversationData =
if (isConversation) {
@@ -122,7 +122,7 @@ internal object SingleLineViewInflater {
com.android.systemui.res.R.drawable
.ic_redacted_notification_single_line_icon
)
- )
+ ),
)
} else {
null
@@ -134,7 +134,7 @@ internal object SingleLineViewInflater {
context.getString(
com.android.systemui.res.R.string.redacted_notification_single_line_text
),
- conversationData
+ conversationData,
)
}
@@ -159,11 +159,13 @@ internal object SingleLineViewInflater {
}
// load the sender's name to display
- val name = lastMessage.senderPerson?.name
+ // null senderPerson means the current user.
+ val name = lastMessage.senderPerson?.name ?: user.name
+
val senderName =
systemUiContext.resources.getString(
R.string.conversation_single_line_name_display,
- if (Flags.cleanUpSpansAndNewLines()) name?.toString() else name
+ if (Flags.cleanUpSpansAndNewLines()) name?.toString() else name,
)
// We need to find back-up values for those texts if they are needed and empty
@@ -333,7 +335,7 @@ internal object SingleLineViewInflater {
sender.icon
?: builder.getDefaultAvatar(
name = sender.name,
- uniqueNames = uniqueNames
+ uniqueNames = uniqueNames,
)
lastKey = senderKey
} else {
@@ -341,7 +343,7 @@ internal object SingleLineViewInflater {
sender.icon
?: builder.getDefaultAvatar(
name = sender.name,
- uniqueNames = uniqueNames
+ uniqueNames = uniqueNames,
)
break
}
@@ -424,7 +426,7 @@ internal object SingleLineViewInflater {
private fun Notification.Builder.getDefaultAvatar(
name: CharSequence?,
- uniqueNames: PeopleHelper.NameToPrefixMap? = null
+ uniqueNames: PeopleHelper.NameToPrefixMap? = null,
): Icon {
val layoutColor = getSmallIconColor(/* isHeader= */ false)
if (!name.isNullOrEmpty()) {
@@ -432,7 +434,7 @@ internal object SingleLineViewInflater {
return peopleHelper.createAvatarSymbol(
/* name = */ name,
/* symbol = */ symbol,
- /* layoutColor = */ layoutColor
+ /* layoutColor = */ layoutColor,
)
}
// If name is null, create default avatar with background color
--
GitLab
From 50655f736d609a5b9614205e4560d07684a432d1 Mon Sep 17 00:00:00 2001
From: Chandru S
Date: Fri, 4 Oct 2024 03:19:34 +0000
Subject: [PATCH 020/652] Fixes the issue of UDFPS icon background being white
when the device is in DOZE_PULSING state
Test: manually
1. Disable dark theme and AOD
2. Enroll fingerprint on a udfps device
3. Go to lockscreen, keep the phone on a table.
4. Press power button to force Lockscreen -> Dozing transition
5. move the phone around on the table to switch from dozing to doze_pulsing
6. Fingerprint icon background should not be visible now (black)
Fixes: 366100470
Flag: EXEMPT bugfix
(cherry picked from commit 331bbabf05c5701b1783a14b382d57bfbb54dc38)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ac2dacc7feece11ebc82af4081411c24078ac372)
Merged-In: I6e962ff0b3bd1184e453b5b1ea247e5efb6f4cec
Change-Id: I6e962ff0b3bd1184e453b5b1ea247e5efb6f4cec
---
.../DeviceEntryBackgroundViewModelTest.kt | 90 +++++++++++++++++++
.../DeviceEntryBackgroundViewModel.kt | 2 +
.../LockscreenToDozingTransitionViewModel.kt | 8 +-
.../DeviceEntryBackgroundViewModelKosmos.kt | 52 +++++++++++
4 files changed, 148 insertions(+), 4 deletions(-)
create mode 100644 packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt
create mode 100644 packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt
new file mode 100644
index 000000000000..22677b2f8e3e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryBackgroundViewModelTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val underTest: DeviceEntryBackgroundViewModel by lazy {
+ kosmos.deviceEntryBackgroundViewModel
+ }
+
+ @Test
+ fun lockscreenToDozingTransitionChangesBackgroundViewAlphaToZero() =
+ testScope.runTest {
+ kosmos.fingerprintPropertyRepository.supportsUdfps()
+ val alpha by collectLastValue(underTest.alpha)
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ listOf(dozingToLockscreen(0f, STARTED), dozingToLockscreen(0.1f)),
+ testScope,
+ )
+ runCurrent()
+ assertThat(alpha).isEqualTo(1.0f)
+
+ kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+ listOf(lockscreenToDozing(0f, STARTED)),
+ testScope,
+ )
+ runCurrent()
+
+ assertThat(alpha).isEqualTo(0.0f)
+ }
+
+ private fun lockscreenToDozing(value: Float, state: TransitionState = RUNNING): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.DOZING,
+ value = value,
+ transitionState = state,
+ ownerName = "DeviceEntryBackgroundViewModelTest",
+ )
+ }
+
+ private fun dozingToLockscreen(value: Float, state: TransitionState = RUNNING): TransitionStep {
+ return TransitionStep(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.LOCKSCREEN,
+ value = value,
+ transitionState = state,
+ ownerName = "DeviceEntryBackgroundViewModelTest",
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index a021de446911..546b32073aca 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -59,6 +59,7 @@ constructor(
primaryBouncerToAodTransitionViewModel: PrimaryBouncerToAodTransitionViewModel,
primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel,
primaryBouncerToLockscreenTransitionViewModel: PrimaryBouncerToLockscreenTransitionViewModel,
+ lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
) {
val color: Flow =
deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -103,6 +104,7 @@ constructor(
primaryBouncerToLockscreenTransitionViewModel
.deviceEntryBackgroundViewAlpha,
occludedToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+ lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
)
.merge()
.onStart {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
index d3eefca67037..7abf35de5dae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
@@ -55,16 +55,16 @@ constructor(
onCancel = { 1f },
)
+ val deviceEntryBackgroundViewAlpha: Flow =
+ transitionAnimation.immediatelyTransitionTo(0f)
+
override val deviceEntryParentViewAlpha: Flow =
deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
isUdfpsEnrolledAndEnabled ->
if (isUdfpsEnrolledAndEnabled) {
transitionAnimation.immediatelyTransitionTo(1f)
} else {
- transitionAnimation.sharedFlow(
- duration = 250.milliseconds,
- onStep = { 1f - it },
- )
+ transitionAnimation.sharedFlow(duration = 250.milliseconds, onStep = { 1f - it })
}
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
new file mode 100644
index 000000000000..09836ed46817
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModelKosmos.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+@ExperimentalCoroutinesApi
+val Kosmos.deviceEntryBackgroundViewModel by Fixture {
+ DeviceEntryBackgroundViewModel(
+ context = applicationContext,
+ deviceEntryIconViewModel = deviceEntryIconViewModel,
+ configurationInteractor = configurationInteractor,
+ keyguardTransitionInteractor = keyguardTransitionInteractor,
+ alternateBouncerToAodTransitionViewModel = alternateBouncerToAodTransitionViewModel,
+ alternateBouncerToDozingTransitionViewModel = alternateBouncerToDozingTransitionViewModel,
+ aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+ dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
+ dreamingToAodTransitionViewModel = dreamingToAodTransitionViewModel,
+ dreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel,
+ goneToAodTransitionViewModel = goneToAodTransitionViewModel,
+ goneToDozingTransitionViewModel = goneToDozingTransitionViewModel,
+ goneToLockscreenTransitionViewModel = goneToLockscreenTransitionViewModel,
+ lockscreenToAodTransitionViewModel = lockscreenToAodTransitionViewModel,
+ occludedToAodTransitionViewModel = occludedToAodTransitionViewModel,
+ occludedToDozingTransitionViewModel = occludedToDozingTransitionViewModel,
+ occludedToLockscreenTransitionViewModel = occludedToLockscreenTransitionViewModel,
+ primaryBouncerToAodTransitionViewModel = primaryBouncerToAodTransitionViewModel,
+ primaryBouncerToDozingTransitionViewModel = primaryBouncerToDozingTransitionViewModel,
+ primaryBouncerToLockscreenTransitionViewModel =
+ primaryBouncerToLockscreenTransitionViewModel,
+ lockscreenToDozingTransitionViewModel = lockscreenToDozingTransitionViewModel,
+ )
+}
--
GitLab
From 69f77e1883047bcfa3b3ad958ee3f077cba8b2d1 Mon Sep 17 00:00:00 2001
From: "hyunjae.choi"
Date: Mon, 14 Oct 2024 19:07:43 +0000
Subject: [PATCH 021/652] Fix the enforcing method to pass current user for
visible background users
To verify if the calling user is the visible background user, we use the
UserManagerService#enforceCurrentUserIfVisibleBackgroundEnabled method.
This method requires the current user to be passed as a parameter.
Bug: 373274137
Flag: EXEMPT bugfix
Test: atest FrameworksUiServicesTests:com.android.server.UiModeManagerServiceTest
Test: atest CtsAppTestCases:UiModeManagerTest
Test: atest --user-type secondary_user CtsAppTestCases:UiModeManagerTest
Test: atest --user-type secondary_user_on_secondary_display CtsAppTestCases:UiModeManagerTest
(cherry picked from https://partner-android-review.googlesource.com/q/commit:87566613c12b7f44bd9465c6226d7b542ea1e3a2)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ec8e8394ba6de60b6466147717d036afdfbefedd)
Merged-In: I3d24a483e3f563778d1e49971a35dd74895c79d1
Change-Id: I3d24a483e3f563778d1e49971a35dd74895c79d1
---
.../android/server/UiModeManagerService.java | 33 +++++++++++--------
.../server/UiModeManagerServiceTest.java | 3 ++
2 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index f32031dec43c..f2069d011958 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -427,6 +427,11 @@ final class UiModeManagerService extends SystemService {
mDreamsDisabledByAmbientModeSuppression = disabledByAmbientModeSuppression;
}
+ @VisibleForTesting
+ void setCurrentUser(int currentUserId) {
+ mCurrentUser = currentUserId;
+ }
+
@Override
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
mCurrentUser = to.getUserIdentifier();
@@ -848,9 +853,9 @@ final class UiModeManagerService extends SystemService {
throw new IllegalArgumentException("Unknown mode: " + mode);
}
- final int user = UserHandle.getCallingUserId();
- enforceCurrentUserIfVisibleBackgroundEnabled(user);
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+ final int user = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
@@ -913,7 +918,7 @@ final class UiModeManagerService extends SystemService {
@AttentionModeThemeOverlayType int attentionModeThemeOverlayType) {
setAttentionModeThemeOverlay_enforcePermission();
- enforceCurrentUserIfVisibleBackgroundEnabled(UserHandle.getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
synchronized (mLock) {
if (mAttentionModeThemeOverlay != attentionModeThemeOverlayType) {
@@ -1004,16 +1009,16 @@ final class UiModeManagerService extends SystemService {
return false;
}
final int user = Binder.getCallingUserHandle().getIdentifier();
- enforceCurrentUserIfVisibleBackgroundEnabled(user);
-
if (user != mCurrentUser && getContext().checkCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS)
!= PackageManager.PERMISSION_GRANTED) {
Slog.e(TAG, "Target user is not current user,"
+ " INTERACT_ACROSS_USERS permission is required");
return false;
-
}
+
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+
// Store the last requested bedtime night mode state so that we don't need to notify
// anyone if the user decides to switch to the night mode to bedtime.
if (modeCustomType == MODE_NIGHT_CUSTOM_TYPE_BEDTIME) {
@@ -1062,9 +1067,10 @@ final class UiModeManagerService extends SystemService {
Slog.e(TAG, "Set custom time start, requires MODIFY_DAY_NIGHT_MODE permission");
return;
}
- final int user = UserHandle.getCallingUserId();
- enforceCurrentUserIfVisibleBackgroundEnabled(user);
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+
+ final int user = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
try {
LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000);
@@ -1092,9 +1098,10 @@ final class UiModeManagerService extends SystemService {
Slog.e(TAG, "Set custom time end, requires MODIFY_DAY_NIGHT_MODE permission");
return;
}
- final int user = UserHandle.getCallingUserId();
- enforceCurrentUserIfVisibleBackgroundEnabled(user);
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
+
+ final int user = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
try {
LocalTime newTime = LocalTime.ofNanoOfDay(time * 1000);
@@ -1115,7 +1122,7 @@ final class UiModeManagerService extends SystemService {
assertLegit(callingPackage);
assertSingleProjectionType(projectionType);
enforceProjectionTypePermissions(projectionType);
- enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
synchronized (mLock) {
if (mProjectionHolders == null) {
@@ -1161,7 +1168,7 @@ final class UiModeManagerService extends SystemService {
assertLegit(callingPackage);
assertSingleProjectionType(projectionType);
enforceProjectionTypePermissions(projectionType);
- enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
return releaseProjectionUnchecked(projectionType, callingPackage);
}
@@ -1203,7 +1210,7 @@ final class UiModeManagerService extends SystemService {
return;
}
- enforceCurrentUserIfVisibleBackgroundEnabled(getCallingUserId());
+ enforceCurrentUserIfVisibleBackgroundEnabled(mCurrentUser);
synchronized (mLock) {
if (mProjectionListeners == null) {
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index c247c08c8010..3b0cb4ad8779 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -68,6 +68,7 @@ import static org.testng.Assert.assertThrows;
import android.Manifest;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.Flags;
import android.app.IOnProjectionStateChangedListener;
@@ -247,6 +248,8 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
mInjector = spy(new TestInjector());
mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
mTwilightManager, mInjector);
+ // Initialize the current user.
+ mUiManagerService.setCurrentUser(ActivityManager.getCurrentUser());
try {
mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
} catch (SecurityException e) {/* ignore for permission denial */}
--
GitLab
From 0c45be989379c5c3869976118283601297fb784b Mon Sep 17 00:00:00 2001
From: Tiger
Date: Wed, 16 Oct 2024 17:25:52 +0800
Subject: [PATCH 022/652] Update mPosition when creating a new
InsetsSourceControl
This should be part of commit: ac6cde62e08f5fe42cabc048ed985537d80d1d6b
that InsetsSourceProvider.mPosition should always be the same as
InsetsSourceControl.mSurfacePosition except during mHasPendingPosition.
Fix: 370738846
Flag: EXEMPT bugfix
Test: Click on the IME switch button and see if the IME position is
correct.
Test: atest InsetsSourceProviderTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:b9474405880eb483cfda7c13111f985bf7d0247d)
Merged-In: I5de9a80cbbb601bbdf39009f962fb1175751db28
Change-Id: I5de9a80cbbb601bbdf39009f962fb1175751db28
---
.../server/wm/InsetsSourceProvider.java | 3 ++-
.../server/wm/InsetsSourceProviderTest.java | 22 +++++++++++++++++++
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 57b879277326..d3cae4c7b940 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -400,7 +400,7 @@ class InsetsSourceProvider {
}
final Point position = getWindowFrameSurfacePosition();
if (!mPosition.equals(position)) {
- mPosition.set(position.x, position.y);
+ mPosition.set(position);
if (windowState != null && windowState.getWindowFrames().didFrameSizeChange()
&& windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) {
windowState.applyWithNextDraw(mSetControlPositionConsumer);
@@ -543,6 +543,7 @@ class InsetsSourceProvider {
}
boolean initiallyVisible = mClientVisible;
final Point surfacePosition = getWindowFrameSurfacePosition();
+ mPosition.set(surfacePosition);
mAdapter = new ControlAdapter(surfacePosition);
if (mSource.getType() == WindowInsets.Type.ime()) {
if (android.view.inputmethod.Flags.refactorInsetsController()) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index e8d089c61362..f48ba65217e2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -30,6 +30,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.graphics.Insets;
+import android.graphics.Point;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
@@ -259,6 +260,27 @@ public class InsetsSourceProviderTest extends WindowTestsBase {
assertEquals(Insets.of(0, 0, 0, 100), insets);
}
+ @Test
+ public void testUpdateInsetsControlPosition() {
+ final WindowState target = createWindow(null, TYPE_APPLICATION, "target");
+
+ final WindowState ime1 = createWindow(null, TYPE_INPUT_METHOD, "ime1");
+ ime1.getFrame().set(new Rect(0, 0, 0, 0));
+ mImeProvider.setWindowContainer(ime1, null, null);
+ mImeProvider.updateControlForTarget(target, false /* force */, null /* statsToken */);
+ ime1.getFrame().set(new Rect(0, 400, 500, 500));
+ mImeProvider.updateInsetsControlPosition(ime1);
+ assertEquals(new Point(0, 400), mImeProvider.getControl(target).getSurfacePosition());
+
+ final WindowState ime2 = createWindow(null, TYPE_INPUT_METHOD, "ime2");
+ ime2.getFrame().set(new Rect(0, 0, 0, 0));
+ mImeProvider.setWindowContainer(ime2, null, null);
+ mImeProvider.updateControlForTarget(target, false /* force */, null /* statsToken */);
+ ime2.getFrame().set(new Rect(0, 400, 500, 500));
+ mImeProvider.updateInsetsControlPosition(ime2);
+ assertEquals(new Point(0, 400), mImeProvider.getControl(target).getSurfacePosition());
+ }
+
@Test
public void testSetRequestedVisibleTypes() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
--
GitLab
From 810d2b8d39d08261f647a7b71c2b3113c2ba6a26 Mon Sep 17 00:00:00 2001
From: Matt Pietal
Date: Mon, 14 Oct 2024 18:31:46 +0000
Subject: [PATCH 023/652] Fix tapping HUNs with weather clock
This reverts another CL which attempted to fix touching the unlock
icon when the notification shelf was next to it. By restoring the
ordering in XML, this restores the proper touch hierarachy.
Fixes: 370270324
Flag: EXEMPT bugfix
(cherry picked from commit 0b558a935f18be75b71f06b81d8a807c3fca4c3d)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2261f88f1ade916d18582edc925e013ed66cce35)
Merged-In: I906da1cf5e5106ada355232941399efe7f1d3b14
Change-Id: I906da1cf5e5106ada355232941399efe7f1d3b14
---
.../res/layout/super_notification_shade.xml | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 22d34eb7b115..fbb07bed4b50 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -58,22 +58,22 @@
android:layout_height="match_parent"
android:visibility="invisible" />
-
-
+
-
-
+
--
GitLab
From d77da0e4f762703bd61a296d7ef4ac3777d78eb0 Mon Sep 17 00:00:00 2001
From: Geoffrey Boullanger
Date: Wed, 16 Oct 2024 14:42:52 +0000
Subject: [PATCH 024/652] Revert "Migrate to best practise to read network
state"
This reverts commit f9f96b6fcb031edcfe7e294fbab071b6b0ce88c5.
Reason for revert: breaking NTP calls when the device's date/time is too old
Bug: b/372188013
(cherry picked from https://android-review.googlesource.com/q/commit:3ae8bf1de1e772922a0670a24d0b40fafa5307cf)
Merged-In: I3f04991e7c9fb8f029da47ce895b1db65365bf9e
Change-Id: I3f04991e7c9fb8f029da47ce895b1db65365bf9e
---
core/java/android/util/NtpTrustedTime.java | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index 9f54d9fca24b..3adbd686cd2c 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -24,7 +24,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.Network;
-import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
import android.net.SntpClient;
import android.os.Build;
import android.os.SystemClock;
@@ -687,16 +687,8 @@ public abstract class NtpTrustedTime implements TrustedTime {
if (connectivityManager == null) {
return false;
}
- final NetworkCapabilities networkCapabilities =
- connectivityManager.getNetworkCapabilities(network);
- if (networkCapabilities == null) {
- if (LOGD) Log.d(TAG, "getNetwork: failed to get network capabilities");
- return false;
- }
- final boolean isConnectedToInternet = networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_INTERNET)
- && networkCapabilities.hasCapability(
- NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ final NetworkInfo ni = connectivityManager.getNetworkInfo(network);
+
// This connectivity check is to avoid performing a DNS lookup for the time server on a
// unconnected network. There are races to obtain time in Android when connectivity
// changes, which means that forceRefresh() can be called by various components before
@@ -706,8 +698,8 @@ public abstract class NtpTrustedTime implements TrustedTime {
// A side effect of check is that tests that run a fake NTP server on the device itself
// will only be able to use it if the active network is connected, even though loopback
// addresses are actually reachable.
- if (!isConnectedToInternet) {
- if (LOGD) Log.d(TAG, "getNetwork: no internet connectivity");
+ if (ni == null || !ni.isConnected()) {
+ if (LOGD) Log.d(TAG, "getNetwork: no connectivity");
return false;
}
return true;
--
GitLab
From 389aab722a4ca5ec4f03131d189f32588344ad10 Mon Sep 17 00:00:00 2001
From: Pavel Grafov
Date: Wed, 18 Sep 2024 16:34:11 +0100
Subject: [PATCH 025/652] Block uninstall if DMRH in a managed user
Previous change introduced a bug - on a personal device with a work
profile the user could uninstall updates from the personal side, thus
downgrading DMRH in the work profile, breaking it. With this change if a
package is DMRH on any managed user, uninstall will be blocked
Bug: 360807442
Test: btest a.d.c.DevicePolicyManagementRoleHolderTest
Flag: EXEMPT bugfix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3d5d962a6156fa822c0038e85315e7823a68ff59)
Merged-In: I9fd8bed4a8203f3dbfa8dc4ea1388e7c8d136d9a
Change-Id: I9fd8bed4a8203f3dbfa8dc4ea1388e7c8d136d9a
---
.../server/pm/PackageManagerService.java | 27 ++++++++++++++-----
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff9c3e5f467b..611e0d86202a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3389,18 +3389,31 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return true;
}
// Does it contain a device admin for any user?
- int[] users;
+ int[] allUsers = mUserManager.getUserIds();
+ int[] targetUsers;
if (userId == UserHandle.USER_ALL) {
- users = mUserManager.getUserIds();
+ targetUsers = allUsers;
} else {
- users = new int[]{userId};
+ targetUsers = new int[]{userId};
}
- for (int i = 0; i < users.length; ++i) {
- if (dpm.packageHasActiveAdmins(packageName, users[i])) {
+
+ for (int i = 0; i < targetUsers.length; ++i) {
+ if (dpm.packageHasActiveAdmins(packageName, targetUsers[i])) {
return true;
}
- if (isDeviceManagementRoleHolder(packageName, users[i])
- && dpmi.isUserOrganizationManaged(users[i])) {
+ }
+
+ // If a package is DMRH on a managed user, it should also be treated as an admin on
+ // that user. If that package is also a system package, it should also be protected
+ // on other users otherwise "uninstall updates" on an unmanaged user may break
+ // management on other users because apk version is shared between all users.
+ var packageState = snapshotComputer().getPackageStateInternal(packageName);
+ if (packageState == null) {
+ return false;
+ }
+ for (int user : packageState.isSystem() ? allUsers : targetUsers) {
+ if (isDeviceManagementRoleHolder(packageName, user)
+ && dpmi.isUserOrganizationManaged(user)) {
return true;
}
}
--
GitLab
From d0114a2027bc9b775001b5e417d90ac0997d59f9 Mon Sep 17 00:00:00 2001
From: Yabin Huang
Date: Thu, 17 Oct 2024 15:29:03 -0700
Subject: [PATCH 026/652] Specify the display ID to mirror when creating
virtual display
In VirtualDisplayConfig, the default value of mDisplayIdToMirror is
DEFAULT_DISPLAY. In order to create virtual display for visible
background users (running on secondary displays), this CL passed the
correct display ID when creating virtual display.
Bug: 355529421
Test: atest CtsWindowManagerDeviceIme
Test: atest --user-type secondary_user CtsWindowManagerDeviceIme
Test: atest --user-type secondary_user_on_secondary_display CtsWindowManagerDeviceIme
Flag: EXEMPT bugfix
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:036933d9608c43e483514e1c1003aaa6531664f1)
Merged-In: Ibdd39e598560c08bcaf6fa2846191b82bae1a8ab
Change-Id: Ibdd39e598560c08bcaf6fa2846191b82bae1a8ab
---
.../android/hardware/display/DisplayManager.java | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 97f6899ff141..b0ea92d140a5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -18,6 +18,7 @@ package android.hardware.display;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.HdrCapabilities.HdrType;
+import static android.view.Display.INVALID_DISPLAY;
import android.Manifest;
import android.annotation.FlaggedApi;
@@ -47,6 +48,7 @@ import android.os.Looper;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserManager;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -96,6 +98,8 @@ public final class DisplayManager {
@GuardedBy("mLock")
private final WeakDisplayCache mDisplayCache = new WeakDisplayCache();
+ private int mDisplayIdToMirror = INVALID_DISPLAY;
+
/**
* Broadcast receiver that indicates when the Wifi display status changes.
*
@@ -1086,6 +1090,7 @@ public final class DisplayManager {
if (surface != null) {
builder.setSurface(surface);
}
+ builder.setDisplayIdToMirror(getDisplayIdToMirror());
return createVirtualDisplay(builder.build(), handler, callback);
}
@@ -1163,6 +1168,7 @@ public final class DisplayManager {
if (surface != null) {
builder.setSurface(surface);
}
+ builder.setDisplayIdToMirror(getDisplayIdToMirror());
return createVirtualDisplay(projection, builder.build(), callback, handler);
}
@@ -1708,6 +1714,16 @@ public final class DisplayManager {
return mGlobal.getDefaultDozeBrightness(displayId);
}
+ private int getDisplayIdToMirror() {
+ if (mDisplayIdToMirror == INVALID_DISPLAY) {
+ final UserManager userManager = mContext.getSystemService(UserManager.class);
+ mDisplayIdToMirror = userManager.isVisibleBackgroundUsersSupported()
+ ? userManager.getMainDisplayIdAssignedToUser()
+ : DEFAULT_DISPLAY;
+ }
+ return mDisplayIdToMirror;
+ }
+
/**
* Listens for changes in available display devices.
*/
--
GitLab
From 543a9e8dffbbd712635729439b9eb52467deccd2 Mon Sep 17 00:00:00 2001
From: wilsonshih
Date: Wed, 11 Sep 2024 08:25:20 +0000
Subject: [PATCH 027/652] Keep wallpaper in prepare back transition.
Revert part of ag/29115929, it would be safe as long as the wallpaper
surface won't merged into next transition.
Bug: 365500016
Flag: com.android.window.flags.migrate_predictive_back_transition
Test: atest BackAnimationControllerTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a3d5df4aaac6d687cde0a31f0e22324a6ac6f9db)
Merged-In: I51232a95a585c1b931a68f456d9f208a6c50cb71
Change-Id: I51232a95a585c1b931a68f456d9f208a6c50cb71
---
.../com/android/wm/shell/back/BackAnimationController.java | 4 ----
1 file changed, 4 deletions(-)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 3e5adf395cdd..5836085e0ddc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -1501,10 +1501,6 @@ public class BackAnimationController implements RemoteCallable= 0; --i) {
final TransitionInfo.Change c = info.getChanges().get(i);
- if (c.hasFlags(FLAG_IS_WALLPAPER)) {
- st.setAlpha(c.getLeash(), 1.0f);
- continue;
- }
if (TransitionUtil.isOpeningMode(c.getMode())) {
final Point offset = c.getEndRelOffset();
st.setPosition(c.getLeash(), offset.x, offset.y);
--
GitLab
From 621c7532c08f3e7535de7ad7f2ccf82e73cd2198 Mon Sep 17 00:00:00 2001
From: Ashley Ingram
Date: Thu, 17 Oct 2024 08:49:21 +0000
Subject: [PATCH 028/652] Make Wearable settings readable
Settings were not hidden on Wear pre-T, so some apps have dependencies on these settings. When they run on U, they crash (because the settings are now hidden). We do not have an alternative API, so there's no other approach apps can take in subsequent API versions.
Change the Settings to be Readable. We can deprecate these when official APIs are added to Wear.
Bug: 372375270
Flag: EXEMPT: unflaggable
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:e0722e9156795c6c97ce232f2e52c686b1bef202)
Merged-In: Ib599b0390980677aa1155366dad7c6f9b584224c
Change-Id: Ib599b0390980677aa1155366dad7c6f9b584224c
---
core/java/android/provider/Settings.java | 114 +++++++++++------------
1 file changed, 57 insertions(+), 57 deletions(-)
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b8a8be159d12..ef8b3d738154 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -19338,14 +19338,14 @@ public final class Settings {
* If hotword detection should be enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String HOTWORD_DETECTION_ENABLED = "hotword_detection_enabled";
/**
* Whether Smart Replies are enabled within Wear.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String SMART_REPLIES_ENABLED = "smart_replies_enabled";
/**
@@ -19359,7 +19359,7 @@ public final class Settings {
* If FLP should obtain location data from the paired device.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String OBTAIN_PAIRED_DEVICE_LOCATION =
"obtain_paired_device_location";
@@ -19367,7 +19367,7 @@ public final class Settings {
* The play store availability on companion phone.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String PHONE_PLAY_STORE_AVAILABILITY =
"phone_play_store_availability";
@@ -19383,7 +19383,7 @@ public final class Settings {
* Whether the bug report is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String BUG_REPORT = "bug_report";
// Possible bug report states
@@ -19396,14 +19396,14 @@ public final class Settings {
* The enabled/disabled state of the SmartIlluminate.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String SMART_ILLUMINATE_ENABLED = "smart_illuminate_enabled";
/**
* Whether automatic time is enabled on the watch.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String CLOCKWORK_AUTO_TIME = "clockwork_auto_time";
// Possible clockwork auto time states
@@ -19421,7 +19421,7 @@ public final class Settings {
* Whether automatic time zone is enabled on the watch.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String CLOCKWORK_AUTO_TIME_ZONE = "clockwork_auto_time_zone";
// Possible clockwork auto time zone states
@@ -19438,14 +19438,14 @@ public final class Settings {
* Whether 24 hour time format is enabled on the watch.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String CLOCKWORK_24HR_TIME = "clockwork_24hr_time";
/**
* Whether the auto wifi toggle setting is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AUTO_WIFI = "auto_wifi";
// Possible force wifi on states
@@ -19465,7 +19465,7 @@ public final class Settings {
* wifi requirement until this time). The time is in millis since epoch.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS =
"alt_bypass_wifi_requirement_time_millis";
@@ -19473,7 +19473,7 @@ public final class Settings {
* Whether the setup was skipped.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String SETUP_SKIPPED = "setup_skipped";
// Possible setup_skipped states
@@ -19488,7 +19488,7 @@ public final class Settings {
* The last requested call forwarding action.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String LAST_CALL_FORWARD_ACTION = "last_call_forward_action";
// Possible call forwarding actions
@@ -19501,31 +19501,31 @@ public final class Settings {
// Stem button settings.
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_1_TYPE = "STEM_1_TYPE";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_1_DATA = "STEM_1_DATA";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_1_DEFAULT_DATA = "STEM_1_DEFAULT_DATA";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_2_TYPE = "STEM_2_TYPE";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_2_DATA = "STEM_2_DATA";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_2_DEFAULT_DATA = "STEM_2_DEFAULT_DATA";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_3_TYPE = "STEM_3_TYPE";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_3_DATA = "STEM_3_DATA";
/** @hide */
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String STEM_3_DEFAULT_DATA = "STEM_3_DEFAULT_DATA";
// Stem types
@@ -19540,14 +19540,14 @@ public final class Settings {
* If the device should be muted when off body.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String MUTE_WHEN_OFF_BODY_ENABLED = "obtain_mute_when_off_body";
/**
* Wear OS version string.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String WEAR_OS_VERSION_STRING = "wear_os_version_string";
/**
@@ -19560,28 +19560,28 @@ public final class Settings {
* The android wear system version.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String ANDROID_WEAR_VERSION = "android_wear_version";
/**
* The wear system capabiltiies.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String SYSTEM_CAPABILITIES = "system_capabilities";
/**
* The android wear system edition.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String SYSTEM_EDITION = "android_wear_system_edition";
/**
* The Wear platform MR number.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String WEAR_PLATFORM_MR_NUMBER = "wear_platform_mr_number";
/**
@@ -19595,42 +19595,42 @@ public final class Settings {
* Whether ambient is currently enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_ENABLED = "ambient_enabled";
/**
* Whether ambient tilt to wake is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_TILT_TO_WAKE = "ambient_tilt_to_wake";
/**
* Whether ambient low bit mode is enabled by developer options.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_LOW_BIT_ENABLED_DEV = "ambient_low_bit_enabled_dev";
/**
* Whether ambient touch to wake is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_TOUCH_TO_WAKE = "ambient_touch_to_wake";
/**
* Whether ambient tilt to bright is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_TILT_TO_BRIGHT = "ambient_tilt_to_bright";
/**
* Whether touch and hold to edit WF is enabled
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String GESTURE_TOUCH_AND_HOLD_WATCH_FACE_ENABLED =
"gesture_touch_and_hold_watchface_enabled";
@@ -19644,7 +19644,7 @@ public final class Settings {
* Whether bedtime mode is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String BEDTIME_MODE = "bedtime_mode";
/**
@@ -19656,35 +19656,35 @@ public final class Settings {
* Whether the current watchface is decomposable.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String DECOMPOSABLE_WATCHFACE = "current_watchface_decomposable";
/**
* Whether to force ambient when docked.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_FORCE_WHEN_DOCKED = "ambient_force_when_docked";
/**
* Whether the ambient low bit mode is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_LOW_BIT_ENABLED = "ambient_low_bit_enabled";
/**
* The timeout duration in minutes of ambient mode when plugged in.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String AMBIENT_PLUGGED_TIMEOUT_MIN = "ambient_plugged_timeout_min";
/**
* What OS does paired device has.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String PAIRED_DEVICE_OS_TYPE = "paired_device_os_type";
// Possible values of PAIRED_DEVICE_OS_TYPE
@@ -19719,7 +19719,7 @@ public final class Settings {
* The user's last setting for hfp client.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String USER_HFP_CLIENT_SETTING = "user_hfp_client_setting";
// Possible hfp client user setting values
@@ -19744,7 +19744,7 @@ public final class Settings {
* The companion App name.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String COMPANION_APP_NAME = "wear_companion_app_name";
/**
@@ -19752,21 +19752,21 @@ public final class Settings {
* wear. 1 for supporting, 0 for not supporting.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String ENABLE_ALL_LANGUAGES = "enable_all_languages";
/**
* The Locale (as language tag) the user chose at startup.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String SETUP_LOCALE = "setup_locale";
/**
* The version of oem setup present.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String OEM_SETUP_VERSION = "oem_setup_version";
/**
@@ -19812,7 +19812,7 @@ public final class Settings {
* -{@link BATTERY_SAVER_MODE_CUSTOM}
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String BATTERY_SAVER_MODE = "battery_saver_mode";
/**
@@ -19869,7 +19869,7 @@ public final class Settings {
* If burn in protection is enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String BURN_IN_PROTECTION_ENABLED = "burn_in_protection";
/**
@@ -19888,7 +19888,7 @@ public final class Settings {
* RIGHT_WRIST_ROTATION_0 = "2", RIGHT_WRIST_ROTATION_180 = "3"
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String WRIST_ORIENTATION_MODE = "wear_wrist_orientation_mode";
/**
@@ -19927,7 +19927,7 @@ public final class Settings {
*
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String CLOCKWORK_SYSUI_PACKAGE = "clockwork_sysui_package";
/**
@@ -19957,7 +19957,7 @@ public final class Settings {
* Whether the device has Wet Mode/ Touch Lock Mode enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String WET_MODE_ON = "wet_mode_on";
/**
@@ -19976,7 +19976,7 @@ public final class Settings {
* Whether charging sounds are enabled.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String CHARGING_SOUNDS_ENABLED = "wear_charging_sounds_enabled";
/**
@@ -19985,7 +19985,7 @@ public final class Settings {
*
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String DYNAMIC_COLOR_THEME_ENABLED = "dynamic_color_theme_enabled";
/**
@@ -20077,7 +20077,7 @@ public final class Settings {
* The key to indicate the data migration status on device upgrade in Wear Services.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String UPGRADE_DATA_MIGRATION_STATUS =
"upgrade_data_migration_status";
@@ -20134,20 +20134,20 @@ public final class Settings {
* The custom foreground color.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String CUSTOM_COLOR_FOREGROUND = "custom_foreground_color";
/**
* The custom background color.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String CUSTOM_COLOR_BACKGROUND = "custom_background_color";
/** The status of the phone switching process.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String PHONE_SWITCHING_STATUS = "phone_switching_status";
/**
@@ -20318,7 +20318,7 @@ public final class Settings {
* Controls the launcher ui mode on wearable devices.
* @hide
*/
- @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Readable
public static final String WEAR_LAUNCHER_UI_MODE = "wear_launcher_ui_mode";
/** Whether Wear Power Anomaly Service is enabled.
--
GitLab
From 5af7ec8fbeb52666d70873b62adbddb696716578 Mon Sep 17 00:00:00 2001
From: Dmitry Dementyev
Date: Thu, 26 Sep 2024 19:45:46 +0000
Subject: [PATCH 029/652] Revert "Sanitize Bundle from
AbstractAccountAuthenticator."
This reverts commit 09d381088952db904dbd0cc1c1c7362c033cf216.
Reason for revert: b/342661425: fix filters obfuscated_gaia_id extra used for Cross profile account setup. A new version will be created.
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2dc861d4ae98f4e18c82d3ad8f3b478dd2ddb7bb)
Merged-In: I4da2ad09473f0155ebf11a45a48562b59ee5de37
Change-Id: I4da2ad09473f0155ebf11a45a48562b59ee5de37
---
.../accounts/AccountManagerService.java | 88 +------------------
.../accounts/AccountManagerServiceTest.java | 62 ++++---------
2 files changed, 20 insertions(+), 130 deletions(-)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 88edb121c0c8..3499a3a5edde 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1773,8 +1773,7 @@ public class AccountManagerService
// Create a Session for the target user and pass in the bundle
completeCloningAccount(response, result, account, toAccounts, userFrom);
} else {
- // Bundle format is not defined.
- super.onResultSkipSanitization(result);
+ super.onResult(result);
}
}
}.bind();
@@ -1861,8 +1860,7 @@ public class AccountManagerService
// account to avoid retries?
// TODO: what we do with the visibility?
- // Bundle format is not defined.
- super.onResultSkipSanitization(result);
+ super.onResult(result);
}
@Override
@@ -2108,7 +2106,6 @@ public class AccountManagerService
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
- result = sanitizeBundle(result);
IAccountManagerResponse response = getResponseAndClose();
if (response != null) {
try {
@@ -2462,7 +2459,6 @@ public class AccountManagerService
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
- result = sanitizeBundle(result);
if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
&& !result.containsKey(AccountManager.KEY_INTENT)) {
final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
@@ -2977,7 +2973,6 @@ public class AccountManagerService
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
- result = sanitizeBundle(result);
if (result != null) {
String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
Bundle bundle = new Bundle();
@@ -3155,7 +3150,6 @@ public class AccountManagerService
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
- result = sanitizeBundle(result);
if (result != null) {
if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
Intent intent = newGrantCredentialsPermissionIntent(
@@ -3627,12 +3621,6 @@ public class AccountManagerService
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
- Bundle sessionBundle = null;
- if (result != null) {
- // Session bundle will be removed from result.
- sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
- }
- result = sanitizeBundle(result);
mNumResults++;
Intent intent = null;
if (result != null) {
@@ -3694,6 +3682,7 @@ public class AccountManagerService
// bundle contains data necessary for finishing the session
// later. The session bundle will be encrypted here and
// decrypted later when trying to finish the session.
+ Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
if (sessionBundle != null) {
String accountType = sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE);
if (TextUtils.isEmpty(accountType)
@@ -4081,7 +4070,6 @@ public class AccountManagerService
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
- result = sanitizeBundle(result);
IAccountManagerResponse response = getResponseAndClose();
if (response == null) {
return;
@@ -4395,7 +4383,6 @@ public class AccountManagerService
@Override
public void onResult(Bundle result) {
Bundle.setDefusable(result, true);
- result = sanitizeBundle(result);
mNumResults++;
if (result == null) {
onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
@@ -4952,68 +4939,6 @@ public class AccountManagerService
callback, resultReceiver);
}
-
- // All keys for Strings passed from AbstractAccountAuthenticator using Bundle.
- private static final String[] sStringBundleKeys = new String[] {
- AccountManager.KEY_ACCOUNT_NAME,
- AccountManager.KEY_ACCOUNT_TYPE,
- AccountManager.KEY_AUTHTOKEN,
- AccountManager.KEY_AUTH_TOKEN_LABEL,
- AccountManager.KEY_ERROR_MESSAGE,
- AccountManager.KEY_PASSWORD,
- AccountManager.KEY_ACCOUNT_STATUS_TOKEN};
-
- /**
- * Keep only documented fields in a Bundle received from AbstractAccountAuthenticator.
- */
- protected static Bundle sanitizeBundle(Bundle bundle) {
- if (bundle == null) {
- return null;
- }
- Bundle sanitizedBundle = new Bundle();
- Bundle.setDefusable(sanitizedBundle, true);
- int updatedKeysCount = 0;
- for (String stringKey : sStringBundleKeys) {
- if (bundle.containsKey(stringKey)) {
- String value = bundle.getString(stringKey);
- sanitizedBundle.putString(stringKey, value);
- updatedKeysCount++;
- }
- }
- String key = AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY;
- if (bundle.containsKey(key)) {
- long expiryMillis = bundle.getLong(key, 0L);
- sanitizedBundle.putLong(key, expiryMillis);
- updatedKeysCount++;
- }
- key = AccountManager.KEY_BOOLEAN_RESULT;
- if (bundle.containsKey(key)) {
- boolean booleanResult = bundle.getBoolean(key, false);
- sanitizedBundle.putBoolean(key, booleanResult);
- updatedKeysCount++;
- }
- key = AccountManager.KEY_ERROR_CODE;
- if (bundle.containsKey(key)) {
- int errorCode = bundle.getInt(key, 0);
- sanitizedBundle.putInt(key, errorCode);
- updatedKeysCount++;
- }
- key = AccountManager.KEY_INTENT;
- if (bundle.containsKey(key)) {
- Intent intent = bundle.getParcelable(key, Intent.class);
- sanitizedBundle.putParcelable(key, intent);
- updatedKeysCount++;
- }
- if (bundle.containsKey(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE)) {
- // The field is not copied in sanitized bundle.
- updatedKeysCount++;
- }
- if (updatedKeysCount != bundle.size()) {
- Log.w(TAG, "Size mismatch after sanitizeBundle call.");
- }
- return sanitizedBundle;
- }
-
private abstract class Session extends IAccountAuthenticatorResponse.Stub
implements IBinder.DeathRecipient, ServiceConnection {
private final Object mSessionLock = new Object();
@@ -5304,14 +5229,9 @@ public class AccountManagerService
}
}
}
+
@Override
public void onResult(Bundle result) {
- Bundle.setDefusable(result, true);
- result = sanitizeBundle(result);
- onResultSkipSanitization(result);
- }
-
- public void onResultSkipSanitization(Bundle result) {
Bundle.setDefusable(result, true);
mNumResults++;
Intent intent = null;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index b9ce8ad0b018..0c92abce7254 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -1163,6 +1163,16 @@ public class AccountManagerServiceTest extends AndroidTestCase {
verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
Bundle result = mBundleCaptor.getValue();
+ Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(sessionBundle);
+ // Assert that session bundle is decrypted and hence data is visible.
+ assertEquals(AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1,
+ sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+ // Assert finishSessionAsUser added calling uid and pid into the sessionBundle
+ assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_UID));
+ assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_PID));
+ assertEquals(sessionBundle.getString(
+ AccountManager.KEY_ANDROID_PACKAGE_NAME), "APCT.package");
// Verify response data
assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
@@ -2111,6 +2121,12 @@ public class AccountManagerServiceTest extends AndroidTestCase {
result.getString(AccountManager.KEY_ACCOUNT_NAME));
assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+
+ Bundle optionBundle = result.getParcelable(
+ AccountManagerServiceTestFixtures.KEY_OPTIONS_BUNDLE);
+ // Assert addAccountAsUser added calling uid and pid into the option bundle
+ assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_UID));
+ assertTrue(optionBundle.containsKey(AccountManager.KEY_CALLER_PID));
}
@SmallTest
@@ -3441,52 +3457,6 @@ public class AccountManagerServiceTest extends AndroidTestCase {
+ (readTotalTime.doubleValue() / readerCount / loopSize));
}
- @SmallTest
- public void testSanitizeBundle_expectedFields() throws Exception {
- Bundle bundle = new Bundle();
- bundle.putString(AccountManager.KEY_ACCOUNT_NAME, "name");
- bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, "type");
- bundle.putString(AccountManager.KEY_AUTHTOKEN, "token");
- bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, "label");
- bundle.putString(AccountManager.KEY_ERROR_MESSAGE, "error message");
- bundle.putString(AccountManager.KEY_PASSWORD, "password");
- bundle.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN, "status");
-
- bundle.putLong(AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 123L);
- bundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
- bundle.putInt(AccountManager.KEY_ERROR_CODE, 456);
-
- Bundle sanitizedBundle = AccountManagerService.sanitizeBundle(bundle);
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_NAME), "name");
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_TYPE), "type");
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_AUTHTOKEN), "token");
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_AUTH_TOKEN_LABEL), "label");
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_ERROR_MESSAGE), "error message");
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_PASSWORD), "password");
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN), "status");
-
- assertEquals(sanitizedBundle.getLong(
- AbstractAccountAuthenticator.KEY_CUSTOM_TOKEN_EXPIRY, 0), 123L);
- assertEquals(sanitizedBundle.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false), true);
- assertEquals(sanitizedBundle.getInt(AccountManager.KEY_ERROR_CODE, 0), 456);
- }
-
- @SmallTest
- public void testSanitizeBundle_filtersUnexpectedFields() throws Exception {
- Bundle bundle = new Bundle();
- bundle.putString(AccountManager.KEY_ACCOUNT_NAME, "name");
- bundle.putString("unknown_key", "value");
- Bundle sessionBundle = new Bundle();
- bundle.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
-
- Bundle sanitizedBundle = AccountManagerService.sanitizeBundle(bundle);
-
- assertEquals(sanitizedBundle.getString(AccountManager.KEY_ACCOUNT_NAME), "name");
- assertFalse(sanitizedBundle.containsKey("unknown_key"));
- // It is a valid response from Authenticator which will be accessed using original Bundle
- assertFalse(sanitizedBundle.containsKey(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
- }
-
private void waitForCyclicBarrier(CyclicBarrier cyclicBarrier) {
try {
cyclicBarrier.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
--
GitLab
From dfa33e98eee99228e83f8d855c89da368433fb38 Mon Sep 17 00:00:00 2001
From: Mayank Garg
Date: Tue, 22 Oct 2024 11:47:30 -0700
Subject: [PATCH 030/652] Always allow System user to change device config in
case of Multi-user-multi-display (MUMD)
When visible background user (aka MUMD) is enabled, background users are visible on other displays. In this config, some namespaces (right now game_overlay) are not allowed to be updated by any user other than current user. The CL allows SYSTEM user to change that namespace config.
Flag: EXEMPT bug fix
Bug: 375232833
Bug: 361502556
Bug: 328686115
Test: atest GameManagerStatsTests
Test: atest AndroidCarApiTest:android.car.apitest.DeviceConfigTest
Test: atest --user-type secondary_user_on_secondary_display AndroidCarApiTest:android.car.apitest.DeviceConfigTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f14825b16b41e97e10deff3c39924a518ecba157)
Merged-In: I73cd0fae216ab9aecefc2fdb49a719e919c6437a
Change-Id: I73cd0fae216ab9aecefc2fdb49a719e919c6437a
---
.../com/android/providers/settings/SettingsProvider.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 749ad0a993b3..6f8947c9bea1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2479,10 +2479,10 @@ public class SettingsProvider extends ContentProvider {
final long identity = Binder.clearCallingIdentity();
try {
int currentUser = ActivityManager.getCurrentUser();
- if (callingUser == currentUser) {
- // enforce the deny list only if the caller is not current user. Currently only auto
- // uses background visible user, and auto doesn't support profiles so profiles of
- // current users is not checked here.
+ if (callingUser == currentUser || callingUser == UserHandle.USER_SYSTEM) {
+ // enforce the deny list only if the caller is not current user or not a system
+ // user. Currently only auto uses background visible user, and auto doesn't
+ // support profiles so profiles of current users is not checked here.
return;
}
} finally {
--
GitLab
From e35050398c862100611b657550163526268589ae Mon Sep 17 00:00:00 2001
From: Mark Renouf
Date: Tue, 15 Oct 2024 11:56:32 -0400
Subject: [PATCH 031/652] Move ScreenshotProxyService, etc to proxy/*, unify
naming
The service implementation is internal and usage should only be
through the injectable interface 'ScreenshotProxy'. This also unifies
the naming to be consistent with the interface and client wrapper.
Flag: NONE straight rename no functional changes
Test: N/A
Bug: 339223847
Change-Id: Ie06aeabfb67f93fddd01981865a03a88c67fc625
---
packages/SystemUI/AndroidManifest.xml | 2 +-
.../systemui/screenshot/ActionIntentExecutorTest.kt | 8 ++++----
.../systemui/screenshot/ActionIntentExecutor.kt | 8 ++++----
.../systemui/screenshot/dagger/ScreenshotModule.java | 4 ++--
.../data/repository/DisplayContentRepositoryImpl.kt | 10 +++++-----
.../screenshot/{ => proxy}/IOnDoneCallback.aidl | 2 +-
.../screenshot/{ => proxy}/IScreenshotProxy.aidl | 4 ++--
.../proxy/{SystemUiProxy.kt => ScreenshotProxy.kt} | 2 +-
...SystemUiProxyClient.kt => ScreenshotProxyClient.kt} | 9 +++------
...SystemUiProxyModule.kt => ScreenshotProxyModule.kt} | 5 ++---
.../screenshot/{ => proxy}/ScreenshotProxyService.kt | 5 +++--
11 files changed, 28 insertions(+), 31 deletions(-)
rename packages/SystemUI/src/com/android/systemui/screenshot/{ => proxy}/IOnDoneCallback.aidl (93%)
rename packages/SystemUI/src/com/android/systemui/screenshot/{ => proxy}/IScreenshotProxy.aidl (89%)
rename packages/SystemUI/src/com/android/systemui/screenshot/proxy/{SystemUiProxy.kt => ScreenshotProxy.kt} (97%)
rename packages/SystemUI/src/com/android/systemui/screenshot/proxy/{SystemUiProxyClient.kt => ScreenshotProxyClient.kt} (85%)
rename packages/SystemUI/src/com/android/systemui/screenshot/proxy/{SystemUiProxyModule.kt => ScreenshotProxyModule.kt} (85%)
rename packages/SystemUI/src/com/android/systemui/screenshot/{ => proxy}/ScreenshotProxyService.kt (97%)
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 510c9b742e74..b43b009302ec 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -458,7 +458,7 @@
android:label="@string/screenshot_scroll_label"
android:finishOnTaskLaunch="true" />
-
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
index 612d646bb7d4..53a083f9ceae 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
@@ -17,13 +17,13 @@
package com.android.systemui.screenshot
import android.content.Intent
-import androidx.test.ext.junit.runners.AndroidJUnit4
import android.os.Process.myUserHandle
import android.platform.test.annotations.EnableFlags
import android.testing.TestableContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.systemui.Flags
import com.android.systemui.SysuiTestCase
-import com.android.systemui.screenshot.proxy.SystemUiProxy
+import com.android.systemui.screenshot.proxy.ScreenshotProxy
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -45,7 +45,7 @@ class ActionIntentExecutorTest : SysuiTestCase() {
private val testableContext = TestableContext(mContext)
private val activityManagerWrapper = mock()
- private val systemUiProxy = mock()
+ private val screenshotProxy = mock()
private val displayTracker = mock()
@@ -55,7 +55,7 @@ class ActionIntentExecutorTest : SysuiTestCase() {
activityManagerWrapper,
testScope,
mainDispatcher,
- systemUiProxy,
+ screenshotProxy,
displayTracker,
)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index 7b01c36489fb..a365b7c5e9a1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -37,7 +37,7 @@ import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.screenshot.proxy.SystemUiProxy
+import com.android.systemui.screenshot.proxy.ScreenshotProxy
import com.android.systemui.settings.DisplayTracker
import com.android.systemui.shared.system.ActivityManagerWrapper
import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -55,7 +55,7 @@ constructor(
private val activityManagerWrapper: ActivityManagerWrapper,
@Application private val applicationScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
- private val systemUiProxy: SystemUiProxy,
+ private val screenshotProxy: ScreenshotProxy,
private val displayTracker: DisplayTracker,
) {
/**
@@ -89,7 +89,7 @@ constructor(
CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT
)
}
- systemUiProxy.dismissKeyguard()
+ screenshotProxy.dismissKeyguard()
var transitionOptions: ActivityOptions? = null
if (transitionCoordinator?.decor?.isAttachedToWindow == true) {
transitionCoordinator.startExit()
@@ -127,7 +127,7 @@ constructor(
private suspend fun launchCrossProfileIntent(
user: UserHandle,
intent: Intent,
- bundle: Bundle?
+ bundle: Bundle?,
) {
val connector = getCrossProfileConnector(user)
val completion = CompletableDeferred()
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
index 90695fa00ceb..253e3a613083 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java
@@ -38,7 +38,7 @@ import com.android.systemui.screenshot.appclips.AppClipsScreenshotHelperService;
import com.android.systemui.screenshot.appclips.AppClipsService;
import com.android.systemui.screenshot.message.MessageModule;
import com.android.systemui.screenshot.policy.ScreenshotPolicyModule;
-import com.android.systemui.screenshot.proxy.SystemUiProxyModule;
+import com.android.systemui.screenshot.proxy.ScreenshotProxyModule;
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel;
import dagger.Binds;
@@ -50,7 +50,7 @@ import dagger.multibindings.IntoMap;
/**
* Defines injectable resources for Screenshots
*/
-@Module(includes = {ScreenshotPolicyModule.class, SystemUiProxyModule.class, MessageModule.class})
+@Module(includes = {ScreenshotPolicyModule.class, ScreenshotProxyModule.class, MessageModule.class})
public abstract class ScreenshotModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt
index e9599dcb026d..ec34808459c8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/data/repository/DisplayContentRepositoryImpl.kt
@@ -22,21 +22,21 @@ import android.app.IActivityTaskManager
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.screenshot.data.model.DisplayContentModel
import com.android.systemui.screenshot.data.model.SystemUiState
-import com.android.systemui.screenshot.proxy.SystemUiProxy
+import com.android.systemui.screenshot.proxy.ScreenshotProxy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
/**
* Implements DisplayTaskRepository using [IActivityTaskManager], along with [ProfileTypeRepository]
- * and [SystemUiProxy].
+ * and [ScreenshotProxy].
*/
@SuppressLint("MissingPermission")
class DisplayContentRepositoryImpl
@Inject
constructor(
private val atmService: IActivityTaskManager,
- private val systemUiProxy: SystemUiProxy,
+ private val screenshotProxy: ScreenshotProxy,
@Background private val background: CoroutineDispatcher,
) : DisplayContentRepository {
@@ -53,8 +53,8 @@ constructor(
): DisplayContentModel {
return DisplayContentModel(
displayId,
- SystemUiState(systemUiProxy.isNotificationShadeExpanded()),
- rootTasks
+ SystemUiState(screenshotProxy.isNotificationShadeExpanded()),
+ rootTasks,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/IOnDoneCallback.aidl b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/IOnDoneCallback.aidl
similarity index 93%
rename from packages/SystemUI/src/com/android/systemui/screenshot/IOnDoneCallback.aidl
rename to packages/SystemUI/src/com/android/systemui/screenshot/proxy/IOnDoneCallback.aidl
index e15030f78234..fb97fa71480b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/IOnDoneCallback.aidl
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/IOnDoneCallback.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.proxy;
interface IOnDoneCallback {
void onDone(boolean success);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/IScreenshotProxy.aidl
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
rename to packages/SystemUI/src/com/android/systemui/screenshot/proxy/IScreenshotProxy.aidl
index d2e3fbd65762..7b2f7e699521 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/IScreenshotProxy.aidl
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/IScreenshotProxy.aidl
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.systemui.screenshot;
+package com.android.systemui.screenshot.proxy;
-import com.android.systemui.screenshot.IOnDoneCallback;
+import com.android.systemui.screenshot.proxy.IOnDoneCallback;
/** Interface implemented by ScreenshotProxyService */
interface IScreenshotProxy {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxy.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxy.kt
rename to packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxy.kt
index e3eb3c4de80a..b44168f70ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxy.kt
@@ -24,7 +24,7 @@ package com.android.systemui.screenshot.proxy
*
* TODO: Rename and relocate 'ScreenshotProxyService' to this package and remove duplicate clients.
*/
-interface SystemUiProxy {
+interface ScreenshotProxy {
/** Indicate if the notification shade is "open"... (not in the fully collapsed position) */
suspend fun isNotificationShadeExpanded(): Boolean
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxyClient.kt b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyClient.kt
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxyClient.kt
rename to packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyClient.kt
index dcf58bde5f70..1158e2eb0ae5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxyClient.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyClient.kt
@@ -22,9 +22,6 @@ import android.content.Intent
import android.util.Log
import com.android.internal.infra.ServiceConnector
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.screenshot.IOnDoneCallback
-import com.android.systemui.screenshot.IScreenshotProxy
-import com.android.systemui.screenshot.ScreenshotProxyService
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@@ -32,8 +29,8 @@ import kotlinx.coroutines.CompletableDeferred
private const val TAG = "SystemUiProxy"
-/** An implementation of [SystemUiProxy] using [ScreenshotProxyService]. */
-class SystemUiProxyClient @Inject constructor(@Application context: Context) : SystemUiProxy {
+/** An implementation of [ScreenshotProxy] using [ScreenshotProxyService]. */
+class ScreenshotProxyClient @Inject constructor(@Application context: Context) : ScreenshotProxy {
@SuppressLint("ImplicitSamInstance")
private val proxyConnector: ServiceConnector =
ServiceConnector.Impl(
@@ -41,7 +38,7 @@ class SystemUiProxyClient @Inject constructor(@Application context: Context) : S
Intent(context, ScreenshotProxyService::class.java),
Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
context.userId,
- IScreenshotProxy.Stub::asInterface
+ IScreenshotProxy.Stub::asInterface,
)
override suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxyModule.kt b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyModule.kt
similarity index 85%
rename from packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxyModule.kt
rename to packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyModule.kt
index 4dd5cc4b55b4..797be9121ae8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/proxy/SystemUiProxyModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyModule.kt
@@ -18,14 +18,13 @@ package com.android.systemui.screenshot.proxy
import android.app.Service
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.screenshot.ScreenshotProxyService
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap
@Module
-interface SystemUiProxyModule {
+interface ScreenshotProxyModule {
@Binds
@IntoMap
@@ -34,5 +33,5 @@ interface SystemUiProxyModule {
@Binds
@SysUISingleton
- fun bindSystemUiProxy(systemUiProxyClient: SystemUiProxyClient): SystemUiProxy
+ fun bindSystemUiProxy(screenshotProxyClient: ScreenshotProxyClient): ScreenshotProxy
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyService.kt
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
rename to packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyService.kt
index 6df22f036273..a84f55268678 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/proxy/ScreenshotProxyService.kt
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.screenshot
+
+package com.android.systemui.screenshot.proxy
import android.content.Intent
import android.os.IBinder
@@ -67,7 +68,7 @@ constructor(
null,
true /* dismissShade */,
true /* afterKeyguardGone */,
- true /* deferred */
+ true, /* deferred */
)
}
--
GitLab
From 1941110a17571b9039645ced44210c56957cbc74 Mon Sep 17 00:00:00 2001
From: Michael Bestas
Date: Wed, 30 Oct 2024 11:22:25 +0200
Subject: [PATCH 032/652] KeyguardUpdateMonitor: Add missing
getFaceAuthInteractor null check
Fixes commit 5e49307013cf55d0e37628b55d84ef71b4855d47
Flag: EXEMPT bugfix
Test: unfold foldable device without face auth.
Change-Id: Idbfab8dbe671bfd6b992f5945d6636e99feccbc4
---
.../src/com/android/keyguard/KeyguardUpdateMonitor.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 7f5839d4f1fb..057fb68bad78 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1873,7 +1873,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
if (posture == DEVICE_POSTURE_OPENED) {
mLogger.d("Posture changed to open - attempting to request active"
+ " unlock and run face auth");
- getFaceAuthInteractor().onDeviceUnfolded();
+ if (getFaceAuthInteractor() != null) {
+ getFaceAuthInteractor().onDeviceUnfolded();
+ }
requestActiveUnlockFromWakeReason(PowerManager.WAKE_REASON_UNFOLD_DEVICE,
false);
}
--
GitLab
From 5e41bb50027ca08201be826f7d94ff5d0fba5c37 Mon Sep 17 00:00:00 2001
From: "seokgyun.hong"
Date: Wed, 30 Oct 2024 17:54:12 +0000
Subject: [PATCH 033/652] Disallow autofill session for visible background
users
Currently, autofill service does not fully support visible background users.
Prevent starting autofill sessions for visible background users to avoid issues with their autofill behavior.
Bug: 375500806
Test: manual - check that autofill is not working for a visible background user.
Flag: EXEMPT bugfix
(cherry picked from https://partner-android-review.googlesource.com/q/commit:9489b856d41b15df98a09e2c5e384e041892ade5)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bc78ceb189e7ec9ce765d83e3dd7f311ccb6de94)
Merged-In: Ibe368d7dd01d62ad5ca3e36ea3dd93e02077d7ad
Change-Id: Ibe368d7dd01d62ad5ca3e36ea3dd93e02077d7ad
---
.../server/autofill/AutofillManagerServiceImpl.java | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index c9f892907b59..b52c65054e51 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -92,6 +92,7 @@ import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.infra.AbstractPerUserSystemService;
import com.android.server.inputmethod.InputMethodManagerInternal;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.PrintWriter;
@@ -192,6 +193,8 @@ final class AutofillManagerServiceImpl
private final ContentCaptureManagerInternal mContentCaptureManagerInternal;
+ private final UserManagerInternal mUserManagerInternal;
+
private final DisabledInfoCache mDisabledInfoCache;
AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
@@ -208,6 +211,7 @@ final class AutofillManagerServiceImpl
mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
mContentCaptureManagerInternal = LocalServices.getService(
ContentCaptureManagerInternal.class);
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mDisabledInfoCache = disableCache;
updateLocked(disabled);
}
@@ -379,6 +383,13 @@ final class AutofillManagerServiceImpl
return 0;
}
+ // TODO(b/376482880): remove this check once autofill service supports visible
+ // background users.
+ if (mUserManagerInternal.isVisibleBackgroundFullUser(mUserId)) {
+ Slog.d(TAG, "Currently, autofill service does not support visible background users.");
+ return 0;
+ }
+
if (!forAugmentedAutofillOnly && isAutofillDisabledLocked(clientActivity)) {
// Standard autofill is enabled, but service disabled autofill for this activity; that
// means no session, unless the activity is allowlisted for augmented autofill
--
GitLab
From d7fa89a02fd7f4c0ea28e26c519bc56de3716df2 Mon Sep 17 00:00:00 2001
From: Beth Thibodeau
Date: Tue, 29 Oct 2024 15:23:09 -0500
Subject: [PATCH 034/652] Use simple equality to compare media notif intents
Intent.filterEquals does not compare extra data included in intents,
which can lead to false positives for some apps, resulting in stale
intents being used
Flag: com.android.systemui.media_controls_posts_optimization
Bug: 369853463
Test: manual with affected apps
Test: MediaDataProcessorTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:d52d5593647e945b172041df267fd53be2b2ab4f)
Merged-In: Ib037ece86cdd887ab0bb56b54648db7b73b42fab
Change-Id: Ib037ece86cdd887ab0bb56b54648db7b73b42fab
---
.../domain/pipeline/MediaProcessingHelper.kt | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt
index 55d7b1d498e0..2bdee67dd57a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaProcessingHelper.kt
@@ -42,7 +42,7 @@ fun isSameMediaData(
context: Context,
newController: MediaController,
new: MediaData,
- old: MediaData?
+ old: MediaData?,
): Boolean {
if (old == null || !mediaControlsPostsOptimization()) return false
@@ -71,7 +71,7 @@ fun isSameMediaData(
/** Returns whether actions lists are equal. */
fun areCustomActionListsEqual(
first: List?,
- second: List?
+ second: List?,
): Boolean {
// Same object, or both null
if (first === second) {
@@ -94,7 +94,7 @@ fun areCustomActionListsEqual(
private fun areCustomActionsEqual(
firstAction: PlaybackState.CustomAction,
- secondAction: PlaybackState.CustomAction
+ secondAction: PlaybackState.CustomAction,
): Boolean {
if (
firstAction.action != secondAction.action ||
@@ -139,7 +139,7 @@ private fun areActionsEqual(
context: Context,
newController: MediaController,
new: MediaData,
- old: MediaData
+ old: MediaData,
): Boolean {
val oldState = MediaController(context, old.token!!).playbackState
return if (
@@ -150,8 +150,7 @@ private fun areActionsEqual(
var same = true
new.actions.asSequence().zip(old.actions.asSequence()).forEach {
if (
- it.first.actionIntent?.intent?.filterEquals(it.second.actionIntent?.intent) !=
- true ||
+ it.first.actionIntent?.intent != it.second.actionIntent?.intent ||
it.first.icon != it.second.icon ||
it.first.contentDescription != it.second.contentDescription
) {
@@ -164,7 +163,7 @@ private fun areActionsEqual(
oldState?.actions == newController.playbackState?.actions &&
areCustomActionListsEqual(
oldState?.customActions,
- newController.playbackState?.customActions
+ newController.playbackState?.customActions,
)
} else {
false
@@ -172,8 +171,5 @@ private fun areActionsEqual(
}
private fun areClickIntentsEqual(newIntent: PendingIntent?, oldIntent: PendingIntent?): Boolean {
- if ((newIntent == null && oldIntent == null) || newIntent === oldIntent) return true
- if (newIntent == null || oldIntent == null) return false
-
- return newIntent.intent?.filterEquals(oldIntent.intent) == true
+ return newIntent == oldIntent
}
--
GitLab
From 0af3e3d44ba7207b99d74d610ab7ab4e4c0331bd Mon Sep 17 00:00:00 2001
From: Eric Laurent
Date: Wed, 30 Oct 2024 14:20:03 +0000
Subject: [PATCH 035/652] Revert "AudioService: synchronize audio mode and
focus for Telecom"
This reverts commit 15f9e56e1f898bd34400db8231f2cda71ca4cc91.
Bug: 375018522
Bug: 350415723
Flag: EXEMPT bug fix
Test: make
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5754baa4be5715b164d3a924e2cd0b327823ee74)
Merged-In: Id8b8a7933976c2a98f42ae23775f1eee66462b92
Change-Id: Id8b8a7933976c2a98f42ae23775f1eee66462b92
---
.../server/audio/AudioDeviceBroker.java | 13 +-
.../android/server/audio/AudioService.java | 130 ++++--------------
2 files changed, 32 insertions(+), 111 deletions(-)
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 2bbe08d22020..0fd22c583192 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1321,9 +1321,9 @@ public class AudioDeviceBroker {
sendLMsgNoDelay(MSG_II_SET_LE_AUDIO_OUT_VOLUME, SENDMSG_REPLACE, info);
}
- /*package*/ void postSetModeOwner(int mode, int pid, int uid, boolean signal) {
- sendILMsgNoDelay(MSG_IL_SET_MODE_OWNER, SENDMSG_REPLACE,
- signal ? 1 : 0, new AudioModeInfo(mode, pid, uid));
+ /*package*/ void postSetModeOwner(int mode, int pid, int uid) {
+ sendLMsgNoDelay(MSG_I_SET_MODE_OWNER, SENDMSG_REPLACE,
+ new AudioModeInfo(mode, pid, uid));
}
/*package*/ void postBluetoothDeviceConfigChange(@NonNull BtDeviceInfo info) {
@@ -2025,7 +2025,7 @@ public class AudioDeviceBroker {
mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1);
}
break;
- case MSG_IL_SET_MODE_OWNER:
+ case MSG_I_SET_MODE_OWNER:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
int btScoRequesterUid = bluetoothScoRequestOwnerUid();
@@ -2036,9 +2036,6 @@ public class AudioDeviceBroker {
}
}
}
- if (msg.arg1 == 1 /*signal*/) {
- mAudioService.decrementAudioModeResetCount();
- }
break;
case MSG_L_SET_COMMUNICATION_DEVICE_FOR_CLIENT:
@@ -2227,7 +2224,7 @@ public class AudioDeviceBroker {
private static final int MSG_REPORT_NEW_ROUTES = 13;
private static final int MSG_II_SET_HEARING_AID_VOLUME = 14;
private static final int MSG_I_SET_AVRCP_ABSOLUTE_VOLUME = 15;
- private static final int MSG_IL_SET_MODE_OWNER = 16;
+ private static final int MSG_I_SET_MODE_OWNER = 16;
private static final int MSG_I_BT_SERVICE_DISCONNECTED_PROFILE = 22;
private static final int MSG_IL_BT_SERVICE_CONNECTED_PROFILE = 23;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c37d47149ef5..e1909d91a77d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1918,7 +1918,7 @@ public class AudioService extends IAudioService.Stub
// Restore call state
synchronized (mDeviceBroker.mSetModeLock) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
- mContext.getPackageName(), true /*force*/, false /*signal*/);
+ mContext.getPackageName(), true /*force*/);
}
final int forSys;
synchronized (mSettingsLock) {
@@ -4746,47 +4746,14 @@ public class AudioService extends IAudioService.Stub
}
}
if (updateAudioMode) {
- postUpdateAudioMode(existingMsgPolicy, AudioSystem.MODE_CURRENT,
- android.os.Process.myPid(), mContext.getPackageName(),
- false /*signal*/, delay);
- }
- }
- }
-
- static class UpdateAudioModeInfo {
- UpdateAudioModeInfo(int mode, int pid, String packageName, boolean signal) {
- mMode = mode;
- mPid = pid;
- mPackageName = packageName;
- mSignal = signal;
- }
- private final int mMode;
- private final int mPid;
- private final String mPackageName;
- private final boolean mSignal;
-
- int getMode() {
- return mMode;
- }
- int getPid() {
- return mPid;
- }
- String getPackageName() {
- return mPackageName;
- }
- boolean getSignal() {
- return mSignal;
- }
- }
-
- void postUpdateAudioMode(int msgPolicy, int mode, int pid, String packageName,
- boolean signal, int delay) {
- synchronized (mAudioModeResetLock) {
- if (signal) {
- mAudioModeResetCount++;
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_AUDIO_MODE,
+ existingMsgPolicy,
+ AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(),
+ mContext.getPackageName(),
+ delay);
}
- sendMsg(mAudioHandler, MSG_UPDATE_AUDIO_MODE, msgPolicy, 0, 0,
- new UpdateAudioModeInfo(mode, pid, packageName, signal), delay);
}
}
@@ -6188,9 +6155,13 @@ public class AudioService extends IAudioService.Stub
} else {
SetModeDeathHandler h = mSetModeDeathHandlers.get(index);
mSetModeDeathHandlers.remove(index);
- postUpdateAudioMode(SENDMSG_QUEUE, AudioSystem.MODE_CURRENT,
- android.os.Process.myPid(), mContext.getPackageName(),
- false /*signal*/, 0);
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_AUDIO_MODE,
+ SENDMSG_QUEUE,
+ AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(),
+ mContext.getPackageName(),
+ 0);
}
}
}
@@ -6436,14 +6407,19 @@ public class AudioService extends IAudioService.Stub
}
}
- postUpdateAudioMode(SENDMSG_REPLACE, mode, pid, callingPackage,
- hasModifyPhoneStatePermission && mode == AudioSystem.MODE_NORMAL, 0);
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_AUDIO_MODE,
+ SENDMSG_REPLACE,
+ mode,
+ pid,
+ callingPackage,
+ 0);
}
}
@GuardedBy("mDeviceBroker.mSetModeLock")
void onUpdateAudioMode(int requestedMode, int requesterPid, String requesterPackage,
- boolean force, boolean signal) {
+ boolean force) {
if (requestedMode == AudioSystem.MODE_CURRENT) {
requestedMode = getMode();
}
@@ -6458,7 +6434,7 @@ public class AudioService extends IAudioService.Stub
}
if (DEBUG_MODE) {
Log.v(TAG, "onUpdateAudioMode() new mode: " + mode + ", current mode: "
- + mMode.get() + " requested mode: " + requestedMode + " signal: " + signal);
+ + mMode.get() + " requested mode: " + requestedMode);
}
if (mode != mMode.get() || force) {
int status = AudioSystem.SUCCESS;
@@ -6504,7 +6480,7 @@ public class AudioService extends IAudioService.Stub
// when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
// connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwner(mode, pid, uid, signal);
+ mDeviceBroker.postSetModeOwner(mode, pid, uid);
} else {
Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
}
@@ -10186,7 +10162,7 @@ public class AudioService extends IAudioService.Stub
h.setRecordingActive(isRecordingActiveForUid(h.getUid()));
if (wasActive != h.isActive()) {
onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
- mContext.getPackageName(), false /*force*/, false /*signal*/);
+ mContext.getPackageName(), false /*force*/);
}
}
break;
@@ -10216,9 +10192,7 @@ public class AudioService extends IAudioService.Stub
case MSG_UPDATE_AUDIO_MODE:
synchronized (mDeviceBroker.mSetModeLock) {
- UpdateAudioModeInfo info = (UpdateAudioModeInfo) msg.obj;
- onUpdateAudioMode(info.getMode(), info.getPid(), info.getPackageName(),
- false /*force*/, info.getSignal());
+ onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj, false /*force*/);
}
break;
@@ -10921,59 +10895,9 @@ public class AudioService extends IAudioService.Stub
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
mmi.record();
- //delay abandon focus requests from Telecom if an audio mode reset from Telecom
- // is still being processed
- final boolean abandonFromTelecom = (mContext.checkCallingOrSelfPermission(
- MODIFY_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
- && ((aa != null && aa.getUsage() == AudioAttributes.USAGE_VOICE_COMMUNICATION)
- || AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId));
- if (abandonFromTelecom) {
- synchronized (mAudioModeResetLock) {
- final long start = java.lang.System.currentTimeMillis();
- long elapsed = 0;
- while (mAudioModeResetCount > 0) {
- if (DEBUG_MODE) {
- Log.i(TAG, "Abandon focus from Telecom, waiting for mode change");
- }
- try {
- mAudioModeResetLock.wait(
- AUDIO_MODE_RESET_TIMEOUT_MS - elapsed);
- } catch (InterruptedException e) {
- Log.w(TAG, "Interrupted while waiting for audio mode reset");
- }
- elapsed = java.lang.System.currentTimeMillis() - start;
- if (elapsed >= AUDIO_MODE_RESET_TIMEOUT_MS) {
- Log.e(TAG, "Timeout waiting for audio mode reset");
- break;
- }
- }
- if (DEBUG_MODE && elapsed != 0) {
- Log.i(TAG, "Abandon focus from Telecom done waiting");
- }
- }
- }
return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
}
- /** synchronization between setMode(NORMAL) and abandonAudioFocus() frmo Telecom */
- private static final long AUDIO_MODE_RESET_TIMEOUT_MS = 3000;
-
- private final Object mAudioModeResetLock = new Object();
-
- @GuardedBy("mAudioModeResetLock")
- private int mAudioModeResetCount = 0;
-
- void decrementAudioModeResetCount() {
- synchronized (mAudioModeResetLock) {
- if (mAudioModeResetCount > 0) {
- mAudioModeResetCount--;
- } else {
- Log.w(TAG, "mAudioModeResetCount already 0");
- }
- mAudioModeResetLock.notify();
- }
- }
-
/** see {@link AudioManager#abandonAudioFocusForTest(AudioFocusRequest, String)} */
public int abandonAudioFocusForTest(IAudioFocusDispatcher fd, String clientId,
AudioAttributes aa, String callingPackageName) {
--
GitLab
From 73d475bc1bc3c3cc497f4fd2043a1eb441f0d1e9 Mon Sep 17 00:00:00 2001
From: Matt Pietal
Date: Thu, 17 Oct 2024 16:49:43 +0000
Subject: [PATCH 036/652] Do not handle touches next to shelf Take #2
NSSL would return true for all touches below the last notification,
and to the right of the shelf. This is essentially empty space.
The reason for this is the SwipeHelper is always returning true,
since it is looking at the full width of the NotificationShelf. By
using getActualWidth() instead, the touches are more accurately
handled.
This fixes an issue where the shelf is vertically overlapping
the unlock icon, and taking touches from it.
Fixes: 358424256
Test: atest NotificationSwipeHelperTest
Test: manual - horizontal swipe notifications
Test: manual - vertically swipe notifications
Test: manual - all touch interactions with notifs
Test: manual - tap on shelf to expand shade
Test: manual - face auth without bypass, add notifications next
to unlock icon, use unlock
Flag: com.android.systemui.ignore_touches_next_to_notification_shelf
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:bff27edb33096142a76fed89dbf0cc4f91df969c)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:4ed24bd6ad4933eba9e4e361bbfde04afa42c211)
Merged-In: Idf22d6e72e7d618ed98e869142b5cc5dc785985e
Change-Id: Idf22d6e72e7d618ed98e869142b5cc5dc785985e
---
packages/SystemUI/aconfig/systemui.aconfig | 10 ++++
...tificationStackScrollLayoutController.java | 11 ++++
.../stack/NotificationSwipeHelper.java | 12 ++++-
.../stack/NotificationSwipeHelperTest.java | 54 +++++++++++++++++++
4 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index f8383d94b1ab..554ad8ba64e6 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1431,4 +1431,14 @@ flag {
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "ignore_touches_next_to_notification_shelf"
+ namespace: "systemui"
+ description: "The shelf can vertically overlap the unlock icon. Ignore touches if so."
+ bug: "358424256"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index dad6894a43ce..ae71ca443236 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -24,6 +24,7 @@ import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_
import static com.android.server.notification.Flags.screenshareNotificationHiding;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.Flags.confineNotificationTouchToViewWidth;
+import static com.android.systemui.Flags.ignoreTouchesNextToNotificationShelf;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnOverscrollTopChangedListener;
@@ -604,6 +605,16 @@ public class NotificationStackScrollLayoutController implements Dumpable {
true /* requireMinHeight */,
false /* ignoreDecors */,
!confineNotificationTouchToViewWidth() /* ignoreWidth */);
+
+ // Verify the MotionEvent x,y are actually inside the touch area of the shelf,
+ // since the shelf may be animated down to a collapsed size on keyguard.
+ if (ignoreTouchesNextToNotificationShelf()) {
+ if (child instanceof NotificationShelf shelf) {
+ if (!NotificationSwipeHelper.isTouchInView(ev, shelf)) {
+ return null;
+ }
+ }
+ }
if (child instanceof ExpandableNotificationRow row) {
ExpandableNotificationRow parent = row.getNotificationParent();
if (parent != null && parent.areChildrenExpanded()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 7e327e66982c..0e94ca351835 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -18,6 +18,7 @@
package com.android.systemui.statusbar.notification.stack;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_ROW_SWIPE;
+import static com.android.systemui.Flags.ignoreTouchesNextToNotificationShelf;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -39,6 +40,7 @@ import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.SourceType;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -503,13 +505,21 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc
final int height = (view instanceof ExpandableView)
? ((ExpandableView) view).getActualHeight()
: view.getHeight();
+ final int width;
+ if (ignoreTouchesNextToNotificationShelf()) {
+ width = (view instanceof NotificationShelf)
+ ? ((NotificationShelf) view).getActualWidth()
+ : view.getWidth();
+ } else {
+ width = view.getWidth();
+ }
final int rx = (int) ev.getRawX();
final int ry = (int) ev.getRawY();
int[] temp = new int[2];
view.getLocationOnScreen(temp);
final int x = temp[0];
final int y = temp[1];
- Rect rect = new Rect(x, y, x + view.getWidth(), y + height);
+ Rect rect = new Rect(x, y, x + width, y + height);
boolean ret = rect.contains(rx, ry);
return ret;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 95db95cd288b..789701f5e4b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -13,6 +13,8 @@
package com.android.systemui.statusbar.notification.stack;
+import static com.android.systemui.Flags.FLAG_IGNORE_TOUCHES_NEXT_TO_NOTIFICATION_SHELF;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -36,6 +38,7 @@ import static org.mockito.Mockito.when;
import android.animation.Animator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.os.Handler;
+import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.service.notification.StatusBarNotification;
import android.testing.TestableLooper;
@@ -52,6 +55,7 @@ import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.shared.NotificationContentAlphaOptimization;
@@ -85,6 +89,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
private NotificationMenuRowPlugin mMenuRow;
private Handler mHandler;
private ExpandableNotificationRow mNotificationRow;
+ private NotificationShelf mShelf;
private Runnable mFalsingCheck;
private final FeatureFlags mFeatureFlags = new FakeFeatureFlags();
@@ -111,6 +116,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
mEvent = mock(MotionEvent.class);
mMenuRow = mock(NotificationMenuRowPlugin.class);
mNotificationRow = mock(ExpandableNotificationRow.class);
+ mShelf = mock(NotificationShelf.class);
mHandler = mock(Handler.class);
mFalsingCheck = mock(Runnable.class);
}
@@ -664,6 +670,54 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
}
+ @Test
+ @EnableFlags(FLAG_IGNORE_TOUCHES_NEXT_TO_NOTIFICATION_SHELF)
+ public void testIsTouchInView_notificationShelf_flagEnabled() {
+ doReturn(500).when(mShelf).getWidth();
+ doReturn(FAKE_ROW_WIDTH).when(mShelf).getActualWidth();
+ doReturn(FAKE_ROW_HEIGHT).when(mShelf).getHeight();
+ doReturn(FAKE_ROW_HEIGHT).when(mShelf).getActualHeight();
+
+ Answer answer = (Answer) invocation -> {
+ int[] arr = invocation.getArgument(0);
+ arr[0] = 0;
+ arr[1] = 0;
+ return null;
+ };
+
+ doReturn(5f).when(mEvent).getRawX();
+ doReturn(10f).when(mEvent).getRawY();
+ doAnswer(answer).when(mShelf).getLocationOnScreen(any());
+ assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mShelf));
+
+ doReturn(50f).when(mEvent).getRawX();
+ assertFalse("Touch is not within the view", mSwipeHelper.isTouchInView(mEvent, mShelf));
+ }
+
+ @Test
+ @DisableFlags(FLAG_IGNORE_TOUCHES_NEXT_TO_NOTIFICATION_SHELF)
+ public void testIsTouchInView_notificationShelf_flagDisabled() {
+ doReturn(500).when(mShelf).getWidth();
+ doReturn(FAKE_ROW_WIDTH).when(mShelf).getActualWidth();
+ doReturn(FAKE_ROW_HEIGHT).when(mShelf).getHeight();
+ doReturn(FAKE_ROW_HEIGHT).when(mShelf).getActualHeight();
+
+ Answer answer = (Answer) invocation -> {
+ int[] arr = invocation.getArgument(0);
+ arr[0] = 0;
+ arr[1] = 0;
+ return null;
+ };
+
+ doReturn(5f).when(mEvent).getRawX();
+ doReturn(10f).when(mEvent).getRawY();
+ doAnswer(answer).when(mShelf).getLocationOnScreen(any());
+ assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mShelf));
+
+ doReturn(50f).when(mEvent).getRawX();
+ assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mShelf));
+ }
+
@Test
public void testContentAlphaRemainsUnchangedWhenNotificationIsNotDismissible() {
doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth();
--
GitLab
From 79a8c7f000793ed78eb95a517bd01d197c57f516 Mon Sep 17 00:00:00 2001
From: Liran Binyamin
Date: Mon, 4 Nov 2024 12:34:01 -0500
Subject: [PATCH 037/652] Move WMComponent to wm shell
This change moves WMComponent into the wm shell library and introduces
HasWMComponent interface to allow classes to do member injection
where constructor injection is not possible.
Flag: EXEMPT refactor
Bug: 378075955
Test: m sysuig
Change-Id: Ifb0eb7be39eb663b4af56fe73e9783299984ef83
---
.../android/wm/shell/dagger/HasWMComponent.kt | 27 +++++++++++++++++++
.../android/wm/shell}/dagger/WMComponent.java | 12 +++------
.../android/systemui/SystemUIApplication.java | 10 ++++++-
.../android/systemui/SystemUIInitializer.java | 2 +-
.../systemui/dagger/GlobalRootComponent.java | 1 +
.../com/android/systemui/wmshell/WMShell.java | 2 +-
6 files changed, 43 insertions(+), 11 deletions(-)
create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/dagger/HasWMComponent.kt
rename {packages/SystemUI/src/com/android/systemui => libs/WindowManager/Shell/src/com/android/wm/shell}/dagger/WMComponent.java (86%)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/HasWMComponent.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/HasWMComponent.kt
new file mode 100644
index 000000000000..d5e0240ea9ad
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/HasWMComponent.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.dagger
+
+/**
+ * An interface implemented by the application that uses [WMComponent].
+ *
+ * This exposes the component to allow classes to do member injection for bindings where constructor
+ * injection is not possible, e.g. views.
+ */
+interface HasWMComponent {
+ fun getWMComponent(): WMComponent
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMComponent.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMComponent.java
index a3cdb2eff601..c493aadd57b0 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMComponent.java
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-package com.android.systemui.dagger;
+package com.android.wm.shell.dagger;
import android.os.HandlerThread;
import androidx.annotation.Nullable;
-import com.android.systemui.SystemUIInitializer;
import com.android.wm.shell.back.BackAnimation;
import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.dagger.WMShellModule;
-import com.android.wm.shell.dagger.WMSingleton;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
import com.android.wm.shell.keyguard.KeyguardTransitions;
@@ -45,12 +42,11 @@ import java.util.Optional;
/**
* Dagger Subcomponent for WindowManager. This class explicitly describes the interfaces exported
- * from the WM component into the SysUI component (in
- * {@link SystemUIInitializer#init(boolean)}), and references the specific dependencies
+ * from the WM component into the SysUI component, and references the specific dependencies
* provided by its particular device/form-factor SystemUI implementation.
*
- * ie. {@link WMComponent} includes {@link WMShellModule}
- * and {@code TvWMComponent} includes {@link com.android.wm.shell.dagger.TvWMShellModule}
+ *
ie. {@link WMComponent} includes {@link WMShellModule} and {@code TvWMComponent} includes
+ * {@link TvWMShellModule}
*/
@WMSingleton
@Subcomponent(modules = {WMShellModule.class})
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 811b47d57c1d..322580e66763 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -45,6 +45,8 @@ import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.phone.ConfigurationForwarder;
import com.android.systemui.util.NotificationChannels;
+import com.android.wm.shell.dagger.HasWMComponent;
+import com.android.wm.shell.dagger.WMComponent;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayDeque;
@@ -61,7 +63,7 @@ import javax.inject.Provider;
* Application class for SystemUI.
*/
public class SystemUIApplication extends Application implements
- SystemUIAppComponentFactoryBase.ContextInitializer {
+ SystemUIAppComponentFactoryBase.ContextInitializer, HasWMComponent {
public static final String TAG = "SystemUIService";
private static final boolean DEBUG = false;
@@ -486,4 +488,10 @@ public class SystemUIApplication extends Application implements
n.addExtras(extras);
}
+
+ @NonNull
+ @Override
+ public WMComponent getWMComponent() {
+ return mInitializer.getWMComponent();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
index 5c75a49818a6..f530522fb707 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
@@ -24,9 +24,9 @@ import android.util.Log;
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
-import com.android.systemui.dagger.WMComponent;
import com.android.systemui.res.R;
import com.android.systemui.util.InitializationChecker;
+import com.android.wm.shell.dagger.WMComponent;
import com.android.wm.shell.dagger.WMShellConcurrencyModule;
import com.android.wm.shell.keyguard.KeyguardTransitions;
import com.android.wm.shell.shared.ShellTransitions;
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
index e78ce3bbb0d1..f804c2e80ac6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalRootComponent.java
@@ -24,6 +24,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.flags.SystemPropertiesHelper;
import com.android.systemui.process.ProcessWrapper;
import com.android.systemui.util.InitializationChecker;
+import com.android.wm.shell.dagger.WMComponent;
import dagger.BindsInstance;
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 8039e00159f0..75881fac380c 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -48,7 +48,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.CoreStartable;
import com.android.systemui.communal.ui.viewmodel.CommunalTransitionViewModel;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.WMComponent;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -60,6 +59,7 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.kotlin.JavaAdapter;
+import com.android.wm.shell.dagger.WMComponent;
import com.android.wm.shell.desktopmode.DesktopMode;
import com.android.wm.shell.desktopmode.DesktopRepository;
import com.android.wm.shell.onehanded.OneHanded;
--
GitLab
From bfae72fd0458e84f9e411f4d513419b5b3ed2dca Mon Sep 17 00:00:00 2001
From: Brian Lindahl
Date: Wed, 20 Nov 2024 08:18:05 -0700
Subject: [PATCH 038/652] Add additional documentation to PictureProfileHandle
Bug: 337330263
Bug: 379941266
Test: build
Flag: DOCS_ONLY
Change-Id: Icce2c19a0bbc442fb5c12bc308b729b9a713176f
---
.../media/quality/PictureProfileHandle.java | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/media/java/android/media/quality/PictureProfileHandle.java b/media/java/android/media/quality/PictureProfileHandle.java
index 714fd36d664a..d9d21932d09a 100644
--- a/media/java/android/media/quality/PictureProfileHandle.java
+++ b/media/java/android/media/quality/PictureProfileHandle.java
@@ -28,11 +28,14 @@ import android.os.Parcelable;
* A picture profile represents a collection of parameters used to configure picture processing
* to enhance the quality of graphic buffers.
*
+ * @see PictureProfile.getHandle
+ *
* @hide
*/
@SystemApi
@FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
public final class PictureProfileHandle implements Parcelable {
+ /** A handle that represents no picture processing configuration. */
public static final @NonNull PictureProfileHandle NONE = new PictureProfileHandle(0);
private final long mId;
@@ -42,7 +45,16 @@ public final class PictureProfileHandle implements Parcelable {
mId = id;
}
- /** @hide */
+ /**
+ * An ID that uniquely identifies the picture profile across the system.
+ *
+ * This ID can be used to construct an NDK PictureProfileHandle to be fed directly into
+ * IGraphicBufferProducer to couple a picture profile to a graphic buffer.
+ *
+ * Note: These IDs are generated randomly and are not stable across reboots.
+ *
+ * @hide
+ */
@SystemApi
@FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES)
public long getId() {
--
GitLab
From aca4ecdccdeb476b48658eed09324f37da371a6b Mon Sep 17 00:00:00 2001
From: Austin Delgado
Date: Wed, 20 Nov 2024 11:52:10 -0800
Subject: [PATCH 039/652] Move keyguard lock callback listener to
AuthController
Test: AuthControllerTest AuthContainerViewTest
Bug: 377614813
Flag: EXEMPT bugfix
Change-Id: I27b00006bfe1877a44ad59d65094b3f5300a5186
---
.../biometrics/AuthControllerTest.java | 22 ++++++++++++++++++-
.../biometrics/AuthContainerView.java | 11 ----------
.../systemui/biometrics/AuthController.java | 11 ++++++++++
3 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 2dcbdc80f695..bb8d2d7ba8fd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -43,6 +43,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
+import android.app.KeyguardManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -181,6 +182,8 @@ public class AuthControllerTest extends SysuiTestCase {
@Captor
private ArgumentCaptor mFaceAuthenticatorsRegisteredCaptor;
@Captor
+ private ArgumentCaptor mKeyguardLockedStateCaptor;
+ @Captor
private ArgumentCaptor mBiometricStateCaptor;
@Captor
private ArgumentCaptor mModalityCaptor;
@@ -191,6 +194,8 @@ public class AuthControllerTest extends SysuiTestCase {
@Mock
private VibratorHelper mVibratorHelper;
@Mock
+ private KeyguardManager mKeyguardManager;
+ @Mock
private MSDLPlayer mMSDLPlayer;
private TestableContext mContextSpy;
@@ -271,6 +276,9 @@ public class AuthControllerTest extends SysuiTestCase {
mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(fpProps);
mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps);
+ verify(mKeyguardManager).addKeyguardLockedStateListener(any(),
+ mKeyguardLockedStateCaptor.capture());
+
// Ensures that the operations posted on the handler get executed.
waitForIdleSync();
}
@@ -975,6 +983,18 @@ public class AuthControllerTest extends SysuiTestCase {
eq(null) /* credentialAttestation */);
}
+ @Test
+ public void testCloseDialog_whenDeviceLocks() throws Exception {
+ showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
+
+ mKeyguardLockedStateCaptor.getValue().onKeyguardLockedStateChanged(
+ true /* isKeyguardLocked */);
+
+ verify(mReceiver).onDialogDismissed(
+ eq(BiometricPrompt.DISMISSED_REASON_USER_CANCEL),
+ eq(null) /* credentialAttestation */);
+ }
+
@Test
public void testShowDialog_whenOwnerNotInForeground() {
PromptInfo promptInfo = createTestPromptInfo();
@@ -1191,7 +1211,7 @@ public class AuthControllerTest extends SysuiTestCase {
mWakefulnessLifecycle, mUserManager, mLockPatternUtils, () -> mUdfpsLogger,
() -> mLogContextInteractor, () -> mPromptSelectionInteractor,
() -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor,
- mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper,
+ mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper, mKeyguardManager,
mLazyViewCapture, mMSDLPlayer);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index b491c94db151..12b5fc01845c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -27,7 +27,6 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlertDialog;
-import android.app.KeyguardManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -316,16 +315,6 @@ public class AuthContainerView extends LinearLayout
mBiometricCallback = new BiometricCallback();
mMSDLPlayer = msdlPlayer;
- // Listener for when device locks from adaptive auth, dismiss prompt
- getContext().getSystemService(KeyguardManager.class).addKeyguardLockedStateListener(
- getContext().getMainExecutor(),
- isKeyguardLocked -> {
- if (isKeyguardLocked) {
- onStartedGoingToSleep();
- }
- }
- );
-
final BiometricModalities biometricModalities = new BiometricModalities(
Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index a5bd559dcbf2..d1fae4866941 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -26,6 +26,7 @@ import static com.android.systemui.util.ConvenienceExtensionsKt.toKotlinLazy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
+import android.app.KeyguardManager;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -732,6 +733,7 @@ public class AuthController implements
@Background DelayableExecutor bgExecutor,
@NonNull UdfpsUtils udfpsUtils,
@NonNull VibratorHelper vibratorHelper,
+ @NonNull KeyguardManager keyguardManager,
Lazy daggerLazyViewCapture,
@NonNull MSDLPlayer msdlPlayer) {
mContext = context;
@@ -762,6 +764,15 @@ public class AuthController implements
mPromptViewModelProvider = promptViewModelProvider;
mCredentialViewModelProvider = credentialViewModelProvider;
+ keyguardManager.addKeyguardLockedStateListener(
+ context.getMainExecutor(),
+ isKeyguardLocked -> {
+ if (isKeyguardLocked) {
+ closeDialog("Device lock");
+ }
+ }
+ );
+
mOrientationListener = new BiometricDisplayListener(
context,
mDisplayManager,
--
GitLab
From 152db50e94e43f355b58833546230a4db00cc5ad Mon Sep 17 00:00:00 2001
From: Miranda Kephart
Date: Thu, 21 Nov 2024 13:16:15 -0500
Subject: [PATCH 040/652] Inset screenshot UI from the nav bar
In seascape, the screenshot UI overlaps the nav bar (especially visible
in 3-button mode). This change adds the nav bar insets to the screenshot
padding.
Bug: 380280383
Fix: 380280383
Test: manual (visual change)
Flag: EXEMPT bugfix
Change-Id: Ib2a683040bc9b1ee43831e89abf379163774bdb4
---
.../systemui/screenshot/ui/ScreenshotShelfView.kt | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt
index b8ea8f9052ca..c58b48122f63 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt
@@ -147,7 +147,12 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) :
)
if (cutout == null) {
- screenshotStatic.setPadding(0, 0, 0, navBarInsets.bottom)
+ screenshotStatic.setPadding(
+ navBarInsets.left,
+ navBarInsets.top,
+ navBarInsets.right,
+ navBarInsets.bottom,
+ )
} else {
val waterfall = cutout.waterfallInsets
if (inPortrait) {
@@ -164,9 +169,9 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) :
)
} else {
screenshotStatic.setPadding(
- max(cutout.safeInsetLeft, waterfall.left),
+ max(cutout.safeInsetLeft, waterfall.left, navBarInsets.left),
waterfall.top,
- max(cutout.safeInsetRight, waterfall.right),
+ max(cutout.safeInsetRight, waterfall.right, navBarInsets.right),
max(
navBarInsets.bottom + verticalPadding,
waterfall.bottom + verticalPadding,
--
GitLab
From 0c3d451978771ed54c16a34611936c9e6c4710b6 Mon Sep 17 00:00:00 2001
From: Aishwarya Mallampati
Date: Thu, 21 Nov 2024 22:19:31 +0000
Subject: [PATCH 041/652] Add RIL constants related to satellite APIs.
The following APIs are added to IRadioNetwork.aidl:
- setSatellitePlmn
- setSatelliteEnabledForCarrier
- isSatelliteEnabledForCarrier
Bug: 380319841
Test: Manually tested SMS/MMS/CALLS/DATA
FLAG: EXEMPT HAL interface change
Change-Id: I4acf9b63c7ffe38fb7f953fcc93dbbd165aa2291
---
.../java/com/android/internal/telephony/RILConstants.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index b7dd4df1c843..461d1579ea45 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -549,6 +549,9 @@ public interface RILConstants {
int RIL_REQUEST_SET_SECURITY_ALGORITHMS_UPDATED_ENABLED = 248;
int RIL_REQUEST_IS_SECURITY_ALGORITHMS_UPDATED_ENABLED = 249;
int RIL_REQUEST_GET_SIMULTANEOUS_CALLING_SUPPORT = 250;
+ int RIL_REQUEST_SET_SATELLITE_PLMN = 251;
+ int RIL_REQUEST_SET_SATELLITE_ENABLED_FOR_CARRIER = 252;
+ int RIL_REQUEST_IS_SATELLITE_ENABLED_FOR_CARRIER = 253;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
--
GitLab
From 7690586c0df43f1055923f4dec1320df03287745 Mon Sep 17 00:00:00 2001
From: Cam Bickel
Date: Fri, 22 Nov 2024 17:55:13 +0000
Subject: [PATCH 042/652] Cleanup flag "remove_on_window_infos_changed_..."
Full flag name:
"remove_on_window_infos_changed_handler"
Bug: b/333834990
Test: presubmit
Flag: EXEMPT flag cleanup
Change-Id: I24ab0c538dac2101e0e9ca36884af6bb7504ad73
---
.../android/server/wm/AccessibilityWindowsPopulator.java | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
index fd2a909f8b05..20493d312873 100644
--- a/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
+++ b/services/core/java/com/android/server/wm/AccessibilityWindowsPopulator.java
@@ -150,11 +150,7 @@ public final class AccessibilityWindowsPopulator extends WindowInfosListener {
@Override
public void onWindowInfosChanged(InputWindowHandle[] windowHandles,
DisplayInfo[] displayInfos) {
- if (com.android.server.accessibility.Flags.removeOnWindowInfosChangedHandler()) {
- onWindowInfosChangedInternal(windowHandles, displayInfos);
- } else {
- mHandler.post(() -> onWindowInfosChangedInternal(windowHandles, displayInfos));
- }
+ onWindowInfosChangedInternal(windowHandles, displayInfos);
}
private void onWindowInfosChangedInternal(InputWindowHandle[] windowHandles,
--
GitLab
From b40e8fecc22773142184398f3c83f1a901d8124a Mon Sep 17 00:00:00 2001
From: Sally Qi
Date: Fri, 22 Nov 2024 21:18:21 +0000
Subject: [PATCH 043/652] [Lut NDK] Add static_assert to ensure that
ADISPLAYLUTS_SAMPLINGKEY_CIE_Y is the same as
android::gui::LutProperties::SamplingKey::CIE_Y.
Bug: 358422255
Change-Id: I31e82bf0b257b6dee6740b53787645589db8c066
Test: builds
Flag: EXEMPT NDK
---
native/android/display_luts.cpp | 9 +++++----
native/android/surface_control.cpp | 2 ++
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/native/android/display_luts.cpp b/native/android/display_luts.cpp
index 179a32bd1c03..b03a718d4a65 100644
--- a/native/android/display_luts.cpp
+++ b/native/android/display_luts.cpp
@@ -26,8 +26,9 @@
#define CHECK_NOT_NULL(name) \
LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
-ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length, int32_t dimension,
- int32_t key) {
+ADisplayLutsEntry* ADisplayLutsEntry_createEntry(float* buffer, int32_t length,
+ ADisplayLuts_Dimension dimension,
+ ADisplayLuts_SamplingKey key) {
CHECK_NOT_NULL(buffer);
LOG_ALWAYS_FATAL_IF(length >= ADISPLAYLUTS_BUFFER_LENGTH_LIMIT,
"the lut raw buffer length is too big to handle");
@@ -64,7 +65,7 @@ void ADisplayLutsEntry_destroy(ADisplayLutsEntry* entry) {
ADisplayLuts_Dimension ADisplayLutsEntry_getDimension(const ADisplayLutsEntry* entry) {
CHECK_NOT_NULL(entry);
- return static_cast(entry->properties.dimension);
+ return entry->properties.dimension;
}
int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* entry) {
@@ -74,7 +75,7 @@ int32_t ADisplayLutsEntry_getSize(const ADisplayLutsEntry* entry) {
ADisplayLuts_SamplingKey ADisplayLutsEntry_getSamplingKey(const ADisplayLutsEntry* entry) {
CHECK_NOT_NULL(entry);
- return static_cast(entry->properties.samplingKey);
+ return entry->properties.samplingKey;
}
const float* ADisplayLutsEntry_getBuffer(const ADisplayLutsEntry* _Nonnull entry) {
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index fc64e9b48f6d..acd3ede358c3 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -64,6 +64,8 @@ static_assert(static_cast(ADISPLAYLUTS_SAMPLINGKEY_RGB) ==
static_cast(android::gui::LutProperties::SamplingKey::RGB));
static_assert(static_cast(ADISPLAYLUTS_SAMPLINGKEY_MAX_RGB) ==
static_cast(android::gui::LutProperties::SamplingKey::MAX_RGB));
+static_assert(static_cast(ADISPLAYLUTS_SAMPLINGKEY_CIE_Y) ==
+ static_cast(android::gui::LutProperties::SamplingKey::CIE_Y));
Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
return reinterpret_cast(aSurfaceTransaction);
--
GitLab
From 507336fe487a8beb0360f74aa0ef526cf326b62a Mon Sep 17 00:00:00 2001
From: lin_yiwen
Date: Thu, 19 Sep 2024 11:38:33 +0800
Subject: [PATCH 044/652] Fix cts testMinimalSizeDocked fail when device
supports multiwindow feature.
Bug: b/367878178
Test:
run cts -m CtsWindowManagerDeviceTestCases -t android.server.wm.ManifestLayoutTests#testMinimalSizeDocked
Change-Id: Id3f7f9784e2ac2d24a0dec8dfb1a49659edab411
---
.../com/android/server/pm/PackageManagerService.java | 10 ++++++++++
services/java/com/android/server/SystemServer.java | 4 ++++
2 files changed, 14 insertions(+)
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 69c78eb155eb..34a15fdb2df5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3019,6 +3019,16 @@ public class PackageManagerService implements PackageSender, TestUtilityService
mDexOptHelper.performPackageDexOptUpgradeIfNeeded();
}
+ public void updateMetricsIfNeeded() {
+ final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+ if (displayManager != null) {
+ final Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ if (display != null) {
+ display.getMetrics(mMetrics);
+ }
+ }
+ }
+
private void notifyPackageUseInternal(String packageName, int reason) {
long time = System.currentTimeMillis();
synchronized (mLock) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cdca948f91ac..4f0234135e27 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1842,6 +1842,10 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
+ t.traceBegin("UpdateMetricsIfNeeded");
+ mPackageManagerService.updateMetricsIfNeeded();
+ t.traceEnd();
+
t.traceBegin("PerformFstrimIfNeeded");
try {
mPackageManagerService.performFstrimIfNeeded();
--
GitLab
From c71850d297ea21a4f9ddfc7fb3ac3be434f6f557 Mon Sep 17 00:00:00 2001
From: Taran Singh
Date: Mon, 25 Nov 2024 19:27:04 +0000
Subject: [PATCH 045/652] Writing tools: selectively enable writing tools in
TextView 5/n
Selectively enabled writing tools on TexView attributes that have
inputType of TYPE_CLASS_TEXT and variations that are text and can use
writing tools. This criteria is same as what we use for suggestions in
isSuggestionsEnabled().
Bug: 350047836
Flag: android.view.inputmethod.adaptive_handwriting_bounds
Test: atest CtsInputMethodTestCases TextViewTest
Change-Id: I66b2fbdd947f2e927d98e04e71f70eff796610de
---
core/java/android/widget/TextView.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index cb70466fcd81..912ab664ff70 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10120,6 +10120,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
outAttrs.extras.putBoolean(
STYLUS_HANDWRITING_ENABLED_ANDROIDX_EXTRAS_KEY, handwritingEnabled);
}
+ if (android.view.inputmethod.Flags.writingTools()) {
+ // default to same behavior as isSuggestionsEnabled().
+ outAttrs.setWritingToolsEnabled(isSuggestionsEnabled());
+ }
ArrayList> gestures = new ArrayList<>();
gestures.add(SelectGesture.class);
gestures.add(SelectRangeGesture.class);
--
GitLab
From d61fc450528c6b2cd9ba0060a3e88a637c35cf79 Mon Sep 17 00:00:00 2001
From: Brandon Edens
Date: Tue, 19 Nov 2024 16:12:02 +0000
Subject: [PATCH 046/652] dock_observer: allow dock rotation in OOBE
Add a resource for configuration on whether or not we allow dock
rotation for the OOBE SetupWizard.
Bug: 374940810
Test: Enable the configuration and test OOBE + Docking for rotation.
Flag: EXEMPT bugfix
Change-Id: Ifba159ee2fdcf5f0b2875a84c4b833c7d454623b
---
core/res/res/values/config.xml | 5 +++++
core/res/res/values/symbols.xml | 1 +
.../java/com/android/server/DockObserver.java | 18 ++++++++++++++----
3 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7799ff951997..eae8d5542436 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -815,6 +815,11 @@
we rely on gravity to determine the effective orientation. -->
true
+
+ false
+
Got it
-
+
Widgets
-
- To add Widgets on the lock screen as a shortcut, make sure it is enabled in settings.
+
+ To add the \"Widgets\" shortcut, make sure \"Show widgets on lock screen\" is enabled in settings.
+
+ Settings
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
index 8906156252a6..71f29c0062bc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/GlanceableHubQuickAffordanceConfig.kt
@@ -17,6 +17,8 @@
package com.android.systemui.keyguard.data.quickaffordance
import android.content.Context
+import android.content.Intent
+import android.provider.Settings
import android.util.Log
import com.android.systemui.Flags.glanceableHubShortcutButton
import com.android.systemui.animation.Expandable
@@ -86,7 +88,13 @@ constructor(
} else if (!communalInteractor.isCommunalEnabled.value) {
Log.i(TAG, "Button disabled in picker: hub not enabled in settings.")
KeyguardQuickAffordanceConfig.PickerScreenState.Disabled(
- context.getString(R.string.glanceable_hub_lockscreen_affordance_disabled_text)
+ explanation =
+ context.getString(R.string.glanceable_hub_lockscreen_affordance_disabled_text),
+ actionText =
+ context.getString(
+ R.string.glanceable_hub_lockscreen_affordance_action_button_label
+ ),
+ actionIntent = Intent(Settings.ACTION_LOCKSCREEN_SETTINGS),
)
} else {
KeyguardQuickAffordanceConfig.PickerScreenState.Default()
--
GitLab
From 1aaeb38e25443572d48505599494f27cc142f242 Mon Sep 17 00:00:00 2001
From: John Johnson
Date: Thu, 21 Nov 2024 16:28:16 -0500
Subject: [PATCH 051/652] Launch card intent from qs tile when flag is enabled
Bug: 378469025
Test: QuickAccessWalletTileTest
Flag: android.service.quickaccesswallet.launch_selected_card_from_qs_tile
Change-Id: I7d66d7b5144d6473136806c60c2dcf3a23ff7761
---
.../qs/tiles/QuickAccessWalletTileTest.java | 33 +++++++++++++++++++
.../qs/tiles/QuickAccessWalletTile.java | 12 +++++--
.../QuickAccessWalletController.java | 18 ++++++++++
.../com/android/systemui/SysuiTestCase.java | 1 +
4 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
index 03c1f92aad4c..4068d9fd7f3d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java
@@ -46,6 +46,9 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.service.quickaccesswallet.Flags;
import android.service.quickaccesswallet.GetWalletCardsError;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
@@ -221,6 +224,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
}
@Test
+ @DisableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
public void testHandleClick_startQuickAccessUiIntent_noCard() {
setUpWalletCard(/* hasCard= */ false);
@@ -234,6 +238,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
}
@Test
+ @DisableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
public void testHandleClick_startQuickAccessUiIntent_hasCard() {
setUpWalletCard(/* hasCard= */ true);
@@ -246,6 +251,34 @@ public class QuickAccessWalletTileTest extends SysuiTestCase {
/* hasCard= */ eq(true));
}
+ @Test
+ @EnableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
+ public void testHandleClick_startCardIntent_noCard() {
+ setUpWalletCard(/* hasCard= */ false);
+
+ mTile.handleClick(/* view= */ null);
+ mTestableLooper.processAllMessages();
+
+ verify(mController).startQuickAccessUiIntent(
+ eq(mActivityStarter),
+ eq(null),
+ /* hasCard= */ eq(false));
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_LAUNCH_SELECTED_CARD_FROM_QS_TILE})
+ public void testHandleClick_startCardIntent_hasCard() {
+ setUpWalletCard(/* hasCard= */ true);
+
+ mTile.handleClick(null /* view */);
+ mTestableLooper.processAllMessages();
+
+ verify(mController).startWalletCardPendingIntent(
+ any(),
+ eq(mActivityStarter),
+ eq(null));
+ }
+
@Test
public void testHandleUpdateState_updateLabelAndIcon() {
QSTile.State state = new QSTile.State();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 37d24debe958..78c435c45c72 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -142,8 +142,16 @@ public class QuickAccessWalletTile extends QSTileImpl {
InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE);
mUiHandler.post(
- () -> mController.startQuickAccessUiIntent(
- mActivityStarter, animationController, mSelectedCard != null));
+ () -> {
+ if (android.service.quickaccesswallet.Flags.launchSelectedCardFromQsTile()
+ && mSelectedCard != null) {
+ mController.startWalletCardPendingIntent(
+ mSelectedCard, mActivityStarter, animationController);
+ } else {
+ mController.startQuickAccessUiIntent(
+ mActivityStarter, animationController, mSelectedCard != null);
+ }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
index 1d32a4fd69d6..389b6fb4b0ef 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/controller/QuickAccessWalletController.java
@@ -32,6 +32,7 @@ import android.provider.Settings;
import android.service.quickaccesswallet.GetWalletCardsRequest;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
+import android.service.quickaccesswallet.WalletCard;
import android.util.Log;
import com.android.systemui.animation.ActivityTransitionAnimator;
@@ -268,6 +269,23 @@ public class QuickAccessWalletController {
});
}
+ /**
+ * Starts the {@link android.app.PendingIntent} for a {@link WalletCard}.
+ *
+ * This should be used to open a selected card from the QuickAccessWallet UI or
+ * the settings tile.
+ *
+ * @param activityStarter an {@link ActivityStarter} to launch the Intent or PendingIntent.
+ * @param animationController an {@link ActivityTransitionAnimator.Controller} to provide a
+ * smooth animation for the activity launch.
+ */
+ public void startWalletCardPendingIntent(WalletCard card,
+ ActivityStarter activityStarter,
+ ActivityTransitionAnimator.Controller animationController) {
+ activityStarter.postStartActivityDismissingKeyguard(
+ card.getPendingIntent(), animationController);
+ }
+
private Intent getSysUiWalletIntent() {
return new Intent(mContext, WalletActivity.class)
.setAction(Intent.ACTION_VIEW);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 153a8be06adc..3e44364dc6a0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -118,6 +118,7 @@ public abstract class SysuiTestCase {
android.net.platform.flags.Flags.class,
android.os.Flags.class,
android.service.controls.flags.Flags.class,
+ android.service.quickaccesswallet.Flags.class,
com.android.internal.telephony.flags.Flags.class,
com.android.server.notification.Flags.class,
com.android.systemui.Flags.class);
--
GitLab
From 250bfa4be0609e69501c07f52d979f52cba04bd5 Mon Sep 17 00:00:00 2001
From: Prince
Date: Tue, 26 Nov 2024 15:35:59 +0000
Subject: [PATCH 052/652] Improve Text Color Contrast in Glanceable hub
Updated the text color from MaterialTheme.colorScheme.secondary
to MaterialTheme.colorScheme.primary to ensure sufficient contrast
on both Light and Dark themes. This change aligns with UX recommendations
to avoid using secondary text color on primary backgrounds.
Test: Device Tested
Flag: NONE small ux change
Fixes: 378418098
Change-Id: I18b76c9b4af71b580bbe353d1af236ab17b3a5f2
---
.../src/com/android/systemui/communal/ui/compose/CommunalHub.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 787edfb9168c..f3cf521f5fbc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -908,7 +908,7 @@ private fun EmptyStateCta(contentPadding: PaddingValues, viewModel: BaseCommunal
text = titleForEmptyStateCTA,
style = MaterialTheme.typography.displaySmall,
textAlign = TextAlign.Center,
- color = colors.secondary,
+ color = colors.primary,
modifier =
Modifier.focusable().semantics(mergeDescendants = true) {
contentDescription = titleForEmptyStateCTA
--
GitLab
From 6491a452d19b663a5a22643c558222b45c0bc41c Mon Sep 17 00:00:00 2001
From: Richard Uhler
Date: Thu, 7 Nov 2024 09:05:16 -0800
Subject: [PATCH 053/652] Add flag to narrow the meaning of JANK_PERCEPTIBLE.
When the jank_perceptible_narrow flag is set, JANK_PERCEPTIBLE is
determined based on a much more narrow scope of process states instead
of whether the process is cached or not.
Bug: 304837972
Flag: android.app.jank_perceptible_narrow
Test: Device boots, MPTS memhog test with jank_perceptible_narrow set.
Change-Id: I0e0ac21c65a3b03a4927a1fd0a67df7045959d75
---
core/java/android/app/ActivityManager.java | 12 +++++++
core/java/android/app/ActivityThread.java | 32 +++++++++----------
.../java/android/app/activity_manager.aconfig | 7 ++++
3 files changed, 34 insertions(+), 17 deletions(-)
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b447897733e1..6c972c87d089 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1180,6 +1180,18 @@ public class ActivityManager {
return procState == PROCESS_STATE_FOREGROUND_SERVICE;
}
+ /** @hide Should this process state be considered jank perceptible? */
+ public static final boolean isProcStateJankPerceptible(int procState) {
+ if (Flags.jankPerceptibleNarrow()) {
+ return procState == PROCESS_STATE_PERSISTENT_UI
+ || procState == PROCESS_STATE_TOP
+ || procState == PROCESS_STATE_IMPORTANT_FOREGROUND
+ || procState == PROCESS_STATE_TOP_SLEEPING;
+ } else {
+ return !isProcStateCached(procState);
+ }
+ }
+
/** @hide requestType for assist context: only basic information. */
public static final int ASSIST_CONTEXT_BASIC = 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 60b8f80d8f2d..a95ce0e24a03 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3911,12 +3911,7 @@ public final class ActivityThread extends ClientTransactionHandler
if (mLastProcessState == processState) {
return;
}
- // Do not issue a transitional GC if we are transitioning between 2 cached states.
- // Only update if the state flips between cached and uncached or vice versa
- if (ActivityManager.isProcStateCached(mLastProcessState)
- != ActivityManager.isProcStateCached(processState)) {
- updateVmProcessState(processState);
- }
+ updateVmProcessState(mLastProcessState, processState);
mLastProcessState = processState;
if (localLOGV) {
Slog.i(TAG, "******************* PROCESS STATE CHANGED TO: " + processState
@@ -3925,18 +3920,21 @@ public final class ActivityThread extends ClientTransactionHandler
}
}
+ /** Converts a process state to a VM process state. */
+ private static int toVmProcessState(int processState) {
+ final int state = ActivityManager.isProcStateJankPerceptible(processState)
+ ? VM_PROCESS_STATE_JANK_PERCEPTIBLE
+ : VM_PROCESS_STATE_JANK_IMPERCEPTIBLE;
+ return state;
+ }
+
/** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */
- // Currently ART VM only uses state updates for Transitional GC, and thus
- // this function initiates a Transitional GC for transitions into Cached apps states.
- private void updateVmProcessState(int processState) {
- // Only a transition into Cached state should result in a Transitional GC request
- // to the ART runtime. Update VM state to JANK_IMPERCEPTIBLE in that case.
- // Note that there are 4 possible cached states currently, all of which are
- // JANK_IMPERCEPTIBLE from GC point of view.
- final int state = ActivityManager.isProcStateCached(processState)
- ? VM_PROCESS_STATE_JANK_IMPERCEPTIBLE
- : VM_PROCESS_STATE_JANK_PERCEPTIBLE;
- VMRuntime.getRuntime().updateProcessState(state);
+ private void updateVmProcessState(int lastProcessState, int newProcessState) {
+ final int state = toVmProcessState(newProcessState);
+ if (lastProcessState == PROCESS_STATE_UNKNOWN
+ || state != toVmProcessState(lastProcessState)) {
+ VMRuntime.getRuntime().updateProcessState(state);
+ }
}
@Override
diff --git a/core/java/android/app/activity_manager.aconfig b/core/java/android/app/activity_manager.aconfig
index 1f31ab5d1849..d4cd02b47e99 100644
--- a/core/java/android/app/activity_manager.aconfig
+++ b/core/java/android/app/activity_manager.aconfig
@@ -165,3 +165,10 @@ flag {
description: "Control ApplicationStartInfo component field and API"
bug: "362537357"
}
+
+flag {
+ name: "jank_perceptible_narrow"
+ namespace: "system_performance"
+ description: "Narrow the scope of Jank Perceptible"
+ bug: "304837972"
+}
--
GitLab
From ce8bee1b93af62a57097ca60c36265488a1d9371 Mon Sep 17 00:00:00 2001
From: Olivier St-Onge
Date: Thu, 21 Nov 2024 10:09:56 -0500
Subject: [PATCH 054/652] Pre load all icon drawables for QS tiles
This change is flag guarded. Preloading drawables improves performance in Compose and is needed for the QS refactor.
Test: manually
Test: local perfetto tracing
Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Bug: 377290311
Change-Id: Ie70debb02f2d58e547d063f5c358286170f4c7b5
---
.../qs/tiles/DeviceControlsTileTest.kt | 205 ++++++++----------
.../ui/compose/infinitegrid/CommonTile.kt | 3 +-
.../systemui/qs/tileimpl/QSTileImpl.java | 19 ++
.../systemui/qs/tiles/AirplaneModeTile.java | 2 +-
.../android/systemui/qs/tiles/AlarmTile.kt | 57 ++---
.../systemui/qs/tiles/BatterySaverTile.java | 5 +-
.../systemui/qs/tiles/BluetoothTile.java | 14 +-
.../android/systemui/qs/tiles/CastTile.java | 4 +-
.../qs/tiles/ColorCorrectionTile.java | 6 +-
.../systemui/qs/tiles/ColorInversionTile.java | 2 +-
.../systemui/qs/tiles/DataSaverTile.java | 2 +-
.../systemui/qs/tiles/DeviceControlsTile.kt | 92 ++++----
.../android/systemui/qs/tiles/DndTile.java | 2 +-
.../android/systemui/qs/tiles/DreamTile.java | 7 +-
.../systemui/qs/tiles/FlashlightTile.java | 4 +-
.../systemui/qs/tiles/FontScalingTile.kt | 5 +-
.../systemui/qs/tiles/HearingDevicesTile.java | 2 +-
.../systemui/qs/tiles/HotspotTile.java | 4 +-
.../systemui/qs/tiles/InternetTile.java | 28 +--
.../systemui/qs/tiles/LocationTile.java | 2 +-
.../android/systemui/qs/tiles/ModesTile.kt | 2 +-
.../android/systemui/qs/tiles/NfcTile.java | 7 +-
.../systemui/qs/tiles/NightDisplayTile.java | 2 +-
.../android/systemui/qs/tiles/NotesTile.kt | 14 +-
.../systemui/qs/tiles/OneHandedModeTile.java | 8 +-
.../systemui/qs/tiles/QRCodeScannerTile.java | 2 +-
.../qs/tiles/QuickAccessWalletTile.java | 2 +-
.../systemui/qs/tiles/RecordIssueTile.kt | 4 +-
.../qs/tiles/ReduceBrightColorsTile.java | 2 +-
.../systemui/qs/tiles/RotationLockTile.java | 7 +-
.../systemui/qs/tiles/ScreenRecordTile.java | 5 +-
.../qs/tiles/SensorPrivacyToggleTile.java | 2 +-
.../systemui/qs/tiles/UiModeNightTile.java | 2 +-
.../systemui/qs/tiles/WorkModeTile.java | 9 +-
.../shared/ui/model/InternetTileModel.kt | 4 +-
35 files changed, 286 insertions(+), 251 deletions(-)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
index 940da9967a68..33748b973f1c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
@@ -27,7 +27,6 @@ import androidx.lifecycle.LifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.MetricsLogger
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.classifier.FalsingManagerFake
@@ -45,13 +44,14 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
-import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.res.R
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.util.settings.SecureSettings
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -67,40 +67,27 @@ import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
-import java.util.Optional
@SmallTest
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class DeviceControlsTileTest : SysuiTestCase() {
- @Mock
- private lateinit var qsHost: QSHost
- @Mock
- private lateinit var metricsLogger: MetricsLogger
- @Mock
- private lateinit var statusBarStateController: StatusBarStateController
- @Mock
- private lateinit var activityStarter: ActivityStarter
- @Mock
- private lateinit var qsLogger: QSLogger
- @Mock
- private lateinit var controlsComponent: ControlsComponent
- @Mock
- private lateinit var controlsUiController: ControlsUiController
- @Mock
- private lateinit var controlsListingController: ControlsListingController
- @Mock
- private lateinit var controlsController: ControlsController
- @Mock
- private lateinit var serviceInfo: ControlsServiceInfo
- @Mock
- private lateinit var uiEventLogger: QsEventLogger
+ @Mock private lateinit var qsHost: QSHost
+ @Mock private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var qsLogger: QSLogger
+ @Mock private lateinit var controlsComponent: ControlsComponent
+ @Mock private lateinit var controlsUiController: ControlsUiController
+ @Mock private lateinit var controlsListingController: ControlsListingController
+ @Mock private lateinit var controlsController: ControlsController
+ @Mock private lateinit var serviceInfo: ControlsServiceInfo
+ @Mock private lateinit var uiEventLogger: QsEventLogger
@Captor
private lateinit var listingCallbackCaptor:
- ArgumentCaptor
- @Captor
- private lateinit var intentCaptor: ArgumentCaptor
+ ArgumentCaptor
+ @Captor private lateinit var intentCaptor: ArgumentCaptor
private lateinit var testableLooper: TestableLooper
private lateinit var tile: DeviceControlsTile
@@ -120,8 +107,11 @@ class DeviceControlsTileTest : SysuiTestCase() {
`when`(qsHost.context).thenReturn(spiedContext)
`when`(controlsComponent.isEnabled()).thenReturn(true)
`when`(controlsController.getPreferredSelection())
- .thenReturn(SelectedItem.StructureItem(
- StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())))
+ .thenReturn(
+ SelectedItem.StructureItem(
+ StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())
+ )
+ )
secureSettings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 1)
setupControlsComponent()
@@ -182,10 +172,11 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testObservingCallback() {
- verify(controlsListingController).observe(
+ verify(controlsListingController)
+ .observe(
any(LifecycleOwner::class.java),
- any(ControlsListingController.ControlsListingCallback::class.java)
- )
+ any(ControlsListingController.ControlsListingCallback::class.java),
+ )
}
@Test
@@ -205,10 +196,8 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testStateUnavailableIfNoListings() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
listingCallbackCaptor.value.onServicesUpdated(emptyList())
testableLooper.processAllMessages()
@@ -218,10 +207,8 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testStateUnavailableIfNotEnabled() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
`when`(controlsComponent.isEnabled()).thenReturn(false)
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
@@ -232,18 +219,19 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testStateActiveIfListingsHasControlsFavorited() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
- `when`(controlsController.getPreferredSelection()).thenReturn(
- SelectedItem.StructureItem(StructureInfo(
- ComponentName("pkg", "cls"),
- "structure",
- listOf(ControlInfo("id", "title", "subtitle", 1))
- ))
- )
+ `when`(controlsController.getPreferredSelection())
+ .thenReturn(
+ SelectedItem.StructureItem(
+ StructureInfo(
+ ComponentName("pkg", "cls"),
+ "structure",
+ listOf(ControlInfo("id", "title", "subtitle", 1)),
+ )
+ )
+ )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -253,14 +241,15 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testStateInactiveIfListingsHasNoControlsFavorited() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
`when`(controlsController.getPreferredSelection())
- .thenReturn(SelectedItem.StructureItem(
- StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())))
+ .thenReturn(
+ SelectedItem.StructureItem(
+ StructureInfo(ComponentName("pkg", "cls"), "structure", listOf())
+ )
+ )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -270,13 +259,11 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testStateActiveIfPreferredIsPanel() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
`when`(controlsController.getPreferredSelection())
- .thenReturn(SelectedItem.PanelItem("appName", ComponentName("pkg", "cls")))
+ .thenReturn(SelectedItem.PanelItem("appName", ComponentName("pkg", "cls")))
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -286,10 +273,8 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testStateInactiveIfLocked() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
`when`(controlsComponent.getVisibility())
.thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
@@ -301,10 +286,8 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun testMoveBetweenStates() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -325,19 +308,20 @@ class DeviceControlsTileTest : SysuiTestCase() {
@Test
fun handleClick_available_shownOverLockscreenWhenLocked() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
`when`(controlsComponent.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
`when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
- `when`(controlsController.getPreferredSelection()).thenReturn(
- SelectedItem.StructureItem(StructureInfo(
- ComponentName("pkg", "cls"),
- "structure",
- listOf(ControlInfo("id", "title", "subtitle", 1))
- ))
- )
+ `when`(controlsController.getPreferredSelection())
+ .thenReturn(
+ SelectedItem.StructureItem(
+ StructureInfo(
+ ComponentName("pkg", "cls"),
+ "structure",
+ listOf(ControlInfo("id", "title", "subtitle", 1)),
+ )
+ )
+ )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -345,30 +329,33 @@ class DeviceControlsTileTest : SysuiTestCase() {
tile.click(null /* view */)
testableLooper.processAllMessages()
- verify(activityStarter).startActivity(
+ verify(activityStarter)
+ .startActivity(
intentCaptor.capture(),
eq(true) /* dismissShade */,
nullable(ActivityTransitionAnimator.Controller::class.java),
- eq(true) /* showOverLockscreenWhenLocked */)
+ eq(true), /* showOverLockscreenWhenLocked */
+ )
assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
}
@Test
fun handleClick_availableAfterUnlock_notShownOverLockscreenWhenLocked() {
- verify(controlsListingController).observe(
- any(LifecycleOwner::class.java),
- capture(listingCallbackCaptor)
- )
+ verify(controlsListingController)
+ .observe(any(LifecycleOwner::class.java), capture(listingCallbackCaptor))
`when`(controlsComponent.getVisibility())
.thenReturn(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK)
`when`(controlsUiController.resolveActivity()).thenReturn(ControlsActivity::class.java)
- `when`(controlsController.getPreferredSelection()).thenReturn(
- SelectedItem.StructureItem(StructureInfo(
- ComponentName("pkg", "cls"),
- "structure",
- listOf(ControlInfo("id", "title", "subtitle", 1))
- ))
- )
+ `when`(controlsController.getPreferredSelection())
+ .thenReturn(
+ SelectedItem.StructureItem(
+ StructureInfo(
+ ComponentName("pkg", "cls"),
+ "structure",
+ listOf(ControlInfo("id", "title", "subtitle", 1)),
+ )
+ )
+ )
listingCallbackCaptor.value.onServicesUpdated(listOf(serviceInfo))
testableLooper.processAllMessages()
@@ -376,26 +363,19 @@ class DeviceControlsTileTest : SysuiTestCase() {
tile.click(null /* view */)
testableLooper.processAllMessages()
- verify(activityStarter).startActivity(
+ verify(activityStarter)
+ .startActivity(
intentCaptor.capture(),
anyBoolean() /* dismissShade */,
nullable(ActivityTransitionAnimator.Controller::class.java),
- eq(false) /* showOverLockscreenWhenLocked */)
+ eq(false), /* showOverLockscreenWhenLocked */
+ )
assertThat(intentCaptor.value.component?.className).isEqualTo(CONTROLS_ACTIVITY_CLASS_NAME)
}
@Test
fun verifyTileEqualsResourceFromComponent() {
- assertThat(tile.tileLabel)
- .isEqualTo(
- context.getText(
- controlsComponent.getTileTitleId()))
- }
-
- @Test
- fun verifyTileImageEqualsResourceFromComponent() {
- assertThat(tile.icon)
- .isEqualTo(QSTileImpl.ResourceIcon.get(controlsComponent.getTileImageId()))
+ assertThat(tile.tileLabel).isEqualTo(context.getText(controlsComponent.getTileTitleId()))
}
private fun createTile(): DeviceControlsTile {
@@ -409,11 +389,12 @@ class DeviceControlsTileTest : SysuiTestCase() {
statusBarStateController,
activityStarter,
qsLogger,
- controlsComponent
- ).also {
- it.initialize()
- testableLooper.processAllMessages()
- }
+ controlsComponent,
+ )
+ .also {
+ it.initialize()
+ testableLooper.processAllMessages()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
index dbad60265645..d72d5f127bba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -21,7 +21,6 @@ import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
import android.text.TextUtils
import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi
import androidx.compose.animation.graphics.res.animatedVectorResource
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
import androidx.compose.animation.graphics.vector.AnimatedImageVector
@@ -192,7 +191,6 @@ fun LargeTileLabels(
}
}
-@OptIn(ExperimentalAnimationGraphicsApi::class)
@Composable
fun SmallTileContent(
modifier: Modifier = Modifier,
@@ -229,6 +227,7 @@ fun SmallTileContent(
}
}
}
+
is Icon.Loaded -> {
LaunchedEffect(loadedDrawable) {
if (loadedDrawable is AnimatedVectorDrawable) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 9abc494e56e6..464eeda6a0a8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -31,6 +31,7 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.annotation.CallSuper;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
@@ -68,6 +69,7 @@ import com.android.systemui.qs.QSEvent;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.SideLabelTileLayout;
+import com.android.systemui.qs.flags.QsInCompose;
import com.android.systemui.qs.logging.QSLogger;
import java.io.PrintWriter;
@@ -535,6 +537,23 @@ public abstract class QSTileImpl implements QSTile, Lifecy
}
}
+ protected Icon maybeLoadResourceIcon(int id) {
+ return maybeLoadResourceIcon(id, mContext);
+ }
+
+ /**
+ * Returns the {@link QSTile.Icon} for the resource ID, optionally loading the drawable if
+ * {@link QsInCompose#isEnabled()} is true.
+ */
+ @SuppressLint("UseCompatLoadingForDrawables")
+ public static Icon maybeLoadResourceIcon(int id, Context context) {
+ if (QsInCompose.isEnabled()) {
+ return new DrawableIconWithRes(context.getDrawable(id), id);
+ } else {
+ return ResourceIcon.get(id);
+ }
+ }
+
@Override
public String getMetricsSpec() {
return mTileSpec;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 71b69c92b87d..bb818fa5e164 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -160,7 +160,7 @@ public class AirplaneModeTile extends QSTileImpl {
final boolean airplaneMode = value != 0;
state.value = airplaneMode;
state.label = mContext.getString(R.string.airplane_mode);
- state.icon = ResourceIcon.get(state.value
+ state.icon = maybeLoadResourceIcon(state.value
? R.drawable.qs_airplane_icon_on : R.drawable.qs_airplane_icon_off);
state.state = airplaneMode ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.contentDescription = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
index 73d991f6efe7..75debb6c4032 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
@@ -42,35 +42,35 @@ constructor(
activityStarter: ActivityStarter,
qsLogger: QSLogger,
private val userTracker: UserTracker,
- nextAlarmController: NextAlarmController
-) : QSTileImpl(
- host,
- uiEventLogger,
- backgroundLooper,
- mainHandler,
- falsingManager,
- metricsLogger,
- statusBarStateController,
- activityStarter,
- qsLogger
-) {
+ nextAlarmController: NextAlarmController,
+) :
+ QSTileImpl(
+ host,
+ uiEventLogger,
+ backgroundLooper,
+ mainHandler,
+ falsingManager,
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ ) {
private var lastAlarmInfo: AlarmManager.AlarmClockInfo? = null
- private val icon = ResourceIcon.get(R.drawable.ic_alarm)
+ private var icon: QSTile.Icon? = null
@VisibleForTesting internal val defaultIntent = Intent(AlarmClock.ACTION_SHOW_ALARMS)
- private val callback = NextAlarmController.NextAlarmChangeCallback { nextAlarm ->
- lastAlarmInfo = nextAlarm
- refreshState()
- }
+ private val callback =
+ NextAlarmController.NextAlarmChangeCallback { nextAlarm ->
+ lastAlarmInfo = nextAlarm
+ refreshState()
+ }
init {
nextAlarmController.observe(this, callback)
}
override fun newTileState(): QSTile.State {
- return QSTile.State().apply {
- handlesLongClick = false
- }
+ return QSTile.State().apply { handlesLongClick = false }
}
override fun handleClick(expandable: Expandable?) {
@@ -82,21 +82,28 @@ constructor(
if (pendingIntent != null) {
mActivityStarter.postStartActivityDismissingKeyguard(pendingIntent, animationController)
} else {
- mActivityStarter.postStartActivityDismissingKeyguard(defaultIntent, 0,
- animationController)
+ mActivityStarter.postStartActivityDismissingKeyguard(
+ defaultIntent,
+ 0,
+ animationController,
+ )
}
}
override fun handleUpdateState(state: QSTile.State, arg: Any?) {
+ if (icon == null) {
+ icon = maybeLoadResourceIcon(R.drawable.ic_alarm)
+ }
state.icon = icon
state.label = tileLabel
lastAlarmInfo?.let {
state.secondaryLabel = formatNextAlarm(it)
state.state = Tile.STATE_ACTIVE
- } ?: run {
- state.secondaryLabel = mContext.getString(R.string.qs_alarm_tile_no_alarm)
- state.state = Tile.STATE_INACTIVE
}
+ ?: run {
+ state.secondaryLabel = mContext.getString(R.string.qs_alarm_tile_no_alarm)
+ state.state = Tile.STATE_INACTIVE
+ }
state.contentDescription = TextUtils.concat(state.label, ", ", state.secondaryLabel)
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 7c0ce4cc75a9..9df4e42d1898 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -147,9 +147,8 @@ public class BatterySaverTile extends QSTileImpl implements
protected void handleUpdateState(BooleanState state, Object arg) {
state.state = mPluggedIn ? Tile.STATE_UNAVAILABLE
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(mPowerSave
- ? R.drawable.qs_battery_saver_icon_on
- : R.drawable.qs_battery_saver_icon_off);
+ state.icon = maybeLoadResourceIcon(mPowerSave
+ ? R.drawable.qs_battery_saver_icon_on : R.drawable.qs_battery_saver_icon_off);
state.label = mContext.getString(R.string.battery_detail_switch_title);
state.secondaryLabel = "";
state.contentDescription = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 7bff827dee03..7eb0aaabb7e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -59,13 +59,13 @@ import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.BluetoothController;
+import kotlinx.coroutines.Job;
+
import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
-import kotlinx.coroutines.Job;
-
/** Quick settings tile: Bluetooth **/
public class BluetoothTile extends QSTileImpl {
@@ -201,7 +201,7 @@ public class BluetoothTile extends QSTileImpl {
if (enabled) {
if (connected) {
- state.icon = ResourceIcon.get(R.drawable.qs_bluetooth_icon_on);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_bluetooth_icon_on);
if (!TextUtils.isEmpty(mController.getConnectedDeviceName())) {
state.label = mController.getConnectedDeviceName();
}
@@ -209,17 +209,15 @@ public class BluetoothTile extends QSTileImpl {
mContext.getString(R.string.accessibility_bluetooth_name, state.label)
+ ", " + state.secondaryLabel;
} else if (state.isTransient) {
- state.icon = ResourceIcon.get(
- R.drawable.qs_bluetooth_icon_search);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_bluetooth_icon_search);
state.stateDescription = state.secondaryLabel;
} else {
- state.icon =
- ResourceIcon.get(R.drawable.qs_bluetooth_icon_off);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_bluetooth_icon_off);
state.stateDescription = mContext.getString(R.string.accessibility_not_connected);
}
state.state = Tile.STATE_ACTIVE;
} else {
- state.icon = ResourceIcon.get(R.drawable.qs_bluetooth_icon_off);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_bluetooth_icon_off);
state.state = Tile.STATE_INACTIVE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 8a72e8db7216..ad027b4346d0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -290,8 +290,8 @@ public class CastTile extends QSTileImpl {
if (connecting && !state.value) {
state.secondaryLabel = mContext.getString(R.string.quick_settings_connecting);
}
- state.icon = ResourceIcon.get(state.value ? R.drawable.ic_cast_connected
- : R.drawable.ic_cast);
+ state.icon = maybeLoadResourceIcon(state.value
+ ? R.drawable.ic_cast_connected : R.drawable.ic_cast);
if (canCastToNetwork() || state.value) {
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
if (!state.value) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
index 871973dfcb7f..c2e609ddfc3a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorCorrectionTile.java
@@ -50,7 +50,8 @@ public class ColorCorrectionTile extends QSTileImpl {
public static final String TILE_SPEC = "color_correction";
- private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_color_correction);
+ @Nullable
+ private Icon mIcon = null;
private final UserSettingObserver mSetting;
@Inject
@@ -122,6 +123,9 @@ public class ColorCorrectionTile extends QSTileImpl {
protected void handleUpdateState(BooleanState state, Object arg) {
final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
final boolean enabled = value != 0;
+ if (mIcon == null) {
+ mIcon = maybeLoadResourceIcon(R.drawable.ic_qs_color_correction);
+ }
state.value = enabled;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.quick_settings_color_correction_label);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 58969107ad22..ce80133e67a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -124,7 +124,7 @@ public class ColorInversionTile extends QSTileImpl {
state.value = enabled;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.quick_settings_inversion_label);
- state.icon = ResourceIcon.get(state.value
+ state.icon = maybeLoadResourceIcon(state.value
? R.drawable.qs_invert_colors_icon_on
: R.drawable.qs_invert_colors_icon_off);
state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index 7760943476bf..deeef550b33f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -147,7 +147,7 @@ public class DataSaverTile extends QSTileImpl implements
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.data_saver);
state.contentDescription = state.label;
- state.icon = ResourceIcon.get(state.value ? R.drawable.qs_data_saver_icon_on
+ state.icon = maybeLoadResourceIcon(state.value ? R.drawable.qs_data_saver_icon_on
: R.drawable.qs_data_saver_icon_off);
state.expandedAccessibilityClassName = Switch.class.getName();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
index cc8a73423174..404ace18d0f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2021 The Android Open Source Project
*
@@ -22,10 +21,8 @@ import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.service.quicksettings.Tile
-import androidx.annotation.VisibleForTesting
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.MetricsLogger
-import com.android.systemui.res.R
import com.android.systemui.animation.Expandable
import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.controls.dagger.ControlsComponent
@@ -43,10 +40,13 @@ import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
+import com.android.systemui.res.R
import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
-class DeviceControlsTile @Inject constructor(
+class DeviceControlsTile
+@Inject
+constructor(
host: QSHost,
uiEventLogger: QsEventLogger,
@Background backgroundLooper: Looper,
@@ -56,32 +56,34 @@ class DeviceControlsTile @Inject constructor(
statusBarStateController: StatusBarStateController,
activityStarter: ActivityStarter,
qsLogger: QSLogger,
- private val controlsComponent: ControlsComponent
-) : QSTileImpl(
- host,
- uiEventLogger,
- backgroundLooper,
- mainHandler,
- falsingManager,
- metricsLogger,
- statusBarStateController,
- activityStarter,
- qsLogger
-) {
+ private val controlsComponent: ControlsComponent,
+) :
+ QSTileImpl(
+ host,
+ uiEventLogger,
+ backgroundLooper,
+ mainHandler,
+ falsingManager,
+ metricsLogger,
+ statusBarStateController,
+ activityStarter,
+ qsLogger,
+ ) {
private var hasControlsApps = AtomicBoolean(false)
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- val icon: QSTile.Icon
- get() = ResourceIcon.get(controlsComponent.getTileImageId())
+ private var icon: QSTile.Icon? = null
- private val listingCallback = object : ControlsListingController.ControlsListingCallback {
- override fun onServicesUpdated(serviceInfos: List) {
- if (hasControlsApps.compareAndSet(serviceInfos.isEmpty(), serviceInfos.isNotEmpty())) {
- refreshState()
+ private val listingCallback =
+ object : ControlsListingController.ControlsListingCallback {
+ override fun onServicesUpdated(serviceInfos: List) {
+ if (
+ hasControlsApps.compareAndSet(serviceInfos.isEmpty(), serviceInfos.isNotEmpty())
+ ) {
+ refreshState()
+ }
}
}
- }
init {
controlsComponent.getControlsListingController().ifPresent {
@@ -105,15 +107,19 @@ class DeviceControlsTile @Inject constructor(
return
}
- val intent = Intent().apply {
- component = ComponentName(mContext, controlsComponent.getControlsUiController().get()
- .resolveActivity())
- addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
- putExtra(ControlsUiController.EXTRA_ANIMATE, true)
- }
+ val intent =
+ Intent().apply {
+ component =
+ ComponentName(
+ mContext,
+ controlsComponent.getControlsUiController().get().resolveActivity(),
+ )
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
+ putExtra(ControlsUiController.EXTRA_ANIMATE, true)
+ }
val animationController =
expandable?.activityTransitionController(
- InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE
+ InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE
)
mUiHandler.post {
@@ -130,17 +136,23 @@ class DeviceControlsTile @Inject constructor(
override fun handleUpdateState(state: QSTile.State, arg: Any?) {
state.label = tileLabel
state.contentDescription = state.label
+ if (icon == null) {
+ icon = maybeLoadResourceIcon(controlsComponent.getTileImageId())
+ }
state.icon = icon
if (controlsComponent.isEnabled() && hasControlsApps.get()) {
if (controlsComponent.getVisibility() == AVAILABLE) {
- val selection = controlsComponent
- .getControlsController().get().getPreferredSelection()
- state.state = if (selection is SelectedItem.StructureItem &&
- selection.structure.controls.isEmpty()) {
- Tile.STATE_INACTIVE
- } else {
- Tile.STATE_ACTIVE
- }
+ val selection =
+ controlsComponent.getControlsController().get().getPreferredSelection()
+ state.state =
+ if (
+ selection is SelectedItem.StructureItem &&
+ selection.structure.controls.isEmpty()
+ ) {
+ Tile.STATE_INACTIVE
+ } else {
+ Tile.STATE_ACTIVE
+ }
val label = selection.name
state.secondaryLabel = if (label == tileLabel) null else label
} else {
@@ -170,4 +182,4 @@ class DeviceControlsTile @Inject constructor(
companion object {
const val TILE_SPEC = "controls"
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index ad76b4f21bfb..04f0b8736598 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -229,7 +229,7 @@ public class DndTile extends QSTileImpl {
state.dualTarget = true;
state.value = newValue;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(state.value
+ state.icon = maybeLoadResourceIcon(state.value
? R.drawable.qs_dnd_icon_on
: R.drawable.qs_dnd_icon_off);
state.label = getTileLabel();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
index 0d3d980f71f4..374bcda5f46a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DreamTile.java
@@ -64,9 +64,6 @@ public class DreamTile extends QSTileImpl {
public static final String TILE_SPEC = "dream";
private static final String LOG_TAG = "QSDream";
- // TODO: consider 1 animated icon instead
- private final Icon mIconDocked = ResourceIcon.get(R.drawable.ic_qs_screen_saver);
- private final Icon mIconUndocked = ResourceIcon.get(R.drawable.ic_qs_screen_saver_undocked);
private final IDreamManager mDreamManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private final UserSettingObserver mEnabledSettingObserver;
@@ -170,7 +167,9 @@ public class DreamTile extends QSTileImpl {
state.label = getTileLabel();
state.secondaryLabel = getActiveDreamName();
state.contentDescription = getContentDescription(state.secondaryLabel);
- state.icon = mIsDocked ? mIconDocked : mIconUndocked;
+ // TODO: consider 1 animated icon instead
+ state.icon = maybeLoadResourceIcon(mIsDocked
+ ? R.drawable.ic_qs_screen_saver : R.drawable.ic_qs_screen_saver_undocked);
if (getActiveDream() == null || !isScreensaverEnabled()) {
state.state = Tile.STATE_UNAVAILABLE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 848ff3c533ba..2b127d60b2be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -128,7 +128,7 @@ public class FlashlightTile extends QSTileImpl implements
R.string.quick_settings_flashlight_camera_in_use);
state.stateDescription = state.secondaryLabel;
state.state = Tile.STATE_UNAVAILABLE;
- state.icon = ResourceIcon.get(R.drawable.qs_flashlight_icon_off);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_flashlight_icon_off);
return;
}
if (arg instanceof Boolean) {
@@ -143,7 +143,7 @@ public class FlashlightTile extends QSTileImpl implements
state.contentDescription = mContext.getString(R.string.quick_settings_flashlight_label);
state.expandedAccessibilityClassName = Switch.class.getName();
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(state.value
+ state.icon = maybeLoadResourceIcon(state.value
? R.drawable.qs_flashlight_icon_on : R.drawable.qs_flashlight_icon_off);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 7606293454f8..43e84a0ee2b4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -68,7 +68,7 @@ constructor(
activityStarter,
qsLogger,
) {
- private val icon = ResourceIcon.get(R.drawable.ic_qs_font_scaling)
+ private var icon: QSTile.Icon? = null
override fun newTileState(): QSTile.State {
return QSTile.State()
@@ -108,6 +108,9 @@ constructor(
}
override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
+ if (icon == null) {
+ icon = maybeLoadResourceIcon(R.drawable.ic_qs_font_scaling)
+ }
state?.label = mContext.getString(R.string.quick_settings_font_scaling_label)
state?.icon = icon
state?.contentDescription = state?.label
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
index f723ff264e0c..48b39dcf29ba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HearingDevicesTile.java
@@ -106,7 +106,7 @@ public class HearingDevicesTile extends QSTileImpl {
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_BLUETOOTH);
state.label = mContext.getString(R.string.quick_settings_hearing_devices_label);
- state.icon = ResourceIcon.get(R.drawable.qs_hearing_devices_icon);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_hearing_devices_icon);
state.forceExpandIcon = true;
boolean isBonded = mDevicesChecker.isAnyPairedHearingDevice();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index ea3993ea88a9..03bbbd7017ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -151,10 +151,10 @@ public class HotspotTile extends QSTileImpl {
state.label = mContext.getString(R.string.quick_settings_hotspot_label);
state.isTransient = isTransient;
if (state.isTransient) {
- state.icon = ResourceIcon.get(
+ state.icon = maybeLoadResourceIcon(
R.drawable.qs_hotspot_icon_search);
} else {
- state.icon = ResourceIcon.get(state.value
+ state.icon = maybeLoadResourceIcon(state.value
? R.drawable.qs_hotspot_icon_on : R.drawable.qs_hotspot_icon_off);
}
state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index 02f6f80d7282..e9c5f4ae9b10 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -529,10 +529,10 @@ public class InternetTile extends QSTileImpl {
if (cb.mAirplaneModeEnabled) {
if (!state.value) {
state.state = Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qs_no_internet_unavailable);
state.secondaryLabel = r.getString(R.string.status_bar_airplane);
} else if (!wifiConnected) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qs_no_internet_unavailable);
if (cb.mNoNetworksAvailable) {
state.secondaryLabel =
r.getString(R.string.quick_settings_networks_unavailable);
@@ -541,28 +541,28 @@ public class InternetTile extends QSTileImpl {
r.getString(R.string.quick_settings_networks_available);
}
} else {
- state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
+ state.icon = maybeLoadResourceIcon(cb.mWifiSignalIconId);
}
} else if (cb.mNoDefaultNetwork) {
if (cb.mNoNetworksAvailable || !cb.mEnabled) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qs_no_internet_unavailable);
state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
} else {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qs_no_internet_available);
state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
}
} else if (cb.mIsTransient) {
- state.icon = ResourceIcon.get(
+ state.icon = maybeLoadResourceIcon(
com.android.internal.R.drawable.ic_signal_wifi_transient_animation);
} else if (!state.value) {
state.state = Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED);
+ state.icon = maybeLoadResourceIcon(WifiIcons.QS_WIFI_DISABLED);
} else if (wifiConnected) {
- state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
+ state.icon = maybeLoadResourceIcon(cb.mWifiSignalIconId);
} else if (wifiNotConnected) {
- state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
+ state.icon = maybeLoadResourceIcon(WifiIcons.QS_WIFI_NO_NETWORK);
} else {
- state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
+ state.icon = maybeLoadResourceIcon(WifiIcons.QS_WIFI_NO_NETWORK);
}
minimalContentDescription.append(
mContext.getString(R.string.quick_settings_internet_label)).append(",");
@@ -598,14 +598,14 @@ public class InternetTile extends QSTileImpl {
if (cb.mAirplaneModeEnabled && cb.mQsTypeIcon != TelephonyIcons.ICON_CWF) {
state.state = Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qs_no_internet_unavailable);
state.secondaryLabel = r.getString(R.string.status_bar_airplane);
} else if (cb.mNoDefaultNetwork) {
if (cb.mNoNetworksAvailable || !mSignalCallback.mWifiInfo.mEnabled) {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_unavailable);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qs_no_internet_unavailable);
state.secondaryLabel = r.getString(R.string.quick_settings_networks_unavailable);
} else {
- state.icon = ResourceIcon.get(R.drawable.ic_qs_no_internet_available);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qs_no_internet_available);
state.secondaryLabel = r.getString(R.string.quick_settings_networks_available);
}
} else {
@@ -637,7 +637,7 @@ public class InternetTile extends QSTileImpl {
final Resources r = mContext.getResources();
state.label = r.getString(R.string.quick_settings_internet_label);
state.state = Tile.STATE_ACTIVE;
- state.icon = ResourceIcon.get(cb.mEthernetSignalIconId);
+ state.icon = maybeLoadResourceIcon(cb.mEthernetSignalIconId);
state.secondaryLabel = cb.mEthernetContentDescription;
if (DEBUG) {
Log.d(TAG, "handleUpdateEthernetState: " + "BooleanState = " + state.toString());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index cad5c0d12d1d..f35c25f24162 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -122,7 +122,7 @@ public class LocationTile extends QSTileImpl {
if (state.disabledByPolicy == false) {
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_LOCATION);
}
- state.icon = ResourceIcon.get(state.value
+ state.icon = maybeLoadResourceIcon(state.value
? R.drawable.qs_location_icon_on : R.drawable.qs_location_icon_off);
state.label = mContext.getString(R.string.quick_settings_location_label);
state.contentDescription = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
index fef5a745c1ca..9c6345666403 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ModesTile.kt
@@ -120,7 +120,7 @@ constructor(
tileState = tileMapper.map(config, model)
state?.apply {
this.state = tileState.activationState.legacyState
- icon = tileState.icon?.asQSTileIcon() ?: ResourceIcon.get(ICON_RES_ID)
+ icon = tileState.icon?.asQSTileIcon() ?: maybeLoadResourceIcon(ICON_RES_ID)
label = tileLabel
secondaryLabel = tileState.secondaryLabel
contentDescription = tileState.contentDescription
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 136eea8331df..683e4e93cf4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -55,7 +55,8 @@ public class NfcTile extends QSTileImpl {
public static final String TILE_SPEC = "nfc";
private static final String NFC = TILE_SPEC;
- private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_nfc);
+ @Nullable
+ private Icon mIcon = null;
@Nullable
private NfcAdapter mAdapter;
@@ -137,6 +138,10 @@ public class NfcTile extends QSTileImpl {
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
+ if (mIcon == null) {
+ mIcon = maybeLoadResourceIcon(R.drawable.ic_qs_nfc);
+ }
+
state.value = getAdapter() != null && getAdapter().isEnabled();
state.state = getAdapter() == null
? Tile.STATE_UNAVAILABLE
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index ac762de6d544..2f5908752111 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -150,7 +150,7 @@ public class NightDisplayTile extends QSTileImpl implements
state.label = mContext.getString(R.string.quick_settings_night_display_label);
state.expandedAccessibilityClassName = Switch.class.getName();
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
- state.icon = ResourceIcon.get(state.value ? R.drawable.qs_nightlight_icon_on
+ state.icon = maybeLoadResourceIcon(state.value ? R.drawable.qs_nightlight_icon_on
: R.drawable.qs_nightlight_icon_off);
state.secondaryLabel = getSecondaryLabel(state.value);
state.contentDescription = TextUtils.isEmpty(state.secondaryLabel)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt
index 69df0961bf66..989fc0fd6f44 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NotesTile.kt
@@ -40,14 +40,14 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider
import com.android.systemui.qs.tiles.viewmodel.QSTileState
import com.android.systemui.res.R
import javax.inject.Inject
-import kotlinx.coroutines.runBlocking
/** Quick settings tile: Notes */
class NotesTile
-@Inject constructor(
+@Inject
+constructor(
private val host: QSHost,
private val uiEventLogger: QsEventLogger,
- @Background private val backgroundLooper: Looper,
+ @Background private val backgroundLooper: Looper,
@Main private val mainHandler: Handler,
private val falsingManager: FalsingManager,
private val metricsLogger: MetricsLogger,
@@ -74,8 +74,7 @@ class NotesTile
private lateinit var tileState: QSTileState
private val config = qsTileConfigProvider.getConfig(TILE_SPEC)
- override fun getTileLabel(): CharSequence =
- mContext.getString(config.uiConfig.labelRes)
+ override fun getTileLabel(): CharSequence = mContext.getString(config.uiConfig.labelRes)
override fun newTileState(): QSTile.State? {
return QSTile.State().apply { state = Tile.STATE_INACTIVE }
@@ -88,13 +87,12 @@ class NotesTile
override fun getLongClickIntent(): Intent = userActionInteractor.longClickIntent
override fun handleUpdateState(state: QSTile.State?, arg: Any?) {
- val model =
- if (arg is NotesTileModel) arg else dataInteractor.getCurrentTileModel()
+ val model = if (arg is NotesTileModel) arg else dataInteractor.getCurrentTileModel()
tileState = tileMapper.map(config, model)
state?.apply {
this.state = tileState.activationState.legacyState
- icon = ResourceIcon.get(tileState.iconRes ?: R.drawable.ic_qs_notes)
+ icon = maybeLoadResourceIcon(tileState.iconRes ?: R.drawable.ic_qs_notes)
label = tileState.label
contentDescription = tileState.contentDescription
expandedAccessibilityClassName = tileState.expandedAccessibilityClassName
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
index 450c95411c3f..c605ac8d80b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/OneHandedModeTile.java
@@ -51,8 +51,8 @@ public class OneHandedModeTile extends QSTileImpl {
public static final String TILE_SPEC = "onehanded";
- private final Icon mIcon = ResourceIcon.get(
- com.android.internal.R.drawable.ic_qs_one_handed_mode);
+ @Nullable
+ private Icon mIcon = null;
private final UserSettingObserver mSetting;
@Inject
@@ -125,6 +125,10 @@ public class OneHandedModeTile extends QSTileImpl {
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
+ if (mIcon == null) {
+ mIcon = maybeLoadResourceIcon(com.android.internal.R.drawable.ic_qs_one_handed_mode);
+ }
+
final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
final boolean enabled = value != 0;
state.value = enabled;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
index 9766fac7965e..93a51cfacf02 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRCodeScannerTile.java
@@ -119,7 +119,7 @@ public class QRCodeScannerTile extends QSTileImpl {
protected void handleUpdateState(State state, Object arg) {
state.label = mContext.getString(R.string.qr_code_scanner_title);
state.contentDescription = state.label;
- state.icon = ResourceIcon.get(R.drawable.ic_qr_code_scanner);
+ state.icon = maybeLoadResourceIcon(R.drawable.ic_qr_code_scanner);
state.state = mQRCodeScannerController.isAbleToLaunchScannerActivity() ? Tile.STATE_INACTIVE
: Tile.STATE_UNAVAILABLE;
// The assumption is that if the OEM has the QR code scanner module enabled then the scanner
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
index 37d24debe958..3d039e6ef824 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java
@@ -154,7 +154,7 @@ public class QuickAccessWalletTile extends QSTileImpl {
Drawable tileIcon = mController.getWalletClient().getTileIcon();
state.icon =
tileIcon == null
- ? ResourceIcon.get(R.drawable.ic_wallet_lockscreen)
+ ? maybeLoadResourceIcon(R.drawable.ic_wallet_lockscreen)
: new DrawableIcon(tileIcon);
boolean isDeviceLocked = !mKeyguardStateController.isUnlocked();
if (mController.getWalletClient().isWalletServiceAvailable()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
index 028ac6f4ac18..ca9d96ebf3e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RecordIssueTile.kt
@@ -221,13 +221,13 @@ constructor(
state = Tile.STATE_ACTIVE
forceExpandIcon = false
secondaryLabel = mContext.getString(R.string.qs_record_issue_stop)
- icon = ResourceIcon.get(R.drawable.qs_record_issue_icon_on)
+ icon = maybeLoadResourceIcon(R.drawable.qs_record_issue_icon_on)
} else {
value = false
state = Tile.STATE_INACTIVE
forceExpandIcon = true
secondaryLabel = mContext.getString(R.string.qs_record_issue_start)
- icon = ResourceIcon.get(R.drawable.qs_record_issue_icon_off)
+ icon = maybeLoadResourceIcon(R.drawable.qs_record_issue_icon_off)
}
label = tileLabel
contentDescription =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
index d624d989f42a..26d43ee92bbc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ReduceBrightColorsTile.java
@@ -141,7 +141,7 @@ public class ReduceBrightColorsTile extends QSTileImpl
state.label = mContext.getString(R.string.reduce_bright_colors_feature_name);
state.expandedAccessibilityClassName = Switch.class.getName();
state.contentDescription = state.label;
- state.icon = ResourceIcon.get(state.value
+ state.icon = maybeLoadResourceIcon(state.value
? drawable.qs_extra_dim_icon_on
: drawable.qs_extra_dim_icon_off);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 35e43b6fed9e..e361bb8ce883 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -63,7 +63,8 @@ public class RotationLockTile extends QSTileImpl implements
private static final String EMPTY_SECONDARY_STRING = "";
- private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate);
+ private final Icon mIcon =
+ maybeLoadResourceIcon(com.android.internal.R.drawable.ic_qs_auto_rotate);
private final RotationLockController mController;
private final SensorPrivacyManager mPrivacyManager;
private final BatteryController mBatteryController;
@@ -153,13 +154,13 @@ public class RotationLockTile extends QSTileImpl implements
&& mController.isCameraRotationEnabled();
state.value = !rotationLocked;
state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
- state.icon = ResourceIcon.get(R.drawable.qs_auto_rotate_icon_off);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_auto_rotate_icon_off);
state.contentDescription = getAccessibilityString(rotationLocked);
if (!rotationLocked) {
state.secondaryLabel = cameraRotation ? mContext.getResources().getString(
R.string.rotation_lock_camera_rotation_on)
: EMPTY_SECONDARY_STRING;
- state.icon = ResourceIcon.get(R.drawable.qs_auto_rotate_icon_on);
+ state.icon = maybeLoadResourceIcon(R.drawable.qs_auto_rotate_icon_on);
} else {
state.secondaryLabel = EMPTY_SECONDARY_STRING;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index f3be340f4951..6b0287ef6848 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -138,9 +138,8 @@ public class ScreenRecordTile extends QSTileImpl
state.value = isRecording || isStarting;
state.state = (isRecording || isStarting) ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.label = mContext.getString(R.string.quick_settings_screen_record_label);
- state.icon = ResourceIcon.get(state.value
- ? R.drawable.qs_screen_record_icon_on
- : R.drawable.qs_screen_record_icon_off);
+ state.icon = maybeLoadResourceIcon(state.value
+ ? R.drawable.qs_screen_record_icon_on : R.drawable.qs_screen_record_icon_off);
// Show expand icon when clicking will open a dialog
state.forceExpandIcon = state.state == Tile.STATE_INACTIVE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
index 036ce080c543..b62e858e6ade 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyToggleTile.java
@@ -119,7 +119,7 @@ public abstract class SensorPrivacyToggleTile extends QSTileImpl implements
} else {
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
- state.icon = ResourceIcon.get(state.state == Tile.STATE_ACTIVE
+ state.icon = maybeLoadResourceIcon(state.state == Tile.STATE_ACTIVE
? R.drawable.qs_light_dark_theme_icon_on
: R.drawable.qs_light_dark_theme_icon_off);
state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 1750347fd2ae..f6f89f759e0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -53,8 +53,8 @@ public class WorkModeTile extends QSTileImpl implements
public static final String TILE_SPEC = "work";
- private final Icon mIcon = ResourceIcon.get(
- com.android.internal.R.drawable.stat_sys_managed_profile_status);
+ @Nullable
+ private Icon mIcon = null;
private final ManagedProfileController mProfileController;
@@ -129,6 +129,11 @@ public class WorkModeTile extends QSTileImpl implements
state.value = mProfileController.isWorkModeEnabled();
}
+ if (mIcon == null) {
+ mIcon = maybeLoadResourceIcon(
+ com.android.internal.R.drawable.stat_sys_managed_profile_status);
+ }
+
state.icon = mIcon;
state.label = getTileLabel();
state.contentDescription = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
index ed0eb6d44508..d3e37119fdcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/InternetTileModel.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.pipeline.shared.ui.model
+import android.annotation.SuppressLint
import android.content.Context
import android.graphics.drawable.Drawable
import android.service.quicksettings.Tile
@@ -36,6 +37,7 @@ sealed interface InternetTileModel {
val stateDescription: ContentDescription?
val contentDescription: ContentDescription?
+ @SuppressLint("UseCompatLoadingForDrawables")
fun applyTo(state: QSTile.BooleanState, context: Context) {
if (secondaryLabel != null) {
state.secondaryLabel = secondaryLabel.loadText(context)
@@ -50,7 +52,7 @@ sealed interface InternetTileModel {
if (icon != null) {
state.icon = icon
} else if (iconId != null) {
- state.icon = QSTileImpl.ResourceIcon.get(iconId!!)
+ state.icon = QSTileImpl.maybeLoadResourceIcon(iconId!!, context)
}
state.state =
--
GitLab
From 04d8822850021386cfa5a45cce9d24a712818406 Mon Sep 17 00:00:00 2001
From: Preethi Kandhalu
Date: Tue, 12 Nov 2024 10:36:52 -0800
Subject: [PATCH 055/652] [Media Quality] Implement Remove Picture Profile API
& temp map functionality
Test: logs and CTS
Bug: 378705930
Flag: android.media.tv.flags.media_quality_fw
Change-Id: If095b33ceb24f13f07cf53bd1c919f8a7918b544
---
services/core/Android.bp | 1 +
.../media/quality/MediaQualityService.java | 73 ++++++++++++++-----
2 files changed, 55 insertions(+), 19 deletions(-)
diff --git a/services/core/Android.bp b/services/core/Android.bp
index b9540eba938f..c6e59a5f567c 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -220,6 +220,7 @@ java_library_static {
"securebox",
"apache-commons-math",
"battery_saver_flag_lib",
+ "guava",
"notification_flags_lib",
"power_hint_flags_lib",
"biometrics_flags_lib",
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 65d0ab337400..2ce03aee2f41 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -35,6 +35,9 @@ import android.util.Log;
import com.android.server.SystemService;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+
import org.json.JSONException;
import org.json.JSONObject;
@@ -43,6 +46,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
+import java.util.UUID;
/**
* This service manage picture profile and sound profile for TV setting. Also communicates with the
@@ -54,10 +58,12 @@ public class MediaQualityService extends SystemService {
private static final String TAG = "MediaQualityService";
private final Context mContext;
private final MediaQualityDbHelper mMediaQualityDbHelper;
+ private final BiMap mTempIdMap;
public MediaQualityService(Context context) {
super(context);
mContext = context;
+ mTempIdMap = HashBiMap.create();
mMediaQualityDbHelper = new MediaQualityDbHelper(mContext);
mMediaQualityDbHelper.setWriteAheadLoggingEnabled(true);
mMediaQualityDbHelper.setIdleConnectionTimeout(30);
@@ -83,8 +89,21 @@ public class MediaQualityService extends SystemService {
values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(pp.getParameters()));
// id is auto-generated by SQLite upon successful insertion of row
- long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, null, values);
- return new PictureProfile.Builder(pp).setProfileId(Long.toString(id)).build();
+ Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+ null, values);
+ populateTempIdMap(id);
+ pp.setProfileId(mTempIdMap.get(id));
+ return pp;
+ }
+
+ private void populateTempIdMap(Long id) {
+ if (id != null && mTempIdMap.get(id) == null) {
+ String uuid = UUID.randomUUID().toString();
+ while (mTempIdMap.inverse().containsKey(uuid)) {
+ uuid = UUID.randomUUID().toString();
+ }
+ mTempIdMap.put(id, uuid);
+ }
}
@Override
@@ -94,7 +113,15 @@ public class MediaQualityService extends SystemService {
@Override
public void removePictureProfile(String id, int userId) {
- // TODO: implement
+ Long intId = mTempIdMap.inverse().get(id);
+ if (intId != null) {
+ SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+ String selection = BaseParameters.PARAMETER_ID + " = ?";
+ String[] selectionArgs = {Long.toString(intId)};
+ db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, selection,
+ selectionArgs);
+ mTempIdMap.remove(intId);
+ }
}
@Override
@@ -126,7 +153,7 @@ public class MediaQualityService extends SystemService {
return null;
}
cursor.moveToFirst();
- return getPictureProfileFromCursor(cursor);
+ return getPictureProfileWithTempIdFromCursor(cursor);
}
}
@@ -187,20 +214,28 @@ public class MediaQualityService extends SystemService {
};
}
- private PictureProfile getPictureProfileFromCursor(Cursor cursor) {
- String returnId = cursor.getString(cursor.getColumnIndexOrThrow(
- BaseParameters.PARAMETER_ID));
- int type = cursor.getInt(cursor.getColumnIndexOrThrow(
- BaseParameters.PARAMETER_TYPE));
- String name = cursor.getString(cursor.getColumnIndexOrThrow(
- BaseParameters.PARAMETER_NAME));
- String inputId = cursor.getString(cursor.getColumnIndexOrThrow(
- BaseParameters.PARAMETER_INPUT_ID));
- String packageName = cursor.getString(cursor.getColumnIndexOrThrow(
- BaseParameters.PARAMETER_PACKAGE));
- String settings = cursor.getString(
- cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
- return new PictureProfile(returnId, type, name, inputId,
+ private PictureProfile getPictureProfileWithTempIdFromCursor(Cursor cursor) {
+ int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_ID);
+ Long dbId = colIndex != -1 ? cursor.getLong(colIndex) : null;
+ populateTempIdMap(dbId);
+ String tempId = mTempIdMap.get(dbId);
+
+ colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_TYPE);
+ int type = colIndex != -1 ? cursor.getInt(colIndex) : 0;
+
+ colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_NAME);
+ String name = colIndex != -1 ? cursor.getString(colIndex) : null;
+
+ colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_INPUT_ID);
+ String inputId = colIndex != -1 ? cursor.getString(colIndex) : null;
+
+ colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_PACKAGE);
+ String packageName = colIndex != -1 ? cursor.getString(colIndex) : null;
+
+ colIndex = cursor.getColumnIndex(mMediaQualityDbHelper.SETTINGS);
+ String settings = colIndex != -1 ? cursor.getString(colIndex) : null;
+
+ return new PictureProfile(tempId, type, name, inputId,
packageName, jsonToBundle(settings));
}
@@ -243,7 +278,7 @@ public class MediaQualityService extends SystemService {
) {
List pictureProfiles = new ArrayList<>();
while (cursor.moveToNext()) {
- pictureProfiles.add(getPictureProfileFromCursor(cursor));
+ pictureProfiles.add(getPictureProfileWithTempIdFromCursor(cursor));
}
return pictureProfiles;
}
--
GitLab
From 2c1a837847e58fef587c2911b242be7ce70ff138 Mon Sep 17 00:00:00 2001
From: Preethi Kandhalu
Date: Tue, 19 Nov 2024 16:10:09 -0800
Subject: [PATCH 056/652] [Media Quality] Add Temp Id Map to Sound Profile and
refactor
Test: logs and CTS
Flag: android.media.tv.flags.media_quality_fw
Bug: 378708165
Change-Id: I962a88849934cee3eb3da7e5ddbb3235e79b25d8
---
.../media/quality/MediaQualityService.java | 368 +++++++++---------
1 file changed, 186 insertions(+), 182 deletions(-)
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index 2ce03aee2f41..14eeb3dc78f8 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -58,12 +58,14 @@ public class MediaQualityService extends SystemService {
private static final String TAG = "MediaQualityService";
private final Context mContext;
private final MediaQualityDbHelper mMediaQualityDbHelper;
- private final BiMap mTempIdMap;
+ private final BiMap mPictureProfileTempIdMap;
+ private final BiMap mSoundProfileTempIdMap;
public MediaQualityService(Context context) {
super(context);
mContext = context;
- mTempIdMap = HashBiMap.create();
+ mPictureProfileTempIdMap = HashBiMap.create();
+ mSoundProfileTempIdMap = HashBiMap.create();
mMediaQualityDbHelper = new MediaQualityDbHelper(mContext);
mMediaQualityDbHelper.setWriteAheadLoggingEnabled(true);
mMediaQualityDbHelper.setIdleConnectionTimeout(30);
@@ -86,26 +88,16 @@ public class MediaQualityService extends SystemService {
values.put(BaseParameters.PARAMETER_NAME, pp.getName());
values.put(BaseParameters.PARAMETER_PACKAGE, pp.getPackageName());
values.put(BaseParameters.PARAMETER_INPUT_ID, pp.getInputId());
- values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(pp.getParameters()));
+ values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(pp.getParameters()));
// id is auto-generated by SQLite upon successful insertion of row
Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
null, values);
- populateTempIdMap(id);
- pp.setProfileId(mTempIdMap.get(id));
+ populateTempIdMap(mPictureProfileTempIdMap, id);
+ pp.setProfileId(mPictureProfileTempIdMap.get(id));
return pp;
}
- private void populateTempIdMap(Long id) {
- if (id != null && mTempIdMap.get(id) == null) {
- String uuid = UUID.randomUUID().toString();
- while (mTempIdMap.inverse().containsKey(uuid)) {
- uuid = UUID.randomUUID().toString();
- }
- mTempIdMap.put(id, uuid);
- }
- }
-
@Override
public void updatePictureProfile(String id, PictureProfile pp, int userId) {
// TODO: implement
@@ -113,34 +105,27 @@ public class MediaQualityService extends SystemService {
@Override
public void removePictureProfile(String id, int userId) {
- Long intId = mTempIdMap.inverse().get(id);
+ Long intId = mPictureProfileTempIdMap.inverse().get(id);
if (intId != null) {
SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
String selection = BaseParameters.PARAMETER_ID + " = ?";
String[] selectionArgs = {Long.toString(intId)};
db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, selection,
selectionArgs);
- mTempIdMap.remove(intId);
+ mPictureProfileTempIdMap.remove(intId);
}
}
@Override
public PictureProfile getPictureProfile(int type, String name, int userId) {
- SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
-
String selection = BaseParameters.PARAMETER_TYPE + " = ? AND "
+ BaseParameters.PARAMETER_NAME + " = ?";
String[] selectionArguments = {Integer.toString(type), name};
try (
- Cursor cursor = db.query(
+ Cursor cursor = getCursorAfterQuerying(
mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
- getAllPictureProfileColumns(),
- selection,
- selectionArguments,
- /*groupBy=*/ null,
- /*having=*/ null,
- /*orderBy=*/ null)
+ getAllMediaProfileColumns(), selection, selectionArguments)
) {
int count = cursor.getCount();
if (count == 0) {
@@ -149,7 +134,7 @@ public class MediaQualityService extends SystemService {
if (count > 1) {
Log.wtf(TAG, String.format(Locale.US, "%d entries found for type=%d and name=%s"
+ " in %s. Should only ever be 0 or 1.", count, type, name,
- mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
+ mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
return null;
}
cursor.moveToFirst();
@@ -157,93 +142,11 @@ public class MediaQualityService extends SystemService {
}
}
- private String bundleToJson(PersistableBundle bundle) {
- JSONObject jsonObject = new JSONObject();
- if (bundle == null) {
- return jsonObject.toString();
- }
- for (String key : bundle.keySet()) {
- try {
- jsonObject.put(key, bundle.getString(key));
- } catch (JSONException e) {
- Log.e(TAG, "Unable to serialize ", e);
- }
- }
- return jsonObject.toString();
- }
-
- private PersistableBundle jsonToBundle(String jsonString) {
- JSONObject jsonObject = null;
- PersistableBundle bundle = new PersistableBundle();
-
- try {
- jsonObject = new JSONObject(jsonString);
-
- Iterator keys = jsonObject.keys();
- while (keys.hasNext()) {
- String key = keys.next();
- Object value = jsonObject.get(key);
-
- if (value instanceof String) {
- bundle.putString(key, (String) value);
- } else if (value instanceof Integer) {
- bundle.putInt(key, (Integer) value);
- } else if (value instanceof Boolean) {
- bundle.putBoolean(key, (Boolean) value);
- } else if (value instanceof Double) {
- bundle.putDouble(key, (Double) value);
- } else if (value instanceof Long) {
- bundle.putLong(key, (Long) value);
- }
- }
- } catch (JSONException e) {
- throw new RuntimeException(e);
- }
-
- return bundle;
- }
-
- private String[] getAllPictureProfileColumns() {
- return new String[]{
- BaseParameters.PARAMETER_ID,
- BaseParameters.PARAMETER_TYPE,
- BaseParameters.PARAMETER_NAME,
- BaseParameters.PARAMETER_INPUT_ID,
- BaseParameters.PARAMETER_PACKAGE,
- mMediaQualityDbHelper.SETTINGS
- };
- }
-
- private PictureProfile getPictureProfileWithTempIdFromCursor(Cursor cursor) {
- int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_ID);
- Long dbId = colIndex != -1 ? cursor.getLong(colIndex) : null;
- populateTempIdMap(dbId);
- String tempId = mTempIdMap.get(dbId);
-
- colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_TYPE);
- int type = colIndex != -1 ? cursor.getInt(colIndex) : 0;
-
- colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_NAME);
- String name = colIndex != -1 ? cursor.getString(colIndex) : null;
-
- colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_INPUT_ID);
- String inputId = colIndex != -1 ? cursor.getString(colIndex) : null;
-
- colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_PACKAGE);
- String packageName = colIndex != -1 ? cursor.getString(colIndex) : null;
-
- colIndex = cursor.getColumnIndex(mMediaQualityDbHelper.SETTINGS);
- String settings = colIndex != -1 ? cursor.getString(colIndex) : null;
-
- return new PictureProfile(tempId, type, name, inputId,
- packageName, jsonToBundle(settings));
- }
-
@Override
public List getPictureProfilesByPackage(String packageName, int userId) {
String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
String[] selectionArguments = {packageName};
- return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection,
+ return getPictureProfilesBasedOnConditions(getAllMediaProfileColumns(), selection,
selectionArguments);
}
@@ -254,36 +157,15 @@ public class MediaQualityService extends SystemService {
@Override
public List getPictureProfilePackageNames(int userId) {
- String [] column = {BaseParameters.PARAMETER_NAME};
+ String [] column = {BaseParameters.PARAMETER_PACKAGE};
List pictureProfiles = getPictureProfilesBasedOnConditions(column,
null, null);
return pictureProfiles.stream()
- .map(PictureProfile::getName)
+ .map(PictureProfile::getPackageName)
+ .distinct()
.collect(Collectors.toList());
}
- private List getPictureProfilesBasedOnConditions(String[] columns,
- String selection, String[] selectionArguments) {
- SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
-
- try (
- Cursor cursor = db.query(
- mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
- columns,
- selection,
- selectionArguments,
- /*groupBy=*/ null,
- /*having=*/ null,
- /*orderBy=*/ null)
- ) {
- List pictureProfiles = new ArrayList<>();
- while (cursor.moveToNext()) {
- pictureProfiles.add(getPictureProfileWithTempIdFromCursor(cursor));
- }
- return pictureProfiles;
- }
- }
-
@Override
public PictureProfileHandle getPictureProfileHandle(String id, int userId) {
return null;
@@ -294,13 +176,18 @@ public class MediaQualityService extends SystemService {
SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
+ values.put(BaseParameters.PARAMETER_TYPE, sp.getProfileType());
values.put(BaseParameters.PARAMETER_NAME, sp.getName());
values.put(BaseParameters.PARAMETER_PACKAGE, sp.getPackageName());
values.put(BaseParameters.PARAMETER_INPUT_ID, sp.getInputId());
- values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(sp.getParameters()));
+ values.put(mMediaQualityDbHelper.SETTINGS, persistableBundleToJson(sp.getParameters()));
- long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, null, values);
- return new SoundProfile.Builder(sp).setProfileId(Long.toString(id)).build();
+ // id is auto-generated by SQLite upon successful insertion of row
+ Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
+ null, values);
+ populateTempIdMap(mSoundProfileTempIdMap, id);
+ sp.setProfileId(mSoundProfileTempIdMap.get(id));
+ return sp;
}
@Override
@@ -310,28 +197,27 @@ public class MediaQualityService extends SystemService {
@Override
public void removeSoundProfile(String id, int userId) {
- SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
- String selection = BaseParameters.PARAMETER_ID + " = ?";
- String[] selectionArgs = {id};
- db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection, selectionArgs);
+ Long intId = mSoundProfileTempIdMap.inverse().get(id);
+ if (intId != null) {
+ SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+ String selection = BaseParameters.PARAMETER_ID + " = ?";
+ String[] selectionArgs = {Long.toString(intId)};
+ db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection,
+ selectionArgs);
+ mSoundProfileTempIdMap.remove(intId);
+ }
}
@Override
public SoundProfile getSoundProfile(int type, String id, int userId) {
- SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
-
- String selection = BaseParameters.PARAMETER_ID + " = ?";
- String[] selectionArguments = {id};
+ String selection = BaseParameters.PARAMETER_TYPE + " = ? AND "
+ + BaseParameters.PARAMETER_NAME + " = ?";
+ String[] selectionArguments = {String.valueOf(type), id};
try (
- Cursor cursor = db.query(
+ Cursor cursor = getCursorAfterQuerying(
mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
- getAllSoundProfileColumns(),
- selection,
- selectionArguments,
- /*groupBy=*/ null,
- /*having=*/ null,
- /*orderBy=*/ null)
+ getAllMediaProfileColumns(), selection, selectionArguments)
) {
int count = cursor.getCount();
if (count == 0) {
@@ -344,7 +230,7 @@ public class MediaQualityService extends SystemService {
return null;
}
cursor.moveToFirst();
- return getSoundProfileFromCursor(cursor);
+ return getSoundProfileWithTempIdFromCursor(cursor);
}
}
@@ -352,7 +238,7 @@ public class MediaQualityService extends SystemService {
public List getSoundProfilesByPackage(String packageName, int userId) {
String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
String[] selectionArguments = {packageName};
- return getSoundProfilesBasedOnConditions(getAllSoundProfileColumns(), selection,
+ return getSoundProfilesBasedOnConditions(getAllMediaProfileColumns(), selection,
selectionArguments);
}
@@ -367,13 +253,79 @@ public class MediaQualityService extends SystemService {
List soundProfiles = getSoundProfilesBasedOnConditions(column,
null, null);
return soundProfiles.stream()
- .map(SoundProfile::getName)
+ .map(SoundProfile::getPackageName)
+ .distinct()
.collect(Collectors.toList());
}
- private String[] getAllSoundProfileColumns() {
+ private void populateTempIdMap(BiMap map, Long id) {
+ if (id != null && map.get(id) == null) {
+ String uuid = UUID.randomUUID().toString();
+ while (map.inverse().containsKey(uuid)) {
+ uuid = UUID.randomUUID().toString();
+ }
+ map.put(id, uuid);
+ }
+ }
+
+ private String persistableBundleToJson(PersistableBundle bundle) {
+ JSONObject json = new JSONObject();
+ for (String key : bundle.keySet()) {
+ Object value = bundle.get(key);
+ try {
+ if (value instanceof String) {
+ json.put(key, bundle.getString(key));
+ } else if (value instanceof Integer) {
+ json.put(key, bundle.getInt(key));
+ } else if (value instanceof Long) {
+ json.put(key, bundle.getLong(key));
+ } else if (value instanceof Boolean) {
+ json.put(key, bundle.getBoolean(key));
+ } else if (value instanceof Double) {
+ json.put(key, bundle.getDouble(key));
+ }
+ } catch (JSONException e) {
+ Log.e(TAG, "Unable to serialize ", e);
+ }
+ }
+ return json.toString();
+ }
+
+ private PersistableBundle jsonToBundle(String jsonString) {
+ PersistableBundle bundle = new PersistableBundle();
+ if (jsonString != null) {
+ JSONObject jsonObject = null;
+ try {
+ jsonObject = new JSONObject(jsonString);
+
+ Iterator keys = jsonObject.keys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ Object value = jsonObject.get(key);
+
+ if (value instanceof String) {
+ bundle.putString(key, (String) value);
+ } else if (value instanceof Integer) {
+ bundle.putInt(key, (Integer) value);
+ } else if (value instanceof Boolean) {
+ bundle.putBoolean(key, (Boolean) value);
+ } else if (value instanceof Double) {
+ bundle.putDouble(key, (Double) value);
+ } else if (value instanceof Long) {
+ bundle.putLong(key, (Long) value);
+ }
+ }
+ } catch (JSONException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return bundle;
+ }
+
+ private String[] getAllMediaProfileColumns() {
return new String[]{
BaseParameters.PARAMETER_ID,
+ BaseParameters.PARAMETER_TYPE,
BaseParameters.PARAMETER_NAME,
BaseParameters.PARAMETER_INPUT_ID,
BaseParameters.PARAMETER_PACKAGE,
@@ -381,40 +333,92 @@ public class MediaQualityService extends SystemService {
};
}
- private SoundProfile getSoundProfileFromCursor(Cursor cursor) {
- String returnId = cursor.getString(
- cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_ID));
- int type = cursor.getInt(
- cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_TYPE));
- String name = cursor.getString(
- cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_NAME));
- String inputId = cursor.getString(
- cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_INPUT_ID));
- String packageName = cursor.getString(
- cursor.getColumnIndexOrThrow(BaseParameters.PARAMETER_PACKAGE));
- String settings = cursor.getString(
- cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS));
- return new SoundProfile(returnId, type, name, inputId, packageName,
- jsonToBundle(settings));
+ private PictureProfile getPictureProfileWithTempIdFromCursor(Cursor cursor) {
+ return new PictureProfile(
+ getTempId(mPictureProfileTempIdMap, cursor),
+ getType(cursor),
+ getName(cursor),
+ getInputId(cursor),
+ getPackageName(cursor),
+ jsonToBundle(getSettingsString(cursor))
+ );
+ }
+
+ private SoundProfile getSoundProfileWithTempIdFromCursor(Cursor cursor) {
+ return new SoundProfile(
+ getTempId(mSoundProfileTempIdMap, cursor),
+ getType(cursor),
+ getName(cursor),
+ getInputId(cursor),
+ getPackageName(cursor),
+ jsonToBundle(getSettingsString(cursor))
+ );
+ }
+
+ private String getTempId(BiMap map, Cursor cursor) {
+ int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_ID);
+ Long dbId = colIndex != -1 ? cursor.getLong(colIndex) : null;
+ populateTempIdMap(map, dbId);
+ return map.get(dbId);
}
- private List getSoundProfilesBasedOnConditions(String[] columns,
- String selection, String[] selectionArguments) {
+ private int getType(Cursor cursor) {
+ int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_TYPE);
+ return colIndex != -1 ? cursor.getInt(colIndex) : 0;
+ }
+
+ private String getName(Cursor cursor) {
+ int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_NAME);
+ return colIndex != -1 ? cursor.getString(colIndex) : null;
+ }
+
+ private String getInputId(Cursor cursor) {
+ int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_INPUT_ID);
+ return colIndex != -1 ? cursor.getString(colIndex) : null;
+ }
+
+ private String getPackageName(Cursor cursor) {
+ int colIndex = cursor.getColumnIndex(BaseParameters.PARAMETER_PACKAGE);
+ return colIndex != -1 ? cursor.getString(colIndex) : null;
+ }
+
+ private String getSettingsString(Cursor cursor) {
+ int colIndex = cursor.getColumnIndex(mMediaQualityDbHelper.SETTINGS);
+ return colIndex != -1 ? cursor.getString(colIndex) : null;
+ }
+
+ private Cursor getCursorAfterQuerying(String table, String[] columns, String selection,
+ String[] selectionArgs) {
SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase();
+ return db.query(table, columns, selection, selectionArgs,
+ /*groupBy=*/ null, /*having=*/ null, /*orderBy=*/ null);
+ }
+ private List getPictureProfilesBasedOnConditions(String[] columns,
+ String selection, String[] selectionArguments) {
try (
- Cursor cursor = db.query(
- mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
- columns,
- selection,
- selectionArguments,
- /*groupBy=*/ null,
- /*having=*/ null,
- /*orderBy=*/ null)
+ Cursor cursor = getCursorAfterQuerying(
+ mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, columns, selection,
+ selectionArguments)
+ ) {
+ List pictureProfiles = new ArrayList<>();
+ while (cursor.moveToNext()) {
+ pictureProfiles.add(getPictureProfileWithTempIdFromCursor(cursor));
+ }
+ return pictureProfiles;
+ }
+ }
+
+ private List getSoundProfilesBasedOnConditions(String[] columns,
+ String selection, String[] selectionArguments) {
+ try (
+ Cursor cursor = getCursorAfterQuerying(
+ mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, columns, selection,
+ selectionArguments)
) {
List soundProfiles = new ArrayList<>();
while (cursor.moveToNext()) {
- soundProfiles.add(getSoundProfileFromCursor(cursor));
+ soundProfiles.add(getSoundProfileWithTempIdFromCursor(cursor));
}
return soundProfiles;
}
--
GitLab
From 4e5754eb549f417430a1b611b0e418f2b88df831 Mon Sep 17 00:00:00 2001
From: Marcelo Arteiro
Date: Mon, 25 Nov 2024 13:17:00 +0000
Subject: [PATCH 057/652] Migrates Monet's Style Enum to @IntDef
This is part of the effort to move all Color System depenencies to
server. Enum are not allowerd there.
Bug: 335429258
Test: None
Flag: EXEMPT rearchitecture
Change-Id: I24f22e3057d81ba32c9e66997b15bbbd75025cc3
---
.../android/systemui/shared/clocks/ClockDesign.kt | 2 +-
.../systemui/theme/ThemeOverlayControllerTest.java | 8 ++++----
.../keyguard/ui/preview/KeyguardPreviewRenderer.kt | 7 +++++--
.../media/controls/ui/util/MediaArtworkHelper.kt | 6 +++++-
.../systemui/theme/ThemeOverlayController.java | 12 +++++++-----
5 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt
index bcf055bd2c40..15373d354ef6 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ClockDesign.kt
@@ -33,7 +33,7 @@ data class ClockDesign(
val thumbnail: String? = null,
val large: ClockFace? = null,
val small: ClockFace? = null,
- val colorPalette: MonetStyle? = null,
+ @MonetStyle.Type val colorPalette: Int? = null,
)
/** Describes a clock using layers */
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index e7ca1dd3e4b7..7b52dd836b51 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -434,13 +434,13 @@ public class ThemeOverlayControllerTest extends SysuiTestCase {
@Test
public void onSettingChanged_honorThemeStyle() {
when(mDeviceProvisionedController.isUserSetup(anyInt())).thenReturn(true);
- List
-
-
--
GitLab
From 3c2cb40abc5508b8fe97a8ea96dafd173a9d7d4a Mon Sep 17 00:00:00 2001
From: Robin Lee
Date: Mon, 2 Dec 2024 12:59:42 +0100
Subject: [PATCH 143/652] SilkFX: Migrate layouts to display edge-to-edge
Bug: 309578419
Test: Manual (open each of the screens and check layout hierarchy)
Flag: com.android.window.flags.disable_opt_out_edge_to_edge
Change-Id: Ie4736d2602d0588199252e28055a42fba212fc2a
---
.../res/layout/activity_background_blur.xml | 277 +++++++++---------
.../SilkFX/res/layout/activity_glass.xml | 3 +-
.../SilkFX/res/layout/color_mode_controls.xml | 3 +-
.../SilkFX/res/layout/common_base.xml | 3 +-
.../graphics/SilkFX/res/layout/hdr_glows.xml | 3 +-
tests/graphics/SilkFX/res/values/style.xml | 2 +-
.../src/com/android/test/silkfx/Main.kt | 1 +
7 files changed, 152 insertions(+), 140 deletions(-)
diff --git a/tests/graphics/SilkFX/res/layout/activity_background_blur.xml b/tests/graphics/SilkFX/res/layout/activity_background_blur.xml
index f13c0883cb01..27eca82dcb23 100644
--- a/tests/graphics/SilkFX/res/layout/activity_background_blur.xml
+++ b/tests/graphics/SilkFX/res/layout/activity_background_blur.xml
@@ -13,161 +13,168 @@
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
- -->
-
+
-
-
-
+ android:layout_gravity="center"
+ android:padding="15dp"
+ android:orientation="vertical">
-
-
-
-
+ android:text="Hello blurry world!"/>
-
-
-
-
-
+ android:orientation="horizontal">
+
-
-
-
-
-
+
+
+
+ android:orientation="horizontal">
+
-
-
+
+
+
-
-
-
+ android:orientation="horizontal">
+
-
+
+
+
+ android:orientation="horizontal">
+
-
+
+
+
+
-
-
+ android:layout_gravity="center"
+ android:layout_marginTop="5dp"
+ android:orientation="vertical"
+ android:gravity="center">
+
+
-
+
+
+
+
+
+
diff --git a/tests/graphics/SilkFX/res/layout/activity_glass.xml b/tests/graphics/SilkFX/res/layout/activity_glass.xml
index aa09f276d5c8..d591fc4606b0 100644
--- a/tests/graphics/SilkFX/res/layout/activity_glass.xml
+++ b/tests/graphics/SilkFX/res/layout/activity_glass.xml
@@ -19,6 +19,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
tools:context=".MainActivity">
-
\ No newline at end of file
+
diff --git a/tests/graphics/SilkFX/res/layout/color_mode_controls.xml b/tests/graphics/SilkFX/res/layout/color_mode_controls.xml
index c0c0bab8a605..9b2b0c818a8e 100644
--- a/tests/graphics/SilkFX/res/layout/color_mode_controls.xml
+++ b/tests/graphics/SilkFX/res/layout/color_mode_controls.xml
@@ -19,6 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_margin="8dp"
android:orientation="vertical">
-
\ No newline at end of file
+
diff --git a/tests/graphics/SilkFX/res/layout/common_base.xml b/tests/graphics/SilkFX/res/layout/common_base.xml
index c0eaf9bc1476..ce6d850af1bc 100644
--- a/tests/graphics/SilkFX/res/layout/common_base.xml
+++ b/tests/graphics/SilkFX/res/layout/common_base.xml
@@ -18,6 +18,7 @@
@@ -26,4 +27,4 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
-
\ No newline at end of file
+
diff --git a/tests/graphics/SilkFX/res/layout/hdr_glows.xml b/tests/graphics/SilkFX/res/layout/hdr_glows.xml
index b6050645866a..f1e553a3df23 100644
--- a/tests/graphics/SilkFX/res/layout/hdr_glows.xml
+++ b/tests/graphics/SilkFX/res/layout/hdr_glows.xml
@@ -18,6 +18,7 @@
@@ -48,4 +49,4 @@
android:layout_height="50dp"
android:layout_margin="8dp" />
-
\ No newline at end of file
+
diff --git a/tests/graphics/SilkFX/res/values/style.xml b/tests/graphics/SilkFX/res/values/style.xml
index 66edbb5c9382..75506978024b 100644
--- a/tests/graphics/SilkFX/res/values/style.xml
+++ b/tests/graphics/SilkFX/res/values/style.xml
@@ -16,7 +16,7 @@
-->
-
-
-
-
-
-
-
\ No newline at end of file
--
GitLab
From e312b3099e75171c4c9d85aa1b2606908552b42d Mon Sep 17 00:00:00 2001
From: Sarp Misoglu
Date: Mon, 2 Dec 2024 18:46:01 +0000
Subject: [PATCH 178/652] Delete Filipendo workaround code for R
It seems this was intended to be removed for S. I've also double checked
this setting isn't used anywhere that I can find.
Fixes: 154822946
Test: presubmit
Change-Id: I974b30a54883280d16dacf9a2de876d87f1e2c13
---
.../backup/UserBackupManagerService.java | 36 ---------------
.../PerformFullTransportBackupTask.java | 2 -
.../restore/PerformUnifiedRestoreTask.java | 2 -
.../backup/UserBackupManagerServiceTest.java | 46 -------------------
4 files changed, 86 deletions(-)
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index a90b693c5a1d..3025e2eaede0 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -314,8 +314,6 @@ public class UserBackupManagerService {
private static final String SERIAL_ID_FILE = "serial_id";
- private static final String SKIP_USER_FACING_PACKAGES = "backup_skip_user_facing_packages";
-
private final @UserIdInt int mUserId;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
private final TransportManager mTransportManager;
@@ -3503,40 +3501,6 @@ public class UserBackupManagerService {
}
}
- /**
- * We want to skip backup/restore of certain packages if 'backup_skip_user_facing_packages' is
- * set to true in secure settings. See b/153940088 for details.
- *
- * TODO(b/154822946): Remove this logic in the next release.
- */
- public List filterUserFacingPackages(List packages) {
- if (!shouldSkipUserFacingData()) {
- return packages;
- }
-
- List filteredPackages = new ArrayList<>(packages.size());
- for (PackageInfo packageInfo : packages) {
- if (!shouldSkipPackage(packageInfo.packageName)) {
- filteredPackages.add(packageInfo);
- } else {
- Slog.i(TAG, "Will skip backup/restore for " + packageInfo.packageName);
- }
- }
-
- return filteredPackages;
- }
-
- @VisibleForTesting
- public boolean shouldSkipUserFacingData() {
- return Settings.Secure.getInt(mContext.getContentResolver(), SKIP_USER_FACING_PACKAGES,
- /* def */ 0) != 0;
- }
-
- @VisibleForTesting
- public boolean shouldSkipPackage(String packageName) {
- return WALLPAPER_PACKAGE.equals(packageName);
- }
-
private void updateStateForTransport(String newTransportName) {
// Publish the name change
Settings.Secure.putStringForUser(mContext.getContentResolver(),
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 799494831f19..990c9416e38d 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -272,8 +272,6 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba
}
}
- mPackages = backupManagerService.filterUserFacingPackages(mPackages);
-
Set packageNames = Sets.newHashSet();
for (PackageInfo pkgInfo : mPackages) {
packageNames.add(pkgInfo.packageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index dad84c86deef..ec9d340abe45 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -315,8 +315,6 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
}
- mAcceptSet = backupManagerService.filterUserFacingPackages(mAcceptSet);
-
if (MORE_DEBUG) {
Slog.v(TAG, "Restore; accept set size is " + mAcceptSet.size());
for (PackageInfo info : mAcceptSet) {
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 02e0bbfd3519..eb61a40e0ba5 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -30,13 +30,10 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
import static org.testng.Assert.expectThrows;
import android.app.backup.BackupManager;
@@ -90,7 +87,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
/**
@@ -110,7 +106,6 @@ public class UserBackupManagerServiceTest {
private static final String TAG = "BMSTest";
private static final String PACKAGE_1 = "some.package.1";
private static final String PACKAGE_2 = "some.package.2";
- private static final String USER_FACING_PACKAGE = "user.facing.package";
private static final int USER_ID = 10;
@Mock private TransportManager mTransportManager;
@@ -1213,47 +1208,6 @@ public class UserBackupManagerServiceTest {
eq(packageTrackingReceiver), eq(UserHandle.of(USER_ID)), any(), any(), any());
}
- @Test
- public void testFilterUserFacingPackages_shouldSkipUserFacing_filtersUserFacing() {
- List packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
- getPackageInfo(PACKAGE_1));
- UserBackupManagerService backupManagerService = spy(
- createUserBackupManagerServiceAndRunTasks());
- when(backupManagerService.shouldSkipUserFacingData()).thenReturn(true);
- when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
-
- List filteredPackages = backupManagerService.filterUserFacingPackages(
- packages);
-
- assertFalse(containsPackage(filteredPackages, USER_FACING_PACKAGE));
- assertTrue(containsPackage(filteredPackages, PACKAGE_1));
- }
-
- @Test
- public void testFilterUserFacingPackages_shouldNotSkipUserFacing_doesNotFilterUserFacing() {
- List packages = Arrays.asList(getPackageInfo(USER_FACING_PACKAGE),
- getPackageInfo(PACKAGE_1));
- UserBackupManagerService backupManagerService = spy(
- createUserBackupManagerServiceAndRunTasks());
- when(backupManagerService.shouldSkipUserFacingData()).thenReturn(false);
- when(backupManagerService.shouldSkipPackage(eq(USER_FACING_PACKAGE))).thenReturn(true);
-
- List filteredPackages = backupManagerService.filterUserFacingPackages(
- packages);
-
- assertTrue(containsPackage(filteredPackages, USER_FACING_PACKAGE));
- assertTrue(containsPackage(filteredPackages, PACKAGE_1));
- }
-
- private static boolean containsPackage(List packages, String targetPackage) {
- for (PackageInfo packageInfo : packages) {
- if (targetPackage.equals(packageInfo.packageName)) {
- return true;
- }
- }
- return false;
- }
-
private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() {
return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
USER_ID, mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager);
--
GitLab
From 384c93fc72dd0f55e7c16e94748fa8ccb0260267 Mon Sep 17 00:00:00 2001
From: Yan Yan
Date: Wed, 27 Nov 2024 16:40:15 -0800
Subject: [PATCH 179/652] Clean up safe_mode_config flag check in the
functional code
This patch cleans up the flag check in the functional code. The
flag is already fully released in Android V
At the same time, the flag definition is not removed because it
is an exportable flag
Bug: 380326369
Bug: 276358140
Test: atest FrameworksVcnTests && atest CtsVcnTestCases
Flag: EXEMPT, clean up released flag
Change-Id: I985d37e192c4bc87ebd433f4de3b7fe93b039f7d
---
.../server/vcn/VcnGatewayConnection.java | 5 +---
...cnGatewayConnectionConnectedStateTest.java | 24 ++-----------------
2 files changed, 3 insertions(+), 26 deletions(-)
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9ccf0401e91d..77bda9dc6b14 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -1228,10 +1228,7 @@ public class VcnGatewayConnection extends StateMachine {
@VisibleForTesting(visibility = Visibility.PRIVATE)
void setSafeModeAlarm() {
- final boolean isFlagSafeModeConfigEnabled = mVcnContext.getFeatureFlags().safeModeConfig();
- logVdbg("isFlagSafeModeConfigEnabled " + isFlagSafeModeConfigEnabled);
-
- if (isFlagSafeModeConfigEnabled && !mConnectionConfig.isSafeModeEnabled()) {
+ if (!mConnectionConfig.isSafeModeEnabled()) {
logVdbg("setSafeModeAlarm: safe mode disabled");
return;
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 76be232c2fe3..74db6a5211a0 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -659,7 +659,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
private void verifySetSafeModeAlarm(
boolean safeModeEnabledByCaller,
- boolean safeModeConfigFlagEnabled,
boolean expectingSafeModeEnabled)
throws Exception {
final VcnGatewayConnectionConfig config =
@@ -670,7 +669,6 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
mock(VcnGatewayConnection.Dependencies.class);
setUpWakeupMessage(
mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, deps);
- doReturn(safeModeConfigFlagEnabled).when(mFeatureFlags).safeModeConfig();
final VcnGatewayConnection connection =
new VcnGatewayConnection(
@@ -694,37 +692,19 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection
}
@Test
- public void testSafeModeEnabled_configFlagEnabled() throws Exception {
+ public void testSafeModeEnabled() throws Exception {
verifySetSafeModeAlarm(
true /* safeModeEnabledByCaller */,
- true /* safeModeConfigFlagEnabled */,
true /* expectingSafeModeEnabled */);
}
@Test
- public void testSafeModeEnabled_configFlagDisabled() throws Exception {
- verifySetSafeModeAlarm(
- true /* safeModeEnabledByCaller */,
- false /* safeModeConfigFlagEnabled */,
- true /* expectingSafeModeEnabled */);
- }
-
- @Test
- public void testSafeModeDisabled_configFlagEnabled() throws Exception {
+ public void testSafeModeDisabled() throws Exception {
verifySetSafeModeAlarm(
false /* safeModeEnabledByCaller */,
- true /* safeModeConfigFlagEnabled */,
false /* expectingSafeModeEnabled */);
}
- @Test
- public void testSafeModeDisabled_configFlagDisabled() throws Exception {
- verifySetSafeModeAlarm(
- false /* safeModeEnabledByCaller */,
- false /* safeModeConfigFlagEnabled */,
- true /* expectingSafeModeEnabled */);
- }
-
private Consumer setupNetworkAndGetUnwantedCallback() {
triggerChildOpened();
mTestLooper.dispatchAll();
--
GitLab
From 2470a475dd420600b1a60d60978051f287faadac Mon Sep 17 00:00:00 2001
From: "Priyanka Advani (xWF)"
Date: Mon, 2 Dec 2024 19:04:52 +0000
Subject: [PATCH 180/652] Revert "ArrayUtils: add secure zeroization support"
This reverts commit c948c80be52d333046b47610668b82113822301c.
Reason for revert: Droidmonitor created revert due to b/381880605. Will be verifying through ABTD before submission.
Change-Id: Iaf6bd3ebd187aa758c524083bc559fac85926ef0
---
.../com/android/internal/util/ArrayUtils.java | 45 -------
core/jni/Android.bp | 1 -
core/jni/AndroidRuntime.cpp | 2 -
.../com_android_internal_util_ArrayUtils.cpp | 122 ------------------
.../android/internal/util/ArrayUtilsTest.java | 47 -------
5 files changed, 217 deletions(-)
delete mode 100644 core/jni/com_android_internal_util_ArrayUtils.cpp
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index c257c5db6465..11123a9986f9 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -84,51 +84,6 @@ public class ArrayUtils {
return (T[])VMRuntime.getRuntime().newUnpaddedArray(clazz, minLen);
}
- /**
- * This is like new byte[length], but it allocates the array as non-movable. This
- * prevents copies of the data from being left on the Java heap as a result of heap compaction.
- * Use this when the array will contain sensitive data such as a password or cryptographic key
- * that needs to be wiped from memory when no longer needed. The owner of the array is still
- * responsible for the zeroization; {@link #zeroize(byte[])} should be used to do so.
- *
- * @param length the length of the array to allocate
- * @return the new array
- */
- public static byte[] newNonMovableByteArray(int length) {
- return (byte[]) VMRuntime.getRuntime().newNonMovableArray(byte.class, length);
- }
-
- /**
- * Like {@link #newNonMovableByteArray(int)}, but allocates a char array.
- *
- * @param length the length of the array to allocate
- * @return the new array
- */
- public static char[] newNonMovableCharArray(int length) {
- return (char[]) VMRuntime.getRuntime().newNonMovableArray(char.class, length);
- }
-
- /**
- * Zeroizes a byte array as securely as possible. Use this when the array contains sensitive
- * data such as a password or cryptographic key.
- *
- * This zeroizes the array in a way that is guaranteed to not be optimized out by the compiler.
- * If supported by the architecture, it zeroizes the data not just in the L1 data cache but also
- * in other levels of the memory hierarchy up to and including main memory (but not above that).
- *
- * This works on any byte[], but to ensure that copies of the array aren't left on
- * the Java heap the array should have been allocated with {@link #newNonMovableByteArray(int)}.
- * Use on other arrays might also introduce performance anomalies.
- *
- * @param array the array to zeroize
- */
- public static native void zeroize(byte[] array);
-
- /**
- * Like {@link #zeroize(byte[])}, but for char arrays.
- */
- public static native void zeroize(char[] array);
-
/**
* Checks if the beginnings of two byte arrays are equal.
*
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 82babe7a3160..f6689d585df1 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -90,7 +90,6 @@ cc_library_shared_for_libandroid_runtime {
"android_view_VelocityTracker.cpp",
"android_view_VerifiedKeyEvent.cpp",
"android_view_VerifiedMotionEvent.cpp",
- "com_android_internal_util_ArrayUtils.cpp",
"com_android_internal_util_VirtualRefBasePtr.cpp",
"core_jni_helpers.cpp",
":deviceproductinfoconstants_aidl",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index c005d63ff797..c5df248ec1a9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -215,7 +215,6 @@ extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_security_VerityUtils(JNIEnv* env);
-extern int register_com_android_internal_util_ArrayUtils(JNIEnv* env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
extern int register_android_window_WindowInfosListener(JNIEnv* env);
extern int register_android_window_ScreenCapture(JNIEnv* env);
@@ -1614,7 +1613,6 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_com_android_internal_security_VerityUtils),
- REG_JNI(register_com_android_internal_util_ArrayUtils),
REG_JNI(register_com_android_internal_util_VirtualRefBasePtr),
REG_JNI(register_android_hardware_Camera),
REG_JNI(register_android_hardware_camera2_CameraMetadata),
diff --git a/core/jni/com_android_internal_util_ArrayUtils.cpp b/core/jni/com_android_internal_util_ArrayUtils.cpp
deleted file mode 100644
index c69e6c903ee5..000000000000
--- a/core/jni/com_android_internal_util_ArrayUtils.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "ArrayUtils"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace android {
-
-static size_t GetCacheLineSize() {
- long size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
- if (size <= 0) {
- ALOGE("Unable to determine L1 data cache line size. Assuming 32 bytes");
- return 32;
- }
- return size;
-}
-
-#ifdef __aarch64__
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {
- // Execute 'dc cvac' at least once on each cache line in the memory region.
- //
- // 'dc cvac' stands for "Data Cache line Clean by Virtual Address to point-of-Coherency".
- // It writes the cache line back to the "point-of-coherency", i.e. main memory.
- //
- // Since the memory region is not guaranteed to be cache-line-aligned, we use an "extra"
- // instruction after the loop to make sure the last cache line gets covered.
- for (size_t i = 0; i < size; i += cache_line_size) {
- asm volatile("dc cvac, %0" ::"r"(p + i));
- }
- asm volatile("dc cvac, %0" ::"r"(p + size - 1));
-}
-#elif defined(__i386__) || defined(__x86_64__)
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {
- for (size_t i = 0; i < size; i += cache_line_size) {
- asm volatile("clflush (%0)" ::"r"(p + i));
- }
- asm volatile("clflush (%0)" ::"r"(p + size - 1));
-}
-#elif defined(__riscv)
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {
- // This should eventually work, but it is not ready to be enabled yet:
- // 1.) The Android emulator needs to add support for zicbom.
- // 2.) Kernel needs to enable zicbom in usermode.
- // 3.) Android clang needs to add zicbom to the target.
-#if 0
- for (size_t i = 0; i < size; i += cache_line_size) {
- asm volatile("cbo.clean (%0)" ::"r"(p + i));
- }
- asm volatile("cbo.clean (%0)" ::"r"(p + size - 1));
-#endif
-}
-#elif defined(__arm__)
-// arm32 has a cacheflush() syscall, but it is undocumented and only flushes the icache.
-// It is not the same as cacheflush(2) as documented in the Linux man-pages project.
-static void CleanDataCache(const uint8_t* p, size_t size, size_t cache_line_size) {}
-#else
-#error "Unknown architecture"
-#endif
-
-static void ZeroizePrimitiveArray(JNIEnv* env, jclass clazz, jarray array, size_t component_len) {
- static const size_t cache_line_size = GetCacheLineSize();
-
- size_t size = env->GetArrayLength(array) * component_len;
- if (size == 0) {
- return;
- }
-
- // ART guarantees that GetPrimitiveArrayCritical never copies.
- jboolean isCopy;
- void* elems = env->GetPrimitiveArrayCritical(array, &isCopy);
- CHECK(!isCopy);
-
-#ifdef __BIONIC__
- memset_explicit(elems, 0, size);
-#else
- memset(elems, 0, size);
-#endif
- // Clean the data cache so that the data gets zeroized in main memory right away. Without this,
- // it might not be written to main memory until the cache line happens to be evicted.
- CleanDataCache(static_cast(elems), size, cache_line_size);
-
- env->ReleasePrimitiveArrayCritical(array, elems, /* mode= */ 0);
-}
-
-static void ZeroizeByteArray(JNIEnv* env, jclass clazz, jbyteArray array) {
- ZeroizePrimitiveArray(env, clazz, array, sizeof(jbyte));
-}
-
-static void ZeroizeCharArray(JNIEnv* env, jclass clazz, jcharArray array) {
- ZeroizePrimitiveArray(env, clazz, array, sizeof(jchar));
-}
-
-static const JNINativeMethod sMethods[] = {
- {"zeroize", "([B)V", (void*)ZeroizeByteArray},
- {"zeroize", "([C)V", (void*)ZeroizeCharArray},
-};
-
-int register_com_android_internal_util_ArrayUtils(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/internal/util/ArrayUtils", sMethods,
- NELEM(sMethods));
-}
-
-} // namespace android
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index f06adcedf645..fc233fba082e 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -496,51 +496,4 @@ public class ArrayUtilsTest {
// expected
}
}
-
- // Note: the zeroize() tests only test the behavior that can be tested from a Java test.
- // They do not verify that no copy of the data is left anywhere.
-
- @Test
- @SmallTest
- public void testZeroizeNonMovableByteArray() {
- final int length = 10;
- byte[] array = ArrayUtils.newNonMovableByteArray(length);
- assertArrayEquals(array, new byte[length]);
- Arrays.fill(array, (byte) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new byte[length]);
- }
-
- @Test
- @SmallTest
- public void testZeroizeRegularByteArray() {
- final int length = 10;
- byte[] array = new byte[length];
- assertArrayEquals(array, new byte[length]);
- Arrays.fill(array, (byte) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new byte[length]);
- }
-
- @Test
- @SmallTest
- public void testZeroizeNonMovableCharArray() {
- final int length = 10;
- char[] array = ArrayUtils.newNonMovableCharArray(length);
- assertArrayEquals(array, new char[length]);
- Arrays.fill(array, (char) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new char[length]);
- }
-
- @Test
- @SmallTest
- public void testZeroizeRegularCharArray() {
- final int length = 10;
- char[] array = new char[length];
- assertArrayEquals(array, new char[length]);
- Arrays.fill(array, (char) 0xff);
- ArrayUtils.zeroize(array);
- assertArrayEquals(array, new char[length]);
- }
}
--
GitLab
From 04f0ee69f2bddd54375a2d7d6aa7570cdda0907b Mon Sep 17 00:00:00 2001
From: Todd Lee
Date: Mon, 2 Dec 2024 19:02:30 +0000
Subject: [PATCH 181/652] Add method to access the View wrapped by the
ViewUIComponent
Bug: b/352680005
Test: manual integration with tile launch
Flag: NONE trivial
Change-Id: I496db1b89ac2a6d6a055c04f14a594dfcf580637
---
.../com/android/systemui/animation/ViewUIComponent.java | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
index cec740ad899b..0317d5f095a1 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
@@ -57,6 +57,14 @@ public class ViewUIComponent implements UIComponent {
mView = view;
}
+ /**
+ * @return the view wrapped by this UI component.
+ * @hide
+ */
+ public View getView() {
+ return mView;
+ }
+
@Override
public float getAlpha() {
return mView.getAlpha();
--
GitLab
From 9ccdb5e23dd078c5d4711b7c496f00a56af6f9a3 Mon Sep 17 00:00:00 2001
From: Ibrahim Yilmaz
Date: Mon, 2 Dec 2024 19:10:39 +0000
Subject: [PATCH 182/652] [AsyncGroup Inflation] Reset header visibility if
needed
Bug: 361552380
Test: Post minimized group notification with Notify. Expand it once and change the theme. Observe there is no text overlap.
Flag: EXEMPT trivial no impact change.
Change-Id: I65f398b7e6e67877c6ca80e233548b2a346f4698
---
.../notification/stack/NotificationChildrenContainer.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index cfca8307e703..6293640a1dc3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -499,7 +499,7 @@ public class NotificationChildrenContainer extends ViewGroup
mGroupHeaderWrapper.setExpanded(mChildrenExpanded);
mGroupHeaderWrapper.onContentUpdated(mContainingNotification);
-
+ resetHeaderVisibilityIfNeeded(mGroupHeader, calculateDesiredHeader());
updateHeaderVisibility(false /* animate */);
updateChildrenAppearance();
@@ -535,6 +535,7 @@ public class NotificationChildrenContainer extends ViewGroup
invalidate();
mMinimizedGroupHeaderWrapper.onContentUpdated(mContainingNotification);
+ resetHeaderVisibilityIfNeeded(mMinimizedGroupHeader, calculateDesiredHeader());
updateHeaderVisibility(false /* animate */);
updateChildrenAppearance();
}
--
GitLab
From 09c1f61869232ac4080688736b37d851c4e0342b Mon Sep 17 00:00:00 2001
From: Eden Mendel
Date: Mon, 2 Dec 2024 19:22:52 +0000
Subject: [PATCH 183/652] Add new native namespaces bindings for
aaos_storage_triage
Change-Id: Ic5b4479c6ac6fd6079289db1d65664bd0a412683
Flag: EXEMPT trunk stable namespace onboarding
Bug: b/379762996
---
.../java/com/android/server/am/SettingsToPropertiesMapper.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index d0153d87ad78..1a8565a4aef6 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -146,6 +146,7 @@ public class SettingsToPropertiesMapper {
"aaos_window_triage",
"aaos_audio_triage",
"aaos_power_triage",
+ "aaos_storage_triage",
"aaos_sdv",
"accessibility",
"android_core_networking",
--
GitLab
From 1af65ef7ba362ba9ed1f60914e522913d16da940 Mon Sep 17 00:00:00 2001
From: Alex Stetson
Date: Wed, 20 Nov 2024 14:04:41 -0800
Subject: [PATCH 184/652] Update API to only modify specified inset types
When there are multiple controllers that update the visible insets,
explicitly setting all the requested visibilities may cause conflicts
with what is set elsewhere when each controller only cares about a
subset of the inset types. This API change will allow controllers to
only modify the visibility of a specific subset of insets while leaving
the rest as they previously were.
Bug: 376131165
Test: manual
Flag: NONE bugfix
Change-Id: Ia12f8b68ad132cc1e40094ba0680ea53fc7b5c65
---
core/java/android/view/IWindowManager.aidl | 2 +-
.../com/android/wm/shell/common/DisplayImeController.java | 7 ++-----
.../core/java/com/android/server/wm/DisplayContent.java | 8 +++++---
.../java/com/android/server/wm/WindowManagerService.java | 5 +++--
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 6d85e7589c48..5da49857dda5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -766,7 +766,7 @@ interface IWindowManager
* container.
*/
@EnforcePermission("MANAGE_APP_TOKENS")
- void updateDisplayWindowRequestedVisibleTypes(int displayId, int requestedVisibleTypes,
+ void updateDisplayWindowRequestedVisibleTypes(int displayId, int visibleTypes, int mask,
in @nullable ImeTracker.Token statsToken);
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 38b859220256..ec3c0b83fe2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -228,7 +228,6 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
public class PerDisplay implements DisplayInsetsController.OnInsetsChangedListener {
final int mDisplayId;
final InsetsState mInsetsState = new InsetsState();
- @InsetsType int mRequestedVisibleTypes = WindowInsets.Type.defaultVisible();
boolean mImeRequestedVisible =
(WindowInsets.Type.defaultVisible() & WindowInsets.Type.ime()) != 0;
InsetsSourceControl mImeSourceControl = null;
@@ -426,12 +425,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
*/
private void setVisibleDirectly(boolean visible, @Nullable ImeTracker.Token statsToken) {
mInsetsState.setSourceVisible(InsetsSource.ID_IME, visible);
- mRequestedVisibleTypes = visible
- ? mRequestedVisibleTypes | WindowInsets.Type.ime()
- : mRequestedVisibleTypes & ~WindowInsets.Type.ime();
+ int visibleTypes = visible ? WindowInsets.Type.ime() : 0;
try {
mWmService.updateDisplayWindowRequestedVisibleTypes(mDisplayId,
- mRequestedVisibleTypes, statsToken);
+ visibleTypes, WindowInsets.Type.ime(), statsToken);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e19096354d64..faeda5fbe428 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -7109,9 +7109,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
/**
* @see #getRequestedVisibleTypes()
*/
- void setRequestedVisibleTypes(@InsetsType int requestedVisibleTypes) {
- if (mRequestedVisibleTypes != requestedVisibleTypes) {
- mRequestedVisibleTypes = requestedVisibleTypes;
+ void updateRequestedVisibleTypes(@InsetsType int visibleTypes, @InsetsType int mask) {
+ int newRequestedVisibleTypes =
+ (mRequestedVisibleTypes & ~mask) | (visibleTypes & mask);
+ if (mRequestedVisibleTypes != newRequestedVisibleTypes) {
+ mRequestedVisibleTypes = newRequestedVisibleTypes;
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7e70e75820a3..591d19f3bfdc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4671,7 +4671,8 @@ public class WindowManagerService extends IWindowManager.Stub
@EnforcePermission(android.Manifest.permission.MANAGE_APP_TOKENS)
@Override
public void updateDisplayWindowRequestedVisibleTypes(int displayId,
- @InsetsType int requestedVisibleTypes, @Nullable ImeTracker.Token statsToken) {
+ @InsetsType int visibleTypes, @InsetsType int mask,
+ @Nullable ImeTracker.Token statsToken) {
updateDisplayWindowRequestedVisibleTypes_enforcePermission();
final long origId = Binder.clearCallingIdentity();
try {
@@ -4684,7 +4685,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_WM_UPDATE_DISPLAY_WINDOW_REQUESTED_VISIBLE_TYPES);
- dc.mRemoteInsetsControlTarget.setRequestedVisibleTypes(requestedVisibleTypes);
+ dc.mRemoteInsetsControlTarget.updateRequestedVisibleTypes(visibleTypes, mask);
// TODO(b/353463205) the statsToken shouldn't be null as it is used later in the
// IME provider. Check if we have to create a new request here, if null.
dc.getInsetsStateController().onRequestedVisibleTypesChanged(
--
GitLab
From 0b432af5bc5e4cf6817c24da58e8cc39ca88bb5d Mon Sep 17 00:00:00 2001
From: Jacqueline Bronger
Date: Mon, 2 Dec 2024 20:34:38 +0100
Subject: [PATCH 185/652] Update javadoc for MediaRoute2Info types
Link to AudioDeviceInfo and add missing getType references.
Bug: 377888097
Test: view javadoc in AndroidStudio
Flag: DOCS_ONLY
Change-Id: I9e88582cc744dfcd4e43e98ac9f0916fdba8c2f4
---
media/java/android/media/MediaRoute2Info.java | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 09022782e6c3..bc5347411ea2 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -187,6 +187,7 @@ public final class MediaRoute2Info implements Parcelable {
* the device.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_BUILTIN_SPEAKER
*/
public static final int TYPE_BUILTIN_SPEAKER = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
@@ -194,6 +195,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a headset, which is the combination of a headphones and a microphone.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_WIRED_HEADSET
*/
public static final int TYPE_WIRED_HEADSET = AudioDeviceInfo.TYPE_WIRED_HEADSET;
@@ -201,6 +203,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a pair of wired headphones.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_WIRED_HEADPHONES
*/
public static final int TYPE_WIRED_HEADPHONES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
@@ -208,6 +211,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a bluetooth device, such as a bluetooth speaker or headphones.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_BLUETOOTH_A2DP
*/
public static final int TYPE_BLUETOOTH_A2DP = AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
@@ -215,6 +219,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is an HDMI connection.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HDMI
*/
public static final int TYPE_HDMI = AudioDeviceInfo.TYPE_HDMI;
@@ -222,6 +227,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is an Audio Return Channel of an HDMI connection.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HDMI_ARC
*/
@FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
public static final int TYPE_HDMI_ARC = AudioDeviceInfo.TYPE_HDMI_ARC;
@@ -230,24 +236,34 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is an Enhanced Audio Return Channel of an HDMI connection.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HDMI_EARC
*/
@FlaggedApi(FLAG_ENABLE_AUDIO_POLICIES_DEVICE_AND_BLUETOOTH_CONTROLLER)
public static final int TYPE_HDMI_EARC = AudioDeviceInfo.TYPE_HDMI_EARC;
/**
* Indicates the route is a digital line connection (for example S/PDIF).
+ *
+ * @see #getType
+ * @see AudioDeviceInfo#TYPE_LINE_DIGITAL
*/
@FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
public static final int TYPE_LINE_DIGITAL = AudioDeviceInfo.TYPE_LINE_DIGITAL;
/**
* Indicates the route is an analog line-level connection.
+ *
+ * @see #getType
+ * @see AudioDeviceInfo#TYPE_LINE_ANALOG
*/
@FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
public static final int TYPE_LINE_ANALOG = AudioDeviceInfo.TYPE_LINE_ANALOG;
/**
* Indicates the route is using the auxiliary line-level connectors.
+ *
+ * @see #getType
+ * @see AudioDeviceInfo#TYPE_AUX_LINE
*/
@FlaggedApi(FLAG_ENABLE_NEW_WIRED_MEDIA_ROUTE_2_INFO_TYPES)
public static final int TYPE_AUX_LINE = AudioDeviceInfo.TYPE_AUX_LINE;
@@ -256,6 +272,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a USB audio device.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_USB_DEVICE
*/
public static final int TYPE_USB_DEVICE = AudioDeviceInfo.TYPE_USB_DEVICE;
@@ -263,6 +280,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a USB audio device in accessory mode.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_USB_ACCESSORY
*/
public static final int TYPE_USB_ACCESSORY = AudioDeviceInfo.TYPE_USB_ACCESSORY;
@@ -270,6 +288,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is the audio device associated with a dock.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_DOCK
*/
public static final int TYPE_DOCK = AudioDeviceInfo.TYPE_DOCK;
@@ -277,6 +296,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a USB audio headset.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_USB_HEADSET
*/
public static final int TYPE_USB_HEADSET = AudioDeviceInfo.TYPE_USB_HEADSET;
@@ -284,6 +304,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a hearing aid.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_HEARING_AID
*/
public static final int TYPE_HEARING_AID = AudioDeviceInfo.TYPE_HEARING_AID;
@@ -291,6 +312,7 @@ public final class MediaRoute2Info implements Parcelable {
* Indicates the route is a Bluetooth Low Energy (BLE) HEADSET.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_BLE_HEADSET
*/
public static final int TYPE_BLE_HEADSET = AudioDeviceInfo.TYPE_BLE_HEADSET;
@@ -302,6 +324,7 @@ public final class MediaRoute2Info implements Parcelable {
* to provide a better experience on multichannel contents.
*
* @see #getType
+ * @see AudioDeviceInfo#TYPE_MULTICHANNEL_GROUP
*/
@FlaggedApi(FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE)
public static final int TYPE_MULTICHANNEL_SPEAKER_GROUP =
--
GitLab
From eec1c2c144a62031d6a24c9f0ae00c3d32472c0b Mon Sep 17 00:00:00 2001
From: Daniel Akinola
Date: Mon, 2 Dec 2024 19:30:27 +0000
Subject: [PATCH 186/652] Add KeyboarDockingIndicationViewModel lint exception
New ShadeDisplayAwareContextChecker linter wasn't checked against a recent change to KeyboarDockingIndicationViewModel, so need to add lint-baseline.xml to stop build from failing. (Future CL will also exclude @GlobalConfig from linter errors)
Bug: 378016985
Test: running linter
Flag: EXEMPT lint only
Change-Id: I679c32fc7720e00f44e386bcf000a6f60645b00d
---
packages/SystemUI/lint-baseline.xml | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/packages/SystemUI/lint-baseline.xml b/packages/SystemUI/lint-baseline.xml
index 42694d5ab119..00b0c44c2077 100644
--- a/packages/SystemUI/lint-baseline.xml
+++ b/packages/SystemUI/lint-baseline.xml
@@ -33752,4 +33752,16 @@
column="5"/>
+
+
+
+
+
--
GitLab
From 9526ea6ca365cc86eea1f1c062a8ff92a713f452 Mon Sep 17 00:00:00 2001
From: Arthur Ishiguro
Date: Sun, 10 Nov 2024 19:19:23 +0000
Subject: [PATCH 187/652] Implements ContextHubEndpointBroker
open/closeEndpointSession
Bug: 378487799
Flag: android.chre.flags.offload_implementation
Test: make services
Change-Id: I5d5fc99be65c89931a3f5b107302d898fb26e551
---
.../contexthub/ContextHubEndpointBroker.java | 35 ++++--
.../contexthub/ContextHubEndpointManager.java | 101 +++++++++++++++++-
.../contexthub/IContextHubWrapper.java | 46 ++++++++
3 files changed, 174 insertions(+), 8 deletions(-)
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
index 53389cafecef..db99ebaef586 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
@@ -24,6 +24,8 @@ import android.hardware.contexthub.HubServiceInfo;
import android.hardware.contexthub.IContextHubEndpoint;
import android.hardware.contexthub.IContextHubEndpointCallback;
import android.hardware.location.IContextHubTransactionCallback;
+import android.os.RemoteException;
+import android.util.Log;
/**
* A class that represents a broker for the endpoint registered by the client app. This class
@@ -72,21 +74,40 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
}
@Override
- public int openSession(HubEndpointInfo destination, HubServiceInfo serviceInfo) {
- // TODO(b/378487799): Implement this
- return 0;
+ public int openSession(HubEndpointInfo destination, HubServiceInfo serviceInfo)
+ throws RemoteException {
+ ContextHubServiceUtil.checkPermissions(mContext);
+ int sessionId = mEndpointManager.reserveSessionId();
+ EndpointInfo halEndpointInfo = ContextHubServiceUtil.convertHalEndpointInfo(destination);
+ try {
+ mContextHubProxy.openEndpointSession(
+ sessionId,
+ halEndpointInfo.id,
+ mHalEndpointInfo.id,
+ serviceInfo == null ? null : serviceInfo.getServiceDescriptor());
+ } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
+ Log.e(TAG, "Exception while calling HAL openEndpointSession", e);
+ mEndpointManager.returnSessionId(sessionId);
+ throw e;
+ }
+
+ return sessionId;
}
@Override
- public void closeSession(int sessionId, int reason) {
- // TODO(b/378487799): Implement this
-
+ public void closeSession(int sessionId, int reason) throws RemoteException {
+ ContextHubServiceUtil.checkPermissions(mContext);
+ try {
+ mContextHubProxy.closeEndpointSession(sessionId, (byte) reason);
+ } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
+ Log.e(TAG, "Exception while calling HAL closeEndpointSession", e);
+ throw e;
+ }
}
@Override
public void openSessionRequestComplete(int sessionId) {
// TODO(b/378487799): Implement this
-
}
@Override
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
index 54ce74f7b2f1..511154271fed 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
@@ -22,11 +22,15 @@ import android.hardware.contexthub.HubEndpointInfo;
import android.hardware.contexthub.IContextHubEndpoint;
import android.hardware.contexthub.IContextHubEndpointCallback;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
@@ -40,6 +44,12 @@ import java.util.concurrent.ConcurrentHashMap;
/** The hub ID of the Context Hub Service. */
private static final long SERVICE_HUB_ID = 0x416e64726f696400L;
+ /** The range of session IDs to use for endpoints */
+ private static final int SERVICE_SESSION_RANGE = 1024;
+
+ /** The length of the array that should be returned by HAL requestSessionIdRange */
+ private static final int SERVICE_SESSION_RANGE_LENGTH = 2;
+
/** The context of the service. */
private final Context mContext;
@@ -55,9 +65,57 @@ import java.util.concurrent.ConcurrentHashMap;
@GuardedBy("mEndpointLock")
private long mNextEndpointId = 0;
+ /** The minimum session ID reservable by endpoints (retrieved from HAL) */
+ private final int mMinSessionId;
+
+ /** The minimum session ID reservable by endpoints (retrieved from HAL) */
+ private final int mMaxSessionId;
+
+ /** Variables for managing session ID creation */
+ private final Object mSessionIdLock = new Object();
+
+ /** A set of session IDs that have been reserved by an endpoint. */
+ @GuardedBy("mSessionIdLock")
+ private final Set mReservedSessionIds =
+ Collections.newSetFromMap(new HashMap());
+
+ @GuardedBy("mSessionIdLock")
+ private int mNextSessionId = 0;
+
+ /** Initialized to true if all initialization in the constructor succeeds. */
+ private final boolean mSessionIdsValid;
+
/* package */ ContextHubEndpointManager(Context context, IContextHubWrapper contextHubProxy) {
mContext = context;
mContextHubProxy = contextHubProxy;
+ int[] range = null;
+ try {
+ range = mContextHubProxy.requestSessionIdRange(SERVICE_SESSION_RANGE);
+ if (range != null && range.length < SERVICE_SESSION_RANGE_LENGTH) {
+ Log.e(TAG, "Invalid session ID range: range array size = " + range.length);
+ range = null;
+ }
+ } catch (RemoteException | IllegalArgumentException | ServiceSpecificException e) {
+ Log.e(TAG, "Exception while calling HAL requestSessionIdRange", e);
+ }
+
+ if (range == null) {
+ mMinSessionId = -1;
+ mMaxSessionId = -1;
+ mSessionIdsValid = false;
+ } else {
+ mMinSessionId = range[0];
+ mMaxSessionId = range[1];
+ if (!isSessionIdRangeValid(mMinSessionId, mMaxSessionId)) {
+ Log.e(
+ TAG,
+ "Invalid session ID range: max=" + mMaxSessionId + " min=" + mMinSessionId);
+ mSessionIdsValid = false;
+ } else {
+ mNextSessionId = mMinSessionId;
+ mSessionIdsValid = true;
+ }
+ }
}
/**
@@ -71,6 +129,9 @@ import java.util.concurrent.ConcurrentHashMap;
/* package */ IContextHubEndpoint registerEndpoint(
HubEndpointInfo pendingEndpointInfo, IContextHubEndpointCallback callback)
throws RemoteException {
+ if (!mSessionIdsValid) {
+ throw new IllegalStateException("ContextHubEndpointManager failed to initialize");
+ }
ContextHubEndpointBroker broker;
long endpointId = getNewEndpointId();
EndpointInfo halEndpointInfo =
@@ -98,8 +159,42 @@ import java.util.concurrent.ConcurrentHashMap;
}
/**
- * @return an available endpoint ID
+ * Reserves an available session ID for an endpoint.
+ *
+ * @throws IllegalStateException if no session ID was available.
+ * @return The reserved session ID.
*/
+ /* package */ int reserveSessionId() {
+ int id = -1;
+ synchronized (mSessionIdLock) {
+ final int maxCapacity = mMaxSessionId - mMinSessionId + 1;
+ if (mReservedSessionIds.size() >= maxCapacity) {
+ throw new IllegalStateException("Too many sessions reserved");
+ }
+
+ id = mNextSessionId;
+ for (int i = mMinSessionId; i <= mMaxSessionId; i++) {
+ if (!mReservedSessionIds.contains(id)) {
+ mNextSessionId = (id == mMaxSessionId) ? mMinSessionId : id + 1;
+ break;
+ }
+
+ id = (id == mMaxSessionId) ? mMinSessionId : id + 1;
+ }
+
+ mReservedSessionIds.add(id);
+ }
+ return id;
+ }
+
+ /** Returns a previously reserved session ID through {@link #reserveSessionId()}. */
+ /* package */ void returnSessionId(int sessionId) {
+ synchronized (mSessionIdLock) {
+ mReservedSessionIds.remove(sessionId);
+ }
+ }
+
+ /** @return an available endpoint ID */
private long getNewEndpointId() {
synchronized (mEndpointLock) {
if (mNextEndpointId == Long.MAX_VALUE) {
@@ -108,4 +203,8 @@ import java.util.concurrent.ConcurrentHashMap;
return mNextEndpointId++;
}
}
+
+ private boolean isSessionIdRangeValid(int minId, int maxId) {
+ return (minId <= maxId) && (minId >= 0) && (maxId >= 0);
+ }
}
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 14d75b02d6b0..42fd53ea12a5 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -18,6 +18,7 @@ package com.android.server.location.contexthub;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.chre.flags.Flags;
+import android.hardware.contexthub.EndpointId;
import android.hardware.contexthub.HostEndpointInfo;
import android.hardware.contexthub.HubEndpointInfo;
import android.hardware.contexthub.MessageDeliveryStatus;
@@ -243,6 +244,19 @@ public abstract class IContextHubWrapper {
public void registerEndpoint(android.hardware.contexthub.EndpointInfo info)
throws RemoteException {}
+ /** Unregisters a previously registered endpoint */
+ public int[] requestSessionIdRange(int size) throws RemoteException {
+ return null;
+ }
+
+ /** Opens an endpoint session between two endpoints */
+ public void openEndpointSession(
+ int sessionId, EndpointId destination, EndpointId initiator, String serviceDescriptor)
+ throws RemoteException {}
+
+ /** Closes a previously opened endpoint */
+ public void closeEndpointSession(int sessionId, byte reason) throws RemoteException {}
+
/**
* @return True if this version of the Contexthub HAL supports Location setting notifications.
*/
@@ -685,6 +699,38 @@ public abstract class IContextHubWrapper {
hub.registerEndpoint(info);
}
+ @Override
+ public int[] requestSessionIdRange(int size) throws RemoteException {
+ android.hardware.contexthub.IContextHub hub = getHub();
+ if (hub == null) {
+ return null;
+ }
+ return hub.requestSessionIdRange(size);
+ }
+
+ @Override
+ public void openEndpointSession(
+ int sessionId,
+ EndpointId destination,
+ EndpointId initiator,
+ String serviceDescriptor)
+ throws RemoteException {
+ android.hardware.contexthub.IContextHub hub = getHub();
+ if (hub == null) {
+ return;
+ }
+ hub.openEndpointSession(sessionId, destination, initiator, serviceDescriptor);
+ }
+
+ @Override
+ public void closeEndpointSession(int sessionId, byte reason) throws RemoteException {
+ android.hardware.contexthub.IContextHub hub = getHub();
+ if (hub == null) {
+ return;
+ }
+ hub.closeEndpointSession(sessionId, reason);
+ }
+
public boolean supportsLocationSettingNotifications() {
return true;
}
--
GitLab
From e997903515cbf81ba59a7b40b0bd1c47f43d0ae1 Mon Sep 17 00:00:00 2001
From: Arthur Ishiguro
Date: Sun, 10 Nov 2024 19:24:20 +0000
Subject: [PATCH 188/652] Implements ContextHubEndpointBroker
unregisterEndpoint
Bug: 378487799
Flag: android.chre.flags.offload_implementation
Test: make services
Change-Id: I200c64e267d56d36dc86ac0e45cc1bc5323bb48b
---
.../contexthub/ContextHubEndpointBroker.java | 18 ++++++++++++++++--
.../contexthub/ContextHubEndpointManager.java | 9 +++++++++
.../contexthub/IContextHubWrapper.java | 14 ++++++++++++++
3 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
index db99ebaef586..a1a09349d883 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
@@ -27,6 +27,8 @@ import android.hardware.location.IContextHubTransactionCallback;
import android.os.RemoteException;
import android.util.Log;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* A class that represents a broker for the endpoint registered by the client app. This class
* manages direct IContextHubEndpoint/IContextHubEndpointCallback API/callback calls.
@@ -54,6 +56,9 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
/** The remote callback interface for this endpoint. */
private final IContextHubEndpointCallback mContextHubEndpointCallback;
+ /** True if this endpoint is registered with the service. */
+ private AtomicBoolean mIsRegistered = new AtomicBoolean(true);
+
/* package */ ContextHubEndpointBroker(
Context context,
IContextHubWrapper contextHubProxy,
@@ -77,6 +82,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
public int openSession(HubEndpointInfo destination, HubServiceInfo serviceInfo)
throws RemoteException {
ContextHubServiceUtil.checkPermissions(mContext);
+ if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered");
int sessionId = mEndpointManager.reserveSessionId();
EndpointInfo halEndpointInfo = ContextHubServiceUtil.convertHalEndpointInfo(destination);
try {
@@ -97,6 +103,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
@Override
public void closeSession(int sessionId, int reason) throws RemoteException {
ContextHubServiceUtil.checkPermissions(mContext);
+ if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered");
try {
mContextHubProxy.closeEndpointSession(sessionId, (byte) reason);
} catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
@@ -112,8 +119,15 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
@Override
public void unregister() {
- // TODO(b/378487799): Implement this
-
+ ContextHubServiceUtil.checkPermissions(mContext);
+ mIsRegistered.set(false);
+ try {
+ mContextHubProxy.unregisterEndpoint(mHalEndpointInfo);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e);
+ }
+ // TODO(b/378487799): Release reserved session IDs
+ mEndpointManager.unregisterEndpoint(mEndpointInfo.getIdentifier().getEndpoint());
}
@Override
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
index 511154271fed..f79f7a300043 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
@@ -194,6 +194,15 @@ import java.util.concurrent.ConcurrentHashMap;
}
}
+ /**
+ * Unregisters an endpoint given its ID.
+ *
+ * @param endpointId The ID of the endpoint to unregister.
+ */
+ /* package */ void unregisterEndpoint(long endpointId) {
+ mEndpointMap.remove(endpointId);
+ }
+
/** @return an available endpoint ID */
private long getNewEndpointId() {
synchronized (mEndpointLock) {
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 42fd53ea12a5..c79dc84ec2af 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -257,6 +257,10 @@ public abstract class IContextHubWrapper {
/** Closes a previously opened endpoint */
public void closeEndpointSession(int sessionId, byte reason) throws RemoteException {}
+ /** Unregisters a previously registered endpoint */
+ public void unregisterEndpoint(android.hardware.contexthub.EndpointInfo info)
+ throws RemoteException {}
+
/**
* @return True if this version of the Contexthub HAL supports Location setting notifications.
*/
@@ -731,6 +735,16 @@ public abstract class IContextHubWrapper {
hub.closeEndpointSession(sessionId, reason);
}
+ @Override
+ public void unregisterEndpoint(android.hardware.contexthub.EndpointInfo info)
+ throws RemoteException {
+ android.hardware.contexthub.IContextHub hub = getHub();
+ if (hub == null) {
+ return;
+ }
+ hub.unregisterEndpoint(info);
+ }
+
public boolean supportsLocationSettingNotifications() {
return true;
}
--
GitLab
From 2e7c7652d9c839995794a6e1d8f19011f6959c41 Mon Sep 17 00:00:00 2001
From: Arthur Ishiguro
Date: Fri, 15 Nov 2024 00:00:08 +0000
Subject: [PATCH 189/652] Implements death recipient handler at
ContextHubEndpointBroker
Bug: 378487799
Flag: android.chre.flags.offload_implementation
Test: make services
Change-Id: I1a50d511dca33f5e072258aae9705e47b80b028c
---
.../contexthub/ContextHubEndpointBroker.java | 16 +++++++++++++++-
.../contexthub/ContextHubEndpointManager.java | 9 ++++++++-
2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
index a1a09349d883..aa215ce8057f 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
@@ -24,6 +24,7 @@ import android.hardware.contexthub.HubServiceInfo;
import android.hardware.contexthub.IContextHubEndpoint;
import android.hardware.contexthub.IContextHubEndpointCallback;
import android.hardware.location.IContextHubTransactionCallback;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -35,7 +36,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* @hide
*/
-public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
+public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
+ implements IBinder.DeathRecipient {
private static final String TAG = "ContextHubEndpointBroker";
/** The context of the service. */
@@ -140,4 +142,16 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
public void sendMessageDeliveryStatus(int sessionId, int messageSeqNumber, byte errorCode) {
// TODO(b/381102453): Implement this
}
+
+ /** Invoked when the underlying binder of this broker has died at the client process. */
+ @Override
+ public void binderDied() {
+ unregister();
+ }
+
+ /* package */ void attachDeathRecipient() throws RemoteException {
+ if (mContextHubEndpointCallback != null) {
+ mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
index f79f7a300043..fb64f99e5904 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java
@@ -152,7 +152,14 @@ import java.util.concurrent.ConcurrentHashMap;
callback);
mEndpointMap.put(endpointId, broker);
- // TODO(b/378487799): Add death recipient
+ try {
+ broker.attachDeathRecipient();
+ } catch (RemoteException e) {
+ // The client process has died, so we close the connection and return null
+ Log.e(TAG, "Failed to attach death recipient to client", e);
+ broker.unregister();
+ return null;
+ }
Log.d(TAG, "Registered endpoint with ID = " + endpointId);
return IContextHubEndpoint.Stub.asInterface(broker);
--
GitLab
From 3189f0ae37c7a5229c9bd76856449a6a5b790528 Mon Sep 17 00:00:00 2001
From: Ibrahim Yilmaz
Date: Mon, 2 Dec 2024 20:06:33 +0000
Subject: [PATCH 190/652] Revert "[ENR] Ensure ENR views visibilities"
This reverts commit 17dc56f99c731b9125384f19780c50325e680dbe.
Reason for revert: not needed
Change-Id: I7a8330cbe4055b70139f12ab8028d1a85b1390c8
---
packages/SystemUI/aconfig/systemui.aconfig | 10 ---
.../row/EnsureEnrViewsVisibility.kt | 61 -------------------
.../row/ExpandableNotificationRow.java | 12 +---
3 files changed, 1 insertion(+), 82 deletions(-)
delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/row/EnsureEnrViewsVisibility.kt
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index e445884d7051..92575e948241 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1800,16 +1800,6 @@ flag {
bug: "370555223"
}
-flag {
- name: "ensure_enr_views_visibility"
- namespace: "systemui"
- description: "Ensures public and private visibilities"
- bug: "361552380"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
flag {
name: "shade_expands_on_status_bar_long_press"
namespace: "systemui"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/EnsureEnrViewsVisibility.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/EnsureEnrViewsVisibility.kt
deleted file mode 100644
index aa63f4ddbd45..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/EnsureEnrViewsVisibility.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.row
-
-import com.android.systemui.Flags
-import com.android.systemui.flags.FlagToken
-import com.android.systemui.flags.RefactorFlagUtils
-
-/** Helper for reading or using the ensure enr views visibility flag state. */
-@Suppress("NOTHING_TO_INLINE")
-object EnsureEnrViewsVisibility {
- /** The aconfig flag name */
- const val FLAG_NAME = Flags.FLAG_ENSURE_ENR_VIEWS_VISIBILITY
-
- /** A token used for dependency declaration */
- val token: FlagToken
- get() = FlagToken(FLAG_NAME, isEnabled)
-
- /** Is the refactor enabled */
- @JvmStatic
- inline val isEnabled
- get() = Flags.ensureEnrViewsVisibility()
-
- /**
- * Called to ensure code is only run when the flag is enabled. This protects users from the
- * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
- * build to ensure that the refactor author catches issues in testing.
- */
- @JvmStatic
- inline fun isUnexpectedlyInLegacyMode() =
- RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)
-
- /**
- * Called to ensure code is only run when the flag is disabled. This will throw an exception if
- * the flag is not enabled to ensure that the refactor author catches issues in testing.
- * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
- */
- @JvmStatic
- inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
-
- /**
- * Called to ensure code is only run when the flag is disabled. This will throw an exception if
- * the flag is enabled to ensure that the refactor author catches issues in testing.
- */
- @JvmStatic
- inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 7ad65fc64735..d71b1b2dd4d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2603,10 +2603,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
private void updateChildrenVisibility() {
- if (EnsureEnrViewsVisibility.isEnabled()) {
- mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
- }
-
boolean hideContentWhileLaunching = mExpandAnimationRunning && mGuts != null
&& mGuts.isExposed();
mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren
@@ -3166,13 +3162,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
} else {
mLogger.logSkipResetAllContentAlphas(getEntry());
}
-
- if (!EnsureEnrViewsVisibility.isEnabled()) {
- // mPublicLayout.setVisibility moved to updateChildrenVisibility when the flag is on
- // in order to ensure public and private views are not visible
- // together at the same time.
- mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
- }
+ mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
updateChildrenVisibility();
} else {
animateShowingPublic(delay, duration, mShowingPublic);
--
GitLab
From 49ff77fe6038e624ee67d55b1de8c9e2a8547892 Mon Sep 17 00:00:00 2001
From: Maryam Dehaini
Date: Mon, 2 Dec 2024 11:42:57 -0800
Subject: [PATCH 191/652] Update corner radius set for mixed transitions
Corner radius of tasks in desktop windowing has been updated to 16dp.
So, the corner radius applied when a task in desktop windowing is in a
mixed transition needs to be updated accordingly.
Bug: 369592605
Test: manual testing
Flag: EXEMPT bugfix
Change-Id: Ifaf0410d7b0823d90f67b6b814767a4274094303
---
.../android/wm/shell/desktopmode/DesktopTasksController.kt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index a94a40bc39f8..de79ca6267d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -67,7 +67,6 @@ import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE
import com.android.internal.jank.InteractionJankMonitor
-import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
import com.android.wm.shell.Flags.enableFlexibleSplit
@@ -1480,7 +1479,10 @@ class DesktopTasksController(
if (!DesktopModeStatus.useRoundedCorners()) {
return
}
- val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
+ val cornerRadius =
+ context.resources
+ .getDimensionPixelSize(R.dimen.desktop_windowing_freeform_rounded_corner_radius)
+ .toFloat()
info.changes
.filter { it.taskInfo?.windowingMode == WINDOWING_MODE_FREEFORM }
.forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) }
--
GitLab
From ae2bb42a6e8a451b034ad9da15f3f17481a4b57f Mon Sep 17 00:00:00 2001
From: Daniel Akinola
Date: Mon, 2 Dec 2024 20:10:46 +0000
Subject: [PATCH 192/652] Fix SnapResizeAppWindowLeftWithDrag Assertions
Tiling made it so that the assertions on the size of the snap resize windows was off, so follow the example of the SnapResizeAppWindowWithButton fix and add a threshold to the assertion
Bug: 377079516
Change-Id: Ib91ab4412872bed092a3bb713b25eac92cfb6926
Test: atest SnapResizeAppWindowLeftWithDrag
Flag: TEST_ONLY
---
.../shell/flicker/DesktopModeFlickerScenarios.kt | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index f6d2cc09d7b0..f4f60d73c25c 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -272,9 +272,11 @@ class DesktopModeFlickerScenarios {
TaggedCujTransitionMatcher(associatedTransitionRequired = false)
)
.build(),
- assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
- listOf(AppWindowCoversLeftHalfScreenAtEnd(DESKTOP_MODE_APP))
- .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+ assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS + listOf(
+ AppWindowCoversLeftHalfScreenAtEnd(
+ DESKTOP_MODE_APP, SNAP_WINDOW_MAX_DIFF_THRESHOLD_RATIO
+ )
+ ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
)
val SNAP_RESIZE_RIGHT_WITH_DRAG =
@@ -287,9 +289,11 @@ class DesktopModeFlickerScenarios {
TaggedCujTransitionMatcher(associatedTransitionRequired = false)
)
.build(),
- assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
- listOf(AppWindowCoversRightHalfScreenAtEnd(DESKTOP_MODE_APP))
- .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+ assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS + listOf(
+ AppWindowCoversRightHalfScreenAtEnd(
+ DESKTOP_MODE_APP, SNAP_WINDOW_MAX_DIFF_THRESHOLD_RATIO
+ )
+ ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
)
val SNAP_RESIZE_WITH_DRAG_NON_RESIZABLE =
--
GitLab
From 910e8387ac3707a63bb76482f47db4f9a66a0d98 Mon Sep 17 00:00:00 2001
From: Chun-Ku Lin
Date: Mon, 2 Dec 2024 19:39:42 +0000
Subject: [PATCH 193/652] Switch to the same user as the current user on the
test device
BUG: 380299157
Test: atest AccessibilityManagerServiceTest
Flag: TEST_ONLY
Change-Id: I5297759daa5b9f1ee145cc7c614b68b750727e7a
---
.../AccessibilityManagerServiceTest.java | 202 ++++++++----------
1 file changed, 93 insertions(+), 109 deletions(-)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 27de7644f6b2..ee7bde0bc3da 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -138,10 +138,12 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import org.mockito.Captor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.internal.util.reflection.FieldReader;
@@ -259,6 +261,11 @@ public class AccessibilityManagerServiceTest {
mMockA11yController);
when(mMockA11yController.isAccessibilityTracingEnabled()).thenReturn(false);
when(mMockUserManagerInternal.isUserUnlockingOrUnlocked(anyInt())).thenReturn(true);
+ when(mMockSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(anyInt()))
+ .then(AdditionalAnswers.returnsFirstArg());
+ when(mMockSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+ eq(UserHandle.USER_CURRENT)))
+ .thenReturn(mTestableContext.getUserId());
final ArrayList displays = new ArrayList<>();
final Display defaultDisplay = new Display(DisplayManagerGlobal.getInstance(),
@@ -282,14 +289,21 @@ public class AccessibilityManagerServiceTest {
mInputFilter,
mProxyManager,
mFakePermissionEnforcer);
+ mA11yms.switchUser(mTestableContext.getUserId());
+ mTestableLooper.processAllMessages();
+ FieldSetter.setField(mA11yms,
+ AccessibilityManagerService.class.getDeclaredField("mHasInputFilter"), true);
+ FieldSetter.setField(mA11yms,
+ AccessibilityManagerService.class.getDeclaredField("mInputFilter"), mInputFilter);
final AccessibilityUserState userState = new AccessibilityUserState(
- mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
- mA11yms.mUserStates.put(mA11yms.getCurrentUserIdLocked(), userState);
+ mTestableContext.getUserId(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
AccessibilityManager am = mTestableContext.getSystemService(AccessibilityManager.class);
mA11yManagerServiceOnDevice = (IAccessibilityManager) new FieldReader(am,
AccessibilityManager.class.getDeclaredField("mService")).read();
FieldSetter.setField(am, AccessibilityManager.class.getDeclaredField("mService"), mA11yms);
+ Mockito.clearInvocations(mMockMagnificationConnectionManager);
}
@After
@@ -652,7 +666,6 @@ public class AccessibilityManagerServiceTest {
mA11yms.getCurrentUserIdLocked());
userState.setMagnificationCapabilitiesLocked(
ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
- //userState.setMagnificationSingleFingerTripleTapEnabledLocked(false);
userState.setMagnificationSingleFingerTripleTapEnabledLocked(false);
// Invokes client change to trigger onUserStateChanged.
@@ -1025,6 +1038,7 @@ public class AccessibilityManagerServiceTest {
when(mMockSecurityPolicy.canRegisterService(any())).thenReturn(true);
mA11yms.switchUser(mA11yms.getCurrentUserIdLocked() + 1);
+ mTestableLooper.processAllMessages();
assertThat(lockState.get()).containsExactly(false);
}
@@ -1114,9 +1128,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn()
throws Exception {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
setupShortcutTargetServices();
String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
@@ -1135,9 +1146,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableHardwareShortcutsForTargets_shortcutDialogSetting_isShown() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
Settings.Secure.putInt(
mTestableContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
@@ -1165,9 +1173,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_disableSoftwareShortcut_shortcutTurnedOff()
throws Exception {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
String target = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
enableShortcutsForTargets_enableSoftwareShortcut_shortcutTurnedOn();
@@ -1185,9 +1190,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_enableSoftwareShortcutWithMagnification_menuSizeIncreased() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
mA11yms.enableShortcutsForTargets(
@@ -1231,9 +1233,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService()
throws Exception {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
setupShortcutTargetServices();
@@ -1254,9 +1253,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_disableAlwaysOnServiceSoftwareShortcut_turnsOffAlwaysOnService()
throws Exception {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
enableShortcutsForTargets_enableAlwaysOnServiceSoftwareShortcut_turnsOnAlwaysOnService();
mA11yms.enableShortcutsForTargets(
@@ -1296,9 +1292,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_disableStandardServiceSoftwareShortcutWithServiceOn_wontTurnOffService()
throws Exception {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
enableShortcutsForTargets_enableStandardServiceSoftwareShortcut_wontTurnOnService();
AccessibilityUtils.setAccessibilityServiceState(
mTestableContext, TARGET_STANDARD_A11Y_SERVICE, /* enabled= */ true);
@@ -1319,9 +1312,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
mA11yms.enableShortcutsForTargets(
@@ -1341,9 +1331,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_disableTripleTapShortcut_settingUpdated() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
enableShortcutsForTargets_enableTripleTapShortcut_settingUpdated();
mA11yms.enableShortcutsForTargets(
@@ -1362,9 +1349,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
mA11yms.enableShortcutsForTargets(
@@ -1384,9 +1368,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_disableMultiFingerMultiTapsShortcut_settingUpdated() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
enableShortcutsForTargets_enableMultiFingerMultiTapsShortcut_settingUpdated();
mA11yms.enableShortcutsForTargets(
@@ -1406,9 +1387,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
setupShortcutTargetServices();
@@ -1428,9 +1406,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_disableVolumeKeysShortcut_shortcutNotSet() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
enableShortcutsForTargets_enableVolumeKeysShortcut_shortcutSet();
mA11yms.enableShortcutsForTargets(
@@ -1450,9 +1425,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_enableQuickSettings_shortcutSet() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
setupShortcutTargetServices();
@@ -1478,9 +1450,6 @@ public class AccessibilityManagerServiceTest {
@Test
public void enableShortcutsForTargets_disableQuickSettings_shortcutNotSet() {
- // TODO(b/111889696): Remove the user 0 assumption once we support multi-user
- assumeTrue("The test is setup to run as a user 0",
- isSameCurrentUser(mA11yms, mTestableContext));
enableShortcutsForTargets_enableQuickSettings_shortcutSet();
mA11yms.enableShortcutsForTargets(
@@ -1684,14 +1653,17 @@ public class AccessibilityManagerServiceTest {
@Test
@EnableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void restoreShortcutTargets_qs_a11yQsTargetsRestored() {
+ // TODO: remove the assumption when we fix b/381294327
+ assumeTrue("The test is setup to run as a user 0",
+ mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
String daltonizerTile =
AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();
String colorInversionTile =
AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString();
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
userState.updateShortcutTargetsLocked(Set.of(daltonizerTile), QUICK_SETTINGS);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
broadcastSettingRestored(
ShortcutUtils.convertToKey(QUICK_SETTINGS),
@@ -1707,15 +1679,18 @@ public class AccessibilityManagerServiceTest {
@Test
@DisableFlags(android.view.accessibility.Flags.FLAG_A11Y_QS_SHORTCUT)
public void restoreShortcutTargets_qs_a11yQsTargetsNotRestored() {
+ // TODO: remove the assumption when we fix b/381294327
+ assumeTrue("The test is setup to run as a user 0",
+ mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
String daltonizerTile =
AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME.flattenToString();
String colorInversionTile =
AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME.flattenToString();
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
userState.updateShortcutTargetsLocked(Set.of(daltonizerTile), QUICK_SETTINGS);
putShortcutSettingForUser(QUICK_SETTINGS, daltonizerTile, userState.mUserId);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
broadcastSettingRestored(
ShortcutUtils.convertToKey(QUICK_SETTINGS),
@@ -1740,13 +1715,13 @@ public class AccessibilityManagerServiceTest {
ComponentName::getPackageName).toList().toArray(new String[0]);
PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
- when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ when(monitor.getChangingUserId()).thenReturn(userState.mUserId);
mA11yms.setPackageMonitor(monitor);
assertTrue(mA11yms.getPackageMonitor().onHandleForceStop(
new Intent(),
packages,
- UserHandle.USER_SYSTEM,
+ userState.mUserId,
false
));
}
@@ -1763,13 +1738,13 @@ public class AccessibilityManagerServiceTest {
ComponentName::getPackageName).toList().toArray(new String[0]);
PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
- when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ when(monitor.getChangingUserId()).thenReturn(userState.mUserId);
mA11yms.setPackageMonitor(monitor);
assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
new Intent(),
packages,
- UserHandle.USER_SYSTEM,
+ userState.mUserId,
true
));
}
@@ -1778,13 +1753,13 @@ public class AccessibilityManagerServiceTest {
@EnableFlags(Flags.FLAG_MANAGER_PACKAGE_MONITOR_LOGIC_FIX)
public void onHandleForceStop_dontDoIt_packageNotEnabled_returnsFalse() {
PackageMonitor monitor = spy(mA11yms.getPackageMonitor());
- when(monitor.getChangingUserId()).thenReturn(UserHandle.USER_SYSTEM);
+ when(monitor.getChangingUserId()).thenReturn(mA11yms.getCurrentUserIdLocked());
mA11yms.setPackageMonitor(monitor);
assertFalse(mA11yms.getPackageMonitor().onHandleForceStop(
new Intent(),
new String[]{"FOO", "BAR"},
- UserHandle.USER_SYSTEM,
+ mA11yms.getCurrentUserIdLocked(),
false
));
}
@@ -1792,13 +1767,16 @@ public class AccessibilityManagerServiceTest {
@Test
@EnableFlags(android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE)
public void restoreShortcutTargets_hardware_targetsMerged() {
+ // TODO: remove the assumption when we fix b/381294327
+ assumeTrue("The test is setup to run as a user 0",
+ mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
mFakePermissionEnforcer.grant(Manifest.permission.MANAGE_ACCESSIBILITY);
final String servicePrevious = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
final String otherPrevious = TARGET_MAGNIFICATION;
final String serviceRestored = TARGET_STANDARD_A11Y_SERVICE_NAME;
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
mA11yms.enableShortcutsForTargets(
true, HARDWARE, List.of(servicePrevious, otherPrevious), userState.mUserId);
@@ -1819,16 +1797,19 @@ public class AccessibilityManagerServiceTest {
android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
public void restoreShortcutTargets_hardware_alreadyHadDefaultService_doesNotClear() {
+ // TODO: remove the assumption when we fix b/381294327
+ assumeTrue("The test is setup to run as a user 0",
+ mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
mTestableContext.getOrCreateTestableResources().addOverride(
R.string.config_defaultAccessibilityService, serviceDefault);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
// default is present in userState & setting, so it's not cleared
- putShortcutSettingForUser(HARDWARE, serviceDefault, UserHandle.USER_SYSTEM);
+ putShortcutSettingForUser(HARDWARE, serviceDefault, userState.mUserId);
userState.updateShortcutTargetsLocked(Set.of(serviceDefault), HARDWARE);
broadcastSettingRestored(
@@ -1847,6 +1828,9 @@ public class AccessibilityManagerServiceTest {
android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
public void restoreShortcutTargets_hardware_didNotHaveDefaultService_clearsDefaultService() {
+ // TODO: remove the assumption when we fix b/381294327
+ assumeTrue("The test is setup to run as a user 0",
+ mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
// Restored value from the broadcast contains both default and non-default service.
@@ -1854,8 +1838,8 @@ public class AccessibilityManagerServiceTest {
mTestableContext.getOrCreateTestableResources().addOverride(
R.string.config_defaultAccessibilityService, serviceDefault);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
broadcastSettingRestored(ShortcutUtils.convertToKey(HARDWARE),
@@ -1874,6 +1858,9 @@ public class AccessibilityManagerServiceTest {
android.view.accessibility.Flags.FLAG_RESTORE_A11Y_SHORTCUT_TARGET_SERVICE,
Flags.FLAG_CLEAR_DEFAULT_FROM_A11Y_SHORTCUT_TARGET_SERVICE_RESTORE})
public void restoreShortcutTargets_hardware_nullSetting_clearsDefaultService() {
+ // TODO: remove the assumption when we fix b/381294327
+ assumeTrue("The test is setup to run as a user 0",
+ mTestableContext.getUserId() == UserHandle.USER_SYSTEM);
final String serviceDefault = TARGET_STANDARD_A11Y_SERVICE_NAME;
final String serviceRestored = TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString();
// Restored value from the broadcast contains both default and non-default service.
@@ -1881,13 +1868,13 @@ public class AccessibilityManagerServiceTest {
mTestableContext.getOrCreateTestableResources().addOverride(
R.string.config_defaultAccessibilityService, serviceDefault);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
// UserState has default, but setting is null (this emulates a typical scenario in SUW).
userState.updateShortcutTargetsLocked(Set.of(serviceDefault), HARDWARE);
- putShortcutSettingForUser(HARDWARE, null, UserHandle.USER_SYSTEM);
+ putShortcutSettingForUser(HARDWARE, null, userState.mUserId);
broadcastSettingRestored(ShortcutUtils.convertToKey(HARDWARE),
/*newValue=*/combinedRestored);
@@ -1905,8 +1892,8 @@ public class AccessibilityManagerServiceTest {
public void onNavButtonNavigation_migratesGestureTargets() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
userState.updateShortcutTargetsLocked(
Set.of(TARGET_STANDARD_A11Y_SERVICE_NAME), SOFTWARE);
@@ -1929,20 +1916,20 @@ public class AccessibilityManagerServiceTest {
public void onNavButtonNavigation_gestureTargets_noButtonTargets_navBarButtonMode() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
userState.updateShortcutTargetsLocked(Set.of(), SOFTWARE);
userState.updateShortcutTargetsLocked(
Set.of(TARGET_ALWAYS_ON_A11Y_SERVICE.flattenToString()), GESTURE);
ShortcutUtils.setButtonMode(
- mTestableContext, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, UserHandle.USER_SYSTEM);
+ mTestableContext, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, userState.mUserId);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
mA11yms.updateShortcutsForCurrentNavigationMode();
- assertThat(ShortcutUtils.getButtonMode(mTestableContext, UserHandle.USER_SYSTEM))
+ assertThat(ShortcutUtils.getButtonMode(mTestableContext, userState.mUserId))
.isEqualTo(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
}
@@ -1951,11 +1938,11 @@ public class AccessibilityManagerServiceTest {
public void onGestureNavigation_floatingMenuMode() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
ShortcutUtils.setButtonMode(
- mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_SYSTEM);
+ mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, userState.mUserId);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
@@ -1970,8 +1957,8 @@ public class AccessibilityManagerServiceTest {
public void onNavigation_revertGestureTargets() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
userState.updateShortcutTargetsLocked(
Set.of(TARGET_STANDARD_A11Y_SERVICE_NAME), SOFTWARE);
@@ -1994,8 +1981,8 @@ public class AccessibilityManagerServiceTest {
public void onNavigation_gestureNavigation_gestureButtonMode_migratesTargetsToGesture() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
userState.updateShortcutTargetsLocked(Set.of(
TARGET_STANDARD_A11Y_SERVICE_NAME,
@@ -2003,7 +1990,7 @@ public class AccessibilityManagerServiceTest {
userState.updateShortcutTargetsLocked(Set.of(), GESTURE);
ShortcutUtils.setButtonMode(
- mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, UserHandle.USER_SYSTEM);
+ mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, userState.mUserId);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
mA11yms.updateShortcutsForCurrentNavigationMode();
@@ -2019,11 +2006,11 @@ public class AccessibilityManagerServiceTest {
@DisableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void onNavigation_gestureNavigation_correctsButtonMode() {
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
ShortcutUtils.setButtonMode(
- mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, UserHandle.USER_SYSTEM);
+ mTestableContext, ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR, userState.mUserId);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
@@ -2037,11 +2024,11 @@ public class AccessibilityManagerServiceTest {
@DisableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void onNavigation_navBarNavigation_correctsButtonMode() {
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
setupShortcutTargetServices(userState);
ShortcutUtils.setButtonMode(
- mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, UserHandle.USER_SYSTEM);
+ mTestableContext, ACCESSIBILITY_BUTTON_MODE_GESTURE, userState.mUserId);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
@@ -2055,8 +2042,8 @@ public class AccessibilityManagerServiceTest {
public void showAccessibilityTargetSelection_navBarNavigationMode_softwareExtra() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
@@ -2071,8 +2058,8 @@ public class AccessibilityManagerServiceTest {
public void showAccessibilityTargetSelection_gestureNavigationMode_softwareExtra() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
@@ -2087,8 +2074,8 @@ public class AccessibilityManagerServiceTest {
public void showAccessibilityTargetSelection_gestureNavigationMode_gestureExtra() {
mFakePermissionEnforcer.grant(Manifest.permission.STATUS_BAR_SERVICE);
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
@@ -2122,18 +2109,19 @@ public class AccessibilityManagerServiceTest {
public void switchUser_callsUserInitializationCompleteCallback() throws RemoteException {
mA11yms.mUserInitializationCompleteCallbacks.add(mUserInitializationCompleteCallback);
- mA11yms.switchUser(UserHandle.MIN_SECONDARY_USER_ID);
+ int newUserId = mA11yms.getCurrentUserIdLocked() + 1;
+ mA11yms.switchUser(newUserId);
+ mTestableLooper.processAllMessages();
- verify(mUserInitializationCompleteCallback).onUserInitializationComplete(
- UserHandle.MIN_SECONDARY_USER_ID);
+ verify(mUserInitializationCompleteCallback).onUserInitializationComplete(newUserId);
}
@Test
@DisableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void getShortcutTypeForGenericShortcutCalls_softwareType() {
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
assertThat(mA11yms.getShortcutTypeForGenericShortcutCalls(userState.mUserId))
.isEqualTo(SOFTWARE);
@@ -2143,8 +2131,8 @@ public class AccessibilityManagerServiceTest {
@EnableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void getShortcutTypeForGenericShortcutCalls_gestureNavigationMode_gestureType() {
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_GESTURAL, userState.mUserId);
@@ -2156,8 +2144,8 @@ public class AccessibilityManagerServiceTest {
@EnableFlags(android.provider.Flags.FLAG_A11Y_STANDALONE_GESTURE_ENABLED)
public void getShortcutTypeForGenericShortcutCalls_buttonNavigationMode_softwareType() {
final AccessibilityUserState userState = new AccessibilityUserState(
- UserHandle.USER_SYSTEM, mTestableContext, mA11yms);
- mA11yms.mUserStates.put(UserHandle.USER_SYSTEM, userState);
+ mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms);
+ mA11yms.mUserStates.put(userState.mUserId, userState);
Settings.Secure.putIntForUser(mTestableContext.getContentResolver(),
NAVIGATION_MODE, NAV_BAR_MODE_3BUTTON, userState.mUserId);
@@ -2348,13 +2336,13 @@ public class AccessibilityManagerServiceTest {
private Set readStringsFromSetting(String setting) {
final Set result = new ArraySet<>();
mA11yms.readColonDelimitedSettingToSet(
- setting, UserHandle.USER_SYSTEM, str -> str, result);
+ setting, mA11yms.getCurrentUserIdLocked(), str -> str, result);
return result;
}
private void writeStringsToSetting(Set strings, String setting) {
mA11yms.persistColonDelimitedSetToSettingLocked(
- setting, UserHandle.USER_SYSTEM, strings, str -> str);
+ setting, mA11yms.getCurrentUserIdLocked(), strings, str -> str);
}
private void broadcastSettingRestored(String setting, String newValue) {
@@ -2525,10 +2513,6 @@ public class AccessibilityManagerServiceTest {
}
}
- private static boolean isSameCurrentUser(AccessibilityManagerService service, Context context) {
- return service.getCurrentUserIdLocked() == context.getUserId();
- }
-
private void putShortcutSettingForUser(@UserShortcutType int shortcutType,
String shortcutValue, int userId) {
Settings.Secure.putStringForUser(
--
GitLab
From 83d1eda1c805c145d74f3e8197c10be6fae894f6 Mon Sep 17 00:00:00 2001
From: Winson Chung
Date: Mon, 2 Dec 2024 19:50:26 +0000
Subject: [PATCH 194/652] Skip calling adpf session if it's null
Bug: 381899878
Flag: EXEMPT bugfix
Test: Presubmit
Change-Id: I536348afcb412d93c8a527ea9490b8cc35609a69
---
.../java/android/window/SystemPerformanceHinter.java | 6 ++----
.../wm/shell/performance/PerfHintController.kt | 12 +++++++++---
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/core/java/android/window/SystemPerformanceHinter.java b/core/java/android/window/SystemPerformanceHinter.java
index cc2329fc47cb..f8899c5764aa 100644
--- a/core/java/android/window/SystemPerformanceHinter.java
+++ b/core/java/android/window/SystemPerformanceHinter.java
@@ -163,7 +163,6 @@ public class SystemPerformanceHinter {
// The active sessions
private final ArrayList mActiveSessions = new ArrayList<>();
private final SurfaceControl.Transaction mTransaction;
- private final PerformanceHintManager mPerfHintManager;
private @Nullable PerformanceHintManager.Session mAdpfSession;
private @Nullable DisplayRootProvider mDisplayRootProvider;
@@ -184,7 +183,6 @@ public class SystemPerformanceHinter {
@Nullable DisplayRootProvider displayRootProvider,
@Nullable Supplier transactionSupplier) {
mDisplayRootProvider = displayRootProvider;
- mPerfHintManager = context.getSystemService(PerformanceHintManager.class);
mTransaction = transactionSupplier != null
? transactionSupplier.get()
: new SurfaceControl.Transaction();
@@ -273,7 +271,7 @@ public class SystemPerformanceHinter {
asyncTraceBegin(HINT_SF_EARLY_WAKEUP, Display.INVALID_DISPLAY);
}
}
- if (nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
+ if (mAdpfSession != null && nowEnabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_UP);
if (isTraceEnabled) {
asyncTraceBegin(HINT_ADPF, Display.INVALID_DISPLAY);
@@ -323,7 +321,7 @@ public class SystemPerformanceHinter {
asyncTraceEnd(HINT_SF_EARLY_WAKEUP);
}
}
- if (nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
+ if (mAdpfSession != null && nowDisabled(oldGlobalFlags, newGlobalFlags, HINT_ADPF)) {
mAdpfSession.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
if (isTraceEnabled) {
asyncTraceEnd(HINT_ADPF);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
index f7977f88006e..c655d86c3ece 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/performance/PerfHintController.kt
@@ -45,9 +45,15 @@ class PerfHintController(private val mContext: Context,
private fun onInit() {
mShellCommandHandler.addDumpCallback(this::dump, this)
val perfHintMgr = mContext.getSystemService(PerformanceHintManager::class.java)
- val adpfSession = perfHintMgr!!.createHintSession(intArrayOf(Process.myTid()),
- TimeUnit.SECONDS.toNanos(1))
- hinter.setAdpfSession(adpfSession)
+ if (perfHintMgr != null) {
+ val adpfSession = perfHintMgr.createHintSession(
+ intArrayOf(Process.myTid()),
+ TimeUnit.SECONDS.toNanos(1)
+ )
+ if (adpfSession != null) {
+ hinter.setAdpfSession(adpfSession)
+ }
+ }
}
fun dump(pw: PrintWriter, prefix: String?) {
--
GitLab
From 3f7dd7d1b1807617ed4bfb058a47eb1fa78c8206 Mon Sep 17 00:00:00 2001
From: Pragya Bajoria
Date: Wed, 27 Nov 2024 12:51:07 +0000
Subject: [PATCH 195/652] Add unit test for DesktopUserRepositories.
Bug: 366397912
Flag: EXEMPT (tests only)
Change-Id: I98d5811b91603227d0c8b51d460dec909d7a035d
---
.../DesktopUserRepositoriesTest.kt | 126 ++++++++++++++++++
1 file changed, 126 insertions(+)
create mode 100644 libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt
new file mode 100644
index 000000000000..5767df4c5a8e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopUserRepositoriesTest.kt
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.app.ActivityManager
+import android.content.pm.UserInfo
+import android.os.UserManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
+import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_HSUM
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.ShellExecutor
+import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
+import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
+import com.android.wm.shell.sysui.ShellInit
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.spy
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@ExperimentalCoroutinesApi
+class DesktopUserRepositoriesTest : ShellTestCase() {
+ @get:Rule val setFlagsRule = SetFlagsRule()
+
+ private lateinit var userRepositories: DesktopUserRepositories
+ private lateinit var shellInit: ShellInit
+ private lateinit var datastoreScope: CoroutineScope
+ private lateinit var mockitoSession: StaticMockitoSession
+
+ private val testExecutor = mock()
+ private val persistentRepository = mock()
+ private val repositoryInitializer = mock()
+ private val userManager = mock()
+
+ @Before
+ fun setUp() {
+ Dispatchers.setMain(StandardTestDispatcher())
+ mockitoSession =
+ mockitoSession()
+ .strictness(Strictness.LENIENT)
+ .spyStatic(ActivityManager::class.java)
+ .startMocking()
+ doReturn(USER_ID_1).`when` { ActivityManager.getCurrentUser() }
+
+ datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
+ shellInit = spy(ShellInit(testExecutor))
+
+ val profiles: MutableList = mutableListOf(
+ UserInfo(USER_ID_1, "User 1", 0),
+ UserInfo(PROFILE_ID_2, "Profile 2", 0))
+ whenever(userManager.getProfiles(USER_ID_1)).thenReturn(profiles)
+
+ userRepositories = DesktopUserRepositories(
+ context, shellInit, persistentRepository, repositoryInitializer, datastoreScope,
+ userManager)
+ }
+
+ @After
+ fun tearDown() {
+ mockitoSession.finishMocking()
+ datastoreScope.cancel()
+ }
+
+ @Test
+ fun getCurrent_returnsUserId() {
+ val desktopRepository: DesktopRepository = userRepositories.current
+
+ assertThat(desktopRepository.userId).isEqualTo(USER_ID_1)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_HSUM)
+ fun getProfile_flagEnabled_returnsProfileGroupId() {
+ val desktopRepository: DesktopRepository = userRepositories.getProfile(PROFILE_ID_2)
+
+ assertThat(desktopRepository.userId).isEqualTo(USER_ID_1)
+ }
+
+ @Test
+ @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_HSUM)
+ fun getProfile_flagDisabled_returnsProfileId() {
+ val desktopRepository: DesktopRepository = userRepositories.getProfile(PROFILE_ID_2)
+
+ assertThat(desktopRepository.userId).isEqualTo(PROFILE_ID_2)
+ }
+
+ private companion object {
+ const val USER_ID_1 = 7
+ const val PROFILE_ID_2 = 5
+ }
+}
--
GitLab
From 93b4e7256c4f674fa96b1bdfd3a089a432f782de Mon Sep 17 00:00:00 2001
From: Rafael Prado
Date: Mon, 2 Dec 2024 20:35:53 +0000
Subject: [PATCH 196/652] Allow callers that have SET_TIME and SET_TIME_ZONE
permissions to call getAutoTimeEnabled and getAutoTimeZoneEnabled
respectively.
Test: btest TimeTest
Flag: android.app.admin.flags.set_auto_time_enabled_coexistence
Flag: android.app.admin.flags.set_auto_time_zone_enabled_coexistence
Bug: 359188869
Bug: 371165720
Change-Id: Ib7cba61a6106703914eee1082605ac5f3d6bf6ce
---
.../DevicePolicyManagerService.java | 22 +++++++++++--------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ac1219c35c3b..3ccde0643eaf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9085,11 +9085,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller = getCallerIdentity(who);
- if (!Flags.setAutoTimeEnabledCoexistence()) {
+ if (Flags.setAutoTimeEnabledCoexistence()) {
+ Preconditions.checkCallAuthorization(hasPermission(SET_TIME, caller.getPackageName()));
+ } else {
Objects.requireNonNull(who, "ComponentName is null");
- }
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(caller));
+ }
return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0;
}
@@ -9166,10 +9168,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller = getCallerIdentity(who);
-
- if (!Flags.setAutoTimeZoneEnabledCoexistence()) {
- Objects.requireNonNull(who, "ComponentName is null");
- }
+ Objects.requireNonNull(who, "ComponentName is null");
Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
caller));
@@ -9193,10 +9192,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller = getCallerIdentity(who);
- Objects.requireNonNull(who, "ComponentName is null");
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
+ if (Flags.setAutoTimeZoneEnabledCoexistence()) {
+ Preconditions.checkCallAuthorization(
+ hasPermission(SET_TIME_ZONE, caller.getPackageName()));
+ } else {
+ Objects.requireNonNull(who, "ComponentName is null");
+ Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
caller));
+ }
return mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) > 0;
}
--
GitLab
From 7bacadc8cd6f21468e46653ae3e2c3151a3e8bb4 Mon Sep 17 00:00:00 2001
From: Lais Andrade
Date: Mon, 2 Dec 2024 17:04:40 +0000
Subject: [PATCH 197/652] Fix flaky VibrationSettingsTest
Update VibrationSettings to expose all listener and observers for
testing.
Change test class to use mocks for internal services, including activity
manager singleton internal service, to avoid flakiness during test runs.
Make all listener/observer tests deterministic by directly triggering
them from the test class.
Change-Id: I95481acb340a27ef115f2605cc2cb7ed2e668b8a
Fix: 381725186
Test: VibrationSettingsTest
Flag: EXEMPT refactor
Merged-In: I7618b7894fa661d1e657c306557717979cbdedbf
---
.../server/vibrator/VibrationSettings.java | 137 +++++++++++-------
.../vibrator/VibrationSettingsTest.java | 134 +++++++----------
2 files changed, 136 insertions(+), 135 deletions(-)
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index 227b6b410e6b..a0dca946a718 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -31,6 +31,7 @@ import static android.os.VibrationAttributes.USAGE_UNKNOWN;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.IActivityManager;
import android.app.SynchronousUserSwitchObserver;
import android.app.UidObserver;
import android.content.BroadcastReceiver;
@@ -73,6 +74,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/** Controls all the system settings related to vibration. */
@@ -146,9 +148,6 @@ final class VibrationSettings {
PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE,
PowerManager.GO_TO_SLEEP_REASON_TIMEOUT));
- private static final IntentFilter INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER =
- new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
-
/** Listener for changes on vibration settings. */
interface OnVibratorSettingsChanged {
/** Callback triggered when any of the vibrator settings change. */
@@ -157,15 +156,18 @@ final class VibrationSettings {
private final Object mLock = new Object();
private final Context mContext;
- private final String mSystemUiPackage;
@VisibleForTesting
final SettingsContentObserver mSettingObserver;
@VisibleForTesting
- final SettingsBroadcastReceiver mSettingChangeReceiver;
+ final RingerModeBroadcastReceiver mRingerModeBroadcastReceiver;
+ @VisibleForTesting
+ final BatteryBroadcastReceiver mBatteryBroadcastReceiver;
@VisibleForTesting
final VibrationUidObserver mUidObserver;
@VisibleForTesting
final VibrationUserSwitchObserver mUserSwitchObserver;
+ @VisibleForTesting
+ final VibrationLowPowerModeListener mLowPowerModeListener;
@GuardedBy("mLock")
private final List mListeners = new ArrayList<>();
@@ -179,9 +181,12 @@ final class VibrationSettings {
@GuardedBy("mLock")
@Nullable
private PowerManagerInternal mPowerManagerInternal;
+ @GuardedBy("mLock")
@Nullable
private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal;
+ @GuardedBy("mLock")
+ private String mSystemUiPackage;
@GuardedBy("mLock")
private boolean mVibrateInputDevices;
@GuardedBy("mLock")
@@ -206,11 +211,11 @@ final class VibrationSettings {
mContext = context;
mVibrationConfig = config;
mSettingObserver = new SettingsContentObserver(handler);
- mSettingChangeReceiver = new SettingsBroadcastReceiver();
+ mRingerModeBroadcastReceiver = new RingerModeBroadcastReceiver();
+ mBatteryBroadcastReceiver = new BatteryBroadcastReceiver();
mUidObserver = new VibrationUidObserver();
mUserSwitchObserver = new VibrationUserSwitchObserver();
- mSystemUiPackage = LocalServices.getService(PackageManagerInternal.class)
- .getSystemUiServiceComponent().getPackageName();
+ mLowPowerModeListener = new VibrationLowPowerModeListener();
VibrationEffect clickEffect = createEffectFromResource(
com.android.internal.R.array.config_virtualKeyVibePattern);
@@ -234,18 +239,34 @@ final class VibrationSettings {
}
public void onSystemReady() {
- PowerManagerInternal pm = LocalServices.getService(PowerManagerInternal.class);
- AudioManager am = mContext.getSystemService(AudioManager.class);
- int ringerMode = (am == null) ? mRingerMode : am.getRingerModeInternal();
+ onSystemReady(LocalServices.getService(PackageManagerInternal.class),
+ LocalServices.getService(PowerManagerInternal.class),
+ ActivityManager.getService(),
+ LocalServices.getService(VirtualDeviceManagerInternal.class),
+ mContext.getSystemService(AudioManager.class));
+ }
+
+ @VisibleForTesting
+ void onSystemReady(PackageManagerInternal packageManagerInternal,
+ PowerManagerInternal powerManagerInternal,
+ IActivityManager activityManagerInternal,
+ @Nullable VirtualDeviceManagerInternal virtualDeviceManagerInternal,
+ @Nullable AudioManager audioManager) {
+ int ringerMode = (audioManager == null)
+ ? AudioManager.RINGER_MODE_NORMAL
+ : audioManager.getRingerModeInternal();
+ String sysUiPackage = packageManagerInternal.getSystemUiServiceComponent().getPackageName();
synchronized (mLock) {
- mPowerManagerInternal = pm;
- mAudioManager = am;
+ mPowerManagerInternal = powerManagerInternal;
+ mVirtualDeviceManagerInternal = virtualDeviceManagerInternal;
+ mAudioManager = audioManager;
mRingerMode = ringerMode;
+ mSystemUiPackage = sysUiPackage;
}
try {
- ActivityManager.getService().registerUidObserver(mUidObserver,
+ activityManagerInternal.registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
ActivityManager.PROCESS_STATE_UNKNOWN, /* callingPackage= */ null);
} catch (RemoteException e) {
@@ -253,32 +274,16 @@ final class VibrationSettings {
}
try {
- ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG);
+ activityManagerInternal.registerUserSwitchObserver(mUserSwitchObserver, TAG);
} catch (RemoteException e) {
// ignored; both services live in system_server
}
- pm.registerLowPowerModeObserver(
- new PowerManagerInternal.LowPowerModeListener() {
- @Override
- public int getServiceType() {
- return PowerManager.ServiceType.VIBRATION;
- }
-
- @Override
- public void onLowPowerModeChanged(PowerSaveState result) {
- boolean shouldNotifyListeners;
- synchronized (mLock) {
- shouldNotifyListeners = result.batterySaverEnabled != mBatterySaverMode;
- mBatterySaverMode = result.batterySaverEnabled;
- }
- if (shouldNotifyListeners) {
- notifyListeners();
- }
- }
- });
-
- registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
+ powerManagerInternal.registerLowPowerModeObserver(mLowPowerModeListener);
+
+ mContext.registerReceiver(mRingerModeBroadcastReceiver,
+ new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION),
+ Context.RECEIVER_EXPORTED_UNAUDITED);
// Listen to all settings that might affect the result of Vibrator.getVibrationIntensity.
registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES));
@@ -302,12 +307,7 @@ final class VibrationSettings {
if (mVibrationConfig.ignoreVibrationsOnWirelessCharger()) {
Intent batteryStatus = mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- updateBatteryInfo(intent);
- }
- },
+ mBatteryBroadcastReceiver,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED),
Context.RECEIVER_NOT_EXPORTED);
// After registering the receiver for battery status, process the sticky broadcast that
@@ -477,8 +477,10 @@ final class VibrationSettings {
public boolean shouldCancelVibrationOnScreenOff(@NonNull Vibration.CallerInfo callerInfo,
long vibrationStartUptimeMillis) {
PowerManagerInternal pm;
+ String sysUiPackageName;
synchronized (mLock) {
pm = mPowerManagerInternal;
+ sysUiPackageName = mSystemUiPackage;
}
if (pm != null) {
// The SleepData from PowerManager may refer to a more recent sleep than the broadcast
@@ -502,7 +504,7 @@ final class VibrationSettings {
}
// Only allow vibrations from System packages to continue vibrating when the screen goes off
return callerInfo.uid != Process.SYSTEM_UID && callerInfo.uid != 0
- && !mSystemUiPackage.equals(callerInfo.opPkg);
+ && !Objects.equals(sysUiPackageName, callerInfo.opPkg);
}
/**
@@ -785,11 +787,6 @@ final class VibrationSettings {
UserHandle.USER_ALL);
}
- private void registerSettingsChangeReceiver(IntentFilter intentFilter) {
- mContext.registerReceiver(mSettingChangeReceiver, intentFilter,
- Context.RECEIVER_EXPORTED_UNAUDITED);
- }
-
@Nullable
private VibrationEffect createEffectFromResource(int resId) {
return createEffectFromResource(mContext.getResources(), resId);
@@ -836,12 +833,11 @@ final class VibrationSettings {
}
private boolean isAppRunningOnAnyVirtualDevice(int uid) {
- if (mVirtualDeviceManagerInternal == null) {
- mVirtualDeviceManagerInternal =
- LocalServices.getService(VirtualDeviceManagerInternal.class);
+ VirtualDeviceManagerInternal vdm;
+ synchronized (mLock) {
+ vdm = mVirtualDeviceManagerInternal;
}
- return mVirtualDeviceManagerInternal != null
- && mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(uid);
+ return vdm != null && vdm.isAppRunningOnAnyVirtualDevice(uid);
}
/** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
@@ -860,7 +856,7 @@ final class VibrationSettings {
/** Implementation of {@link BroadcastReceiver} to update on ringer mode change. */
@VisibleForTesting
- final class SettingsBroadcastReceiver extends BroadcastReceiver {
+ final class RingerModeBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -871,6 +867,18 @@ final class VibrationSettings {
}
}
+ /** Implementation of {@link BroadcastReceiver} to update on battery mode change. */
+ @VisibleForTesting
+ final class BatteryBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
+ updateBatteryInfo(intent);
+ }
+ }
+ }
+
/** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */
@VisibleForTesting
final class VibrationUidObserver extends UidObserver {
@@ -916,4 +924,25 @@ final class VibrationSettings {
update();
}
}
+
+ /** Implementation of {@link PowerManagerInternal.LowPowerModeListener} for low battery. */
+ @VisibleForTesting
+ final class VibrationLowPowerModeListener implements PowerManagerInternal.LowPowerModeListener {
+ @Override
+ public int getServiceType() {
+ return PowerManager.ServiceType.VIBRATION;
+ }
+
+ @Override
+ public void onLowPowerModeChanged(PowerSaveState result) {
+ boolean shouldNotifyListeners;
+ synchronized (mLock) {
+ shouldNotifyListeners = result.batterySaverEnabled != mBatterySaverMode;
+ mBatterySaverMode = result.batterySaverEnabled;
+ }
+ if (shouldNotifyListeners) {
+ notifyListeners();
+ }
+ }
+ }
}
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
index 21604df87fe7..0f2017897719 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationSettingsTest.java
@@ -43,7 +43,8 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -51,12 +52,14 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
+import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.media.AudioManager;
import android.os.Handler;
@@ -80,10 +83,8 @@ import androidx.test.InstrumentationRegistry;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
-import com.android.server.LocalServices;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -100,8 +101,7 @@ public class VibrationSettingsTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
- private static final int OLD_USER_ID = 123;
- private static final int NEW_USER_ID = 456;
+ private static final int USER_ID = 123;
private static final int UID = 1;
private static final int VIRTUAL_DEVICE_ID = 1;
private static final String SYSUI_PACKAGE_NAME = "sysui";
@@ -130,13 +130,12 @@ public class VibrationSettingsTest {
@Mock private VirtualDeviceManagerInternal mVirtualDeviceManagerInternalMock;
@Mock private PackageManagerInternal mPackageManagerInternalMock;
@Mock private AudioManager mAudioManagerMock;
+ @Mock private IActivityManager mActivityManagerMock;
@Mock private VibrationConfig mVibrationConfigMock;
private TestLooper mTestLooper;
private ContextWrapper mContextSpy;
private VibrationSettings mVibrationSettings;
- private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
- private BroadcastReceiver mRegisteredBatteryBroadcastReceiver;
@Before
public void setUp() throws Exception {
@@ -144,24 +143,20 @@ public class VibrationSettingsTest {
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
- when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
- when(mContextSpy.getSystemService(eq(Context.AUDIO_SERVICE))).thenReturn(mAudioManagerMock);
- doAnswer(invocation -> {
- mRegisteredPowerModeListener = invocation.getArgument(0);
- return null;
- }).when(mPowerManagerInternalMock).registerLowPowerModeObserver(any());
+ doReturn(contentResolver).when(mContextSpy).getContentResolver();
+
+ // Make sure broadcast receivers are not registered for this test, to avoid flakes.
+ doReturn(null).when(mContextSpy)
+ .registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class), anyInt());
when(mPackageManagerInternalMock.getSystemUiServiceComponent())
.thenReturn(new ComponentName(SYSUI_PACKAGE_NAME, ""));
- removeServicesForTest();
- addServicesForTest();
-
setDefaultIntensity(VIBRATION_INTENSITY_MEDIUM);
setIgnoreVibrationsOnWirelessCharger(false);
- createSystemReadyVibrationSettings();
mockGoToSleep(/* goToSleepTime= */ 0, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ createSystemReadyVibrationSettings();
}
private void createSystemReadyVibrationSettings() {
@@ -175,38 +170,18 @@ public class VibrationSettingsTest {
setUserSetting(Settings.System.APPLY_RAMPING_RINGER, 0);
setRingerMode(AudioManager.RINGER_MODE_NORMAL);
- mVibrationSettings.onSystemReady();
- }
-
- private void removeServicesForTest() {
- LocalServices.removeServiceForTest(PowerManagerInternal.class);
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class);
- }
-
- private void addServicesForTest() {
- LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
- LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
- LocalServices.addService(VirtualDeviceManagerInternal.class,
- mVirtualDeviceManagerInternalMock);
- }
-
- @After
- public void tearDown() throws Exception {
- removeServicesForTest();
+ mVibrationSettings.onSystemReady(mPackageManagerInternalMock, mPowerManagerInternalMock,
+ mActivityManagerMock, mVirtualDeviceManagerInternalMock, mAudioManagerMock);
}
@Test
public void create_withOnlyRequiredSystemServices() {
- // The only core services that we depend on are PowerManager and PackageManager
- removeServicesForTest();
- LocalServices.addService(PowerManagerInternal.class, mPowerManagerInternalMock);
- LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternalMock);
- when(mContextSpy.getSystemService(eq(Context.AUDIO_SERVICE))).thenReturn(null);
-
VibrationSettings minimalVibrationSettings = new VibrationSettings(mContextSpy,
new Handler(mTestLooper.getLooper()), mVibrationConfigMock);
- minimalVibrationSettings.onSystemReady();
+
+ // The only core services that we depend on are Power, Package and Activity managers
+ minimalVibrationSettings.onSystemReady(mPackageManagerInternalMock,
+ mPowerManagerInternalMock, mActivityManagerMock, null, null);
}
@Test
@@ -214,8 +189,8 @@ public class VibrationSettingsTest {
mVibrationSettings.addListener(mListenerMock);
// Testing the broadcast flow manually.
- mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID);
- mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
+ mVibrationSettings.mUserSwitchObserver.onUserSwitching(USER_ID);
+ mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(USER_ID);
verify(mListenerMock, times(2)).onChange();
}
@@ -225,9 +200,9 @@ public class VibrationSettingsTest {
mVibrationSettings.addListener(mListenerMock);
// Testing the broadcast flow manually.
- mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+ mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy,
new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
- mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+ mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy,
new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
verify(mListenerMock, times(2)).onChange();
@@ -249,9 +224,9 @@ public class VibrationSettingsTest {
mVibrationSettings.addListener(mListenerMock);
// Testing the broadcast flow manually.
- mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
- mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
- mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); // No change.
+ mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+ mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
+ mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE); // Noop.
verify(mListenerMock, times(2)).onChange();
}
@@ -266,10 +241,9 @@ public class VibrationSettingsTest {
mVibrationSettings.removeListener(mListenerMock);
// Trigger multiple observers manually.
- mVibrationSettings.mSettingObserver.onChange(false);
- mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
- mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
- mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+ mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+ mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(USER_ID);
+ mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy,
new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
verifyNoMoreInteractions(mListenerMock);
@@ -310,11 +284,12 @@ public class VibrationSettingsTest {
@Test
public void wirelessChargingVibrationsEnabled_doesNotRegisterBatteryReceiver_allowsAnyUsage() {
- setBatteryReceiverRegistrationResult(getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS));
setIgnoreVibrationsOnWirelessCharger(false);
createSystemReadyVibrationSettings();
- assertNull(mRegisteredBatteryBroadcastReceiver);
+ verify(mContextSpy, never()).registerReceiver(any(BroadcastReceiver.class),
+ argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt());
+
for (int usage : ALL_USAGES) {
assertVibrationNotIgnoredForUsage(usage);
}
@@ -322,7 +297,6 @@ public class VibrationSettingsTest {
@Test
public void shouldIgnoreVibration_noBatteryIntentWhenSystemReady_allowsAnyUsage() {
- setBatteryReceiverRegistrationResult(null);
setIgnoreVibrationsOnWirelessCharger(true);
createSystemReadyVibrationSettings();
@@ -334,7 +308,9 @@ public class VibrationSettingsTest {
@Test
public void shouldIgnoreVibration_onNonWirelessChargerWhenSystemReady_allowsAnyUsage() {
Intent nonWirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_USB);
- setBatteryReceiverRegistrationResult(nonWirelessChargingIntent);
+ doReturn(nonWirelessChargingIntent).when(mContextSpy).registerReceiver(
+ any(BroadcastReceiver.class),
+ argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt());
setIgnoreVibrationsOnWirelessCharger(true);
createSystemReadyVibrationSettings();
@@ -346,7 +322,9 @@ public class VibrationSettingsTest {
@Test
public void shouldIgnoreVibration_onWirelessChargerWhenSystemReady_doesNotAllowFromAnyUsage() {
Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS);
- setBatteryReceiverRegistrationResult(wirelessChargingIntent);
+ doReturn(wirelessChargingIntent).when(mContextSpy).registerReceiver(
+ any(BroadcastReceiver.class),
+ argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt());
setIgnoreVibrationsOnWirelessCharger(true);
createSystemReadyVibrationSettings();
@@ -357,13 +335,12 @@ public class VibrationSettingsTest {
@Test
public void shouldIgnoreVibration_receivesWirelessChargingIntent_doesNotAllowFromAnyUsage() {
- Intent nonWirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_USB);
- setBatteryReceiverRegistrationResult(nonWirelessChargingIntent);
setIgnoreVibrationsOnWirelessCharger(true);
createSystemReadyVibrationSettings();
Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS);
- mRegisteredBatteryBroadcastReceiver.onReceive(mContextSpy, wirelessChargingIntent);
+ mVibrationSettings.mBatteryBroadcastReceiver.onReceive(
+ mContextSpy, wirelessChargingIntent);
for (int usage : ALL_USAGES) {
assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_ON_WIRELESS_CHARGER);
@@ -372,17 +349,21 @@ public class VibrationSettingsTest {
@Test
public void shouldIgnoreVibration_receivesNonWirelessChargingIntent_allowsAnyUsage() {
- Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS);
- setBatteryReceiverRegistrationResult(wirelessChargingIntent);
setIgnoreVibrationsOnWirelessCharger(true);
createSystemReadyVibrationSettings();
+
+ Intent wirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_WIRELESS);
+ mVibrationSettings.mBatteryBroadcastReceiver.onReceive(
+ mContextSpy, wirelessChargingIntent);
+
// Check that initially, all usages are ignored due to the wireless charging.
for (int usage : ALL_USAGES) {
assertVibrationIgnoredForUsage(usage, Vibration.Status.IGNORED_ON_WIRELESS_CHARGER);
}
Intent nonWirelessChargingIntent = getBatteryChangedIntent(BATTERY_PLUGGED_USB);
- mRegisteredBatteryBroadcastReceiver.onReceive(mContextSpy, nonWirelessChargingIntent);
+ mVibrationSettings.mBatteryBroadcastReceiver.onReceive(
+ mContextSpy, nonWirelessChargingIntent);
for (int usage : ALL_USAGES) {
assertVibrationNotIgnoredForUsage(usage);
@@ -399,7 +380,7 @@ public class VibrationSettingsTest {
USAGE_HARDWARE_FEEDBACK
));
- mRegisteredPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
+ mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(LOW_POWER_STATE);
for (int usage : ALL_USAGES) {
if (expectedAllowedVibrations.contains(usage)) {
@@ -412,7 +393,7 @@ public class VibrationSettingsTest {
@Test
public void shouldIgnoreVibration_notInBatterySaverMode_allowsAnyUsage() {
- mRegisteredPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
+ mVibrationSettings.mLowPowerModeListener.onLowPowerModeChanged(NORMAL_POWER_STATE);
for (int usage : ALL_USAGES) {
assertVibrationNotIgnoredForUsage(usage);
@@ -605,7 +586,7 @@ public class VibrationSettingsTest {
// Testing the broadcast flow manually.
when(mAudioManagerMock.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
- mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+ mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy,
new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
assertVibrationIgnoredForUsage(USAGE_RINGTONE, Vibration.Status.IGNORED_FOR_RINGER_MODE);
@@ -868,16 +849,15 @@ public class VibrationSettingsTest {
mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
// Test early update of settings based on new user id.
- putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
- NEW_USER_ID);
- mVibrationSettings.mUserSwitchObserver.onUserSwitching(NEW_USER_ID);
+ putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW, USER_ID);
+ mVibrationSettings.mUserSwitchObserver.onUserSwitching(USER_ID);
assertEquals(VIBRATION_INTENSITY_LOW,
mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
// Test later update of settings for UserHandle.USER_CURRENT.
putUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_LOW,
UserHandle.USER_CURRENT);
- mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(NEW_USER_ID);
+ mVibrationSettings.mUserSwitchObserver.onUserSwitchComplete(USER_ID);
assertEquals(VIBRATION_INTENSITY_LOW,
mVibrationSettings.getCurrentIntensity(USAGE_RINGTONE));
}
@@ -1010,7 +990,7 @@ public class VibrationSettingsTest {
private void setRingerMode(int ringerMode) {
when(mAudioManagerMock.getRingerModeInternal()).thenReturn(ringerMode);
// Mock AudioManager broadcast of internal ringer mode change.
- mVibrationSettings.mSettingChangeReceiver.onReceive(mContextSpy,
+ mVibrationSettings.mRingerModeBroadcastReceiver.onReceive(mContextSpy,
new Intent(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION));
}
@@ -1025,14 +1005,6 @@ public class VibrationSettingsTest {
return new Vibration.CallerInfo(attrs, uid, VIRTUAL_DEVICE_ID, opPkg, null);
}
- private void setBatteryReceiverRegistrationResult(Intent result) {
- doAnswer(invocation -> {
- mRegisteredBatteryBroadcastReceiver = invocation.getArgument(0);
- return result;
- }).when(mContextSpy).registerReceiver(any(BroadcastReceiver.class),
- argThat(filter -> filter.matchAction(Intent.ACTION_BATTERY_CHANGED)), anyInt());
- }
-
private Intent getBatteryChangedIntent(int extraPluggedValue) {
Intent batteryIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
batteryIntent.putExtra(EXTRA_PLUGGED, extraPluggedValue);
--
GitLab
From b1e17a3f3bf4acf038758cfb8635ec459b837eec Mon Sep 17 00:00:00 2001
From: David Padlipsky
Date: Tue, 19 Nov 2024 02:39:16 +0000
Subject: [PATCH 198/652] Persist and load input gestures from disk
Saves custom key and touchpad input gestures to disk and loads them in
future sessions. The gestures are stored in an XML file in the system_de
directory per-user.
The same XML format will be used to implement backup and restore for the
feature as well.
Test: atest InputTests:InputDataStoreTests
Test: atest InputTests:KeyGestureControllerTests
Test: Manually on device rebooting restores custom gestures
Bug: 365064144
Flag: com.android.hardware.input.enable_customizable_input_gestures
Change-Id: I55a875044367efcd3840b975cbe74520794c3ac7
---
.../hardware/input/KeyGestureEvent.java | 2 +
.../android/server/input/InputDataStore.java | 309 ++++++++++++
.../server/input/InputManagerService.java | 7 +-
.../server/input/KeyGestureController.java | 59 ++-
.../server/input/InputDataStoreTests.kt | 444 ++++++++++++++++++
.../server/input/KeyGestureControllerTests.kt | 111 ++++-
6 files changed, 927 insertions(+), 5 deletions(-)
create mode 100644 services/core/java/com/android/server/input/InputDataStore.java
create mode 100644 tests/Input/src/com/android/server/input/InputDataStoreTests.kt
diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java
index 711dc3a2cf7c..af756b9217d3 100644
--- a/core/java/android/hardware/input/KeyGestureEvent.java
+++ b/core/java/android/hardware/input/KeyGestureEvent.java
@@ -43,6 +43,8 @@ public final class KeyGestureEvent {
private static final int LOG_EVENT_UNSPECIFIED =
FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED;
+ // These values should not change and values should not be re-used as this data is persisted to
+ // long term storage and must be kept backwards compatible.
public static final int KEY_GESTURE_TYPE_UNSPECIFIED = 0;
public static final int KEY_GESTURE_TYPE_HOME = 1;
public static final int KEY_GESTURE_TYPE_RECENT_APPS = 2;
diff --git a/services/core/java/com/android/server/input/InputDataStore.java b/services/core/java/com/android/server/input/InputDataStore.java
new file mode 100644
index 000000000000..bfed69543265
--- /dev/null
+++ b/services/core/java/com/android/server/input/InputDataStore.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input;
+
+import android.hardware.input.InputGestureData;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages persistent state recorded by the input manager service as a set of XML files.
+ * Caller must acquire lock on the data store before accessing it.
+ */
+public final class InputDataStore {
+ private static final String TAG = "InputDataStore";
+
+ private static final String INPUT_MANAGER_DIRECTORY = "input";
+
+ private static final String TAG_ROOT = "root";
+
+ private static final String TAG_INPUT_GESTURE_LIST = "input_gesture_list";
+ private static final String TAG_INPUT_GESTURE = "input_gesture";
+ private static final String TAG_KEY_TRIGGER = "key_trigger";
+ private static final String TAG_TOUCHPAD_TRIGGER = "touchpad_trigger";
+
+ private static final String ATTR_KEY_TRIGGER_KEYCODE = "keycode";
+ private static final String ATTR_KEY_TRIGGER_MODIFIER_STATE = "modifiers";
+ private static final String ATTR_KEY_GESTURE_TYPE = "key_gesture_type";
+ private static final String ATTR_TOUCHPAD_TRIGGER_GESTURE_TYPE = "touchpad_gesture_type";
+
+ private final FileInjector mInputGestureFileInjector;
+
+ public InputDataStore() {
+ this(new FileInjector("input_gestures.xml"));
+ }
+
+ public InputDataStore(final FileInjector inputGestureFileInjector) {
+ mInputGestureFileInjector = inputGestureFileInjector;
+ }
+
+ /**
+ * Reads from the local disk storage the list of customized input gestures.
+ *
+ * @param userId The user id to fetch the gestures for.
+ * @return List of {@link InputGestureData} which the user previously customized.
+ */
+ public List loadInputGestures(int userId) {
+ List inputGestureDataList;
+ try {
+ final InputStream inputStream = mInputGestureFileInjector.openRead(userId);
+ inputGestureDataList = readInputGesturesXml(inputStream, false);
+ inputStream.close();
+ } catch (IOException exception) {
+ // In case we are unable to read from the file on disk or another IO operation error,
+ // fail gracefully.
+ Slog.e(TAG, "Failed to read from " + mInputGestureFileInjector.getAtomicFileForUserId(
+ userId), exception);
+ return List.of();
+ } catch (Exception exception) {
+ // In the case of any other exception, we want it to bubble up as this would be due
+ // to malformed trusted XML data.
+ throw new RuntimeException(
+ "Failed to read from " + mInputGestureFileInjector.getAtomicFileForUserId(
+ userId), exception);
+ }
+ return inputGestureDataList;
+ }
+
+ /**
+ * Writes to the local disk storage the list of customized input gestures provided as a param.
+ *
+ * @param userId The user id to store the {@link InputGestureData} list under.
+ * @param inputGestureDataList The list of custom input gestures for the given {@code userId}.
+ */
+ public void saveInputGestures(int userId, List inputGestureDataList) {
+ FileOutputStream outputStream = null;
+ try {
+ outputStream = mInputGestureFileInjector.startWrite(userId);
+ writeInputGestureXml(outputStream, false, inputGestureDataList);
+ mInputGestureFileInjector.finishWrite(userId, outputStream, true);
+ } catch (IOException e) {
+ Slog.e(TAG,
+ "Failed to write to file " + mInputGestureFileInjector.getAtomicFileForUserId(
+ userId), e);
+ mInputGestureFileInjector.finishWrite(userId, outputStream, false);
+ }
+ }
+
+ @VisibleForTesting
+ List readInputGesturesXml(InputStream stream, boolean utf8Encoded)
+ throws XmlPullParserException, IOException {
+ List inputGestureDataList = new ArrayList<>();
+ TypedXmlPullParser parser;
+ if (utf8Encoded) {
+ parser = Xml.newFastPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ } else {
+ parser = Xml.resolvePullParser(stream);
+ }
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final String tag = parser.getName();
+ if (TAG_ROOT.equals(tag)) {
+ continue;
+ }
+
+ if (TAG_INPUT_GESTURE_LIST.equals(tag)) {
+ inputGestureDataList.addAll(readInputGestureListFromXml(parser));
+ }
+ }
+ return inputGestureDataList;
+ }
+
+ private InputGestureData readInputGestureFromXml(TypedXmlPullParser parser)
+ throws XmlPullParserException, IOException, IllegalArgumentException {
+ InputGestureData.Builder builder = new InputGestureData.Builder();
+ builder.setKeyGestureType(parser.getAttributeInt(null, ATTR_KEY_GESTURE_TYPE));
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ // If the parser has left the initial scope when it was called, break out.
+ if (outerDepth > parser.getDepth()) {
+ throw new RuntimeException(
+ "Parser has left the initial scope of the tag that was being parsed on "
+ + "line number: "
+ + parser.getLineNumber());
+ }
+
+ // If the parser has reached the closing tag for the Input Gesture, break out.
+ if (type == XmlPullParser.END_TAG && parser.getName().equals(TAG_INPUT_GESTURE)) {
+ break;
+ }
+
+ final String tag = parser.getName();
+ if (type == XmlPullParser.START_TAG && TAG_KEY_TRIGGER.equals(tag)) {
+ builder.setTrigger(InputGestureData.createKeyTrigger(
+ parser.getAttributeInt(null, ATTR_KEY_TRIGGER_KEYCODE),
+ parser.getAttributeInt(null, ATTR_KEY_TRIGGER_MODIFIER_STATE)));
+ } else if (type == XmlPullParser.START_TAG && TAG_TOUCHPAD_TRIGGER.equals(tag)) {
+ builder.setTrigger(
+ InputGestureData.createTouchpadTrigger(parser.getAttributeInt(null,
+ ATTR_TOUCHPAD_TRIGGER_GESTURE_TYPE)));
+ }
+ }
+ return builder.build();
+ }
+
+ private List readInputGestureListFromXml(TypedXmlPullParser parser) throws
+ XmlPullParserException, IOException {
+ List inputGestureDataList = new ArrayList<>();
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ // If the parser has left the initial scope when it was called, break out.
+ if (outerDepth > parser.getDepth()) {
+ throw new RuntimeException(
+ "Parser has left the initial scope of the tag that was being parsed on "
+ + "line number: "
+ + parser.getLineNumber());
+ }
+
+ // If the parser has reached the closing tag for the Input Gesture List, break out.
+ if (type == XmlPullParser.END_TAG && parser.getName().equals(TAG_INPUT_GESTURE_LIST)) {
+ break;
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ final String tag = parser.getName();
+ if (TAG_INPUT_GESTURE.equals(tag)) {
+ try {
+ inputGestureDataList.add(readInputGestureFromXml(parser));
+ } catch (IllegalArgumentException exception) {
+ Slog.w(TAG, "Invalid parameters for input gesture data: ", exception);
+ continue;
+ }
+ }
+ }
+ return inputGestureDataList;
+ }
+
+ @VisibleForTesting
+ void writeInputGestureXml(OutputStream stream, boolean utf8Encoded,
+ List inputGestureDataList) throws IOException {
+ final TypedXmlSerializer serializer;
+ if (utf8Encoded) {
+ serializer = Xml.newFastSerializer();
+ serializer.setOutput(stream, StandardCharsets.UTF_8.name());
+ } else {
+ serializer = Xml.resolveSerializer(stream);
+ }
+
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_ROOT);
+ writeInputGestureListToXml(serializer, inputGestureDataList);
+ serializer.endTag(null, TAG_ROOT);
+ serializer.endDocument();
+ }
+
+ private void writeInputGestureToXml(TypedXmlSerializer serializer,
+ InputGestureData inputGestureData) throws IOException {
+ // TODO(b/365064144): Implement storage of AppLaunch data.
+ if (inputGestureData.getAction().appLaunchData() != null) {
+ return;
+ }
+
+ serializer.startTag(null, TAG_INPUT_GESTURE);
+ serializer.attributeInt(null, ATTR_KEY_GESTURE_TYPE,
+ inputGestureData.getAction().keyGestureType());
+
+ final InputGestureData.Trigger trigger = inputGestureData.getTrigger();
+ if (trigger instanceof InputGestureData.KeyTrigger keyTrigger) {
+ serializer.startTag(null, TAG_KEY_TRIGGER);
+ serializer.attributeInt(null, ATTR_KEY_TRIGGER_KEYCODE, keyTrigger.getKeycode());
+ serializer.attributeInt(null, ATTR_KEY_TRIGGER_MODIFIER_STATE,
+ keyTrigger.getModifierState());
+ serializer.endTag(null, TAG_KEY_TRIGGER);
+ } else if (trigger instanceof InputGestureData.TouchpadTrigger touchpadTrigger) {
+ serializer.startTag(null, TAG_TOUCHPAD_TRIGGER);
+ serializer.attributeInt(null, ATTR_TOUCHPAD_TRIGGER_GESTURE_TYPE,
+ touchpadTrigger.getTouchpadGestureType());
+ serializer.endTag(null, TAG_TOUCHPAD_TRIGGER);
+ }
+
+ serializer.endTag(null, TAG_INPUT_GESTURE);
+ }
+
+ private void writeInputGestureListToXml(TypedXmlSerializer serializer,
+ List inputGestureDataList) throws IOException {
+ serializer.startTag(null, TAG_INPUT_GESTURE_LIST);
+ for (final InputGestureData inputGestureData : inputGestureDataList) {
+ writeInputGestureToXml(serializer, inputGestureData);
+ }
+ serializer.endTag(null, TAG_INPUT_GESTURE_LIST);
+ }
+
+ @VisibleForTesting
+ static class FileInjector {
+ private final SparseArray mAtomicFileMap = new SparseArray<>();
+ private final String mFileName;
+
+ FileInjector(String fileName) {
+ mFileName = fileName;
+ }
+
+ InputStream openRead(int userId) throws FileNotFoundException {
+ return getAtomicFileForUserId(userId).openRead();
+ }
+
+ FileOutputStream startWrite(int userId) throws IOException {
+ return getAtomicFileForUserId(userId).startWrite();
+ }
+
+ void finishWrite(int userId, FileOutputStream os, boolean success) {
+ if (success) {
+ getAtomicFileForUserId(userId).finishWrite(os);
+ } else {
+ getAtomicFileForUserId(userId).failWrite(os);
+ }
+ }
+
+ AtomicFile getAtomicFileForUserId(int userId) {
+ if (!mAtomicFileMap.contains(userId)) {
+ mAtomicFileMap.put(userId, new AtomicFile(new File(
+ Environment.buildPath(Environment.getDataSystemDeDirectory(userId),
+ INPUT_MANAGER_DIRECTORY), mFileName)));
+ }
+ return mAtomicFileMap.get(userId);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 1adf1c99024a..251f345224a2 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -351,6 +351,9 @@ public class InputManagerService extends IInputManager.Stub
// Manages loading PointerIcons
private final PointerIconCache mPointerIconCache;
+ // Manages storage and retrieval of input data.
+ private final InputDataStore mInputDataStore;
+
// Maximum number of milliseconds to wait for input event injection.
private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
@@ -502,7 +505,9 @@ public class InputManagerService extends IInputManager.Stub
injector.getUEventManager());
mKeyboardBacklightController = injector.getKeyboardBacklightController(mNative, mDataStore);
mStickyModifierStateController = new StickyModifierStateController();
- mKeyGestureController = new KeyGestureController(mContext, injector.getLooper());
+ mInputDataStore = new InputDataStore();
+ mKeyGestureController = new KeyGestureController(mContext, injector.getLooper(),
+ mInputDataStore);
mKeyboardLedController = new KeyboardLedController(mContext, injector.getLooper(),
mNative);
mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
diff --git a/services/core/java/com/android/server/input/KeyGestureController.java b/services/core/java/com/android/server/input/KeyGestureController.java
index 55d2de2b6865..99c01ce5c15a 100644
--- a/services/core/java/com/android/server/input/KeyGestureController.java
+++ b/services/core/java/com/android/server/input/KeyGestureController.java
@@ -92,6 +92,8 @@ final class KeyGestureController {
| KeyEvent.META_SHIFT_ON;
private static final int MSG_NOTIFY_KEY_GESTURE_EVENT = 1;
+ private static final int MSG_PERSIST_CUSTOM_GESTURES = 2;
+ private static final int MSG_LOAD_CUSTOM_GESTURES = 3;
// must match: config_settingsKeyBehavior in config.xml
private static final int SETTINGS_KEY_BEHAVIOR_SETTINGS_ACTIVITY = 0;
@@ -116,6 +118,8 @@ final class KeyGestureController {
private final SettingsObserver mSettingsObserver;
private final AppLaunchShortcutManager mAppLaunchShortcutManager;
private final InputGestureManager mInputGestureManager;
+ @GuardedBy("mInputDataStore")
+ private final InputDataStore mInputDataStore;
private static final Object mUserLock = new Object();
@UserIdInt
@GuardedBy("mUserLock")
@@ -155,7 +159,7 @@ final class KeyGestureController {
/** Currently fully consumed key codes per device */
private final SparseArray> mConsumedKeysForDevice = new SparseArray<>();
- KeyGestureController(Context context, Looper looper) {
+ KeyGestureController(Context context, Looper looper, InputDataStore inputDataStore) {
mContext = context;
mHandler = new Handler(looper, this::handleMessage);
mSystemPid = Process.myPid();
@@ -175,6 +179,7 @@ final class KeyGestureController {
mSettingsObserver = new SettingsObserver(mHandler);
mAppLaunchShortcutManager = new AppLaunchShortcutManager(mContext);
mInputGestureManager = new InputGestureManager(mContext);
+ mInputDataStore = inputDataStore;
initBehaviors();
initKeyCombinationRules();
}
@@ -434,6 +439,13 @@ final class KeyGestureController {
mSettingsObserver.observe();
mAppLaunchShortcutManager.systemRunning();
mInputGestureManager.systemRunning();
+
+ int userId;
+ synchronized (mUserLock) {
+ userId = mCurrentUserId;
+ }
+ // Load the system user's input gestures.
+ mHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget();
}
public boolean interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
@@ -955,6 +967,7 @@ final class KeyGestureController {
synchronized (mUserLock) {
mCurrentUserId = userId;
}
+ mHandler.obtainMessage(MSG_LOAD_CUSTOM_GESTURES, userId).sendToTarget();
}
@MainThread
@@ -995,6 +1008,17 @@ final class KeyGestureController {
AidlKeyGestureEvent event = (AidlKeyGestureEvent) msg.obj;
notifyKeyGestureEvent(event);
break;
+ case MSG_PERSIST_CUSTOM_GESTURES: {
+ final int userId = (Integer) msg.obj;
+ persistInputGestures(userId);
+ break;
+ }
+ case MSG_LOAD_CUSTOM_GESTURES: {
+ final int userId = (Integer) msg.obj;
+ loadInputGestures(userId);
+ break;
+ }
+
}
return true;
}
@@ -1040,22 +1064,31 @@ final class KeyGestureController {
@InputManager.CustomInputGestureResult
public int addCustomInputGesture(@UserIdInt int userId,
@NonNull AidlInputGestureData inputGestureData) {
- return mInputGestureManager.addCustomInputGesture(userId,
+ final int result = mInputGestureManager.addCustomInputGesture(userId,
new InputGestureData(inputGestureData));
+ if (result == InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) {
+ mHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget();
+ }
+ return result;
}
@BinderThread
@InputManager.CustomInputGestureResult
public int removeCustomInputGesture(@UserIdInt int userId,
@NonNull AidlInputGestureData inputGestureData) {
- return mInputGestureManager.removeCustomInputGesture(userId,
+ final int result = mInputGestureManager.removeCustomInputGesture(userId,
new InputGestureData(inputGestureData));
+ if (result == InputManager.CUSTOM_INPUT_GESTURE_RESULT_SUCCESS) {
+ mHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget();
+ }
+ return result;
}
@BinderThread
public void removeAllCustomInputGestures(@UserIdInt int userId,
@Nullable InputGestureData.Filter filter) {
mInputGestureManager.removeAllCustomInputGestures(userId, filter);
+ mHandler.obtainMessage(MSG_PERSIST_CUSTOM_GESTURES, userId).sendToTarget();
}
@BinderThread
@@ -1166,6 +1199,26 @@ final class KeyGestureController {
}
}
+ private void persistInputGestures(int userId) {
+ synchronized (mInputDataStore) {
+ final List inputGestureDataList =
+ mInputGestureManager.getCustomInputGestures(userId,
+ null);
+ mInputDataStore.saveInputGestures(userId, inputGestureDataList);
+ }
+ }
+
+ private void loadInputGestures(int userId) {
+ synchronized (mInputDataStore) {
+ mInputGestureManager.removeAllCustomInputGestures(userId, null);
+ final List inputGestureDataList = mInputDataStore.loadInputGestures(
+ userId);
+ for (final InputGestureData inputGestureData : inputGestureDataList) {
+ mInputGestureManager.addCustomInputGesture(userId, inputGestureData);
+ }
+ }
+ }
+
// A record of a registered key gesture event listener from one process.
private class KeyGestureHandlerRecord implements IBinder.DeathRecipient {
public final int mPid;
diff --git a/tests/Input/src/com/android/server/input/InputDataStoreTests.kt b/tests/Input/src/com/android/server/input/InputDataStoreTests.kt
new file mode 100644
index 000000000000..1e96e439e251
--- /dev/null
+++ b/tests/Input/src/com/android/server/input/InputDataStoreTests.kt
@@ -0,0 +1,444 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.hardware.input.InputGestureData
+import android.hardware.input.KeyGestureEvent
+import android.platform.test.annotations.Presubmit
+import android.util.AtomicFile
+import android.view.KeyEvent
+import androidx.test.core.app.ApplicationProvider
+import java.io.ByteArrayInputStream
+import java.io.ByteArrayOutputStream
+import java.io.File
+import java.io.FileOutputStream
+import java.io.InputStream
+import java.nio.charset.StandardCharsets
+import kotlin.test.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito
+
+/**
+ * Tests for {@link InputDataStore}.
+ *
+ * Build/Install/Run:
+ * atest InputTests:InputDataStoreTests
+ */
+@Presubmit
+class InputDataStoreTests {
+
+ companion object {
+ const val USER_ID = 1
+ }
+
+ private lateinit var context: Context
+ private lateinit var inputDataStore: InputDataStore
+ private lateinit var tempFile: File
+
+ @Before
+ fun setup() {
+ context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
+ setupInputDataStore()
+ }
+
+ private fun setupInputDataStore() {
+ tempFile = File.createTempFile("input_gestures", ".xml")
+ inputDataStore = InputDataStore(object : InputDataStore.FileInjector("input_gestures") {
+ private val atomicFile: AtomicFile = AtomicFile(tempFile)
+
+ override fun openRead(userId: Int): InputStream? {
+ return atomicFile.openRead()
+ }
+
+ override fun startWrite(userId: Int): FileOutputStream? {
+ return atomicFile.startWrite()
+ }
+
+ override fun finishWrite(userId: Int, fos: FileOutputStream?, success: Boolean) {
+ if (success) {
+ atomicFile.finishWrite(fos)
+ } else {
+ atomicFile.failWrite(fos)
+ }
+ }
+ })
+ }
+
+ private fun getPrintableXml(inputGestures: List): String {
+ val outputStream = ByteArrayOutputStream()
+ inputDataStore.writeInputGestureXml(outputStream, true, inputGestures)
+ return outputStream.toString(StandardCharsets.UTF_8).trimIndent()
+ }
+
+ @Test
+ fun saveToDiskKeyGesturesOnly() {
+ val inputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_H,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_1,
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_2,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+ .build()
+ )
+
+ inputDataStore.saveInputGestures(USER_ID, inputGestures)
+ assertEquals(
+ inputGestures,
+ inputDataStore.loadInputGestures(USER_ID),
+ getPrintableXml(inputGestures)
+ )
+ }
+
+ @Test
+ fun saveToDiskTouchpadGestures() {
+ val inputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createTouchpadTrigger(
+ InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build()
+ )
+
+ inputDataStore.saveInputGestures(USER_ID, inputGestures)
+ assertEquals(
+ inputGestures,
+ inputDataStore.loadInputGestures(USER_ID),
+ getPrintableXml(inputGestures)
+ )
+ }
+
+ @Test
+ fun saveToDiskCombineGestures() {
+ val inputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_1,
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_2,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createTouchpadTrigger(
+ InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build()
+ )
+
+ inputDataStore.saveInputGestures(USER_ID, inputGestures)
+ assertEquals(
+ inputGestures,
+ inputDataStore.loadInputGestures(USER_ID),
+ getPrintableXml(inputGestures)
+ )
+ }
+
+ @Test
+ fun validXmlParse() {
+ val xmlData = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """.trimIndent()
+ val validInputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_1,
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_2,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createTouchpadTrigger(
+ InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build()
+ )
+ val inputStream = ByteArrayInputStream(xmlData.toByteArray(Charsets.UTF_8))
+ assertEquals(
+ validInputGestures,
+ inputDataStore.readInputGesturesXml(inputStream, true)
+ )
+ }
+
+ @Test
+ fun missingTriggerData() {
+ val xmlData = """
+
+
+
+
+
+
+
+
+
+
+
+
+ """.trimIndent()
+ val validInputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_2,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createTouchpadTrigger(
+ InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build()
+ )
+ val inputStream = ByteArrayInputStream(xmlData.toByteArray(Charsets.UTF_8))
+ assertEquals(
+ validInputGestures,
+ inputDataStore.readInputGesturesXml(inputStream, true)
+ )
+ }
+
+ @Test
+ fun invalidKeycode() {
+ val xmlData = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """.trimIndent()
+ val validInputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_1,
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createTouchpadTrigger(
+ InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
+ .build()
+ )
+ val inputStream = ByteArrayInputStream(xmlData.toByteArray(Charsets.UTF_8))
+ assertEquals(
+ validInputGestures,
+ inputDataStore.readInputGesturesXml(inputStream, true)
+ )
+ }
+
+ @Test
+ fun invalidTriggerName() {
+ val xmlData = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """.trimIndent()
+ val validInputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_1,
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_2,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+ .build(),
+ )
+ val inputStream = ByteArrayInputStream(xmlData.toByteArray(Charsets.UTF_8))
+ assertEquals(
+ validInputGestures,
+ inputDataStore.readInputGesturesXml(inputStream, true)
+ )
+ }
+
+ @Test
+ fun invalidTouchpadGestureType() {
+ val xmlData = """
+
+
+
+
+
+
+
+
+
+
+
+
+
+ """.trimIndent()
+ val validInputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_1,
+ KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_BACK)
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_2,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_ALL_APPS)
+ .build(),
+ )
+ val inputStream = ByteArrayInputStream(xmlData.toByteArray(Charsets.UTF_8))
+ assertEquals(
+ validInputGestures,
+ inputDataStore.readInputGesturesXml(inputStream, true)
+ )
+ }
+
+ @Test
+ fun emptyInputGestureList() {
+ val xmlData = """
+
+
+
+
+ """.trimIndent()
+ val inputStream = ByteArrayInputStream(xmlData.toByteArray(Charsets.UTF_8))
+ assertEquals(
+ listOf(),
+ inputDataStore.readInputGesturesXml(inputStream, true)
+ )
+ }
+
+ @Test
+ fun invalidTag() {
+ val xmlData = """
+
+
+
+
+ """.trimIndent()
+ val inputStream = ByteArrayInputStream(xmlData.toByteArray(Charsets.UTF_8))
+ assertEquals(
+ listOf(),
+ inputDataStore.readInputGesturesXml(inputStream, true)
+ )
+ }
+}
\ No newline at end of file
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index 36a89f95aa6f..a8bb0db9cbcd 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -40,6 +40,7 @@ import android.os.test.TestLooper
import android.platform.test.annotations.EnableFlags
import android.platform.test.annotations.Presubmit
import android.platform.test.flag.junit.SetFlagsRule
+import android.util.AtomicFile
import android.view.InputDevice
import android.view.KeyCharacterMap
import android.view.KeyEvent
@@ -50,6 +51,9 @@ import com.android.internal.R
import com.android.internal.annotations.Keep
import com.android.internal.util.FrameworkStatsLog
import com.android.modules.utils.testing.ExtendedMockitoRule
+import java.io.File
+import java.io.FileOutputStream
+import java.io.InputStream
import junitparams.JUnitParamsRunner
import junitparams.Parameters
import org.junit.After
@@ -123,6 +127,8 @@ class KeyGestureControllerTests {
private lateinit var keyGestureController: KeyGestureController
private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession
private lateinit var testLooper: TestLooper
+ private lateinit var tempFile: File
+ private lateinit var inputDataStore: InputDataStore
private var events = mutableListOf()
@Before
@@ -133,6 +139,31 @@ class KeyGestureControllerTests {
setupBehaviors()
testLooper = TestLooper()
currentPid = Process.myPid()
+ tempFile = File.createTempFile("input_gestures", ".xml")
+ inputDataStore =
+ InputDataStore(object : InputDataStore.FileInjector("input_gestures.xml") {
+ private val atomicFile: AtomicFile = AtomicFile(tempFile)
+
+ override fun openRead(userId: Int): InputStream? {
+ return atomicFile.openRead()
+ }
+
+ override fun startWrite(userId: Int): FileOutputStream? {
+ return atomicFile.startWrite()
+ }
+
+ override fun finishWrite(userId: Int, fos: FileOutputStream?, success: Boolean) {
+ if (success) {
+ atomicFile.finishWrite(fos)
+ } else {
+ atomicFile.failWrite(fos)
+ }
+ }
+
+ override fun getAtomicFileForUserId(userId: Int): AtomicFile {
+ return atomicFile
+ }
+ })
}
@After
@@ -174,10 +205,12 @@ class KeyGestureControllerTests {
}
private fun setupKeyGestureController() {
- keyGestureController = KeyGestureController(context, testLooper.looper)
+ keyGestureController =
+ KeyGestureController(context, testLooper.looper, inputDataStore)
Mockito.`when`(iInputManager.getAppLaunchBookmarks())
.thenReturn(keyGestureController.appLaunchBookmarks)
keyGestureController.systemRunning()
+ testLooper.dispatchAll()
}
private fun notifyHomeGestureCompleted() {
@@ -1424,6 +1457,47 @@ class KeyGestureControllerTests {
testKeyGestureInternal(test)
}
+ @Test
+ @Parameters(method = "customInputGesturesTestArguments")
+ fun testCustomKeyGesturesSavedAndLoadedByController(test: TestData) {
+ // TODO(b/365064144): Implement storage of AppLaunch data.
+ if (test.expectedAppLaunchData != null) {
+ return
+ }
+
+ val userId = 10
+ setupKeyGestureController()
+ val builder = InputGestureData.Builder()
+ .setKeyGestureType(test.expectedKeyGestureType)
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ test.expectedKeys[0],
+ test.expectedModifierState
+ )
+ )
+ val inputGestureData = builder.build()
+
+ keyGestureController.setCurrentUserId(userId)
+ testLooper.dispatchAll()
+ keyGestureController.addCustomInputGesture(userId, inputGestureData.aidlData)
+ testLooper.dispatchAll()
+
+ // Reinitialize the gesture controller simulating a login/logout for the user.
+ setupKeyGestureController()
+ keyGestureController.setCurrentUserId(userId)
+ testLooper.dispatchAll()
+ val savedInputGestures = keyGestureController.getCustomInputGestures(userId, null)
+ assertEquals(
+ "Test: $test doesn't produce correct number of saved input gestures",
+ 1,
+ savedInputGestures.size
+ )
+ assertEquals(
+ "Test: $test doesn't produce correct input gesture data", inputGestureData,
+ InputGestureData(savedInputGestures[0])
+ )
+ }
+
class TouchpadTestData(
val name: String,
val touchpadGestureType: Int,
@@ -1502,6 +1576,41 @@ class KeyGestureControllerTests {
keyGestureController.unregisterKeyGestureHandler(handler, 0)
}
+ @Test
+ @Parameters(method = "customTouchpadGesturesTestArguments")
+ fun testCustomTouchpadGesturesSavedAndLoadedByController(test: TouchpadTestData) {
+ // TODO(b/365064144): Implement storage of AppLaunch data.
+ if (test.expectedAppLaunchData != null) {
+ return
+ }
+
+ val userId = 10
+ setupKeyGestureController()
+ val builder = InputGestureData.Builder()
+ .setKeyGestureType(test.expectedKeyGestureType)
+ .setTrigger(InputGestureData.createTouchpadTrigger(test.touchpadGestureType))
+ val inputGestureData = builder.build()
+ keyGestureController.setCurrentUserId(userId)
+ testLooper.dispatchAll()
+ keyGestureController.addCustomInputGesture(userId, inputGestureData.aidlData)
+ testLooper.dispatchAll()
+
+ // Reinitialize the gesture controller simulating a login/logout for the user.
+ setupKeyGestureController()
+ keyGestureController.setCurrentUserId(userId)
+ testLooper.dispatchAll()
+ val savedInputGestures = keyGestureController.getCustomInputGestures(userId, null)
+ assertEquals(
+ "Test: $test doesn't produce correct number of saved input gestures",
+ 1,
+ savedInputGestures.size
+ )
+ assertEquals(
+ "Test: $test doesn't produce correct input gesture data", inputGestureData,
+ InputGestureData(savedInputGestures[0])
+ )
+ }
+
private fun testKeyGestureInternal(test: TestData) {
val handledEvents = mutableListOf()
val handler = KeyGestureHandler { event, _ ->
--
GitLab
From 13bc56e04dc169df9fddb475575a4fcb598c0c3b Mon Sep 17 00:00:00 2001
From: David Padlipsky
Date: Fri, 22 Nov 2024 01:19:01 +0000
Subject: [PATCH 199/652] Implement AppLaunchData persistance for input
gestures
Adds support for persisting AppLaunchData for custom input gestures.
Test: atest InputTests:InputDataStoreTests
Bug: 365064144
Flag: com.android.hardware.input.enable_customizable_input_gestures
Change-Id: I1cfed974485077096ba5c3feac5b1b8ea07a8c47
---
.../android/server/input/InputDataStore.java | 55 +++++++++++++---
.../server/input/InputDataStoreTests.kt | 64 ++++++++++++++++++-
.../server/input/KeyGestureControllerTests.kt | 16 ++---
3 files changed, 113 insertions(+), 22 deletions(-)
diff --git a/services/core/java/com/android/server/input/InputDataStore.java b/services/core/java/com/android/server/input/InputDataStore.java
index bfed69543265..e8f21fe8fb74 100644
--- a/services/core/java/com/android/server/input/InputDataStore.java
+++ b/services/core/java/com/android/server/input/InputDataStore.java
@@ -16,6 +16,7 @@
package com.android.server.input;
+import android.hardware.input.AppLaunchData;
import android.hardware.input.InputGestureData;
import android.os.Environment;
import android.util.AtomicFile;
@@ -55,11 +56,16 @@ public final class InputDataStore {
private static final String TAG_INPUT_GESTURE = "input_gesture";
private static final String TAG_KEY_TRIGGER = "key_trigger";
private static final String TAG_TOUCHPAD_TRIGGER = "touchpad_trigger";
+ private static final String TAG_APP_LAUNCH_DATA = "app_launch_data";
private static final String ATTR_KEY_TRIGGER_KEYCODE = "keycode";
private static final String ATTR_KEY_TRIGGER_MODIFIER_STATE = "modifiers";
private static final String ATTR_KEY_GESTURE_TYPE = "key_gesture_type";
private static final String ATTR_TOUCHPAD_TRIGGER_GESTURE_TYPE = "touchpad_gesture_type";
+ private static final String ATTR_APP_LAUNCH_DATA_CATEGORY = "category";
+ private static final String ATTR_APP_LAUNCH_DATA_ROLE = "role";
+ private static final String ATTR_APP_LAUNCH_DATA_PACKAGE_NAME = "package_name";
+ private static final String ATTR_APP_LAUNCH_DATA_CLASS_NAME = "class_name";
private final FileInjector mInputGestureFileInjector;
@@ -167,15 +173,31 @@ public final class InputDataStore {
break;
}
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
final String tag = parser.getName();
- if (type == XmlPullParser.START_TAG && TAG_KEY_TRIGGER.equals(tag)) {
+ if (TAG_KEY_TRIGGER.equals(tag)) {
builder.setTrigger(InputGestureData.createKeyTrigger(
parser.getAttributeInt(null, ATTR_KEY_TRIGGER_KEYCODE),
parser.getAttributeInt(null, ATTR_KEY_TRIGGER_MODIFIER_STATE)));
- } else if (type == XmlPullParser.START_TAG && TAG_TOUCHPAD_TRIGGER.equals(tag)) {
- builder.setTrigger(
- InputGestureData.createTouchpadTrigger(parser.getAttributeInt(null,
- ATTR_TOUCHPAD_TRIGGER_GESTURE_TYPE)));
+ } else if (TAG_TOUCHPAD_TRIGGER.equals(tag)) {
+ builder.setTrigger(InputGestureData.createTouchpadTrigger(
+ parser.getAttributeInt(null, ATTR_TOUCHPAD_TRIGGER_GESTURE_TYPE)));
+ } else if (TAG_APP_LAUNCH_DATA.equals(tag)) {
+ final String roleValue = parser.getAttributeValue(null, ATTR_APP_LAUNCH_DATA_ROLE);
+ final String categoryValue = parser.getAttributeValue(null,
+ ATTR_APP_LAUNCH_DATA_CATEGORY);
+ final String classNameValue = parser.getAttributeValue(null,
+ ATTR_APP_LAUNCH_DATA_CLASS_NAME);
+ final String packageNameValue = parser.getAttributeValue(null,
+ ATTR_APP_LAUNCH_DATA_PACKAGE_NAME);
+ final AppLaunchData appLaunchData = AppLaunchData.createLaunchData(categoryValue,
+ roleValue, packageNameValue, classNameValue);
+ if (appLaunchData != null) {
+ builder.setAppLaunchData(appLaunchData);
+ }
}
}
return builder.build();
@@ -237,11 +259,6 @@ public final class InputDataStore {
private void writeInputGestureToXml(TypedXmlSerializer serializer,
InputGestureData inputGestureData) throws IOException {
- // TODO(b/365064144): Implement storage of AppLaunch data.
- if (inputGestureData.getAction().appLaunchData() != null) {
- return;
- }
-
serializer.startTag(null, TAG_INPUT_GESTURE);
serializer.attributeInt(null, ATTR_KEY_GESTURE_TYPE,
inputGestureData.getAction().keyGestureType());
@@ -260,6 +277,24 @@ public final class InputDataStore {
serializer.endTag(null, TAG_TOUCHPAD_TRIGGER);
}
+ if (inputGestureData.getAction().appLaunchData() != null) {
+ serializer.startTag(null, TAG_APP_LAUNCH_DATA);
+ final AppLaunchData appLaunchData = inputGestureData.getAction().appLaunchData();
+ if (appLaunchData instanceof AppLaunchData.RoleData roleData) {
+ serializer.attribute(null, ATTR_APP_LAUNCH_DATA_ROLE, roleData.getRole());
+ } else if (appLaunchData
+ instanceof AppLaunchData.CategoryData categoryData) {
+ serializer.attribute(null, ATTR_APP_LAUNCH_DATA_CATEGORY,
+ categoryData.getCategory());
+ } else if (appLaunchData instanceof AppLaunchData.ComponentData componentData) {
+ serializer.attribute(null, ATTR_APP_LAUNCH_DATA_PACKAGE_NAME,
+ componentData.getPackageName());
+ serializer.attribute(null, ATTR_APP_LAUNCH_DATA_CLASS_NAME,
+ componentData.getClassName());
+ }
+ serializer.endTag(null, TAG_APP_LAUNCH_DATA);
+ }
+
serializer.endTag(null, TAG_INPUT_GESTURE);
}
diff --git a/tests/Input/src/com/android/server/input/InputDataStoreTests.kt b/tests/Input/src/com/android/server/input/InputDataStoreTests.kt
index 1e96e439e251..78c828bafd8f 100644
--- a/tests/Input/src/com/android/server/input/InputDataStoreTests.kt
+++ b/tests/Input/src/com/android/server/input/InputDataStoreTests.kt
@@ -16,8 +16,11 @@
package com.android.server.input
+import android.app.role.RoleManager
import android.content.Context
import android.content.ContextWrapper
+import android.content.Intent
+import android.hardware.input.AppLaunchData
import android.hardware.input.InputGestureData
import android.hardware.input.KeyGestureEvent
import android.platform.test.annotations.Presubmit
@@ -149,7 +152,54 @@ class InputDataStoreTests {
}
@Test
- fun saveToDiskCombineGestures() {
+ fun saveToDiskAppLaunchGestures() {
+ val inputGestures = listOf(
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createTouchpadTrigger(
+ InputGestureData.TOUCHPAD_GESTURE_TYPE_THREE_FINGER_TAP
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION)
+ .setAppLaunchData(AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER))
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_2,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION)
+ .setAppLaunchData(AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS))
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_1,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION)
+ .setAppLaunchData(
+ AppLaunchData.createLaunchDataForComponent(
+ "com.test",
+ "com.test.BookmarkTest"
+ )
+ )
+ .build()
+ )
+
+ inputDataStore.saveInputGestures(USER_ID, inputGestures)
+ assertEquals(
+ inputGestures,
+ inputDataStore.loadInputGestures(USER_ID),
+ getPrintableXml(inputGestures)
+ )
+ }
+
+ @Test
+ fun saveToDiskCombinedGestures() {
val inputGestures = listOf(
InputGestureData.Builder()
.setTrigger(
@@ -176,7 +226,17 @@ class InputDataStoreTests {
)
)
.setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
- .build()
+ .build(),
+ InputGestureData.Builder()
+ .setTrigger(
+ InputGestureData.createKeyTrigger(
+ KeyEvent.KEYCODE_9,
+ KeyEvent.META_META_ON
+ )
+ )
+ .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION)
+ .setAppLaunchData(AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS))
+ .build(),
)
inputDataStore.saveInputGestures(USER_ID, inputGestures)
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index a8bb0db9cbcd..c6d281914f2c 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -1460,11 +1460,6 @@ class KeyGestureControllerTests {
@Test
@Parameters(method = "customInputGesturesTestArguments")
fun testCustomKeyGesturesSavedAndLoadedByController(test: TestData) {
- // TODO(b/365064144): Implement storage of AppLaunch data.
- if (test.expectedAppLaunchData != null) {
- return
- }
-
val userId = 10
setupKeyGestureController()
val builder = InputGestureData.Builder()
@@ -1475,6 +1470,9 @@ class KeyGestureControllerTests {
test.expectedModifierState
)
)
+ if (test.expectedAppLaunchData != null) {
+ builder.setAppLaunchData(test.expectedAppLaunchData)
+ }
val inputGestureData = builder.build()
keyGestureController.setCurrentUserId(userId)
@@ -1579,16 +1577,14 @@ class KeyGestureControllerTests {
@Test
@Parameters(method = "customTouchpadGesturesTestArguments")
fun testCustomTouchpadGesturesSavedAndLoadedByController(test: TouchpadTestData) {
- // TODO(b/365064144): Implement storage of AppLaunch data.
- if (test.expectedAppLaunchData != null) {
- return
- }
-
val userId = 10
setupKeyGestureController()
val builder = InputGestureData.Builder()
.setKeyGestureType(test.expectedKeyGestureType)
.setTrigger(InputGestureData.createTouchpadTrigger(test.touchpadGestureType))
+ if (test.expectedAppLaunchData != null) {
+ builder.setAppLaunchData(test.expectedAppLaunchData)
+ }
val inputGestureData = builder.build()
keyGestureController.setCurrentUserId(userId)
testLooper.dispatchAll()
--
GitLab
From 229d3a9e05404306bf748c4866e0fedb15ac77d2 Mon Sep 17 00:00:00 2001
From: John Wu
Date: Mon, 2 Dec 2024 21:27:00 +0000
Subject: [PATCH 200/652] [Ravenwood] Remove usage of
RavenwoodFlagsValueProvider
Flag: EXEMPT host test change only
Bug: 379740361
Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh
Change-Id: Ib6aba3c972ffa26ccb282ce55908cf165bb5068c
---
.../content/res/FontScaleConverterFactoryTest.kt | 13 +------------
.../android/content/res/ResourcesManagerTest.java | 10 +---------
2 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index c0a9bc2cdd24..f9d449cd3b10 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -18,10 +18,7 @@ package android.content.res
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresFlagsEnabled
-import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
-import android.platform.test.flag.junit.RavenwoodFlagsValueProvider
-import android.platform.test.ravenwood.RavenwoodRule
import android.util.SparseArray
import androidx.core.util.forEach
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -47,15 +44,7 @@ import org.junit.runner.RunWith
class FontScaleConverterFactoryTest {
@get:Rule
- val ravenwoodRule: RavenwoodRule = RavenwoodRule.Builder().build()
-
- @get:Rule
- val checkFlagsRule: CheckFlagsRule =
- if (RavenwoodRule.isOnRavenwood()) {
- RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
- } else {
- DeviceFlagsValueProvider.createCheckFlagsRule()
- }
+ val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
private var defaultLookupTables: SparseArray? = null
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index be8ecbe66791..cfcd53e14c79 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -33,8 +33,6 @@ import android.platform.test.annotations.Postsubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-import android.platform.test.flag.junit.RavenwoodFlagsValueProvider;
-import android.platform.test.ravenwood.RavenwoodRule;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -65,13 +63,7 @@ public class ResourcesManagerTest {
private static final String TEST_LIB = "com.android.frameworks.coretests.bdr_helper_app1";
@Rule
- public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder().build();
-
- @Rule
- public final CheckFlagsRule mCheckFlagsRule =
- RavenwoodRule.isOnRavenwood()
- ? RavenwoodFlagsValueProvider.createAllOnCheckFlagsRule()
- : DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private ResourcesManager mResourcesManager;
private Map mDisplayMetricsMap;
--
GitLab
From eb467cbd4e4e836a9621728c9016515ee7d816cb Mon Sep 17 00:00:00 2001
From: mattsziklay
Date: Thu, 21 Nov 2024 14:19:22 -0800
Subject: [PATCH 201/652] Update openInstance logic.
Utilizes existing task opening logic in DesktopTasksController for
openInstance, preventing issues with freeform task launches.
Bug: 380183384
Bug: 374341889
Test: Manual
Flag: EXEMPT bugfix
Change-Id: Icbedf07391d1e2824e3f635b2eed9efb24a2fbd6
---
.../desktopmode/DesktopTasksController.kt | 30 +++++---------
.../desktopmode/DesktopTasksControllerTest.kt | 41 +++++++++----------
2 files changed, 31 insertions(+), 40 deletions(-)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index a94a40bc39f8..2e5cab2ef13f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -1505,28 +1505,20 @@ class DesktopTasksController(
/** Open an existing instance of an app. */
fun openInstance(callingTask: RunningTaskInfo, requestedTaskId: Int) {
- val wct = WindowContainerTransaction()
- val options = createNewWindowOptions(callingTask)
- if (options.launchWindowingMode == WINDOWING_MODE_FREEFORM) {
- wct.startTask(requestedTaskId, options.toBundle())
- val taskIdToMinimize =
- bringDesktopAppsToFrontBeforeShowingNewTask(
- callingTask.displayId,
- wct,
+ if (callingTask.isFreeform) {
+ val requestedTaskInfo = shellTaskOrganizer.getRunningTaskInfo(requestedTaskId)
+ if (requestedTaskInfo?.isFreeform == true) {
+ // If requested task is an already open freeform task, just move it to front.
+ moveTaskToFront(requestedTaskId)
+ } else {
+ moveBackgroundTaskToDesktop(
requestedTaskId,
+ WindowContainerTransaction(),
+ DesktopModeTransitionSource.APP_HANDLE_MENU_BUTTON,
)
- val exitResult =
- desktopImmersiveController.exitImmersiveIfApplicable(
- wct = wct,
- displayId = callingTask.displayId,
- excludeTaskId = requestedTaskId,
- reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
- )
- val transition = transitions.startTransition(TRANSIT_OPEN, wct, null)
- taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
- addPendingAppLaunchTransition(transition, requestedTaskId, taskIdToMinimize)
- exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
+ }
} else {
+ val options = createNewWindowOptions(callingTask)
val splitPosition = splitScreenController.determineNewInstancePosition(callingTask)
splitScreenController.startTask(
requestedTaskId,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index c10434aa6d6f..8e210719dbd0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -3305,44 +3305,41 @@ class DesktopTasksControllerTest : ShellTestCase() {
setUpLandscapeDisplay()
val task = setUpFreeformTask()
val taskToRequest = setUpFreeformTask()
- val wctCaptor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
runOpenInstance(task, taskToRequest.taskId)
- verify(transitions).startTransition(anyInt(), wctCaptor.capture(), anyOrNull())
- assertThat(ActivityOptions.fromBundle(wctCaptor.value.hierarchyOps[0].launchOptions)
- .launchWindowingMode).isEqualTo(WINDOWING_MODE_FREEFORM)
+ verify(desktopMixedTransitionHandler).startLaunchTransition(anyInt(), any(), anyInt(),
+ anyOrNull(), anyOrNull())
+ val wct = getLatestDesktopMixedTaskWct(type = TRANSIT_TO_FRONT)
+ assertThat(wct.hierarchyOps).hasSize(1)
+ wct.assertReorderAt(index = 0, taskToRequest)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
fun openInstance_fromFreeform_minimizesIfNeeded() {
setUpLandscapeDisplay()
- val homeTask = setUpHomeTask()
val freeformTasks = (1..MAX_TASK_LIMIT + 1).map { _ -> setUpFreeformTask() }
val oldestTask = freeformTasks.first()
val newestTask = freeformTasks.last()
+ val transition = Binder()
+ val wctCaptor = argumentCaptor()
+ whenever(desktopMixedTransitionHandler.startLaunchTransition(anyInt(), wctCaptor.capture(),
+ anyInt(), anyOrNull(), anyOrNull()
+ ))
+ .thenReturn(transition)
+
runOpenInstance(newestTask, freeformTasks[1].taskId)
- val wct = getLatestWct(type = TRANSIT_OPEN)
- // Home is moved to front of everything.
- assertThat(
- wct.hierarchyOps.any { hop ->
- hop.container == homeTask.token.asBinder() && hop.toTop
- }
- ).isTrue()
- // And the oldest task isn't moved in front of home, effectively minimizing it.
- assertThat(
- wct.hierarchyOps.none { hop ->
- hop.container == oldestTask.token.asBinder() && hop.toTop
- }
- ).isTrue()
+ val wct = wctCaptor.firstValue
+ assertThat(wct.hierarchyOps.size).isEqualTo(2) // move-to-front + minimize
+ wct.assertReorderAt(0, freeformTasks[1], toTop = true)
+ wct.assertReorderAt(1, oldestTask, toTop = false)
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES)
fun openInstance_fromFreeform_exitsImmersiveIfNeeded() {
setUpLandscapeDisplay()
- val homeTask = setUpHomeTask()
val freeformTask = setUpFreeformTask()
val immersiveTask = setUpFreeformTask()
taskRepository.setTaskInFullImmersiveState(
@@ -3352,11 +3349,13 @@ class DesktopTasksControllerTest : ShellTestCase() {
)
val runOnStartTransit = RunOnStartTransitionCallback()
val transition = Binder()
- whenever(transitions.startTransition(eq(TRANSIT_OPEN), any(), anyOrNull()))
+ whenever(desktopMixedTransitionHandler.startLaunchTransition(anyInt(), any(), anyInt(),
+ anyOrNull(), anyOrNull()
+ ))
.thenReturn(transition)
whenever(mMockDesktopImmersiveController
.exitImmersiveIfApplicable(
- any(), eq(immersiveTask.displayId), eq(freeformTask.taskId), any()))
+ any(), eq(DEFAULT_DISPLAY), eq(freeformTask.taskId), any()))
.thenReturn(
ExitResult.Exit(
exitingTask = immersiveTask.taskId,
--
GitLab
From a39d37d1ad67c28840c955b7b24dd2a5eaf13a3b Mon Sep 17 00:00:00 2001
From: Ben Lin
Date: Mon, 2 Dec 2024 13:34:56 -0800
Subject: [PATCH 202/652] WMLockScreenVisibilityMgrTest: update test for
keyguard shell transit.
For this test, without transitions, we expect one call of each: 1)
ATMS#setLockscreenShown and ATMS#setKeyguardShown. But with shell
transitions, they are now both keyguardTransitions#startTransition.
Update test accordingly.
Bug: 364930619
Test: atest
Flag: com.android.window.flags.ensure_keyguard_does_transition_starting
Change-Id: Ia0907e0a2f6fc4832aa7a53b2b4c668012205103
---
.../ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
index 74a0bafda931..df4d5ab90f5e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/binder/WindowManagerLockscreenVisibilityManagerTest.kt
@@ -195,6 +195,7 @@ class WindowManagerLockscreenVisibilityManagerTest : SysuiTestCase() {
@RequiresFlagsEnabled(Flags.FLAG_ENSURE_KEYGUARD_DOES_TRANSITION_STARTING)
fun setSurfaceBehindVisibility_goesAwayFirst_andIgnoresSecondCall_with_keyguard_shell_transitions() {
underTest.setLockscreenShown(true)
+ verify(keyguardTransitions).startKeyguardTransition(true, false)
underTest.setSurfaceBehindVisibility(true)
verify(keyguardTransitions).startKeyguardTransition(false, false)
--
GitLab
From fcbce46fadf0e7cfb9dde61cf945ee15f7e8332b Mon Sep 17 00:00:00 2001
From: Arthur Ishiguro
Date: Mon, 2 Dec 2024 18:39:10 +0000
Subject: [PATCH 203/652] Adds missing permission annotation to
HubEndpointSession
Bug: 381090691
Flag: android.chre.flags.offload_api
Test: Compile
Change-Id: Ie1017d5c1eb63a68d66aa79063b3e95d490f7292
---
core/api/system-current.txt | 4 ++--
core/java/android/hardware/contexthub/HubEndpointSession.java | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0a3ecef8ecad..e7efa24c87ac 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5254,9 +5254,9 @@ package android.hardware.contexthub {
}
@FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSession implements java.lang.AutoCloseable {
- method public void close();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void close();
method @Nullable public android.hardware.contexthub.HubServiceInfo getServiceInfo();
- method @NonNull public android.hardware.location.ContextHubTransaction sendMessage(@NonNull android.hardware.contexthub.HubMessage);
+ method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction sendMessage(@NonNull android.hardware.contexthub.HubMessage);
}
@FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSessionResult {
diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java
index cf952cbdbfdc..b3d65c1a4cae 100644
--- a/core/java/android/hardware/contexthub/HubEndpointSession.java
+++ b/core/java/android/hardware/contexthub/HubEndpointSession.java
@@ -19,6 +19,7 @@ package android.hardware.contexthub;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.chre.flags.Flags;
import android.hardware.location.ContextHubTransaction;
@@ -70,6 +71,7 @@ public class HubEndpointSession implements AutoCloseable {
* receiving the response for the message.
*/
@NonNull
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
public ContextHubTransaction sendMessage(@NonNull HubMessage message) {
if (mIsClosed.get()) {
throw new IllegalStateException("Session is already closed.");
@@ -120,6 +122,7 @@ public class HubEndpointSession implements AutoCloseable {
*
When this function is invoked, the messaging associated with this session is invalidated.
* All futures messages targeted for this client are dropped.
*/
+ @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
public void close() {
if (!mIsClosed.getAndSet(true)) {
mCloseGuard.close();
--
GitLab
From eb57a51e09b95f169e87e4f467aadd6bf7247663 Mon Sep 17 00:00:00 2001
From: Trevor Knight
Date: Mon, 2 Dec 2024 21:48:24 +0000
Subject: [PATCH 204/652] Add @IntDef to getSpeakerLayoutChannelMask and
clarify comment
Flag: android.media.audio.speaker_layout_api
Bug: 380260651
Change-Id: Ic53e0fbfb88a5570903a24704dab2091025f7a1c
---
media/java/android/media/AudioDeviceInfo.java | 40 ++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index b41f40f412d2..5689df0784f0 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -548,8 +548,45 @@ public final class AudioDeviceInfo {
return counts;
}
+ /** @hide */
+ @IntDef(flag = true, prefix = "AudioFormat.CHANNEL_OUT_", value = {
+ AudioFormat.CHANNEL_INVALID,
+ AudioFormat.CHANNEL_OUT_DEFAULT,
+ AudioFormat.CHANNEL_OUT_FRONT_LEFT,
+ AudioFormat.CHANNEL_OUT_FRONT_RIGHT,
+ AudioFormat.CHANNEL_OUT_FRONT_CENTER,
+ AudioFormat.CHANNEL_OUT_LOW_FREQUENCY,
+ AudioFormat.CHANNEL_OUT_BACK_LEFT,
+ AudioFormat.CHANNEL_OUT_BACK_RIGHT,
+ AudioFormat.CHANNEL_OUT_FRONT_LEFT_OF_CENTER,
+ AudioFormat.CHANNEL_OUT_FRONT_RIGHT_OF_CENTER,
+ AudioFormat.CHANNEL_OUT_BACK_CENTER,
+ AudioFormat.CHANNEL_OUT_SIDE_LEFT,
+ AudioFormat.CHANNEL_OUT_SIDE_RIGHT,
+ AudioFormat.CHANNEL_OUT_TOP_CENTER,
+ AudioFormat.CHANNEL_OUT_TOP_FRONT_LEFT,
+ AudioFormat.CHANNEL_OUT_TOP_FRONT_CENTER,
+ AudioFormat.CHANNEL_OUT_TOP_FRONT_RIGHT,
+ AudioFormat.CHANNEL_OUT_TOP_BACK_LEFT,
+ AudioFormat.CHANNEL_OUT_TOP_BACK_CENTER,
+ AudioFormat.CHANNEL_OUT_TOP_BACK_RIGHT,
+ AudioFormat.CHANNEL_OUT_TOP_SIDE_LEFT,
+ AudioFormat.CHANNEL_OUT_TOP_SIDE_RIGHT,
+ AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_LEFT,
+ AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_CENTER,
+ AudioFormat.CHANNEL_OUT_BOTTOM_FRONT_RIGHT,
+ AudioFormat.CHANNEL_OUT_LOW_FREQUENCY_2,
+ AudioFormat.CHANNEL_OUT_FRONT_WIDE_LEFT,
+ AudioFormat.CHANNEL_OUT_FRONT_WIDE_RIGHT}
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ @FlaggedApi(FLAG_SPEAKER_LAYOUT_API)
+ public @interface SpeakerLayoutChannelMask {}
+
/**
- * @return A ChannelMask representing the physical output speaker layout of the device.
+ * @return A ChannelMask representing the speaker layout of a TYPE_BUILTIN_SPEAKER device.
+ *
+ * Valid only for speakers built-in to the device.
*
* The layout channel mask only indicates which speaker channels are present, the
* physical layout of the speakers should be informed by a standard for multi-channel
@@ -557,6 +594,7 @@ public final class AudioDeviceInfo {
* @see AudioFormat
*/
@FlaggedApi(FLAG_SPEAKER_LAYOUT_API)
+ @SpeakerLayoutChannelMask
public int getSpeakerLayoutChannelMask() {
return mPort.speakerLayoutChannelMask();
}
--
GitLab
From 164ec92f139976cabb37b1284fd677b004fb1f84 Mon Sep 17 00:00:00 2001
From: Chris Antol
Date: Fri, 22 Nov 2024 22:46:26 +0000
Subject: [PATCH 205/652] Update Sensitivity Levels for Preferences
Bug: 375193223
Flag: com.android.settingslib.flags.settings_catalyst
Test: atest CtsSettingsPreferenceServiceTest
Change-Id: Ie4354f1a5e397e6e61a3dcc24b781f05b70993a4
---
core/api/current.txt | 7 ++--
.../SettingsPreferenceMetadata.java | 39 +++++++++++++------
2 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/core/api/current.txt b/core/api/current.txt
index 55e1aeccd0fd..7fbab8cfbe62 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -42616,9 +42616,10 @@ package android.service.settings.preferences {
method public boolean isWritable();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator CREATOR;
- field public static final int INTENT_ONLY = 2; // 0x2
- field public static final int NOT_SENSITIVE = 0; // 0x0
- field public static final int SENSITIVE = 1; // 0x1
+ field public static final int EXPECT_POST_CONFIRMATION = 1; // 0x1
+ field public static final int EXPECT_PRE_CONFIRMATION = 2; // 0x2
+ field public static final int NO_DIRECT_ACCESS = 3; // 0x3
+ field public static final int NO_SENSITIVITY = 0; // 0x0
}
public static final class SettingsPreferenceMetadata.Builder {
diff --git a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
index 1acb7b8460cf..ea7d4a675713 100644
--- a/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
+++ b/core/java/android/service/settings/preferences/SettingsPreferenceMetadata.java
@@ -187,27 +187,39 @@ public final class SettingsPreferenceMetadata implements Parcelable {
/** @hide */
@IntDef(value = {
- NOT_SENSITIVE,
- SENSITIVE,
- INTENT_ONLY
+ NO_SENSITIVITY,
+ EXPECT_POST_CONFIRMATION,
+ EXPECT_PRE_CONFIRMATION,
+ NO_DIRECT_ACCESS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WriteSensitivity {}
/**
- * Preference is not sensitive, thus its value is writable without explicit consent, assuming
- * all necessary permissions are granted.
+ * Indicates preference is not sensitive.
+ *
Its value is writable without explicit consent, assuming all necessary permissions are
+ * granted.
*/
- public static final int NOT_SENSITIVE = 0;
+ public static final int NO_SENSITIVITY = 0;
/**
- * Preference is sensitive, meaning that in addition to necessary permissions, writing its value
- * will also request explicit user consent.
+ * Indicates preference is mildly sensitive.
+ *
In addition to necessary permissions, after writing its value the user should be
+ * given the option to revert back.
*/
- public static final int SENSITIVE = 1;
+ public static final int EXPECT_POST_CONFIRMATION = 1;
/**
- * Preference is not permitted for write-access via API and must be changed via Settings page.
+ * Indicates preference is sensitive.
+ *
In addition to necessary permissions, the user should be prompted for confirmation prior
+ * to making a change. Otherwise it is suggested to provide a deeplink to the Preference's page
+ * instead, accessible via {@link #getLaunchIntent}.
*/
- public static final int INTENT_ONLY = 2;
+ public static final int EXPECT_PRE_CONFIRMATION = 2;
+ /**
+ * Indicates preference is highly sensitivity and carries significant user-risk.
+ *
This Preference cannot be changed through this API and no direct deeplink is available.
+ * Other Metadata is still available.
+ */
+ public static final int NO_DIRECT_ACCESS = 3;
private SettingsPreferenceMetadata(@NonNull Builder builder) {
mKey = builder.mKey;
@@ -303,7 +315,7 @@ public final class SettingsPreferenceMetadata implements Parcelable {
private boolean mAvailable = false;
private boolean mWritable = false;
private boolean mRestricted = false;
- @WriteSensitivity private int mSensitivity = INTENT_ONLY;
+ @WriteSensitivity private int mSensitivity = NO_DIRECT_ACCESS;
private Intent mLaunchIntent;
private Bundle mExtras;
@@ -436,6 +448,9 @@ public final class SettingsPreferenceMetadata implements Parcelable {
*/
@NonNull
public SettingsPreferenceMetadata build() {
+ if (mSensitivity == NO_DIRECT_ACCESS) {
+ mLaunchIntent = null;
+ }
return new SettingsPreferenceMetadata(this);
}
}
--
GitLab
From e6177f7ab51ce97261e9f2a51196b7971ddf84ca Mon Sep 17 00:00:00 2001
From: Xiang Wang
Date: Mon, 2 Dec 2024 22:17:27 +0000
Subject: [PATCH 206/652] Revert the hint session support part
It's from a rebased parent change which was not submitted yet
Bug: 346604998
Change-Id: I8b86d5be56be3b517986c6d0d5e11baa5c8ff36f
Flag: android.os.cpu_gpu_headrooms
Test: atest HintManagerServiceTest
---
.../server/power/hint/HintManagerService.java | 30 -------------------
.../power/hint/HintManagerServiceTest.java | 6 ----
2 files changed, 36 deletions(-)
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index f1f1e6031718..987a84994451 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -325,36 +325,6 @@ public final class HintManagerService extends SystemService {
}
SupportInfo supportInfo = new SupportInfo();
- supportInfo.usesSessions = isHintSessionSupported();
- // Global boosts & modes aren't currently relevant for HMS clients
- supportInfo.boosts = 0;
- supportInfo.modes = 0;
- supportInfo.sessionHints = 0;
- supportInfo.sessionModes = 0;
- supportInfo.sessionTags = 0;
- if (isHintSessionSupported()) {
- if (mPowerHalVersion == 4) {
- // Assume we support the V4 hints & modes unless specified
- // otherwise; this is to avoid breaking backwards compat
- // since we historically just assumed they were.
- supportInfo.sessionHints = 31; // first 5 bits are ones
- }
- if (mPowerHalVersion == 5) {
- // Assume we support the V5 hints & modes unless specified
- // otherwise; this is to avoid breaking backwards compat
- // since we historically just assumed they were.
-
- // Hal V5 has 8 modes, all of which it assumes are supported,
- // so we represent that by having the first 8 bits set
- supportInfo.sessionHints = 255; // first 8 bits are ones
- // Hal V5 has 1 mode which it assumes is supported, so we
- // represent that by having the first bit set
- supportInfo.sessionModes = 1;
- // Hal V5 has 5 tags, all of which it assumes are supported,
- // so we represent that by having the first 5 bits set
- supportInfo.sessionTags = 31;
- }
- }
supportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
supportInfo.headroom.isCpuSupported = false;
supportInfo.headroom.isGpuSupported = false;
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index a9b4ca1e7963..7248833d876c 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -182,12 +182,6 @@ public class HintManagerServiceTest {
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
mSupportInfo = new SupportInfo();
- mSupportInfo.usesSessions = true;
- mSupportInfo.sessionHints = 5;
- mSupportInfo.sessionModes = 1;
- mSupportInfo.modes = 3;
- mSupportInfo.boosts = 3;
- mSupportInfo.sessionTags = 63;
mSupportInfo.headroom = new SupportInfo.HeadroomSupportInfo();
mSupportInfo.headroom.isCpuSupported = true;
mSupportInfo.headroom.cpuMinIntervalMillis = 2000;
--
GitLab
From 838d72554248f08c304f391c3d692358f39ce8fe Mon Sep 17 00:00:00 2001
From: Ted Bauer
Date: Mon, 2 Dec 2024 22:06:31 +0000
Subject: [PATCH 207/652] Treat undefined flags as false in resource flag
processor
Relanding with fix for b/373685244. When a flag is undefined, treat it as disabled, but cache it as null.
Bug: 373685244
Test: atest PackageParserTest
Flag: EXEMPT bugfix
Change-Id: I978c837f13605d3958b176dec95565fdab1080a5
---
.../pm/pkg/component/AconfigFlags.java | 22 ++++++++++---------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
index c953d88c9482..445dac7411da 100644
--- a/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
+++ b/core/java/com/android/internal/pm/pkg/component/AconfigFlags.java
@@ -25,7 +25,6 @@ import android.aconfig.nano.Aconfig.parsed_flags;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Flags;
-import android.content.res.XmlResourceParser;
import android.os.Environment;
import android.os.Process;
import android.util.ArrayMap;
@@ -247,20 +246,23 @@ public class AconfigFlags {
negated = true;
featureFlag = featureFlag.substring(1).strip();
}
- final Boolean flagValue = getFlagValue(featureFlag);
- boolean shouldSkip = false;
+ Boolean flagValue = getFlagValue(featureFlag);
+ boolean isUndefined = false;
if (flagValue == null) {
- Slog.w(LOG_TAG, "Skipping element " + parser.getName()
- + " due to unknown feature flag " + featureFlag);
- shouldSkip = true;
- } else if (flagValue == negated) {
+ isUndefined = true;
+ flagValue = false;
+ }
+ boolean shouldSkip = false;
+ if (flagValue == negated) {
// Skip if flag==false && attr=="flag" OR flag==true && attr=="!flag" (negated)
- Slog.i(LOG_TAG, "Skipping element " + parser.getName()
- + " behind feature flag " + featureFlag + " = " + flagValue);
shouldSkip = true;
}
if (pkg != null && android.content.pm.Flags.includeFeatureFlagsInPackageCacher()) {
- pkg.addFeatureFlag(featureFlag, flagValue);
+ if (isUndefined) {
+ pkg.addFeatureFlag(featureFlag, null);
+ } else {
+ pkg.addFeatureFlag(featureFlag, flagValue);
+ }
}
return shouldSkip;
}
--
GitLab
From ec23043661c514cf48a065d3ff2c30bbb7004f45 Mon Sep 17 00:00:00 2001
From: Nicolas Roard
Date: Mon, 2 Dec 2024 21:58:30 +0000
Subject: [PATCH 208/652] Update to ToT RemoteCompose
Bug: 339721781
Flag: EXEMPT External Libraries
Test: in GoB
Change-Id: I6a66651c026d7a58fdb461d54d4b453541d10439
---
core/java/android/widget/RemoteViews.java | 2 +-
.../AndroidPlatformSemanticNodeApplier.java | 169 ++++----------
.../BaseSemanticNodeApplier.java | 208 ++++++++++++++++++
.../CoreDocumentAccessibility.java | 78 ++++---
...rmRemoteComposeAccessibilityRegistrar.java | 46 ++++
.../PlatformRemoteComposeTouchHelper.java | 54 ++---
.../RemoteComposeAccessibilityRegistrar.java | 33 +++
.../RemoteComposeDocumentAccessibility.java | 20 +-
.../RemoteComposeTouchHelper.java | 18 +-
.../accessibility/SemanticNodeApplier.java | 13 +-
.../remotecompose/core/CoreDocument.java | 26 +--
.../core/operations/TouchExpression.java | 1 +
.../modifiers/MarqueeModifierOperation.java | 4 +-
.../core/semantics/CoreSemantics.java | 9 +
.../player/RemoteComposePlayer.java | 32 ++-
.../player/platform/RemoteComposeCanvas.java | 19 +-
16 files changed, 499 insertions(+), 233 deletions(-)
create mode 100644 core/java/com/android/internal/widget/remotecompose/accessibility/BaseSemanticNodeApplier.java
create mode 100644 core/java/com/android/internal/widget/remotecompose/accessibility/PlatformRemoteComposeAccessibilityRegistrar.java
create mode 100644 core/java/com/android/internal/widget/remotecompose/accessibility/RemoteComposeAccessibilityRegistrar.java
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7e3b90444429..bf385e98f2c9 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -5825,7 +5825,7 @@ public class RemoteViews implements Parcelable, Filter {
}
try (ByteArrayInputStream is = new ByteArrayInputStream(bytes.get(0))) {
player.setDocument(new RemoteComposeDocument(is));
- player.addClickListener((viewId, metadata) -> {
+ player.addIdActionListener((viewId, metadata) -> {
mActions.forEach(action -> {
if (viewId == action.mViewId
&& action instanceof SetOnClickResponse setOnClickResponse) {
diff --git a/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
index 410e021f5162..1bdbaa48d18c 100644
--- a/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
+++ b/core/java/com/android/internal/widget/remotecompose/accessibility/AndroidPlatformSemanticNodeApplier.java
@@ -15,157 +15,72 @@
*/
package com.android.internal.widget.remotecompose.accessibility;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.graphics.Rect;
import android.view.accessibility.AccessibilityNodeInfo;
-import com.android.internal.widget.remotecompose.core.operations.layout.Component;
-import com.android.internal.widget.remotecompose.core.semantics.AccessibilitySemantics;
-import com.android.internal.widget.remotecompose.core.semantics.AccessibleComponent;
-import com.android.internal.widget.remotecompose.core.semantics.CoreSemantics;
-
-import java.util.List;
-
public class AndroidPlatformSemanticNodeApplier
- implements SemanticNodeApplier {
+ extends BaseSemanticNodeApplier {
private static final String ROLE_DESCRIPTION_KEY = "AccessibilityNodeInfo.roleDescription";
@Override
- public void applyComponent(
- @NonNull
- RemoteComposeDocumentAccessibility
- remoteComposeAccessibility,
- AccessibilityNodeInfo nodeInfo,
- Component component,
- List semantics) {
- if (component instanceof AccessibleComponent) {
- applyContentDescription(
- ((AccessibleComponent) component).getContentDescriptionId(),
- nodeInfo,
- remoteComposeAccessibility);
-
- applyRole(((AccessibleComponent) component).getRole(), nodeInfo);
- }
-
- applySemantics(remoteComposeAccessibility, nodeInfo, semantics);
-
- float[] locationInWindow = new float[2];
- component.getLocationInWindow(locationInWindow);
- Rect bounds =
- new Rect(
- (int) locationInWindow[0],
- (int) locationInWindow[1],
- (int) (locationInWindow[0] + component.getWidth()),
- (int) (locationInWindow[1] + component.getHeight()));
- //noinspection deprecation
- nodeInfo.setBoundsInParent(bounds);
- nodeInfo.setBoundsInScreen(bounds);
-
- if (component instanceof AccessibleComponent) {
- applyContentDescription(
- ((AccessibleComponent) component).getContentDescriptionId(),
- nodeInfo,
- remoteComposeAccessibility);
-
- applyText(
- ((AccessibleComponent) component).getTextId(),
- nodeInfo,
- remoteComposeAccessibility);
-
- applyRole(((AccessibleComponent) component).getRole(), nodeInfo);
- }
-
- applySemantics(remoteComposeAccessibility, nodeInfo, semantics);
-
- if (nodeInfo.getText() == null && nodeInfo.getContentDescription() == null) {
- nodeInfo.setContentDescription("");
+ protected void setClickable(AccessibilityNodeInfo nodeInfo, boolean clickable) {
+ nodeInfo.setClickable(clickable);
+ if (clickable) {
+ nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
+ } else {
+ nodeInfo.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
}
}
- public void applySemantics(
- RemoteComposeDocumentAccessibility
- remoteComposeAccessibility,
- AccessibilityNodeInfo nodeInfo,
- List semantics) {
- for (AccessibilitySemantics semantic : semantics) {
- if (semantic.isInterestingForSemantics()) {
- if (semantic instanceof CoreSemantics) {
- applyCoreSemantics(
- remoteComposeAccessibility, nodeInfo, (CoreSemantics) semantic);
- } else if (semantic instanceof AccessibleComponent) {
- AccessibleComponent s = (AccessibleComponent) semantic;
-
- applyContentDescription(
- s.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility);
-
- applyRole(s.getRole(), nodeInfo);
-
- applyText(s.getTextId(), nodeInfo, remoteComposeAccessibility);
-
- if (s.isClickable()) {
- nodeInfo.setClickable(true);
- nodeInfo.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
- }
- }
- }
- }
+ @Override
+ protected void setEnabled(AccessibilityNodeInfo nodeInfo, boolean enabled) {
+ nodeInfo.setEnabled(enabled);
}
- private void applyCoreSemantics(
- RemoteComposeDocumentAccessibility
- remoteComposeAccessibility,
- AccessibilityNodeInfo nodeInfo,
- CoreSemantics semantics) {
- applyContentDescription(
- semantics.getContentDescriptionId(), nodeInfo, remoteComposeAccessibility);
+ @Override
+ protected CharSequence getStateDescription(AccessibilityNodeInfo nodeInfo) {
+ return nodeInfo.getStateDescription();
+ }
- applyRole(semantics.getRole(), nodeInfo);
+ @Override
+ protected void setStateDescription(AccessibilityNodeInfo nodeInfo, CharSequence description) {
+ nodeInfo.setStateDescription(description);
+ }
- applyText(semantics.getTextId(), nodeInfo, remoteComposeAccessibility);
+ @Override
+ protected void setRoleDescription(AccessibilityNodeInfo nodeInfo, String description) {
+ nodeInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, description);
+ }
- applyStateDescription(
- semantics.getStateDescriptionId(), nodeInfo, remoteComposeAccessibility);
+ @Override
+ protected CharSequence getText(AccessibilityNodeInfo nodeInfo) {
+ return nodeInfo.getText();
+ }
- nodeInfo.setEnabled(semantics.mEnabled);
+ @Override
+ protected void setText(AccessibilityNodeInfo nodeInfo, CharSequence text) {
+ nodeInfo.setText(text);
}
- void applyRole(@Nullable AccessibleComponent.Role role, AccessibilityNodeInfo nodeInfo) {
- if (role != null) {
- nodeInfo.getExtras().putCharSequence(ROLE_DESCRIPTION_KEY, role.getDescription());
- }
+ @Override
+ protected CharSequence getContentDescription(AccessibilityNodeInfo nodeInfo) {
+ return nodeInfo.getContentDescription();
}
- void applyContentDescription(
- @Nullable Integer contentDescriptionId,
- AccessibilityNodeInfo nodeInfo,
- RemoteComposeDocumentAccessibility
- remoteComposeAccessibility) {
- if (contentDescriptionId != null) {
- nodeInfo.setContentDescription(
- remoteComposeAccessibility.stringValue(contentDescriptionId));
- }
+ @Override
+ protected void setContentDescription(AccessibilityNodeInfo nodeInfo, CharSequence description) {
+ nodeInfo.setContentDescription(description);
}
- void applyText(
- @Nullable Integer textId,
- AccessibilityNodeInfo nodeInfo,
- RemoteComposeDocumentAccessibility