From 3f20161d8b9c0ba139d893da0d9ff23f942bf913 Mon Sep 17 00:00:00 2001 From: Olivier Gaillard Date: Fri, 5 Jan 2024 15:25:38 +0000 Subject: Log an event when packages are installed to understand the impact on ANRs. Bug: 318823843 Change-Id: I700ff65587f14a75e869c8c76a6ae7022f6c3067 --- proto/src/criticalevents/critical_event_log.proto | 3 +++ 1 file changed, 3 insertions(+) (limited to 'proto/src') diff --git a/proto/src/criticalevents/critical_event_log.proto b/proto/src/criticalevents/critical_event_log.proto index 9cda2672eab0..cffcd0941df8 100644 --- a/proto/src/criticalevents/critical_event_log.proto +++ b/proto/src/criticalevents/critical_event_log.proto @@ -60,8 +60,11 @@ message CriticalEventProto { JavaCrash java_crash = 5; NativeCrash native_crash = 6; SystemServerStarted system_server_started = 7; + InstallPackages install_packages = 8; } + message InstallPackages {} + message SystemServerStarted {} message Watchdog { -- cgit v1.2.3-59-g8ed1b From 72fa82d56999e8b70afa8d0fa38e4d4d227b470a Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Wed, 15 Nov 2023 13:34:29 +0800 Subject: [Drag To Hide] Shows notification when user drag-to-hide a11y floating button * Click on notification to bring back a11y floating button * Swipe notification to remove a11y floating button and its services * A11y service key changed to dismiss notification * Align to create ACCESSIBILITY channel in systemui NotificationChannels Bug: 298718415 Flag: ACONFIG com.android.systemui.floating_menu_drag_to_hide DEVELOPMENT Test: atest MenuViewLayerTest MenuNotificationFactoryTest NotificationChannelsTest Change-Id: Ie209ec946ea15903acfa6913492605277e9d7057 --- packages/SystemUI/aconfig/accessibility.aconfig | 9 +- packages/SystemUI/res/values/strings.xml | 7 ++ .../DragToInteractAnimationController.java | 6 ++ .../floatingmenu/MenuNotificationFactory.java | 75 ++++++++++++++ .../accessibility/floatingmenu/MenuViewLayer.java | 114 ++++++++++++++++++--- .../floatingmenu/MenuNotificationFactoryTest.java | 51 +++++++++ .../floatingmenu/MenuViewLayerTest.java | 111 ++++++++++++++++++-- proto/src/system_messages.proto | 4 + 8 files changed, 353 insertions(+), 24 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactory.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java (limited to 'proto/src') diff --git a/packages/SystemUI/aconfig/accessibility.aconfig b/packages/SystemUI/aconfig/accessibility.aconfig index 21263a92ae26..f7b1a26c9df9 100644 --- a/packages/SystemUI/aconfig/accessibility.aconfig +++ b/packages/SystemUI/aconfig/accessibility.aconfig @@ -9,6 +9,13 @@ flag { bug: "297556899" } +flag { + name: "floating_menu_drag_to_hide" + namespace: "accessibility" + description: "Allows users to hide the FAB then use notification to dismiss or bring it back." + bug: "298718415" +} + flag { name: "floating_menu_ime_displacement_animation" namespace: "accessibility" @@ -28,4 +35,4 @@ flag { namespace: "accessibility" description: "Animates the floating menu's transition between curved and jagged edges." bug: "281140482" -} \ No newline at end of file +} diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index f4b25a701825..8d560c37e5db 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2274,6 +2274,8 @@ Storage Hints + + Accessibility Instant Apps @@ -2544,6 +2546,11 @@ Move button to the edge to hide it temporarily Undo + + Accessibility button hidden + + Tap to show accessibility button + %s shortcut removed diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java index 49e0df6f6afc..568b24dbd4f3 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationController.java @@ -24,6 +24,7 @@ import android.view.MotionEvent; import androidx.annotation.NonNull; import androidx.dynamicanimation.animation.DynamicAnimation; +import com.android.internal.annotations.VisibleForTesting; import com.android.wm.shell.common.bubbles.DismissView; import com.android.wm.shell.common.magnetictarget.MagnetizedObject; @@ -116,6 +117,11 @@ class DragToInteractAnimationController { mMagnetizedObject.setMagnetListener(magnetListener); } + @VisibleForTesting + MagnetizedObject.MagnetListener getMagnetListener() { + return mMagnetizedObject.getMagnetListener(); + } + void maybeConsumeDownMotionEvent(MotionEvent event) { mMagnetizedObject.maybeConsumeMotionEvent(event); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactory.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactory.java new file mode 100644 index 000000000000..b5eeaa18447e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactory.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.floatingmenu; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; + +import com.android.systemui.res.R; +import com.android.systemui.util.NotificationChannels; + +class MenuNotificationFactory { + public static final String ACTION_UNDO = + "com.android.systemui.accessibility.floatingmenu.action.UNDO"; + public static final String ACTION_DELETE = + "com.android.systemui.accessibility.floatingmenu.action.DELETE"; + + private final Context mContext; + + MenuNotificationFactory(Context context) { + mContext = context; + } + + public Notification createHiddenNotification() { + final CharSequence title = mContext.getText( + R.string.accessibility_floating_button_hidden_notification_title); + final CharSequence content = mContext.getText( + R.string.accessibility_floating_button_hidden_notification_text); + + return new Notification.Builder(mContext, NotificationChannels.ALERTS) + .setContentTitle(title) + .setContentText(content) + .setSmallIcon(R.drawable.ic_settings_24dp) + .setContentIntent(buildUndoIntent()) + .setDeleteIntent(buildDeleteIntent()) + .setColor(mContext.getResources().getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setLocalOnly(true) + .setCategory(Notification.CATEGORY_SYSTEM) + .build(); + } + + private PendingIntent buildUndoIntent() { + final Intent intent = new Intent(ACTION_UNDO); + + return PendingIntent.getBroadcast(mContext, /* requestCode= */ 0, intent, + PendingIntent.FLAG_IMMUTABLE); + + } + + private PendingIntent buildDeleteIntent() { + final Intent intent = new Intent(ACTION_DELETE); + + return PendingIntent.getBroadcastAsUser(mContext, /* requestCode= */ 0, intent, + PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT + | PendingIntent.FLAG_IMMUTABLE, UserHandle.CURRENT); + + } +} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java index 62d5feb7d024..6869bbaedcf3 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java @@ -26,16 +26,21 @@ import static com.android.internal.accessibility.common.ShortcutConstants.Access import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType; import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState; import static com.android.systemui.accessibility.floatingmenu.MenuMessageView.Index; +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_DELETE; +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_UNDO; import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat; import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.IntDef; import android.annotation.StringDef; import android.annotation.SuppressLint; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; import android.content.ComponentCallbacks; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; @@ -58,6 +63,7 @@ import androidx.lifecycle.Observer; import com.android.internal.accessibility.dialog.AccessibilityTarget; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.util.Preconditions; import com.android.systemui.Flags; import com.android.systemui.res.R; @@ -91,6 +97,8 @@ class MenuViewLayer extends FrameLayout implements private final MenuViewAppearance mMenuViewAppearance; private final MenuAnimationController mMenuAnimationController; private final AccessibilityManager mAccessibilityManager; + private final NotificationManager mNotificationManager; + private final MenuNotificationFactory mNotificationFactory; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final IAccessibilityFloatingMenu mFloatingMenu; private final SecureSettings mSecureSettings; @@ -103,7 +111,9 @@ class MenuViewLayer extends FrameLayout implements private final Rect mImeInsetsRect = new Rect(); private boolean mIsMigrationTooltipShowing; private boolean mShouldShowDockTooltip; + private boolean mIsNotificationShown; private Optional mEduTooltipView = Optional.empty(); + private BroadcastReceiver mNotificationActionReceiver; @IntDef({ LayerIndex.MENU_VIEW, @@ -184,10 +194,16 @@ class MenuViewLayer extends FrameLayout implements mMenuViewAppearance = new MenuViewAppearance(context, windowManager); mMenuView = new MenuView(context, mMenuViewModel, mMenuViewAppearance); mMenuAnimationController = mMenuView.getMenuAnimationController(); - mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage); + if (Flags.floatingMenuDragToHide()) { + mMenuAnimationController.setDismissCallback(this::hideMenuAndShowNotification); + } else { + mMenuAnimationController.setDismissCallback(this::hideMenuAndShowMessage); + } mMenuAnimationController.setSpringAnimationsEndAction(this::onSpringAnimationsEndAction); mDismissView = new DismissView(context); DismissViewUtils.setup(mDismissView); + mNotificationFactory = new MenuNotificationFactory(context); + mNotificationManager = context.getSystemService(NotificationManager.class); mDragToInteractAnimationController = new DragToInteractAnimationController( mDismissView, mMenuView); mDragToInteractAnimationController.setMagnetListener(new MagnetizedObject.MagnetListener() { @@ -204,7 +220,11 @@ class MenuViewLayer extends FrameLayout implements @Override public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) { - hideMenuAndShowMessage(); + if (Flags.floatingMenuDragToHide()) { + hideMenuAndShowNotification(); + } else { + hideMenuAndShowMessage(); + } mDismissView.hide(); mDragToInteractAnimationController.animateDismissMenu(/* scaleUp= */ false); } @@ -218,18 +238,25 @@ class MenuViewLayer extends FrameLayout implements mMessageView = new MenuMessageView(context); mMenuView.setOnTargetFeaturesChangeListener(newTargetFeatures -> { - if (newTargetFeatures.size() < 1) { - return; - } - - // During the undo action period, the pending action will be canceled and undo back - // to the previous state if users did any action related to the accessibility features. - if (mMessageView.getVisibility() == VISIBLE) { + if (Flags.floatingMenuDragToHide()) { + dismissNotification(); undo(); - } + } else { + if (newTargetFeatures.size() < 1) { + return; + } + + // During the undo action period, the pending action will be canceled and undo back + // to the previous state if users did any action related to the accessibility + // features. + if (mMessageView.getVisibility() == VISIBLE) { + undo(); + } - final TextView messageText = (TextView) mMessageView.getChildAt(Index.TEXT_VIEW); - messageText.setText(getMessageText(newTargetFeatures)); + + final TextView messageText = (TextView) mMessageView.getChildAt(Index.TEXT_VIEW); + messageText.setText(getMessageText(newTargetFeatures)); + } }); addView(mMenuView, LayerIndex.MENU_VIEW); @@ -456,6 +483,50 @@ class MenuViewLayer extends FrameLayout implements mMenuAnimationController.startShrinkAnimation(() -> mMenuView.setVisibility(GONE)); } + private void hideMenuAndShowNotification() { + mMenuAnimationController.startShrinkAnimation(() -> mMenuView.setVisibility(GONE)); + showNotification(); + } + + private void showNotification() { + registerReceiverIfNeeded(); + if (!mIsNotificationShown) { + mNotificationManager.notify( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN, + mNotificationFactory.createHiddenNotification()); + mIsNotificationShown = true; + } + } + + private void dismissNotification() { + unregisterReceiverIfNeeded(); + if (mIsNotificationShown) { + mNotificationManager.cancel( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN); + mIsNotificationShown = false; + } + } + + private void registerReceiverIfNeeded() { + if (mNotificationActionReceiver != null) { + return; + } + mNotificationActionReceiver = new MenuNotificationActionReceiver(); + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_UNDO); + intentFilter.addAction(ACTION_DELETE); + getContext().registerReceiver(mNotificationActionReceiver, intentFilter, + Context.RECEIVER_EXPORTED); + } + + private void unregisterReceiverIfNeeded() { + if (mNotificationActionReceiver == null) { + return; + } + getContext().unregisterReceiver(mNotificationActionReceiver); + mNotificationActionReceiver = null; + } + private void undo() { mHandler.removeCallbacksAndMessages(/* token= */ null); mMessageView.setVisibility(GONE); @@ -464,4 +535,23 @@ class MenuViewLayer extends FrameLayout implements mMenuView.setVisibility(VISIBLE); mMenuAnimationController.startGrowAnimation(); } + + @VisibleForTesting + DragToInteractAnimationController getDragToInteractAnimationController() { + return mDragToInteractAnimationController; + } + + private class MenuNotificationActionReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (ACTION_UNDO.equals(action)) { + dismissNotification(); + undo(); + } else if (ACTION_DELETE.equals(action)) { + dismissNotification(); + mDismissMenuAction.run(); + } + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java new file mode 100644 index 000000000000..9dd337e43b6a --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuNotificationFactoryTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.accessibility.floatingmenu; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Notification; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class MenuNotificationFactoryTest extends SysuiTestCase { + private MenuNotificationFactory mMenuNotificationFactory; + + @Before + public void setUp() { + mMenuNotificationFactory = new MenuNotificationFactory(mContext); + } + + @Test + public void createHiddenNotification_hasUndoAndDeleteAction() { + Notification notification = mMenuNotificationFactory.createHiddenNotification(); + + assertThat(notification.contentIntent.getIntent().getAction()).isEqualTo( + MenuNotificationFactory.ACTION_UNDO); + assertThat(notification.deleteIntent.getIntent().getAction()).isEqualTo( + MenuNotificationFactory.ACTION_DELETE); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java index be6f3ff8d3f9..68879a54cfe4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java @@ -21,15 +21,30 @@ import static android.view.View.VISIBLE; import static android.view.WindowInsets.Type.displayCutout; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; + +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_DELETE; +import static com.android.systemui.accessibility.floatingmenu.MenuNotificationFactory.ACTION_UNDO; import static com.android.systemui.accessibility.floatingmenu.MenuViewLayer.LayerIndex; + import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.accessibilityservice.AccessibilityServiceInfo; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -40,6 +55,8 @@ import android.os.Build; import android.os.UserHandle; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -53,16 +70,21 @@ import androidx.dynamicanimation.animation.DynamicAnimation; import androidx.dynamicanimation.animation.SpringAnimation; import androidx.test.filters.SmallTest; +import com.android.internal.messages.nano.SystemMessageProto; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; +import com.android.systemui.SysuiTestableContext; import com.android.systemui.util.settings.SecureSettings; +import com.android.wm.shell.common.magnetictarget.MagnetizedObject; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.Spy; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -98,6 +120,12 @@ public class MenuViewLayerTest extends SysuiTestCase { @Rule public MockitoRule mockito = MockitoJUnit.rule(); + @Rule + public final CheckFlagsRule mCheckFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Spy + private SysuiTestableContext mSpyContext = getContext(); @Mock private IAccessibilityFloatingMenu mFloatingMenu; @@ -110,8 +138,12 @@ public class MenuViewLayerTest extends SysuiTestCase { @Mock private AccessibilityManager mStubAccessibilityManager; + private final NotificationManager mMockNotificationManager = mock(NotificationManager.class); + @Before public void setUp() throws Exception { + mSpyContext.addMockSystemService(Context.NOTIFICATION_SERVICE, mMockNotificationManager); + final Rect mDisplayBounds = new Rect(); mDisplayBounds.set(/* left= */ 0, /* top= */ 0, DISPLAY_WINDOW_WIDTH, DISPLAY_WINDOW_HEIGHT); @@ -119,31 +151,31 @@ public class MenuViewLayerTest extends SysuiTestCase { new WindowMetrics(mDisplayBounds, fakeDisplayInsets(), /* density = */ 0.0f)); doReturn(mWindowMetrics).when(mStubWindowManager).getCurrentWindowMetrics(); - mMenuViewLayer = new MenuViewLayer(mContext, mStubWindowManager, mStubAccessibilityManager, - mFloatingMenu, mSecureSettings); + mMenuViewLayer = new MenuViewLayer(mSpyContext, mStubWindowManager, + mStubAccessibilityManager, mFloatingMenu, mSecureSettings); mMenuView = (MenuView) mMenuViewLayer.getChildAt(LayerIndex.MENU_VIEW); mMenuAnimationController = mMenuView.getMenuAnimationController(); mLastAccessibilityButtonTargets = - Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.getStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, UserHandle.USER_CURRENT); mLastEnabledAccessibilityServices = - Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.getStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, UserHandle.USER_CURRENT); mMenuViewLayer.onAttachedToWindow(); - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, "", UserHandle.USER_CURRENT); - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "", UserHandle.USER_CURRENT); } @After public void tearDown() throws Exception { - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, mLastAccessibilityButtonTargets, UserHandle.USER_CURRENT); - Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.putStringForUser(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, mLastEnabledAccessibilityServices, UserHandle.USER_CURRENT); @@ -188,7 +220,7 @@ public class MenuViewLayerTest extends SysuiTestCase { setupEnabledAccessibilityServiceList(); mMenuViewLayer.mDismissMenuAction.run(); - final String value = Settings.Secure.getString(mContext.getContentResolver(), + final String value = Settings.Secure.getString(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); assertThat(value).isEqualTo(""); @@ -203,7 +235,7 @@ public class MenuViewLayerTest extends SysuiTestCase { AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY)).thenReturn(stubShortcutTargets); mMenuViewLayer.mDismissMenuAction.run(); - final String value = Settings.Secure.getString(mContext.getContentResolver(), + final String value = Settings.Secure.getString(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); assertThat(value).isEqualTo(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString()); @@ -278,9 +310,60 @@ public class MenuViewLayerTest extends SysuiTestCase { assertThat(mMenuView.getTranslationX()).isEqualTo(beforePosition.x); assertThat(mMenuView.getTranslationY()).isEqualTo(beforePosition.y); } + @Test + @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE) + public void onReleasedInTarget_hideMenuAndShowNotificationWithExpectedActions() { + dragMenuThenReleasedInTarget(); + + verify(mMockNotificationManager).notify( + eq(SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN), + any(Notification.class)); + ArgumentCaptor intentFilterCaptor = ArgumentCaptor.forClass( + IntentFilter.class); + verify(mSpyContext).registerReceiver( + any(BroadcastReceiver.class), + intentFilterCaptor.capture(), + anyInt()); + assertThat(intentFilterCaptor.getValue().matchAction(ACTION_UNDO)).isTrue(); + assertThat(intentFilterCaptor.getValue().matchAction(ACTION_DELETE)).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE) + public void receiveActionUndo_dismissNotificationAndMenuVisible() { + ArgumentCaptor broadcastReceiverCaptor = ArgumentCaptor.forClass( + BroadcastReceiver.class); + dragMenuThenReleasedInTarget(); + + verify(mSpyContext).registerReceiver(broadcastReceiverCaptor.capture(), + any(IntentFilter.class), anyInt()); + broadcastReceiverCaptor.getValue().onReceive(mSpyContext, new Intent(ACTION_UNDO)); + + verify(mSpyContext).unregisterReceiver(broadcastReceiverCaptor.getValue()); + verify(mMockNotificationManager).cancel( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN); + assertThat(mMenuView.getVisibility()).isEqualTo(VISIBLE); + } + + @Test + @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_HIDE) + public void receiveActionDelete_dismissNotificationAndHideMenu() { + ArgumentCaptor broadcastReceiverCaptor = ArgumentCaptor.forClass( + BroadcastReceiver.class); + dragMenuThenReleasedInTarget(); + + verify(mSpyContext).registerReceiver(broadcastReceiverCaptor.capture(), + any(IntentFilter.class), anyInt()); + broadcastReceiverCaptor.getValue().onReceive(mSpyContext, new Intent(ACTION_DELETE)); + + verify(mSpyContext).unregisterReceiver(broadcastReceiverCaptor.getValue()); + verify(mMockNotificationManager).cancel( + SystemMessageProto.SystemMessage.NOTE_A11Y_FLOATING_MENU_HIDDEN); + verify(mFloatingMenu).hide(); + } private void setupEnabledAccessibilityServiceList() { - Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.putString(mSpyContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString()); @@ -344,6 +427,12 @@ public class MenuViewLayerTest extends SysuiTestCase { springAnimation.skipToEnd(); springAnimation.doAnimationFrame(500); }); + } + private void dragMenuThenReleasedInTarget() { + MagnetizedObject.MagnetListener magnetListener = + mMenuViewLayer.getDragToInteractAnimationController().getMagnetListener(); + magnetListener.onReleasedInTarget( + new MagnetizedObject.MagneticTarget(mock(View.class), 200)); } } diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index b403a7fe8f12..7f542d130cf7 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -408,5 +408,9 @@ message SystemMessage { // Notify the user about external display events related to screenshot. // Package: com.android.systemui NOTE_GLOBAL_SCREENSHOT_EXTERNAL_DISPLAY = 1008; + + // Notify the user that accessibility floating menu is hidden. + // Package: com.android.systemui + NOTE_A11Y_FLOATING_MENU_HIDDEN = 1009; } } -- cgit v1.2.3-59-g8ed1b From 82865bfc48c55df9aa9f80bc6ae64ae0043f6fc2 Mon Sep 17 00:00:00 2001 From: Olivier Gaillard Date: Thu, 22 Feb 2024 12:56:00 +0000 Subject: Track excessive binder calls in the critical event logs. It will help to understand if any ANRs are due to high binder calls. Change-Id: I3aad499f73ff00c52689c69e85ac87ca8b91e5ac --- proto/src/criticalevents/critical_event_log.proto | 6 ++++++ .../java/com/android/server/am/ActivityManagerService.java | 1 + .../com/android/server/criticalevents/CriticalEventLog.java | 10 ++++++++++ 3 files changed, 17 insertions(+) (limited to 'proto/src') diff --git a/proto/src/criticalevents/critical_event_log.proto b/proto/src/criticalevents/critical_event_log.proto index cffcd0941df8..71d291a6f877 100644 --- a/proto/src/criticalevents/critical_event_log.proto +++ b/proto/src/criticalevents/critical_event_log.proto @@ -61,6 +61,12 @@ message CriticalEventProto { NativeCrash native_crash = 6; SystemServerStarted system_server_started = 7; InstallPackages install_packages = 8; + ExcessiveBinderCalls excessive_binder_calls = 9; + } + + message ExcessiveBinderCalls { + // The uid sending many calls. + optional int32 uid = 1; } message InstallPackages {} diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2dd2f8fde797..d87846183f3e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9028,6 +9028,7 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid " + Process.myUid()); BinderProxy.dumpProxyDebugInfo(); + CriticalEventLog.getInstance().logExcessiveBinderCalls(uid); if (uid == Process.SYSTEM_UID) { Slog.i(TAG, "Skipping kill (uid is SYSTEM)"); } else { diff --git a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java index 816c3490d0a0..036284f53749 100644 --- a/services/core/java/com/android/server/criticalevents/CriticalEventLog.java +++ b/services/core/java/com/android/server/criticalevents/CriticalEventLog.java @@ -30,6 +30,7 @@ import com.android.server.criticalevents.nano.CriticalEventProto; import com.android.server.criticalevents.nano.CriticalEventProto.AppNotResponding; import com.android.server.criticalevents.nano.CriticalEventProto.HalfWatchdog; import com.android.server.criticalevents.nano.CriticalEventProto.InstallPackages; +import com.android.server.criticalevents.nano.CriticalEventProto.ExcessiveBinderCalls; import com.android.server.criticalevents.nano.CriticalEventProto.JavaCrash; import com.android.server.criticalevents.nano.CriticalEventProto.NativeCrash; import com.android.server.criticalevents.nano.CriticalEventProto.SystemServerStarted; @@ -143,6 +144,15 @@ public class CriticalEventLog { return System.currentTimeMillis(); } + /** Logs when a uid sends an excessive number of binder calls. */ + public void logExcessiveBinderCalls(int uid) { + CriticalEventProto event = new CriticalEventProto(); + ExcessiveBinderCalls calls = new ExcessiveBinderCalls(); + calls.uid = uid; + event.setExcessiveBinderCalls(calls); + log(event); + } + /** Logs when one or more packages are installed. */ public void logInstallPackagesStarted() { CriticalEventProto event = new CriticalEventProto(); -- cgit v1.2.3-59-g8ed1b