From c6ee1e9e03371690bed9dc659622268ab1b5bcac Mon Sep 17 00:00:00 2001 From: Peter Liang Date: Tue, 31 Jan 2023 14:45:16 +0800 Subject: [PATCH 1/2] Remove the feature flag of the A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS. Actions: Replace the legacy implementation with a new one. Bug: 262224538 Test: atest AccessibilityFloatingMenuControllerTest Change-Id: I01226212f8fccb4d95eb7fd55b1219198d1dea5e --- .../AccessibilityFloatingMenuController.java | 25 ++++-------- .../src/com/android/systemui/flags/Flags.kt | 6 --- ...cessibilityFloatingMenuControllerTest.java | 40 +++++-------------- 3 files changed, 18 insertions(+), 53 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java index 2c413a234c598..592414952ea82 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java @@ -19,8 +19,6 @@ package com.android.systemui.accessibility.floatingmenu; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; -import static com.android.systemui.flags.Flags.A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS; - import android.content.Context; import android.hardware.display.DisplayManager; import android.os.UserHandle; @@ -38,7 +36,6 @@ import com.android.systemui.accessibility.AccessibilityButtonModeObserver; import com.android.systemui.accessibility.AccessibilityButtonModeObserver.AccessibilityButtonMode; import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; import com.android.systemui.dagger.SysUISingleton; -import com.android.systemui.flags.FeatureFlags; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.util.settings.SecureSettings; @@ -59,7 +56,7 @@ public class AccessibilityFloatingMenuController implements private final WindowManager mWindowManager; private final DisplayManager mDisplayManager; private final AccessibilityManager mAccessibilityManager; - private final FeatureFlags mFeatureFlags; + private final SecureSettings mSecureSettings; private final DisplayTracker mDisplayTracker; @VisibleForTesting @@ -105,7 +102,6 @@ public class AccessibilityFloatingMenuController implements AccessibilityButtonTargetsObserver accessibilityButtonTargetsObserver, AccessibilityButtonModeObserver accessibilityButtonModeObserver, KeyguardUpdateMonitor keyguardUpdateMonitor, - FeatureFlags featureFlags, SecureSettings secureSettings, DisplayTracker displayTracker) { mContext = context; @@ -115,7 +111,6 @@ public class AccessibilityFloatingMenuController implements mAccessibilityButtonTargetsObserver = accessibilityButtonTargetsObserver; mAccessibilityButtonModeObserver = accessibilityButtonModeObserver; mKeyguardUpdateMonitor = keyguardUpdateMonitor; - mFeatureFlags = featureFlags; mSecureSettings = secureSettings; mDisplayTracker = displayTracker; @@ -162,7 +157,7 @@ public class AccessibilityFloatingMenuController implements * Handles the accessibility floating menu visibility with the given values. * * @param keyguardVisible the keyguard visibility status. Not show the - * {@link AccessibilityFloatingMenu} when keyguard appears. + * {@link MenuView} when keyguard appears. * @param mode accessibility button mode {@link AccessibilityButtonMode} * @param targets accessibility button list; it should comes from * {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. @@ -187,16 +182,12 @@ public class AccessibilityFloatingMenuController implements private void showFloatingMenu() { if (mFloatingMenu == null) { - if (mFeatureFlags.isEnabled(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS)) { - final Display defaultDisplay = mDisplayManager.getDisplay( - mDisplayTracker.getDefaultDisplayId()); - final Context windowContext = mContext.createWindowContext(defaultDisplay, - TYPE_NAVIGATION_BAR_PANEL, /* options= */ null); - mFloatingMenu = new MenuViewLayerController(windowContext, mWindowManager, - mAccessibilityManager, mSecureSettings); - } else { - mFloatingMenu = new AccessibilityFloatingMenu(mContext, mSecureSettings); - } + final Display defaultDisplay = mDisplayManager.getDisplay( + mDisplayTracker.getDefaultDisplayId()); + final Context windowContext = mContext.createWindowContext(defaultDisplay, + TYPE_NAVIGATION_BAR_PANEL, /* options= */ null); + mFloatingMenu = new MenuViewLayerController(windowContext, mWindowManager, + mAccessibilityManager, mSecureSettings); } mFloatingMenu.show(); diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 7ff27cfdb08b6..7c0345ebdb9e5 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -535,12 +535,6 @@ object Flags { // TODO(b/266983474) Tracking Bug val SHARESHEET_IMAGE_AND_TEXT_PREVIEW = unreleasedFlag(1503, "sharesheet_image_text_preview") - // 1600 - accessibility - // TODO(b/262224538): Tracking Bug - @JvmField - val A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS = - releasedFlag(1600, "a11y_floating_menu_fling_spring_animations") - // 1700 - clipboard @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior") diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java index aac0b511a56c2..3da72618fb601 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuControllerTest.java @@ -19,8 +19,6 @@ package com.android.systemui.accessibility.floatingmenu; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; -import static com.android.systemui.flags.Flags.A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -46,7 +44,6 @@ import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.AccessibilityButtonModeObserver; import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver; -import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.settings.FakeDisplayTracker; import com.android.systemui.util.settings.SecureSettings; @@ -74,6 +71,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { public MockitoRule mockito = MockitoJUnit.rule(); private Context mContextWrapper; + private WindowManager mWindowManager; private AccessibilityManager mAccessibilityManager; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; private AccessibilityFloatingMenuController mController; @@ -97,6 +95,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { } }; + mWindowManager = mContext.getSystemService(WindowManager.class); mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mLastButtonTargets = Settings.Secure.getStringForUser(mContextWrapper.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, UserHandle.USER_CURRENT); @@ -158,7 +157,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { public void onKeyguardVisibilityChanged_showing_destroyWidget() { enableAccessibilityFloatingMenuConfig(); mController = setUpController(); - mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper, mSecureSettings); + mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager, + mAccessibilityManager, mSecureSettings); captureKeyguardUpdateMonitorCallback(); mKeyguardCallback.onUserUnlocked(); @@ -184,7 +184,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { final int fakeUserId = 1; enableAccessibilityFloatingMenuConfig(); mController = setUpController(); - mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper, mSecureSettings); + mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager, + mAccessibilityManager, mSecureSettings); captureKeyguardUpdateMonitorCallback(); mKeyguardCallback.onUserSwitching(fakeUserId); @@ -197,7 +198,8 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { final int fakeUserId = 1; enableAccessibilityFloatingMenuConfig(); mController = setUpController(); - mController.mFloatingMenu = new AccessibilityFloatingMenu(mContextWrapper, mSecureSettings); + mController.mFloatingMenu = new MenuViewLayerController(mContextWrapper, mWindowManager, + mAccessibilityManager, mSecureSettings); captureKeyguardUpdateMonitorCallback(); mKeyguardCallback.onUserUnlocked(); mKeyguardCallback.onKeyguardVisibilityChanged(true); @@ -317,41 +319,19 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { assertThat(mController.mFloatingMenu).isNull(); } - @Test - public void onTargetsChanged_flingSpringAnimationsDisabled_floatingMenuIsCreated() { - Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(), - Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, - UserHandle.USER_CURRENT); - final FakeFeatureFlags featureFlags = new FakeFeatureFlags(); - featureFlags.set(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS, false); - - mController = setUpController(); - mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS); - - assertThat(mController.mFloatingMenu).isInstanceOf(AccessibilityFloatingMenu.class); - } - @Test public void onTargetsChanged_isFloatingViewLayerControllerCreated() { Settings.Secure.putIntForUser(mContextWrapper.getContentResolver(), Settings.Secure.ACCESSIBILITY_BUTTON_MODE, ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU, UserHandle.USER_CURRENT); - final FakeFeatureFlags featureFlags = new FakeFeatureFlags(); - featureFlags.set(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS, true); - mController = setUpController(featureFlags); + mController = setUpController(); mController.onAccessibilityButtonTargetsChanged(TEST_A11Y_BTN_TARGETS); assertThat(mController.mFloatingMenu).isInstanceOf(MenuViewLayerController.class); } private AccessibilityFloatingMenuController setUpController() { - final FakeFeatureFlags featureFlags = new FakeFeatureFlags(); - featureFlags.set(A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS, false); - return setUpController(featureFlags); - } - - private AccessibilityFloatingMenuController setUpController(FakeFeatureFlags featureFlags) { final WindowManager windowManager = mContext.getSystemService(WindowManager.class); final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); final FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext); @@ -361,7 +341,7 @@ public class AccessibilityFloatingMenuControllerTest extends SysuiTestCase { final AccessibilityFloatingMenuController controller = new AccessibilityFloatingMenuController(mContextWrapper, windowManager, displayManager, mAccessibilityManager, mTargetsObserver, mModeObserver, - mKeyguardUpdateMonitor, featureFlags, mSecureSettings, displayTracker); + mKeyguardUpdateMonitor, mSecureSettings, displayTracker); controller.init(); return controller; From 3fe5422595ebd133bf1023a414e273f94a93f072 Mon Sep 17 00:00:00 2001 From: Peter Liang Date: Tue, 31 Jan 2023 15:48:41 +0800 Subject: [PATCH 2/2] Remove the legacy implementation of the accessibility floating menu. Goal: Replace the legacy implementation with a new one. Bug: 262224538 Test: manual test Change-Id: I92149aedc57a2dbeec4e0dcba331b025fd24bf61 --- .../AccessibilityFloatingMenu.java | 277 ------ .../AccessibilityFloatingMenuView.java | 921 ------------------ .../floatingmenu/BaseTooltipView.java | 299 ------ .../floatingmenu/DockTooltipView.java | 50 - .../floatingmenu/ItemDelegateCompat.java | 141 --- .../floatingmenu/MigrationTooltipView.java | 52 - .../AccessibilityFloatingMenuTest.java | 108 -- .../AccessibilityFloatingMenuViewTest.java | 527 ---------- .../floatingmenu/BaseTooltipViewTest.java | 133 --- .../floatingmenu/DockTooltipViewTest.java | 116 --- .../floatingmenu/ItemDelegateCompatTest.java | 178 ---- .../MigrationTooltipViewTest.java | 71 -- 12 files changed, 2873 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java delete mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java delete mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java delete mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DockTooltipView.java delete mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompat.java delete mode 100644 packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipView.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipViewTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DockTooltipViewTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompatTest.java delete mode 100644 packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipViewTest.java diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java deleted file mode 100644 index 81d7766ac275a..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright (C) 2021 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 android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED; -import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE; -import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT; -import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY; -import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE; -import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON; - -import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets; -import static com.android.systemui.Prefs.Key.HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP; -import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.ShapeType; -import static com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.SizeType; - -import android.annotation.FloatRange; -import android.content.Context; -import android.database.ContentObserver; -import android.os.Handler; -import android.os.Looper; -import android.os.UserHandle; -import android.provider.Settings; -import android.text.TextUtils; - -import androidx.annotation.NonNull; - -import com.android.internal.accessibility.dialog.AccessibilityTarget; -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Prefs; -import com.android.systemui.shared.system.SysUiStatsLog; -import com.android.systemui.util.settings.SecureSettings; - -import java.util.List; - -/** - * Contains logic for an accessibility floating menu view. - */ -public class AccessibilityFloatingMenu implements IAccessibilityFloatingMenu { - private static final int DEFAULT_FADE_EFFECT_IS_ENABLED = 1; - private static final int DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED = 0; - @FloatRange(from = 0.0, to = 1.0) - private static final float DEFAULT_OPACITY_VALUE = 0.55f; - @FloatRange(from = 0.0, to = 1.0) - private static final float DEFAULT_POSITION_X_PERCENT = 1.0f; - @FloatRange(from = 0.0, to = 1.0) - private static final float DEFAULT_POSITION_Y_PERCENT = 0.77f; - - private final Context mContext; - private final SecureSettings mSecureSettings; - private final AccessibilityFloatingMenuView mMenuView; - private final MigrationTooltipView mMigrationTooltipView; - private final DockTooltipView mDockTooltipView; - private final Handler mHandler = new Handler(Looper.getMainLooper()); - - private final ContentObserver mContentObserver = - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON)); - } - }; - - private final ContentObserver mSizeContentObserver = - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - mMenuView.setSizeType(getSizeType()); - } - }; - - private final ContentObserver mFadeOutContentObserver = - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - mMenuView.updateOpacityWith(isFadeEffectEnabled(), - getOpacityValue()); - } - }; - - private final ContentObserver mEnabledA11yServicesContentObserver = - new ContentObserver(mHandler) { - @Override - public void onChange(boolean selfChange) { - mMenuView.onEnabledFeaturesChanged(); - } - }; - - public AccessibilityFloatingMenu(Context context, SecureSettings secureSettings) { - mContext = context; - mSecureSettings = secureSettings; - mMenuView = new AccessibilityFloatingMenuView(context, getPosition(context)); - mMigrationTooltipView = new MigrationTooltipView(mContext, mMenuView); - mDockTooltipView = new DockTooltipView(mContext, mMenuView); - } - - @VisibleForTesting - AccessibilityFloatingMenu(Context context, SecureSettings secureSettings, - AccessibilityFloatingMenuView menuView) { - mContext = context; - mSecureSettings = secureSettings; - mMenuView = menuView; - mMigrationTooltipView = new MigrationTooltipView(mContext, mMenuView); - mDockTooltipView = new DockTooltipView(mContext, mMenuView); - } - - @Override - public boolean isShowing() { - return mMenuView.isShowing(); - } - - @Override - public void show() { - if (isShowing()) { - return; - } - final List targetList = getTargets(mContext, ACCESSIBILITY_BUTTON); - if (targetList.isEmpty()) { - return; - } - - mMenuView.show(); - mMenuView.onTargetsChanged(targetList); - mMenuView.updateOpacityWith(isFadeEffectEnabled(), - getOpacityValue()); - mMenuView.setSizeType(getSizeType()); - mMenuView.setShapeType(getShapeType()); - mMenuView.setOnDragEndListener(this::onDragEnd); - - showMigrationTooltipIfNecessary(); - - registerContentObservers(); - } - - @Override - public void hide() { - if (!isShowing()) { - return; - } - - mMenuView.hide(); - mMenuView.setOnDragEndListener(null); - mMigrationTooltipView.hide(); - mDockTooltipView.hide(); - - unregisterContentObservers(); - } - - @NonNull - private Position getPosition(Context context) { - final String absolutePositionString = Prefs.getString(context, - Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, /* defaultValue= */ null); - - if (TextUtils.isEmpty(absolutePositionString)) { - return new Position(DEFAULT_POSITION_X_PERCENT, DEFAULT_POSITION_Y_PERCENT); - } else { - return Position.fromString(absolutePositionString); - } - } - - // Migration tooltip was the android S feature. It's just used on the Android version from R - // to S. In addition, it only shows once. - private void showMigrationTooltipIfNecessary() { - if (isMigrationTooltipPromptEnabled()) { - mMigrationTooltipView.show(); - - mSecureSettings.putInt( - ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT, /* disabled */ 0); - } - } - - private boolean isMigrationTooltipPromptEnabled() { - return mSecureSettings.getInt( - ACCESSIBILITY_FLOATING_MENU_MIGRATION_TOOLTIP_PROMPT, - DEFAULT_MIGRATION_TOOLTIP_PROMPT_IS_DISABLED) == /* enabled */ 1; - } - - private void onDragEnd(Position position) { - SysUiStatsLog.write(SysUiStatsLog.ACCESSIBILITY_FLOATING_MENU_UI_CHANGED, - position.getPercentageX(), position.getPercentageY(), - mContext.getResources().getConfiguration().orientation); - savePosition(mContext, position); - showDockTooltipIfNecessary(mContext); - } - - private void savePosition(Context context, Position position) { - Prefs.putString(context, Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION, - position.toString()); - } - - /** - * Shows tooltip when user drags accessibility floating menu for the first time. - */ - private void showDockTooltipIfNecessary(Context context) { - if (!Prefs.get(context).getBoolean( - HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP, false)) { - // if the menu is an oval, the user has already dragged it out, so show the tooltip. - if (mMenuView.isOvalShape()) { - mDockTooltipView.show(); - } - - Prefs.putBoolean(context, HAS_SEEN_ACCESSIBILITY_FLOATING_MENU_DOCK_TOOLTIP, true); - } - } - - private boolean isFadeEffectEnabled() { - return mSecureSettings.getInt( - ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, - DEFAULT_FADE_EFFECT_IS_ENABLED) == /* enabled */ 1; - } - - private float getOpacityValue() { - return mSecureSettings.getFloat( - ACCESSIBILITY_FLOATING_MENU_OPACITY, - DEFAULT_OPACITY_VALUE); - } - - private int getSizeType() { - return mSecureSettings.getInt( - ACCESSIBILITY_FLOATING_MENU_SIZE, SizeType.SMALL); - } - - private int getShapeType() { - return mSecureSettings.getInt( - ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, - ShapeType.OVAL); - } - - private void registerContentObservers() { - mSecureSettings.registerContentObserverForUser( - Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, - /* notifyForDescendants */ false, mContentObserver, - UserHandle.USER_CURRENT); - mSecureSettings.registerContentObserverForUser( - Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, - /* notifyForDescendants */ false, mContentObserver, - UserHandle.USER_CURRENT); - mSecureSettings.registerContentObserverForUser( - Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, - /* notifyForDescendants */ false, mSizeContentObserver, - UserHandle.USER_CURRENT); - mSecureSettings.registerContentObserverForUser( - Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, - /* notifyForDescendants */ false, mFadeOutContentObserver, - UserHandle.USER_CURRENT); - mSecureSettings.registerContentObserverForUser( - Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, - /* notifyForDescendants */ false, mFadeOutContentObserver, - UserHandle.USER_CURRENT); - mSecureSettings.registerContentObserverForUser( - Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, - /* notifyForDescendants */ false, - mEnabledA11yServicesContentObserver, UserHandle.USER_CURRENT); - } - - private void unregisterContentObservers() { - mSecureSettings.unregisterContentObserver(mContentObserver); - mSecureSettings.unregisterContentObserver(mSizeContentObserver); - mSecureSettings.unregisterContentObserver(mFadeOutContentObserver); - mSecureSettings.unregisterContentObserver( - mEnabledA11yServicesContentObserver); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java deleted file mode 100644 index aff0b1fe287c0..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuView.java +++ /dev/null @@ -1,921 +0,0 @@ -/* - * Copyright (C) 2021 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 android.content.res.Configuration.ORIENTATION_PORTRAIT; -import static android.util.MathUtils.constrain; -import static android.util.MathUtils.sq; -import static android.view.WindowInsets.Type.displayCutout; -import static android.view.WindowInsets.Type.ime; -import static android.view.WindowInsets.Type.systemBars; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION; - -import static java.util.Objects.requireNonNull; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.annotation.FloatRange; -import android.annotation.IntDef; -import android.content.Context; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Insets; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.LayerDrawable; -import android.os.Handler; -import android.os.Looper; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; -import android.view.animation.Animation; -import android.view.animation.OvershootInterpolator; -import android.view.animation.TranslateAnimation; -import android.widget.FrameLayout; - -import androidx.annotation.DimenRes; -import androidx.annotation.NonNull; -import androidx.core.view.AccessibilityDelegateCompat; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate; - -import com.android.internal.accessibility.dialog.AccessibilityTarget; -import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.R; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -/** - * Accessibility floating menu is used for the actions of accessibility features, it's also the - * action set. - * - *

The number of items would depend on strings key - * {@link android.provider.Settings.Secure#ACCESSIBILITY_BUTTON_TARGETS}. - */ -public class AccessibilityFloatingMenuView extends FrameLayout - implements RecyclerView.OnItemTouchListener { - private static final int INDEX_MENU_ITEM = 0; - private static final int FADE_OUT_DURATION_MS = 1000; - private static final int FADE_EFFECT_DURATION_MS = 3000; - private static final int SNAP_TO_LOCATION_DURATION_MS = 150; - private static final int MIN_WINDOW_Y = 0; - - private static final int ANIMATION_START_OFFSET = 600; - private static final int ANIMATION_DURATION_MS = 600; - private static final float ANIMATION_TO_X_VALUE = 0.5f; - - private boolean mIsFadeEffectEnabled; - private boolean mIsShowing; - private boolean mIsDownInEnlargedTouchArea; - private boolean mIsDragging = false; - @Alignment - private int mAlignment; - @SizeType - private int mSizeType = SizeType.SMALL; - @VisibleForTesting - @ShapeType - int mShapeType = ShapeType.OVAL; - private int mTemporaryShapeType; - @RadiusType - private int mRadiusType; - private int mMargin; - private int mPadding; - // The display width excludes the window insets of the system bar and display cutout. - private int mDisplayHeight; - // The display Height excludes the window insets of the system bar and display cutout. - private int mDisplayWidth; - private int mIconWidth; - private int mIconHeight; - private int mInset; - private int mDownX; - private int mDownY; - private int mRelativeToPointerDownX; - private int mRelativeToPointerDownY; - private float mRadius; - private final Rect mDisplayInsetsRect = new Rect(); - private final Rect mImeInsetsRect = new Rect(); - private final Position mPosition; - private float mSquareScaledTouchSlop; - private final Configuration mLastConfiguration; - private Optional mOnDragEndListener = Optional.empty(); - private final RecyclerView mListView; - private final AccessibilityTargetAdapter mAdapter; - private float mFadeOutValue; - private final ValueAnimator mFadeOutAnimator; - @VisibleForTesting - final ValueAnimator mDragAnimator; - private final Handler mUiHandler; - @VisibleForTesting - final WindowManager.LayoutParams mCurrentLayoutParams; - private final WindowManager mWindowManager; - private final List mTargets = new ArrayList<>(); - - @IntDef({ - SizeType.SMALL, - SizeType.LARGE - }) - @Retention(RetentionPolicy.SOURCE) - @interface SizeType { - int SMALL = 0; - int LARGE = 1; - } - - @IntDef({ - ShapeType.OVAL, - ShapeType.HALF_OVAL - }) - @Retention(RetentionPolicy.SOURCE) - @interface ShapeType { - int OVAL = 0; - int HALF_OVAL = 1; - } - - @IntDef({ - RadiusType.LEFT_HALF_OVAL, - RadiusType.OVAL, - RadiusType.RIGHT_HALF_OVAL - }) - @Retention(RetentionPolicy.SOURCE) - @interface RadiusType { - int LEFT_HALF_OVAL = 0; - int OVAL = 1; - int RIGHT_HALF_OVAL = 2; - } - - @IntDef({ - Alignment.LEFT, - Alignment.RIGHT - }) - @Retention(RetentionPolicy.SOURCE) - @interface Alignment { - int LEFT = 0; - int RIGHT = 1; - } - - /** - * Interface for a callback to be invoked when the floating menu was dragging. - */ - interface OnDragEndListener { - - /** - * Called when a drag is completed. - * - * @param position Stores information about the position - */ - void onDragEnd(Position position); - } - - public AccessibilityFloatingMenuView(Context context, @NonNull Position position) { - this(context, position, new RecyclerView(context)); - } - - @VisibleForTesting - AccessibilityFloatingMenuView(Context context, @NonNull Position position, - RecyclerView listView) { - super(context); - - mListView = listView; - mWindowManager = context.getSystemService(WindowManager.class); - mLastConfiguration = new Configuration(getResources().getConfiguration()); - mAdapter = new AccessibilityTargetAdapter(mTargets); - mUiHandler = createUiHandler(); - mPosition = position; - mAlignment = transformToAlignment(mPosition.getPercentageX()); - mRadiusType = (mAlignment == Alignment.RIGHT) - ? RadiusType.LEFT_HALF_OVAL - : RadiusType.RIGHT_HALF_OVAL; - - updateDimensions(); - - mCurrentLayoutParams = createDefaultLayoutParams(); - - mFadeOutAnimator = ValueAnimator.ofFloat(1.0f, mFadeOutValue); - mFadeOutAnimator.setDuration(FADE_OUT_DURATION_MS); - mFadeOutAnimator.addUpdateListener( - (animation) -> setAlpha((float) animation.getAnimatedValue())); - - mDragAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); - mDragAnimator.setDuration(SNAP_TO_LOCATION_DURATION_MS); - mDragAnimator.setInterpolator(new OvershootInterpolator()); - mDragAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mPosition.update(transformCurrentPercentageXToEdge(), - calculateCurrentPercentageY()); - mAlignment = transformToAlignment(mPosition.getPercentageX()); - - updateLocationWith(mPosition); - - updateInsetWith(getResources().getConfiguration().uiMode, mAlignment); - - mRadiusType = (mAlignment == Alignment.RIGHT) - ? RadiusType.LEFT_HALF_OVAL - : RadiusType.RIGHT_HALF_OVAL; - updateRadiusWith(mSizeType, mRadiusType, mTargets.size()); - - fadeOut(); - - mOnDragEndListener.ifPresent( - onDragEndListener -> onDragEndListener.onDragEnd(mPosition)); - } - }); - - - initListView(); - updateStrokeWith(getResources().getConfiguration().uiMode, mAlignment); - } - - @Override - public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, - @NonNull MotionEvent event) { - final int currentRawX = (int) event.getRawX(); - final int currentRawY = (int) event.getRawY(); - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - fadeIn(); - - mDownX = currentRawX; - mDownY = currentRawY; - mRelativeToPointerDownX = mCurrentLayoutParams.x - mDownX; - mRelativeToPointerDownY = mCurrentLayoutParams.y - mDownY; - mListView.animate().translationX(0); - break; - case MotionEvent.ACTION_MOVE: - if (mIsDragging - || hasExceededTouchSlop(mDownX, mDownY, currentRawX, currentRawY)) { - if (!mIsDragging) { - mIsDragging = true; - setRadius(mRadius, RadiusType.OVAL); - setInset(0, 0); - } - - mTemporaryShapeType = - isMovingTowardsScreenEdge(mAlignment, currentRawX, mDownX) - ? ShapeType.HALF_OVAL - : ShapeType.OVAL; - final int newWindowX = currentRawX + mRelativeToPointerDownX; - final int newWindowY = currentRawY + mRelativeToPointerDownY; - mCurrentLayoutParams.x = - constrain(newWindowX, getMinWindowX(), getMaxWindowX()); - mCurrentLayoutParams.y = constrain(newWindowY, MIN_WINDOW_Y, getMaxWindowY()); - mWindowManager.updateViewLayout(this, mCurrentLayoutParams); - } - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - if (mIsDragging) { - mIsDragging = false; - - final int minX = getMinWindowX(); - final int maxX = getMaxWindowX(); - final int endX = mCurrentLayoutParams.x > ((minX + maxX) / 2) - ? maxX : minX; - final int endY = mCurrentLayoutParams.y; - snapToLocation(endX, endY); - - setShapeType(mTemporaryShapeType); - - // Avoid triggering the listener of the item. - return true; - } - - // Must switch the oval shape type before tapping the corresponding item in the - // list view, otherwise it can't work on it. - if (!isOvalShape()) { - setShapeType(ShapeType.OVAL); - - return true; - } - - fadeOut(); - break; - default: // Do nothing - } - - // not consume all the events here because keeping the scroll behavior of list view. - return false; - } - - @Override - public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent motionEvent) { - // Do Nothing - } - - @Override - public void onRequestDisallowInterceptTouchEvent(boolean b) { - // Do Nothing - } - - void show() { - if (isShowing()) { - return; - } - - mIsShowing = true; - mWindowManager.addView(this, mCurrentLayoutParams); - - setOnApplyWindowInsetsListener((view, insets) -> onWindowInsetsApplied(insets)); - setSystemGestureExclusion(); - } - - void hide() { - if (!isShowing()) { - return; - } - - mIsShowing = false; - mDragAnimator.cancel(); - mWindowManager.removeView(this); - - setOnApplyWindowInsetsListener(null); - setSystemGestureExclusion(); - } - - boolean isShowing() { - return mIsShowing; - } - - boolean isOvalShape() { - return mShapeType == ShapeType.OVAL; - } - - void onTargetsChanged(List newTargets) { - fadeIn(); - - mTargets.clear(); - mTargets.addAll(newTargets); - onEnabledFeaturesChanged(); - - updateRadiusWith(mSizeType, mRadiusType, mTargets.size()); - updateScrollModeWith(hasExceededMaxLayoutHeight()); - setSystemGestureExclusion(); - - fadeOut(); - } - - void setSizeType(@SizeType int newSizeType) { - fadeIn(); - - mSizeType = newSizeType; - - updateItemViewWith(newSizeType); - updateRadiusWith(newSizeType, mRadiusType, mTargets.size()); - - // When the icon sized changed, the menu size and location will be impacted. - updateLocationWith(mPosition); - updateScrollModeWith(hasExceededMaxLayoutHeight()); - updateOffsetWith(mShapeType, mAlignment); - setSystemGestureExclusion(); - - fadeOut(); - } - - void setShapeType(@ShapeType int newShapeType) { - fadeIn(); - - mShapeType = newShapeType; - - updateOffsetWith(newShapeType, mAlignment); - - setOnTouchListener( - newShapeType == ShapeType.OVAL - ? null - : (view, event) -> onTouched(event)); - - fadeOut(); - } - - public void setOnDragEndListener(OnDragEndListener onDragEndListener) { - mOnDragEndListener = Optional.ofNullable(onDragEndListener); - } - - void startTranslateXAnimation() { - fadeIn(); - - final float toXValue = (mAlignment == Alignment.RIGHT) - ? ANIMATION_TO_X_VALUE - : -ANIMATION_TO_X_VALUE; - final TranslateAnimation animation = - new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, - Animation.RELATIVE_TO_SELF, toXValue, - Animation.RELATIVE_TO_SELF, 0, - Animation.RELATIVE_TO_SELF, 0); - animation.setDuration(ANIMATION_DURATION_MS); - animation.setRepeatMode(Animation.REVERSE); - animation.setInterpolator(new OvershootInterpolator()); - animation.setRepeatCount(Animation.INFINITE); - animation.setStartOffset(ANIMATION_START_OFFSET); - mListView.startAnimation(animation); - } - - void stopTranslateXAnimation() { - mListView.clearAnimation(); - - fadeOut(); - } - - Rect getWindowLocationOnScreen() { - final int left = mCurrentLayoutParams.x; - final int top = mCurrentLayoutParams.y; - return new Rect(left, top, left + getWindowWidth(), top + getWindowHeight()); - } - - void updateOpacityWith(boolean isFadeEffectEnabled, float newOpacityValue) { - mIsFadeEffectEnabled = isFadeEffectEnabled; - mFadeOutValue = newOpacityValue; - - mFadeOutAnimator.cancel(); - mFadeOutAnimator.setFloatValues(1.0f, mFadeOutValue); - setAlpha(mIsFadeEffectEnabled ? mFadeOutValue : /* completely opaque */ 1.0f); - } - - void onEnabledFeaturesChanged() { - mAdapter.notifyDataSetChanged(); - } - - @VisibleForTesting - void fadeIn() { - if (!mIsFadeEffectEnabled) { - return; - } - - mFadeOutAnimator.cancel(); - mUiHandler.removeCallbacksAndMessages(null); - mUiHandler.post(() -> setAlpha(/* completely opaque */ 1.0f)); - } - - @VisibleForTesting - void fadeOut() { - if (!mIsFadeEffectEnabled) { - return; - } - - mUiHandler.postDelayed(() -> mFadeOutAnimator.start(), FADE_EFFECT_DURATION_MS); - } - - private boolean onTouched(MotionEvent event) { - final int action = event.getAction(); - final int currentX = (int) event.getX(); - final int currentY = (int) event.getY(); - - final int marginStartEnd = getMarginStartEndWith(mLastConfiguration); - final Rect touchDelegateBounds = - new Rect(marginStartEnd, mMargin, marginStartEnd + getLayoutWidth(), - mMargin + getLayoutHeight()); - if (action == MotionEvent.ACTION_DOWN - && touchDelegateBounds.contains(currentX, currentY)) { - mIsDownInEnlargedTouchArea = true; - } - - if (!mIsDownInEnlargedTouchArea) { - return false; - } - - if (action == MotionEvent.ACTION_UP - || action == MotionEvent.ACTION_CANCEL) { - mIsDownInEnlargedTouchArea = false; - } - - // In order to correspond to the correct item of list view. - event.setLocation(currentX - mMargin, currentY - mMargin); - return mListView.dispatchTouchEvent(event); - } - - private WindowInsets onWindowInsetsApplied(WindowInsets insets) { - final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics(); - final Rect displayWindowInsetsRect = getDisplayInsets(windowMetrics).toRect(); - if (!displayWindowInsetsRect.equals(mDisplayInsetsRect)) { - updateDisplaySizeWith(windowMetrics); - updateLocationWith(mPosition); - } - - final Rect imeInsetsRect = windowMetrics.getWindowInsets().getInsets(ime()).toRect(); - if (!imeInsetsRect.equals(mImeInsetsRect)) { - if (isImeVisible(imeInsetsRect)) { - mImeInsetsRect.set(imeInsetsRect); - } else { - mImeInsetsRect.setEmpty(); - } - - updateLocationWith(mPosition); - } - - return insets; - } - - private boolean isMovingTowardsScreenEdge(@Alignment int side, int currentRawX, int downX) { - return (side == Alignment.RIGHT && currentRawX > downX) - || (side == Alignment.LEFT && downX > currentRawX); - } - - private boolean isImeVisible(Rect imeInsetsRect) { - return imeInsetsRect.left != 0 || imeInsetsRect.top != 0 || imeInsetsRect.right != 0 - || imeInsetsRect.bottom != 0; - } - - private boolean hasExceededTouchSlop(int startX, int startY, int endX, int endY) { - return (sq(endX - startX) + sq(endY - startY)) > mSquareScaledTouchSlop; - } - - private void setRadius(float radius, @RadiusType int type) { - getMenuGradientDrawable().setCornerRadii(createRadii(radius, type)); - } - - private float[] createRadii(float radius, @RadiusType int type) { - if (type == RadiusType.LEFT_HALF_OVAL) { - return new float[]{radius, radius, 0.0f, 0.0f, 0.0f, 0.0f, radius, radius}; - } - - if (type == RadiusType.RIGHT_HALF_OVAL) { - return new float[]{0.0f, 0.0f, radius, radius, radius, radius, 0.0f, 0.0f}; - } - - return new float[]{radius, radius, radius, radius, radius, radius, radius, radius}; - } - - private Handler createUiHandler() { - return new Handler(requireNonNull(Looper.myLooper(), "looper must not be null")); - } - - private void updateDimensions() { - final Resources res = getResources(); - - updateDisplaySizeWith(mWindowManager.getCurrentWindowMetrics()); - - mMargin = - res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin); - mInset = - res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_inset); - - mSquareScaledTouchSlop = - sq(ViewConfiguration.get(getContext()).getScaledTouchSlop()); - - updateItemViewDimensionsWith(mSizeType); - } - - private void updateDisplaySizeWith(WindowMetrics metrics) { - final Rect displayBounds = metrics.getBounds(); - final Insets displayInsets = getDisplayInsets(metrics); - mDisplayInsetsRect.set(displayInsets.toRect()); - displayBounds.inset(displayInsets); - mDisplayWidth = displayBounds.width(); - mDisplayHeight = displayBounds.height(); - } - - private void updateItemViewDimensionsWith(@SizeType int sizeType) { - final Resources res = getResources(); - final int paddingResId = - sizeType == SizeType.SMALL - ? R.dimen.accessibility_floating_menu_small_padding - : R.dimen.accessibility_floating_menu_large_padding; - mPadding = res.getDimensionPixelSize(paddingResId); - - final int iconResId = - sizeType == SizeType.SMALL - ? R.dimen.accessibility_floating_menu_small_width_height - : R.dimen.accessibility_floating_menu_large_width_height; - mIconWidth = res.getDimensionPixelSize(iconResId); - mIconHeight = mIconWidth; - } - - private void updateItemViewWith(@SizeType int sizeType) { - updateItemViewDimensionsWith(sizeType); - - mAdapter.setItemPadding(mPadding); - mAdapter.setIconWidthHeight(mIconWidth); - mAdapter.notifyDataSetChanged(); - } - - private void initListView() { - final Drawable background = - getContext().getDrawable(R.drawable.accessibility_floating_menu_background); - final LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); - final LayoutParams layoutParams = - new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - mListView.setLayoutParams(layoutParams); - final InstantInsetLayerDrawable layerDrawable = - new InstantInsetLayerDrawable(new Drawable[]{background}); - mListView.setBackground(layerDrawable); - mListView.setAdapter(mAdapter); - mListView.setLayoutManager(layoutManager); - mListView.addOnItemTouchListener(this); - mListView.animate().setInterpolator(new OvershootInterpolator()); - mListView.setAccessibilityDelegateCompat(new RecyclerViewAccessibilityDelegate(mListView) { - @NonNull - @Override - public AccessibilityDelegateCompat getItemDelegate() { - return new ItemDelegateCompat(this, - AccessibilityFloatingMenuView.this); - } - }); - - updateListViewWith(mLastConfiguration); - - addView(mListView); - } - - private void updateListViewWith(Configuration configuration) { - updateMarginWith(configuration); - - final int elevation = - getResources().getDimensionPixelSize(R.dimen.accessibility_floating_menu_elevation); - mListView.setElevation(elevation); - } - - private WindowManager.LayoutParams createDefaultLayoutParams() { - final WindowManager.LayoutParams params = new WindowManager.LayoutParams( - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, - PixelFormat.TRANSLUCENT); - params.receiveInsetsIgnoringZOrder = true; - params.privateFlags |= PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION; - params.windowAnimations = android.R.style.Animation_Translucent; - params.gravity = Gravity.START | Gravity.TOP; - params.x = (mAlignment == Alignment.RIGHT) ? getMaxWindowX() : getMinWindowX(); -// params.y = (int) (mPosition.getPercentageY() * getMaxWindowY()); - final int currentLayoutY = (int) (mPosition.getPercentageY() * getMaxWindowY()); - params.y = Math.max(MIN_WINDOW_Y, currentLayoutY - getInterval()); - updateAccessibilityTitle(params); - return params; - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mLastConfiguration.setTo(newConfig); - - final int diff = newConfig.diff(mLastConfiguration); - if ((diff & ActivityInfo.CONFIG_LOCALE) != 0) { - updateAccessibilityTitle(mCurrentLayoutParams); - } - - updateDimensions(); - updateListViewWith(newConfig); - updateItemViewWith(mSizeType); - updateColor(); - updateStrokeWith(newConfig.uiMode, mAlignment); - updateLocationWith(mPosition); - updateRadiusWith(mSizeType, mRadiusType, mTargets.size()); - updateScrollModeWith(hasExceededMaxLayoutHeight()); - setSystemGestureExclusion(); - } - - @VisibleForTesting - void snapToLocation(int endX, int endY) { - mDragAnimator.cancel(); - mDragAnimator.removeAllUpdateListeners(); - mDragAnimator.addUpdateListener(anim -> onDragAnimationUpdate(anim, endX, endY)); - mDragAnimator.start(); - } - - private void onDragAnimationUpdate(ValueAnimator animator, int endX, int endY) { - float value = (float) animator.getAnimatedValue(); - final int newX = (int) (((1 - value) * mCurrentLayoutParams.x) + (value * endX)); - final int newY = (int) (((1 - value) * mCurrentLayoutParams.y) + (value * endY)); - - mCurrentLayoutParams.x = newX; - mCurrentLayoutParams.y = newY; - mWindowManager.updateViewLayout(this, mCurrentLayoutParams); - } - - private int getMinWindowX() { - return -getMarginStartEndWith(mLastConfiguration); - } - - private int getMaxWindowX() { - return mDisplayWidth - getMarginStartEndWith(mLastConfiguration) - getLayoutWidth(); - } - - private int getMaxWindowY() { - return mDisplayHeight - getWindowHeight(); - } - - private InstantInsetLayerDrawable getMenuLayerDrawable() { - return (InstantInsetLayerDrawable) mListView.getBackground(); - } - - private GradientDrawable getMenuGradientDrawable() { - return (GradientDrawable) getMenuLayerDrawable().getDrawable(INDEX_MENU_ITEM); - } - - private Insets getDisplayInsets(WindowMetrics metrics) { - return metrics.getWindowInsets().getInsetsIgnoringVisibility( - systemBars() | displayCutout()); - } - - /** - * Updates the floating menu to be fixed at the side of the display. - */ - private void updateLocationWith(Position position) { - final @Alignment int alignment = transformToAlignment(position.getPercentageX()); - mCurrentLayoutParams.x = (alignment == Alignment.RIGHT) ? getMaxWindowX() : getMinWindowX(); - final int currentLayoutY = (int) (position.getPercentageY() * getMaxWindowY()); - mCurrentLayoutParams.y = Math.max(MIN_WINDOW_Y, currentLayoutY - getInterval()); - mWindowManager.updateViewLayout(this, mCurrentLayoutParams); - } - - /** - * Gets the moving interval to not overlap between the keyboard and menu view. - * - * @return the moving interval if they overlap each other, otherwise 0. - */ - private int getInterval() { - final int currentLayoutY = (int) (mPosition.getPercentageY() * getMaxWindowY()); - final int imeY = mDisplayHeight - mImeInsetsRect.bottom; - final int layoutBottomY = currentLayoutY + getWindowHeight(); - - return layoutBottomY > imeY ? (layoutBottomY - imeY) : 0; - } - - private void updateMarginWith(Configuration configuration) { - // Avoid overlapping with system bars under landscape mode, update the margins of the menu - // to align the edge of system bars. - final int marginStartEnd = getMarginStartEndWith(configuration); - final LayoutParams layoutParams = (FrameLayout.LayoutParams) mListView.getLayoutParams(); - layoutParams.setMargins(marginStartEnd, mMargin, marginStartEnd, mMargin); - mListView.setLayoutParams(layoutParams); - } - - private void updateOffsetWith(@ShapeType int shapeType, @Alignment int side) { - final float halfWidth = getLayoutWidth() / 2.0f; - final float offset = (shapeType == ShapeType.OVAL) ? 0 : halfWidth; - mListView.animate().translationX(side == Alignment.RIGHT ? offset : -offset); - } - - private void updateScrollModeWith(boolean hasExceededMaxLayoutHeight) { - mListView.setOverScrollMode(hasExceededMaxLayoutHeight - ? OVER_SCROLL_ALWAYS - : OVER_SCROLL_NEVER); - } - - private void updateColor() { - final int menuColorResId = R.color.accessibility_floating_menu_background; - getMenuGradientDrawable().setColor(getResources().getColor(menuColorResId)); - } - - private void updateStrokeWith(int uiMode, @Alignment int side) { - updateInsetWith(uiMode, side); - - final boolean isNightMode = - (uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES; - final Resources res = getResources(); - final int width = - res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_stroke_width); - final int strokeWidth = isNightMode ? width : 0; - final int strokeColor = res.getColor(R.color.accessibility_floating_menu_stroke_dark); - getMenuGradientDrawable().setStroke(strokeWidth, strokeColor); - } - - private void updateRadiusWith(@SizeType int sizeType, @RadiusType int radiusType, - int itemCount) { - mRadius = - getResources().getDimensionPixelSize(getRadiusResId(sizeType, itemCount)); - setRadius(mRadius, radiusType); - } - - private void updateInsetWith(int uiMode, @Alignment int side) { - final boolean isNightMode = - (uiMode & Configuration.UI_MODE_NIGHT_MASK) - == Configuration.UI_MODE_NIGHT_YES; - - final int layerInset = isNightMode ? mInset : 0; - final int insetLeft = (side == Alignment.LEFT) ? layerInset : 0; - final int insetRight = (side == Alignment.RIGHT) ? layerInset : 0; - setInset(insetLeft, insetRight); - } - - private void updateAccessibilityTitle(WindowManager.LayoutParams params) { - params.accessibilityTitle = getResources().getString( - com.android.internal.R.string.accessibility_select_shortcut_menu_title); - } - - private void setInset(int left, int right) { - final LayerDrawable layerDrawable = getMenuLayerDrawable(); - if (layerDrawable.getLayerInsetLeft(INDEX_MENU_ITEM) == left - && layerDrawable.getLayerInsetRight(INDEX_MENU_ITEM) == right) { - return; - } - - layerDrawable.setLayerInset(INDEX_MENU_ITEM, left, 0, right, 0); - } - - @VisibleForTesting - boolean hasExceededMaxLayoutHeight() { - return calculateActualLayoutHeight() > getMaxLayoutHeight(); - } - - @Alignment - private int transformToAlignment(@FloatRange(from = 0.0, to = 1.0) float percentageX) { - return (percentageX < 0.5f) ? Alignment.LEFT : Alignment.RIGHT; - } - - private float transformCurrentPercentageXToEdge() { - final float percentageX = calculateCurrentPercentageX(); - return (percentageX < 0.5) ? 0.0f : 1.0f; - } - - private float calculateCurrentPercentageX() { - return mCurrentLayoutParams.x / (float) getMaxWindowX(); - } - - private float calculateCurrentPercentageY() { - return mCurrentLayoutParams.y / (float) getMaxWindowY(); - } - - private int calculateActualLayoutHeight() { - return (mPadding + mIconHeight) * mTargets.size() + mPadding; - } - - private int getMarginStartEndWith(Configuration configuration) { - return configuration != null - && configuration.orientation == ORIENTATION_PORTRAIT - ? mMargin : 0; - } - - private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) { - return sizeType == SizeType.SMALL - ? getSmallSizeResIdWith(itemCount) - : getLargeSizeResIdWith(itemCount); - } - - private int getSmallSizeResIdWith(int itemCount) { - return itemCount > 1 - ? R.dimen.accessibility_floating_menu_small_multiple_radius - : R.dimen.accessibility_floating_menu_small_single_radius; - } - - private int getLargeSizeResIdWith(int itemCount) { - return itemCount > 1 - ? R.dimen.accessibility_floating_menu_large_multiple_radius - : R.dimen.accessibility_floating_menu_large_single_radius; - } - - @VisibleForTesting - Rect getAvailableBounds() { - return new Rect(0, 0, mDisplayWidth - getWindowWidth(), - mDisplayHeight - getWindowHeight()); - } - - private int getMaxLayoutHeight() { - return mDisplayHeight - mMargin * 2; - } - - private int getLayoutWidth() { - return mPadding * 2 + mIconWidth; - } - - private int getLayoutHeight() { - return Math.min(getMaxLayoutHeight(), calculateActualLayoutHeight()); - } - - private int getWindowWidth() { - return getMarginStartEndWith(mLastConfiguration) * 2 + getLayoutWidth(); - } - - private int getWindowHeight() { - return Math.min(mDisplayHeight, mMargin * 2 + getLayoutHeight()); - } - - private void setSystemGestureExclusion() { - final Rect excludeZone = - new Rect(0, 0, getWindowWidth(), getWindowHeight()); - post(() -> setSystemGestureExclusionRects( - mIsShowing - ? Collections.singletonList(excludeZone) - : Collections.emptyList())); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java deleted file mode 100644 index 61fc7edcd9a02..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipView.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (C) 2021 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 android.util.TypedValue.COMPLEX_UNIT_PX; -import static android.view.View.MeasureSpec.AT_MOST; -import static android.view.View.MeasureSpec.UNSPECIFIED; - -import android.annotation.UiContext; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.CornerPathEffect; -import android.graphics.Paint; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.ShapeDrawable; -import android.os.Bundle; -import android.text.method.MovementMethod; -import android.util.DisplayMetrics; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.settingslib.Utils; -import com.android.systemui.R; -import com.android.systemui.recents.TriangleShape; - -/** - * Base tooltip view that shows the information about the operation of the - * Accessibility floating menu. In addition, the anchor view is only for {@link - * AccessibilityFloatingMenuView}, it should be more suited for displaying one-off menus to avoid - * the performance hit for the extra window. - */ -class BaseTooltipView extends FrameLayout { - private int mFontSize; - private int mTextViewMargin; - private int mTextViewPadding; - private int mTextViewCornerRadius; - private int mArrowMargin; - private int mArrowWidth; - private int mArrowHeight; - private int mArrowCornerRadius; - private int mScreenWidth; - private boolean mIsShowing; - private TextView mTextView; - private final WindowManager.LayoutParams mCurrentLayoutParams; - private final WindowManager mWindowManager; - private final AccessibilityFloatingMenuView mAnchorView; - - BaseTooltipView(@UiContext Context context, AccessibilityFloatingMenuView anchorView) { - super(context); - mWindowManager = context.getSystemService(WindowManager.class); - mAnchorView = anchorView; - mCurrentLayoutParams = createDefaultLayoutParams(); - - initViews(); - } - - @Override - protected void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - mAnchorView.onConfigurationChanged(newConfig); - updateTooltipView(); - - mWindowManager.updateViewLayout(this, mCurrentLayoutParams); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { - hide(); - } - - return super.onTouchEvent(event); - } - - @Override - public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - - info.addAction(AccessibilityAction.ACTION_DISMISS); - } - - @Override - public boolean performAccessibilityAction(int action, Bundle arguments) { - if (action == AccessibilityAction.ACTION_DISMISS.getId()) { - hide(); - return true; - } - - return super.performAccessibilityAction(action, arguments); - } - - void show() { - if (isShowing()) { - return; - } - - mIsShowing = true; - updateTooltipView(); - - mWindowManager.addView(this, mCurrentLayoutParams); - } - - void hide() { - if (!isShowing()) { - return; - } - - mIsShowing = false; - mWindowManager.removeView(this); - } - - void setDescription(CharSequence text) { - mTextView.setText(text); - } - - void setMovementMethod(MovementMethod movement) { - mTextView.setMovementMethod(movement); - } - - private boolean isShowing() { - return mIsShowing; - } - - private void initViews() { - final View contentView = - LayoutInflater.from(getContext()).inflate( - R.layout.accessibility_floating_menu_tooltip, this, false); - - mTextView = contentView.findViewById(R.id.text); - - addView(contentView); - } - - private static WindowManager.LayoutParams createDefaultLayoutParams() { - final WindowManager.LayoutParams params = new WindowManager.LayoutParams( - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, - PixelFormat.TRANSLUCENT); - params.windowAnimations = android.R.style.Animation_Translucent; - params.gravity = Gravity.START | Gravity.TOP; - - return params; - } - - private void updateDimensions() { - final Resources res = getResources(); - final DisplayMetrics dm = res.getDisplayMetrics(); - mScreenWidth = dm.widthPixels; - mArrowWidth = - res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_width); - mArrowHeight = - res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_arrow_height); - mArrowMargin = - res.getDimensionPixelSize( - R.dimen.accessibility_floating_tooltip_arrow_margin); - mArrowCornerRadius = - res.getDimensionPixelSize( - R.dimen.accessibility_floating_tooltip_arrow_corner_radius); - mFontSize = - res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_font_size); - mTextViewMargin = - res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_margin); - mTextViewPadding = - res.getDimensionPixelSize(R.dimen.accessibility_floating_tooltip_padding); - mTextViewCornerRadius = - res.getDimensionPixelSize( - R.dimen.accessibility_floating_tooltip_text_corner_radius); - } - - private void updateTooltipView() { - updateDimensions(); - updateTextView(); - - final Rect anchorViewLocation = mAnchorView.getWindowLocationOnScreen(); - updateArrowWith(anchorViewLocation); - updateWidthWith(anchorViewLocation); - updateLocationWith(anchorViewLocation); - } - - private void updateTextView() { - mTextView.setTextSize(COMPLEX_UNIT_PX, mFontSize); - mTextView.setPadding(mTextViewPadding, mTextViewPadding, mTextViewPadding, - mTextViewPadding); - - final GradientDrawable gradientDrawable = (GradientDrawable) mTextView.getBackground(); - gradientDrawable.setCornerRadius(mTextViewCornerRadius); - gradientDrawable.setColor(Utils.getColorAttrDefaultColor(getContext(), - com.android.internal.R.attr.colorAccentPrimary)); - } - - private void updateArrowWith(Rect anchorViewLocation) { - final boolean isAnchorViewOnLeft = isAnchorViewOnLeft(anchorViewLocation); - final View arrowView = findViewById(isAnchorViewOnLeft - ? R.id.arrow_left - : R.id.arrow_right); - arrowView.setVisibility(VISIBLE); - drawArrow(arrowView, isAnchorViewOnLeft); - - final LinearLayout.LayoutParams layoutParams = - (LinearLayout.LayoutParams) arrowView.getLayoutParams(); - layoutParams.width = mArrowWidth; - layoutParams.height = mArrowHeight; - - final int leftMargin = isAnchorViewOnLeft ? 0 : mArrowMargin; - final int rightMargin = isAnchorViewOnLeft ? mArrowMargin : 0; - layoutParams.setMargins(leftMargin, 0, rightMargin, 0); - arrowView.setLayoutParams(layoutParams); - } - - private void updateWidthWith(Rect anchorViewLocation) { - final ViewGroup.LayoutParams layoutParams = mTextView.getLayoutParams(); - layoutParams.width = getTextWidthWith(anchorViewLocation); - mTextView.setLayoutParams(layoutParams); - } - - private void updateLocationWith(Rect anchorViewLocation) { - mCurrentLayoutParams.x = isAnchorViewOnLeft(anchorViewLocation) - ? anchorViewLocation.width() - : mScreenWidth - getWindowWidthWith(anchorViewLocation) - - anchorViewLocation.width(); - mCurrentLayoutParams.y = - anchorViewLocation.centerY() - (getTextHeightWith(anchorViewLocation) / 2); - } - - private void drawArrow(View view, boolean isPointingLeft) { - final ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); - final TriangleShape triangleShape = - TriangleShape.createHorizontal(layoutParams.width, layoutParams.height, - isPointingLeft); - final ShapeDrawable arrowDrawable = new ShapeDrawable(triangleShape); - final Paint arrowPaint = arrowDrawable.getPaint(); - arrowPaint.setColor(Utils.getColorAttrDefaultColor(getContext(), - com.android.internal.R.attr.colorAccentPrimary)); - final CornerPathEffect effect = new CornerPathEffect(mArrowCornerRadius); - arrowPaint.setPathEffect(effect); - view.setBackground(arrowDrawable); - } - - private boolean isAnchorViewOnLeft(Rect anchorViewLocation) { - return anchorViewLocation.left < (mScreenWidth / 2); - } - - private int getTextWidthWith(Rect anchorViewLocation) { - final int widthSpec = - MeasureSpec.makeMeasureSpec(getAvailableTextWidthWith(anchorViewLocation), AT_MOST); - final int heightSpec = - MeasureSpec.makeMeasureSpec(0, UNSPECIFIED); - mTextView.measure(widthSpec, heightSpec); - return mTextView.getMeasuredWidth(); - } - - private int getTextHeightWith(Rect anchorViewLocation) { - final int widthSpec = - MeasureSpec.makeMeasureSpec(getAvailableTextWidthWith(anchorViewLocation), AT_MOST); - final int heightSpec = - MeasureSpec.makeMeasureSpec(0, UNSPECIFIED); - mTextView.measure(widthSpec, heightSpec); - return mTextView.getMeasuredHeight(); - } - - private int getAvailableTextWidthWith(Rect anchorViewLocation) { - return mScreenWidth - anchorViewLocation.width() - mArrowWidth - mArrowMargin - - mTextViewMargin; - } - - private int getWindowWidthWith(Rect anchorViewLocation) { - return getTextWidthWith(anchorViewLocation) + mArrowWidth + mArrowMargin; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DockTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DockTooltipView.java deleted file mode 100644 index 49056a6039ec0..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/DockTooltipView.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2021 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.content.Context; - -import com.android.systemui.R; - -/** - * Dock tooltip view that shows the info about moving the Accessibility button to the edge to hide. - */ -class DockTooltipView extends BaseTooltipView { - private final AccessibilityFloatingMenuView mAnchorView; - - DockTooltipView(Context context, AccessibilityFloatingMenuView anchorView) { - super(context, anchorView); - mAnchorView = anchorView; - - setDescription( - getContext().getText(R.string.accessibility_floating_button_docking_tooltip)); - } - - @Override - void hide() { - super.hide(); - - mAnchorView.stopTranslateXAnimation(); - } - - @Override - void show() { - super.show(); - - mAnchorView.startTranslateXAnimation(); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompat.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompat.java deleted file mode 100644 index 93b0676b49300..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompat.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2021 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.content.res.Resources; -import android.graphics.Rect; -import android.os.Bundle; -import android.view.View; - -import androidx.annotation.NonNull; -import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; -import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate; - -import com.android.systemui.R; -import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuView.ShapeType; - -import java.lang.ref.WeakReference; - -/** - * An accessibility item delegate for the individual items of the list view - * {@link AccessibilityFloatingMenuView}. - */ -final class ItemDelegateCompat extends RecyclerViewAccessibilityDelegate.ItemDelegate { - private final WeakReference mMenuViewRef; - - ItemDelegateCompat(@NonNull RecyclerViewAccessibilityDelegate recyclerViewDelegate, - AccessibilityFloatingMenuView menuView) { - super(recyclerViewDelegate); - this.mMenuViewRef = new WeakReference<>(menuView); - } - - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { - super.onInitializeAccessibilityNodeInfo(host, info); - - if (mMenuViewRef.get() == null) { - return; - } - final AccessibilityFloatingMenuView menuView = mMenuViewRef.get(); - - final Resources res = menuView.getResources(); - final AccessibilityNodeInfoCompat.AccessibilityActionCompat moveTopLeft = - new AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.action_move_top_left, - res.getString( - R.string.accessibility_floating_button_action_move_top_left)); - info.addAction(moveTopLeft); - - final AccessibilityNodeInfoCompat.AccessibilityActionCompat moveTopRight = - new AccessibilityNodeInfoCompat.AccessibilityActionCompat( - R.id.action_move_top_right, - res.getString( - R.string.accessibility_floating_button_action_move_top_right)); - info.addAction(moveTopRight); - - final AccessibilityNodeInfoCompat.AccessibilityActionCompat moveBottomLeft = - new AccessibilityNodeInfoCompat.AccessibilityActionCompat( - R.id.action_move_bottom_left, - res.getString( - R.string.accessibility_floating_button_action_move_bottom_left)); - info.addAction(moveBottomLeft); - - final AccessibilityNodeInfoCompat.AccessibilityActionCompat moveBottomRight = - new AccessibilityNodeInfoCompat.AccessibilityActionCompat( - R.id.action_move_bottom_right, - res.getString( - R.string.accessibility_floating_button_action_move_bottom_right)); - info.addAction(moveBottomRight); - - final int moveEdgeId = menuView.isOvalShape() - ? R.id.action_move_to_edge_and_hide - : R.id.action_move_out_edge_and_show; - final int moveEdgeTextResId = menuView.isOvalShape() - ? R.string.accessibility_floating_button_action_move_to_edge_and_hide_to_half - : R.string.accessibility_floating_button_action_move_out_edge_and_show; - final AccessibilityNodeInfoCompat.AccessibilityActionCompat moveToOrOutEdge = - new AccessibilityNodeInfoCompat.AccessibilityActionCompat(moveEdgeId, - res.getString(moveEdgeTextResId)); - info.addAction(moveToOrOutEdge); - } - - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - if (mMenuViewRef.get() == null) { - return super.performAccessibilityAction(host, action, args); - } - final AccessibilityFloatingMenuView menuView = mMenuViewRef.get(); - - menuView.fadeIn(); - - final Rect bounds = menuView.getAvailableBounds(); - if (action == R.id.action_move_top_left) { - menuView.setShapeType(ShapeType.OVAL); - menuView.snapToLocation(bounds.left, bounds.top); - return true; - } - - if (action == R.id.action_move_top_right) { - menuView.setShapeType(ShapeType.OVAL); - menuView.snapToLocation(bounds.right, bounds.top); - return true; - } - - if (action == R.id.action_move_bottom_left) { - menuView.setShapeType(ShapeType.OVAL); - menuView.snapToLocation(bounds.left, bounds.bottom); - return true; - } - - if (action == R.id.action_move_bottom_right) { - menuView.setShapeType(ShapeType.OVAL); - menuView.snapToLocation(bounds.right, bounds.bottom); - return true; - } - - if (action == R.id.action_move_to_edge_and_hide) { - menuView.setShapeType(ShapeType.HALF_OVAL); - return true; - } - - if (action == R.id.action_move_out_edge_and_show) { - menuView.setShapeType(ShapeType.OVAL); - return true; - } - - return super.performAccessibilityAction(host, action, args); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipView.java deleted file mode 100644 index e4f3e31459983..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipView.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2021 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.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_BUTTON_COMPONENT_NAME; - -import android.content.Context; -import android.content.Intent; -import android.provider.Settings; -import android.text.method.LinkMovementMethod; - -import com.android.systemui.R; - -/** - * Migration tooltip view that shows the information about the Accessibility button was replaced - * with the floating menu. - */ -class MigrationTooltipView extends BaseTooltipView { - MigrationTooltipView(Context context, AccessibilityFloatingMenuView anchorView) { - super(context, anchorView); - - final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(Intent.EXTRA_COMPONENT_NAME, - ACCESSIBILITY_BUTTON_COMPONENT_NAME.flattenToShortString()); - - final AnnotationLinkSpan.LinkInfo linkInfo = new AnnotationLinkSpan.LinkInfo( - AnnotationLinkSpan.LinkInfo.DEFAULT_ANNOTATION, - v -> { - getContext().startActivity(intent); - hide(); - }); - - final int textResId = R.string.accessibility_floating_button_migration_tooltip; - setDescription(AnnotationLinkSpan.linkify(getContext().getText(textResId), linkInfo)); - setMovementMethod(LinkMovementMethod.getInstance()); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java deleted file mode 100644 index 04345fdf28933..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2021 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.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doReturn; - -import android.content.Context; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.accessibility.AccessibilityManager; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.util.settings.SecureSettings; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.ArrayList; -import java.util.List; - -/** Tests for {@link AccessibilityFloatingMenu}. */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class AccessibilityFloatingMenuTest extends SysuiTestCase { - - @Rule - public MockitoRule mockito = MockitoJUnit.rule(); - - @Mock - private AccessibilityManager mAccessibilityManager; - @Mock - private SecureSettings mSecureSettings; - - private AccessibilityFloatingMenuView mMenuView; - private AccessibilityFloatingMenu mMenu; - - @Before - public void initMenu() { - final List assignedTargets = new ArrayList<>(); - mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); - assignedTargets.add(MAGNIFICATION_CONTROLLER_NAME); - doReturn(assignedTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets( - anyInt()); - - final Position position = new Position(0, 0); - mMenuView = new AccessibilityFloatingMenuView(mContext, position); - mMenu = new AccessibilityFloatingMenu(mContext, mSecureSettings, mMenuView); - } - - @Test - public void showMenuView_success() { - mMenu.show(); - - assertThat(mMenuView.isShowing()).isTrue(); - } - - @Test - public void hideMenuView_success() { - mMenu.show(); - mMenu.hide(); - - assertThat(mMenuView.isShowing()).isFalse(); - } - - @Test - public void showMenuView_emptyTarget_notShow() { - final List emptyTargets = new ArrayList<>(); - doReturn(emptyTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets( - anyInt()); - - mMenu.show(); - - assertThat(mMenuView.isShowing()).isFalse(); - } - - @After - public void tearDown() { - mMenu.hide(); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java deleted file mode 100644 index bebd8712a7505..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuViewTest.java +++ /dev/null @@ -1,527 +0,0 @@ -/* - * Copyright (C) 2021 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 android.content.res.Configuration.ORIENTATION_PORTRAIT; -import static android.view.View.OVER_SCROLL_ALWAYS; -import static android.view.View.OVER_SCROLL_NEVER; -import static android.view.WindowInsets.Type.displayCutout; -import static android.view.WindowInsets.Type.ime; -import static android.view.WindowInsets.Type.systemBars; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyFloat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -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 android.content.Context; -import android.content.res.Resources; -import android.graphics.Insets; -import android.graphics.Rect; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.LayerDrawable; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewPropertyAnimator; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import androidx.test.filters.SmallTest; - -import com.android.internal.accessibility.dialog.AccessibilityTarget; -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; -import com.android.systemui.accessibility.MotionEventHelper; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** Tests for {@link AccessibilityFloatingMenuView}. */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class AccessibilityFloatingMenuViewTest extends SysuiTestCase { - - @Rule - public MockitoRule mockito = MockitoJUnit.rule(); - - private final MotionEventHelper mMotionEventHelper = new MotionEventHelper(); - private final List mTargets = new ArrayList<>( - Collections.singletonList(mock(AccessibilityTarget.class))); - - private final Position mPlaceholderPosition = new Position(0.0f, 0.0f); - - @Mock - private WindowManager mWindowManager; - @Mock - private ViewPropertyAnimator mAnimator; - @Mock - private WindowMetrics mWindowMetrics; - private MotionEvent mInterceptMotionEvent; - private AccessibilityFloatingMenuView mMenuView; - private RecyclerView mListView = new RecyclerView(mContext); - - private int mMenuWindowHeight; - private int mMenuHalfWidth; - private int mMenuHalfHeight; - private int mDisplayHalfWidth; - private int mDisplayHalfHeight; - private int mMaxWindowX; - private int mMaxWindowY; - private final int mDisplayWindowWidth = 1080; - private final int mDisplayWindowHeight = 2340; - - @Before - public void initMenuView() { - final WindowManager wm = mContext.getSystemService(WindowManager.class); - doAnswer(invocation -> wm.getMaximumWindowMetrics()).when( - mWindowManager).getMaximumWindowMetrics(); - mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getBounds()).thenReturn(new Rect(0, 0, mDisplayWindowWidth, - mDisplayWindowHeight)); - when(mWindowMetrics.getWindowInsets()).thenReturn(fakeDisplayInsets()); - mMenuView = spy( - new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition, mListView)); - } - - @Before - public void setUpMatrices() { - final Resources res = mContext.getResources(); - final int margin = - res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_margin); - final int padding = - res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_padding); - final int iconWidthHeight = - res.getDimensionPixelSize(R.dimen.accessibility_floating_menu_small_width_height); - final int menuWidth = padding * 2 + iconWidthHeight; - final int menuHeight = (padding + iconWidthHeight) * mTargets.size() + padding; - mMenuHalfWidth = menuWidth / 2; - mMenuHalfHeight = menuHeight / 2; - mDisplayHalfWidth = mDisplayWindowWidth / 2; - mDisplayHalfHeight = mDisplayWindowHeight / 2; - int marginStartEnd = - mContext.getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT - ? margin : 0; - mMaxWindowX = mDisplayWindowWidth - marginStartEnd - menuWidth; - mMenuWindowHeight = menuHeight + margin * 2; - mMaxWindowY = mDisplayWindowHeight - mMenuWindowHeight; - } - - @Test - public void initListView_success() { - assertThat(mListView.getCompatAccessibilityDelegate()).isNotNull(); - assertThat(mMenuView.getChildCount()).isEqualTo(1); - } - - @Test - public void showMenuView_success() { - mMenuView.show(); - - assertThat(mMenuView.isShowing()).isTrue(); - verify(mWindowManager).addView(eq(mMenuView), any(WindowManager.LayoutParams.class)); - } - - @Test - public void showMenuView_showTwice_addViewOnce() { - mMenuView.show(); - mMenuView.show(); - - assertThat(mMenuView.isShowing()).isTrue(); - verify(mWindowManager, times(1)).addView(eq(mMenuView), - any(WindowManager.LayoutParams.class)); - } - - @Test - public void hideMenuView_success() { - mMenuView.show(); - mMenuView.hide(); - - assertThat(mMenuView.isShowing()).isFalse(); - verify(mWindowManager).removeView(eq(mMenuView)); - } - - @Test - public void hideMenuView_hideTwice_removeViewOnce() { - mMenuView.show(); - mMenuView.hide(); - mMenuView.hide(); - - assertThat(mMenuView.isShowing()).isFalse(); - verify(mWindowManager, times(1)).removeView(eq(mMenuView)); - } - - @Test - public void hideMenuViewWhenStartingAnimation_animatorNotRunning() { - mMenuView.show(); - - mMenuView.mDragAnimator.start(); - mMenuView.hide(); - - assertThat(mMenuView.mDragAnimator.isRunning()).isFalse(); - } - - @Test - public void onTargetsChanged_singleTarget_expectedRadii() { - final Position alignRightPosition = new Position(1.0f, 0.0f); - final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext, - alignRightPosition); - setupBasicMenuView(menuView); - - menuView.onTargetsChanged(mTargets); - - final View view = menuView.getChildAt(0); - final LayerDrawable layerDrawable = (LayerDrawable) view.getBackground(); - final GradientDrawable gradientDrawable = - (GradientDrawable) layerDrawable.getDrawable(0); - final float smallRadius = - getContext().getResources().getDimensionPixelSize( - R.dimen.accessibility_floating_menu_small_single_radius); - final float[] expectedRadii = - new float[]{smallRadius, smallRadius, 0.0f, 0.0f, 0.0f, 0.0f, smallRadius, - smallRadius}; - assertThat(gradientDrawable.getCornerRadii()).isEqualTo(expectedRadii); - } - - @Test - public void setSizeType_alignRightAndLargeSize_expectedRadii() { - final RecyclerView listView = spy(new RecyclerView(mContext)); - final Position alignRightPosition = new Position(1.0f, 0.0f); - final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext, - alignRightPosition, listView); - setupBasicMenuView(menuView); - - menuView.setSizeType(/* largeSize */ 1); - - final LayerDrawable layerDrawable = - (LayerDrawable) listView.getBackground(); - final GradientDrawable gradientDrawable = - (GradientDrawable) layerDrawable.getDrawable(0); - final float largeRadius = getContext().getResources().getDimensionPixelSize( - R.dimen.accessibility_floating_menu_large_single_radius); - final float[] expectedRadii = - new float[] {largeRadius, largeRadius, 0.0f, 0.0f, 0.0f, 0.0f, largeRadius, - largeRadius}; - assertThat(gradientDrawable.getCornerRadii()).isEqualTo(expectedRadii); - } - - @Test - public void setShapeType_halfCircle_translationX() { - final RecyclerView listView = spy(new RecyclerView(mContext)); - final AccessibilityFloatingMenuView menuView = - new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition, listView); - setupBasicMenuView(menuView); - doReturn(mAnimator).when(listView).animate(); - - menuView.setShapeType(/* halfOvalShape */ 1); - - verify(mAnimator).translationX(anyFloat()); - } - - @Test - public void onTargetsChanged_fadeInOut() { - final InOrder inOrderMenuView = inOrder(mMenuView); - - mMenuView.onTargetsChanged(mTargets); - - inOrderMenuView.verify(mMenuView).fadeIn(); - inOrderMenuView.verify(mMenuView).fadeOut(); - } - - @Test - public void setSizeType_fadeInOut() { - final InOrder inOrderMenuView = inOrder(mMenuView); - - mMenuView.setSizeType(/* smallSize */ 0); - - inOrderMenuView.verify(mMenuView).fadeIn(); - inOrderMenuView.verify(mMenuView).fadeOut(); - } - - @Test - public void tapOnAndDragMenu_interceptUpEvent() { - final RecyclerView listView = new RecyclerView(mContext); - final TestAccessibilityFloatingMenu menuView = - new TestAccessibilityFloatingMenu(mContext, mPlaceholderPosition, listView); - setupBasicMenuView(menuView); - final int currentWindowX = menuView.mCurrentLayoutParams.x; - final int currentWindowY = menuView.mCurrentLayoutParams.y; - final MotionEvent downEvent = - mMotionEventHelper.obtainMotionEvent(0, 1, - MotionEvent.ACTION_DOWN, - currentWindowX + /* offsetXToMenuCenterX */ mMenuHalfWidth, - currentWindowY + /* offsetYToMenuCenterY */ mMenuHalfHeight); - final MotionEvent moveEvent = - mMotionEventHelper.obtainMotionEvent(2, 3, - MotionEvent.ACTION_MOVE, - /* displayCenterX */mDisplayHalfWidth - - /* offsetXToDisplayLeftHalfRegion */ 10, - /* displayCenterY */ mDisplayHalfHeight); - final MotionEvent upEvent = - mMotionEventHelper.obtainMotionEvent(4, 5, - MotionEvent.ACTION_UP, - /* displayCenterX */ mDisplayHalfWidth - - /* offsetXToDisplayLeftHalfRegion */ 10, - /* displayCenterY */ mDisplayHalfHeight); - - listView.dispatchTouchEvent(downEvent); - listView.dispatchTouchEvent(moveEvent); - listView.dispatchTouchEvent(upEvent); - - assertThat(mInterceptMotionEvent.getAction()).isEqualTo(MotionEvent.ACTION_UP); - } - - @Test - public void tapOnAndDragMenu_matchLocation() { - final float expectedX = 1.0f; - final float expectedY = 0.7f; - final Position position = new Position(expectedX, expectedY); - final RecyclerView listView = new RecyclerView(mContext); - final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext, - position, listView); - setupBasicMenuView(menuView); - final int currentWindowX = menuView.mCurrentLayoutParams.x; - final int currentWindowY = menuView.mCurrentLayoutParams.y; - final MotionEvent downEvent = - mMotionEventHelper.obtainMotionEvent(0, 1, - MotionEvent.ACTION_DOWN, - currentWindowX + /* offsetXToMenuCenterX */ mMenuHalfWidth, - currentWindowY + /* offsetYToMenuCenterY */ mMenuHalfHeight); - final MotionEvent moveEvent = - mMotionEventHelper.obtainMotionEvent(2, 3, - MotionEvent.ACTION_MOVE, - /* displayCenterX */mDisplayHalfWidth - + /* offsetXToDisplayRightHalfRegion */ 10, - /* displayCenterY */ mDisplayHalfHeight); - final MotionEvent upEvent = - mMotionEventHelper.obtainMotionEvent(4, 5, - MotionEvent.ACTION_UP, - /* displayCenterX */ mDisplayHalfWidth - + /* offsetXToDisplayRightHalfRegion */ 10, - /* displayCenterY */ mDisplayHalfHeight); - - listView.dispatchTouchEvent(downEvent); - listView.dispatchTouchEvent(moveEvent); - listView.dispatchTouchEvent(upEvent); - menuView.mDragAnimator.end(); - - assertThat((float) menuView.mCurrentLayoutParams.x).isWithin(1.0f).of(mMaxWindowX); - assertThat((float) menuView.mCurrentLayoutParams.y).isWithin(1.0f).of( - /* newWindowY = displayCenterY - offsetY */ mDisplayHalfHeight - mMenuHalfHeight); - } - - - @Test - public void tapOnAndDragMenuToDisplaySide_transformShapeHalfOval() { - final Position alignRightPosition = new Position(1.0f, 0.8f); - final RecyclerView listView = new RecyclerView(mContext); - final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext, - alignRightPosition, listView); - setupBasicMenuView(menuView); - - final int currentWindowX = menuView.mCurrentLayoutParams.x; - final int currentWindowY = menuView.mCurrentLayoutParams.y; - final MotionEvent downEvent = - mMotionEventHelper.obtainMotionEvent(0, 1, - MotionEvent.ACTION_DOWN, - currentWindowX + /* offsetXToMenuCenterX */ mMenuHalfWidth, - currentWindowY + /* offsetYToMenuCenterY */ mMenuHalfHeight); - final MotionEvent moveEvent = - mMotionEventHelper.obtainMotionEvent(2, 3, - MotionEvent.ACTION_MOVE, - /* downX */(currentWindowX + mMenuHalfWidth) - + /* offsetXToDisplayRightSide */ mMenuHalfWidth, - /* downY */ (currentWindowY + mMenuHalfHeight)); - final MotionEvent upEvent = - mMotionEventHelper.obtainMotionEvent(4, 5, - MotionEvent.ACTION_UP, - /* downX */(currentWindowX + mMenuHalfWidth) - + /* offsetXToDisplayRightSide */ mMenuHalfWidth, - /* downY */ (currentWindowY + mMenuHalfHeight)); - - listView.dispatchTouchEvent(downEvent); - listView.dispatchTouchEvent(moveEvent); - listView.dispatchTouchEvent(upEvent); - - assertThat(menuView.mShapeType).isEqualTo(/* halfOval */ 1); - } - - @Test - public void onTargetsChanged_exceedAvailableHeight_overScrollAlways() { - doReturn(true).when(mMenuView).hasExceededMaxLayoutHeight(); - - mMenuView.onTargetsChanged(mTargets); - - assertThat(mListView.getOverScrollMode()).isEqualTo(OVER_SCROLL_ALWAYS); - } - - @Test - public void onTargetsChanged_notExceedAvailableHeight_overScrollNever() { - doReturn(false).when(mMenuView).hasExceededMaxLayoutHeight(); - - mMenuView.onTargetsChanged(mTargets); - - assertThat(mListView.getOverScrollMode()).isEqualTo(OVER_SCROLL_NEVER); - } - - @Test - public void showMenuView_insetsListener_overlapWithIme_menuViewShifted() { - final int offset = 200; - - final Position alignRightPosition = new Position(1.0f, 0.8f); - final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext, - alignRightPosition); - setupBasicMenuView(menuView); - final WindowInsets imeInset = fakeImeInsetWith(menuView, offset); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getWindowInsets()).thenReturn(imeInset); - final int expectedLayoutY = menuView.mCurrentLayoutParams.y - offset; - menuView.dispatchApplyWindowInsets(imeInset); - - assertThat(menuView.mCurrentLayoutParams.y).isEqualTo(expectedLayoutY); - } - - @Test - public void hideIme_onMenuViewShifted_menuViewMovedBack() { - final int offset = 200; - setupBasicMenuView(mMenuView); - final WindowInsets imeInset = fakeImeInsetWith(mMenuView, offset); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getWindowInsets()).thenReturn(imeInset); - final int expectedLayoutY = mMenuView.mCurrentLayoutParams.y; - mMenuView.dispatchApplyWindowInsets(imeInset); - - mMenuView.dispatchApplyWindowInsets( - new WindowInsets.Builder().setVisible(ime(), false).build()); - - assertThat(mMenuView.mCurrentLayoutParams.y).isEqualTo(expectedLayoutY); - } - - @Test - public void showMenuAndIme_withHigherIme_alignDisplayTopEdge() { - final int offset = 99999; - - setupBasicMenuView(mMenuView); - final WindowInsets imeInset = fakeImeInsetWith(mMenuView, offset); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getWindowInsets()).thenReturn(imeInset); - mMenuView.dispatchApplyWindowInsets(imeInset); - - assertThat(mMenuView.mCurrentLayoutParams.y).isEqualTo(0); - } - - @Test - public void testConstructor_withPosition_expectedPosition() { - final float expectedX = 1.0f; - final float expectedY = 0.7f; - final Position position = new Position(expectedX, expectedY); - - final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext, - position); - setupBasicMenuView(menuView); - - assertThat((float) menuView.mCurrentLayoutParams.x).isWithin(1.0f).of(mMaxWindowX); - assertThat((float) menuView.mCurrentLayoutParams.y).isWithin(1.0f).of( - expectedY * mMaxWindowY); - } - - @After - public void tearDown() { - mInterceptMotionEvent = null; - mMotionEventHelper.recycleEvents(); - mListView = null; - } - - private void setupBasicMenuView(AccessibilityFloatingMenuView menuView) { - menuView.show(); - menuView.onTargetsChanged(mTargets); - menuView.setSizeType(0); - menuView.setShapeType(0); - } - - /** - * Based on the current menu status, fake the ime inset component {@link WindowInsets} used - * for testing. - * - * @param menuView {@link AccessibilityFloatingMenuView} that needs to be changed - * @param offset is used for the y-axis position of ime higher than the y-axis position of menu - * @return the ime inset - */ - private WindowInsets fakeImeInsetWith(AccessibilityFloatingMenuView menuView, int offset) { - // Ensure the keyboard has overlapped on the menu view. - final int fakeImeHeight = - mDisplayWindowHeight - (menuView.mCurrentLayoutParams.y + mMenuWindowHeight) - + offset; - return new WindowInsets.Builder() - .setVisible(ime(), true) - .setInsets(ime(), Insets.of(0, 0, 0, fakeImeHeight)) - .build(); - } - - private WindowInsets fakeDisplayInsets() { - final int fakeStatusBarHeight = 75; - final int fakeNavigationBarHeight = 125; - return new WindowInsets.Builder() - .setVisible(systemBars() | displayCutout(), true) - .setInsets(systemBars() | displayCutout(), - Insets.of(0, fakeStatusBarHeight, 0, fakeNavigationBarHeight)) - .build(); - } - - private class TestAccessibilityFloatingMenu extends AccessibilityFloatingMenuView { - TestAccessibilityFloatingMenu(Context context, Position position, RecyclerView listView) { - super(context, position, listView); - } - - @Override - public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, - @NonNull MotionEvent event) { - final boolean intercept = super.onInterceptTouchEvent(recyclerView, event); - - if (intercept) { - mInterceptMotionEvent = event; - } - - return intercept; - } - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipViewTest.java deleted file mode 100644 index 3553a0adce27e..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/BaseTooltipViewTest.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2021 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 static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.graphics.Rect; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.MotionEvent; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; -import android.view.accessibility.AccessibilityNodeInfo; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.accessibility.MotionEventHelper; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** Tests for {@link BaseTooltipView}. */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class BaseTooltipViewTest extends SysuiTestCase { - - @Mock - private WindowManager mWindowManager; - - @Mock - private WindowMetrics mWindowMetrics; - - private AccessibilityFloatingMenuView mMenuView; - private BaseTooltipView mToolTipView; - - private final Position mPlaceholderPosition = new Position(0.0f, 0.0f); - private final MotionEventHelper mMotionEventHelper = new MotionEventHelper(); - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - final WindowManager wm = mContext.getSystemService(WindowManager.class); - doAnswer(invocation -> wm.getMaximumWindowMetrics()).when( - mWindowManager).getMaximumWindowMetrics(); - mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getBounds()).thenReturn(new Rect()); - when(mWindowMetrics.getWindowInsets()).thenReturn(new WindowInsets.Builder().build()); - - mMenuView = new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition); - mToolTipView = new BaseTooltipView(mContext, mMenuView); - } - - @Test - public void showToolTipView_success() { - mToolTipView.show(); - - verify(mWindowManager).addView(eq(mToolTipView), any(WindowManager.LayoutParams.class)); - } - - @Test - public void touchOutsideWhenToolTipViewShown_dismiss() { - final MotionEvent outsideEvent = - mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, - /* eventTime= */1, - MotionEvent.ACTION_OUTSIDE, - /* x= */ 0, - /* y= */ 0); - - mToolTipView.show(); - mToolTipView.dispatchTouchEvent(outsideEvent); - - verify(mWindowManager).removeView(mToolTipView); - } - - @Test - public void getAccessibilityActionList_matchResult() { - final AccessibilityNodeInfo infos = new AccessibilityNodeInfo(); - mToolTipView.onInitializeAccessibilityNodeInfo(infos); - - assertThat(infos.getActionList().size()).isEqualTo(1); - } - - @Test - public void accessibilityAction_dismiss_success() { - final BaseTooltipView tooltipView = - spy(new BaseTooltipView(mContext, mMenuView)); - - final boolean isActionPerformed = - tooltipView.performAccessibilityAction( - AccessibilityNodeInfo.AccessibilityAction.ACTION_DISMISS.getId(), - /* arguments= */ null); - - assertThat(isActionPerformed).isTrue(); - verify(tooltipView).hide(); - } - - @After - public void tearDown() { - mToolTipView.hide(); - mMotionEventHelper.recycleEvents(); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DockTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DockTooltipViewTest.java deleted file mode 100644 index 9eba49daaf6b4..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DockTooltipViewTest.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2021 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 org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.graphics.Rect; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.MotionEvent; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.accessibility.MotionEventHelper; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** Tests for {@link DockTooltipView}. */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class DockTooltipViewTest extends SysuiTestCase { - - @Mock - private WindowManager mWindowManager; - - @Mock - private WindowMetrics mWindowMetrics; - - private AccessibilityFloatingMenuView mMenuView; - private DockTooltipView mDockTooltipView; - private final Position mPlaceholderPosition = new Position(0.0f, 0.0f); - private final MotionEventHelper mMotionEventHelper = new MotionEventHelper(); - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - final WindowManager wm = mContext.getSystemService(WindowManager.class); - doAnswer(invocation -> wm.getMaximumWindowMetrics()).when( - mWindowManager).getMaximumWindowMetrics(); - mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getBounds()).thenReturn(new Rect()); - when(mWindowMetrics.getWindowInsets()).thenReturn(new WindowInsets.Builder().build()); - - mMenuView = spy(new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition)); - mDockTooltipView = new DockTooltipView(mContext, mMenuView); - } - - @Test - public void showTooltip_success() { - mDockTooltipView.show(); - - verify(mMenuView).startTranslateXAnimation(); - verify(mWindowManager).addView(eq(mDockTooltipView), any(WindowManager.LayoutParams.class)); - } - - @Test - public void hideTooltip_success() { - mDockTooltipView.show(); - mDockTooltipView.hide(); - - verify(mMenuView).stopTranslateXAnimation(); - verify(mWindowManager).removeView(mDockTooltipView); - } - - @Test - public void touchOutsideWhenToolTipViewShown_stopAnimation() { - final MotionEvent outsideEvent = - mMotionEventHelper.obtainMotionEvent(/* downTime= */ 0, - /* eventTime= */ 1, - MotionEvent.ACTION_OUTSIDE, - /* x= */ 0, - /* y= */ 0); - - mDockTooltipView.show(); - mDockTooltipView.dispatchTouchEvent(outsideEvent); - - verify(mMenuView).stopTranslateXAnimation(); - } - - @After - public void tearDown() { - mMotionEventHelper.recycleEvents(); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompatTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompatTest.java deleted file mode 100644 index ea104a724b8a2..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/ItemDelegateCompatTest.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2021 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 static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.graphics.Rect; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.WindowInsets; -import android.view.WindowManager; -import android.view.WindowMetrics; -import android.view.accessibility.AccessibilityNodeInfo; - -import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate; -import androidx.test.filters.SmallTest; - -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -/** Tests for {@link ItemDelegateCompat}. */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class ItemDelegateCompatTest extends SysuiTestCase { - @Rule - public MockitoRule mockito = MockitoJUnit.rule(); - - @Mock - private WindowManager mWindowManager; - - @Mock - private WindowMetrics mWindowMetrics; - private RecyclerView mListView; - private AccessibilityFloatingMenuView mMenuView; - private ItemDelegateCompat mItemDelegateCompat; - private final Rect mAvailableBounds = new Rect(100, 200, 300, 400); - private final Position mPlaceholderPosition = new Position(0.0f, 0.0f); - - @Before - public void setUp() { - final WindowManager wm = mContext.getSystemService(WindowManager.class); - doAnswer(invocation -> wm.getMaximumWindowMetrics()).when( - mWindowManager).getMaximumWindowMetrics(); - mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); - when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics); - when(mWindowMetrics.getBounds()).thenReturn(new Rect()); - when(mWindowMetrics.getWindowInsets()).thenReturn(new WindowInsets.Builder().build()); - - mListView = new RecyclerView(mContext); - mMenuView = - spy(new AccessibilityFloatingMenuView(mContext, mPlaceholderPosition, mListView)); - mItemDelegateCompat = - new ItemDelegateCompat(new RecyclerViewAccessibilityDelegate(mListView), mMenuView); - } - - @Test - public void getAccessibilityActionList_matchResult() { - final AccessibilityNodeInfoCompat info = - new AccessibilityNodeInfoCompat(new AccessibilityNodeInfo()); - - mItemDelegateCompat.onInitializeAccessibilityNodeInfo(mListView, info); - - assertThat(info.getActionList().size()).isEqualTo(5); - } - - @Test - public void performAccessibilityMoveTopLeftAction_halfOval_success() { - doReturn(mAvailableBounds).when(mMenuView).getAvailableBounds(); - mMenuView.setShapeType(/* halfOvalShape */ 1); - - final boolean moveTopLeftAction = - mItemDelegateCompat.performAccessibilityAction(mListView, R.id.action_move_top_left, - null); - - assertThat(moveTopLeftAction).isTrue(); - assertThat(mMenuView.mShapeType).isEqualTo(/* ovalShape */ 0); - verify(mMenuView).snapToLocation(mAvailableBounds.left, mAvailableBounds.top); - } - - @Test - public void performAccessibilityMoveTopRightAction_halfOval_success() { - doReturn(mAvailableBounds).when(mMenuView).getAvailableBounds(); - mMenuView.setShapeType(/* halfOvalShape */ 1); - - final boolean moveTopRightAction = - mItemDelegateCompat.performAccessibilityAction(mListView, - R.id.action_move_top_right, null); - - assertThat(moveTopRightAction).isTrue(); - assertThat(mMenuView.mShapeType).isEqualTo(/* ovalShape */ 0); - verify(mMenuView).snapToLocation(mAvailableBounds.right, mAvailableBounds.top); - } - - @Test - public void performAccessibilityMoveBottomLeftAction_halfOval_success() { - doReturn(mAvailableBounds).when(mMenuView).getAvailableBounds(); - mMenuView.setShapeType(/* halfOvalShape */ 1); - - final boolean moveBottomLeftAction = - mItemDelegateCompat.performAccessibilityAction(mListView, - R.id.action_move_bottom_left, null); - - assertThat(moveBottomLeftAction).isTrue(); - assertThat(mMenuView.mShapeType).isEqualTo(/* ovalShape */ 0); - verify(mMenuView).snapToLocation(mAvailableBounds.left, mAvailableBounds.bottom); - } - - @Test - public void performAccessibilityMoveBottomRightAction_halfOval_success() { - doReturn(mAvailableBounds).when(mMenuView).getAvailableBounds(); - mMenuView.setShapeType(/* halfOvalShape */ 1); - - final boolean moveBottomRightAction = - mItemDelegateCompat.performAccessibilityAction(mListView, - R.id.action_move_bottom_right, null); - - assertThat(moveBottomRightAction).isTrue(); - assertThat(mMenuView.mShapeType).isEqualTo(/* ovalShape */ 0); - verify(mMenuView).snapToLocation(mAvailableBounds.right, mAvailableBounds.bottom); - } - - @Test - public void performAccessibilityMoveOutEdgeAction_halfOval_success() { - doReturn(mAvailableBounds).when(mMenuView).getAvailableBounds(); - mMenuView.setShapeType(/* halfOvalShape */ 1); - - final boolean moveOutEdgeAndShowAction = - mItemDelegateCompat.performAccessibilityAction(mListView, - R.id.action_move_out_edge_and_show, null); - - assertThat(moveOutEdgeAndShowAction).isTrue(); - assertThat(mMenuView.mShapeType).isEqualTo(/* ovalShape */ 0); - } - - @Test - public void setupAccessibilityActions_oval_hasActionMoveToEdgeAndHide() { - final AccessibilityNodeInfoCompat info = - new AccessibilityNodeInfoCompat(new AccessibilityNodeInfo()); - mMenuView.setShapeType(/* ovalShape */ 0); - - mItemDelegateCompat.onInitializeAccessibilityNodeInfo(mListView, info); - - assertThat(info.getActionList().stream().anyMatch( - action -> action.getId() == R.id.action_move_to_edge_and_hide)).isTrue(); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipViewTest.java deleted file mode 100644 index 2fb0a90e7fc21..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MigrationTooltipViewTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2021 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.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.text.SpannableString; -import android.text.method.LinkMovementMethod; -import android.widget.TextView; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.R; -import com.android.systemui.SysuiTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** Tests for {@link MigrationTooltipView}. */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class MigrationTooltipViewTest extends SysuiTestCase { - - private TextView mTextView; - private final Position mPlaceholderPosition = new Position(0.0f, 0.0f); - - @Before - public void setUp() { - final AccessibilityFloatingMenuView menuView = new AccessibilityFloatingMenuView(mContext, - mPlaceholderPosition); - final MigrationTooltipView toolTipView = new MigrationTooltipView(mContext, menuView); - mTextView = toolTipView.findViewById(R.id.text); - } - - @Test - public void onCreate_setLinkMovementMethod() { - assertThat(mTextView.getMovementMethod()).isInstanceOf(LinkMovementMethod.class); - } - - @Test - public void onCreate_setDescription_matchTextAndSpanNum() { - final CharSequence expectedTextWithoutSpan = - AnnotationLinkSpan.linkify(mContext.getText( - R.string.accessibility_floating_button_migration_tooltip)).toString(); - final SpannableString spannableString = (SpannableString) mTextView.getText(); - final int AnnotationLinkSpanNum = - spannableString.getSpans(/* queryStart= */ 0, spannableString.length(), - AnnotationLinkSpan.class).length; - - assertThat(AnnotationLinkSpanNum).isEqualTo(1); - assertThat(mTextView.getText().toString().contentEquals(expectedTextWithoutSpan)).isTrue(); - } -}