Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea5f5bb2 authored by Riley Jones's avatar Riley Jones
Browse files

Drag-to-edit closes quick settings when going to the edit shortcut screen.

Also, previously MenuView was responsible for handling traversal to the edit screen.
Now, that responsibility has been given to MenuViewLayer
(it better aligns with MenuViewLayer's existing responsibilities).

Bug: 324931103
Test: atest com.android.systemui.accessibility.floatingmenu
Flag: aconfig FLOATING_MENU_DRAG_TO_EDIT ENABLED
Change-Id: I06392f958a966907fcb2c7390b4df6348070babf
parent 678cba88
Loading
Loading
Loading
Loading
+0 −40
Original line number Diff line number Diff line
@@ -21,17 +21,10 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.annotation.SuppressLint;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.SettingsStringUtil;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
@@ -431,22 +424,6 @@ class MenuView extends FrameLayout implements
        onPositionChanged();
    }

    void gotoEditScreen() {
        if (!Flags.floatingMenuDragToEdit()) {
            return;
        }
        mMenuAnimationController.flingMenuThenSpringToEdge(
                getMenuPosition().x, 100f, 0f);

        Intent intent = getIntentForEditScreen();
        PackageManager packageManager = getContext().getPackageManager();
        List<ResolveInfo> activities = packageManager.queryIntentActivities(intent,
                PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
        if (!activities.isEmpty()) {
            mContext.startActivity(intent);
        }
    }

    void incrementTexMetricForAllTargets(String metric) {
        if (!Flags.floatingMenuDragToEdit()) {
            return;
@@ -461,23 +438,6 @@ class MenuView extends FrameLayout implements
        Counter.logIncrementWithUid(metric, uid);
    }

    Intent getIntentForEditScreen() {
        List<String> targets = new SettingsStringUtil.ColonDelimitedSet.OfStrings(
                mSecureSettings.getStringForUser(
                        Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
                        UserHandle.USER_CURRENT)).stream().toList();

        Intent intent = new Intent(
                Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS);
        Bundle args = new Bundle();
        Bundle fragmentArgs = new Bundle();
        fragmentArgs.putStringArray("targets", targets.toArray(new String[0]));
        args.putBundle(":settings:show_fragment_args", fragmentArgs);
        intent.replaceExtras(args);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        return intent;
    }

    private InstantInsetLayerDrawable getContainerViewInsetLayer() {
        return (InstantInsetLayerDrawable) getBackground();
    }
+42 −1
Original line number Diff line number Diff line
@@ -36,19 +36,24 @@ import android.annotation.IntDef;
import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.app.NotificationManager;
import android.app.StatusBarManager;
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.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.SettingsStringUtil;
import android.util.ArraySet;
import android.view.MotionEvent;
import android.view.View;
@@ -120,6 +125,7 @@ class MenuViewLayer extends FrameLayout implements
    private final MenuAnimationController mMenuAnimationController;
    private final AccessibilityManager mAccessibilityManager;
    private final NotificationManager mNotificationManager;
    private StatusBarManager mStatusBarManager;
    private final MenuNotificationFactory mNotificationFactory;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final IAccessibilityFloatingMenu mFloatingMenu;
@@ -246,6 +252,7 @@ class MenuViewLayer extends FrameLayout implements
        mDismissView.getCircle().setId(R.id.action_remove_menu);
        mNotificationFactory = new MenuNotificationFactory(context);
        mNotificationManager = context.getSystemService(NotificationManager.class);
        mStatusBarManager = context.getSystemService(StatusBarManager.class);

        if (Flags.floatingMenuDragToEdit()) {
            mDragToInteractAnimationController = new DragToInteractAnimationController(
@@ -490,7 +497,7 @@ class MenuViewLayer extends FrameLayout implements
            mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_DISMISS);
        } else if (id == R.id.action_edit
                && Flags.floatingMenuDragToEdit()) {
            mMenuView.gotoEditScreen();
            gotoEditScreen();
            mMenuView.incrementTexMetricForAllTargets(TEX_METRIC_EDIT);
        }
        mDismissView.hide();
@@ -499,6 +506,40 @@ class MenuViewLayer extends FrameLayout implements
                id, /* scaleUp= */ false);
    }

    void gotoEditScreen() {
        if (!Flags.floatingMenuDragToEdit()) {
            return;
        }
        mMenuAnimationController.flingMenuThenSpringToEdge(
                mMenuView.getMenuPosition().x, 100f, 0f);

        Intent intent = getIntentForEditScreen();
        PackageManager packageManager = getContext().getPackageManager();
        List<ResolveInfo> activities = packageManager.queryIntentActivities(intent,
                PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
        if (!activities.isEmpty()) {
            mContext.startActivity(intent);
            mStatusBarManager.collapsePanels();
        }
    }

    Intent getIntentForEditScreen() {
        List<String> targets = new SettingsStringUtil.ColonDelimitedSet.OfStrings(
                mSecureSettings.getStringForUser(
                        Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
                        UserHandle.USER_CURRENT)).stream().toList();

        Intent intent = new Intent(
                Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS);
        Bundle args = new Bundle();
        Bundle fragmentArgs = new Bundle();
        fragmentArgs.putStringArray("targets", targets.toArray(new String[0]));
        args.putBundle(":settings:show_fragment_args", fragmentArgs);
        intent.replaceExtras(args);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        return intent;
    }

    private CharSequence getMigrationMessage() {
        final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+1 −1
Original line number Diff line number Diff line
@@ -90,12 +90,12 @@ public class MenuItemAccessibilityDelegateTest extends SysuiTestCase {
        mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance,
                mSecureSettings));
        mMenuView.setTranslationY(halfScreenHeight);
        doNothing().when(mMenuView).gotoEditScreen();

        mMenuViewLayer = spy(new MenuViewLayer(
                mContext, stubWindowManager, mAccessibilityManager,
                stubMenuViewModel, stubMenuViewAppearance, mMenuView,
                mock(IAccessibilityFloatingMenu.class), mSecureSettings));
        doNothing().when(mMenuViewLayer).gotoEditScreen();

        doReturn(mDraggableBounds).when(mMenuView).getMenuDraggableBounds();
        mStubListView = new RecyclerView(mContext);
+42 −4
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.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;
@@ -49,6 +50,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.Insets;
@@ -136,6 +138,8 @@ public class MenuViewLayerTest extends SysuiTestCase {
    private WindowManager mStubWindowManager;
    @Mock
    private AccessibilityManager mStubAccessibilityManager;
    @Mock
    private PackageManager mMockPackageManager;
    private final SecureSettings mSecureSettings = TestUtils.mockSecureSettings();

    private final NotificationManager mMockNotificationManager = mock(NotificationManager.class);
@@ -162,14 +166,15 @@ public class MenuViewLayerTest extends SysuiTestCase {
                new MenuView(mSpyContext, mMenuViewModel, menuViewAppearance, mSecureSettings));
        // Ensure tests don't actually update metrics.
        doNothing().when(mMenuView).incrementTexMetric(any(), anyInt());
        doNothing().when(mMenuView).gotoEditScreen();

        mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager,
                mStubAccessibilityManager, mMenuViewModel, menuViewAppearance, mMenuView,
                mFloatingMenu, mSecureSettings));
        mMenuView = (MenuView) mMenuViewLayer.getChildAt(LayerIndex.MENU_VIEW);
        mMenuAnimationController = mMenuView.getMenuAnimationController();

        doNothing().when(mSpyContext).startActivity(any());
        when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);

        mLastAccessibilityButtonTargets =
                Settings.Secure.getStringForUser(mSpyContext.getContentResolver(),
                        Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, UserHandle.USER_CURRENT);
@@ -277,9 +282,31 @@ public class MenuViewLayerTest extends SysuiTestCase {

    @Test
    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
    public void onEditAction_gotoEditScreen_isCalled() {
    public void onEditAction_startsActivity() {
        mockActivityQuery(true);
        mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
        verify(mSpyContext).startActivity(intentCaptor.capture());
        assertThat(intentCaptor.getValue().getAction()).isEqualTo(
                mMenuViewLayer.getIntentForEditScreen().getAction());
    }

    @Test
    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
    public void onEditAction_noResolve_doesNotStart() {
        mockActivityQuery(false);
        mMenuViewLayer.dispatchAccessibilityAction(R.id.action_edit);
        verify(mMenuView).gotoEditScreen();
        verify(mSpyContext, never()).startActivity(any());
    }

    @Test
    public void getIntentForEditScreen_validate() {
        Intent intent = mMenuViewLayer.getIntentForEditScreen();
        String[] targets = intent.getBundleExtra(
                ":settings:show_fragment_args").getStringArray("targets");

        assertThat(intent.getAction()).isEqualTo(Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS);
        assertThat(targets).asList().containsExactlyElementsIn(TestUtils.TEST_BUTTON_TARGETS);
    }

    @Test
@@ -527,4 +554,15 @@ public class MenuViewLayerTest extends SysuiTestCase {
        magnetListener.onReleasedInTarget(
                new MagnetizedObject.MagneticTarget(view, 200), mock(MagnetizedObject.class));
    }

    private void mockActivityQuery(boolean successfulQuery) {
        // Query just needs to return a non-empty set to be successful.
        ArrayList<ResolveInfo> resolveInfos = new ArrayList<>();
        if (successfulQuery) {
            resolveInfos.add(new ResolveInfo());
        }
        when(mMockPackageManager.queryIntentActivities(
                any(), any(PackageManager.ResolveInfoFlags.class))).thenReturn(resolveInfos);
    }

}
+0 −47
Original line number Diff line number Diff line
@@ -22,19 +22,13 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.UiModeManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.graphics.drawable.GradientDrawable;
import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.WindowManager;
@@ -58,8 +52,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.ArrayList;

/** Tests for {@link MenuView}. */
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -79,8 +71,6 @@ public class MenuViewTest extends SysuiTestCase {
    private AccessibilityManager mAccessibilityManager;

    private SysuiTestableContext mSpyContext;
    @Mock
    private PackageManager mMockPackageManager;

    @Before
    public void setUp() throws Exception {
@@ -91,7 +81,6 @@ public class MenuViewTest extends SysuiTestCase {
        mSpyContext = spy(mContext);
        doNothing().when(mSpyContext).startActivity(any());

        when(mSpyContext.getPackageManager()).thenReturn(mMockPackageManager);
        final SecureSettings secureSettings = TestUtils.mockSecureSettings();
        final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
                secureSettings);
@@ -178,32 +167,6 @@ public class MenuViewTest extends SysuiTestCase {
        assertThat(radiiAnimator.isStarted()).isTrue();
    }

    @Test
    public void getIntentForEditScreen_validate() {
        Intent intent = mMenuView.getIntentForEditScreen();
        String[] targets = intent.getBundleExtra(
                ":settings:show_fragment_args").getStringArray("targets");

        assertThat(intent.getAction()).isEqualTo(Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS);
        assertThat(targets).asList().containsExactlyElementsIn(TestUtils.TEST_BUTTON_TARGETS);
    }

    @Test
    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
    public void gotoEditScreen_sendsIntent() {
        mockActivityQuery(true);
        mMenuView.gotoEditScreen();
        verify(mSpyContext).startActivity(any());
    }

    @Test
    @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
    public void gotoEditScreen_noResolve_doesNotStart() {
        mockActivityQuery(false);
        mMenuView.gotoEditScreen();
        verify(mSpyContext, never()).startActivity(any());
    }

    private InstantInsetLayerDrawable getMenuViewInsetLayer() {
        return (InstantInsetLayerDrawable) mMenuView.getBackground();
    }
@@ -226,14 +189,4 @@ public class MenuViewTest extends SysuiTestCase {
        mUiModeManager.setNightMode(mNightMode);
        Prefs.putString(mContext, Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, mLastPosition);
    }

    private void mockActivityQuery(boolean successfulQuery) {
        // Query just needs to return a non-empty set to be successful.
        ArrayList<ResolveInfo> resolveInfos = new ArrayList<>();
        if (successfulQuery) {
            resolveInfos.add(new ResolveInfo());
        }
        when(mMockPackageManager.queryIntentActivities(
                any(), any(PackageManager.ResolveInfoFlags.class))).thenReturn(resolveInfos);
    }
}