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

Commit 9f360cb8 authored by PETER LIANG's avatar PETER LIANG Committed by Android (Google) Code Review
Browse files

Merge changes Ib4a67fd2,I2dbf7c4a,I8309e5b6,Iebaa99c0

* changes:
  Refactor the design and improve the animations of Accessibility Floating Menu(8/n).
  Refactor the design and improve the animations of Accessibility Floating Menu(7/n).
  Refactor the design and improve the animations of Accessibility Floating Menu(6/n).
  Refactor the design and improve the animations of Accessibility Floating Menu(5/n).
parents 152e6909 12b10143
Loading
Loading
Loading
Loading
+342 −3
Original line number Diff line number Diff line
@@ -16,24 +16,363 @@

package com.android.systemui.accessibility.floatingmenu;

import static android.util.MathUtils.constrain;

import static java.util.Objects.requireNonNull;

import android.animation.ValueAnimator;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;

import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FlingAnimation;
import androidx.dynamicanimation.animation.FloatPropertyCompat;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import androidx.recyclerview.widget.RecyclerView;

import java.util.HashMap;

/**
 * Controls the interaction animations of the menu view {@link MenuView}.
 * Controls the interaction animations of the {@link MenuView}. Also, it will use the relative
 * coordinate based on the {@link MenuViewLayer} to compute the offset of the {@link MenuView}.
 */
class MenuAnimationController {
    private static final String TAG = "MenuAnimationController";
    private static final boolean DEBUG = false;
    private static final float MIN_PERCENT = 0.0f;
    private static final float MAX_PERCENT = 1.0f;
    private static final float COMPLETELY_OPAQUE = 1.0f;
    private static final float FLING_FRICTION_SCALAR = 1.9f;
    private static final float DEFAULT_FRICTION = 4.2f;
    private static final float SPRING_AFTER_FLING_DAMPING_RATIO = 0.85f;
    private static final float SPRING_STIFFNESS = 700f;
    private static final float ESCAPE_VELOCITY = 750f;

    private static final int FADE_OUT_DURATION_MS = 1000;
    private static final int FADE_EFFECT_DURATION_MS = 3000;

    private final MenuView mMenuView;
    private final ValueAnimator mFadeOutAnimator;
    private final Handler mHandler;
    private boolean mIsMovedToEdge;
    private boolean mIsFadeEffectEnabled;

    // Cache the animations state of {@link DynamicAnimation.TRANSLATION_X} and {@link
    // DynamicAnimation.TRANSLATION_Y} to be well controlled by the touch handler
    private final HashMap<DynamicAnimation.ViewProperty, DynamicAnimation> mPositionAnimations =
            new HashMap<>();

    MenuAnimationController(MenuView menuView) {
        mMenuView = menuView;

        mHandler = createUiHandler();
        mFadeOutAnimator = new ValueAnimator();
        mFadeOutAnimator.setDuration(FADE_OUT_DURATION_MS);
        mFadeOutAnimator.addUpdateListener(
                (animation) -> menuView.setAlpha((float) animation.getAnimatedValue()));
    }

    void moveToPosition(PointF position) {
        DynamicAnimation.TRANSLATION_X.setValue(mMenuView, position.x);
        DynamicAnimation.TRANSLATION_Y.setValue(mMenuView, position.y);
        moveToPositionX(position.x);
        moveToPositionY(position.y);
    }

    void moveToPositionX(float positionX) {
        DynamicAnimation.TRANSLATION_X.setValue(mMenuView, positionX);
    }

    private void moveToPositionY(float positionY) {
        DynamicAnimation.TRANSLATION_Y.setValue(mMenuView, positionY);
    }

    void moveToPositionYIfNeeded(float positionY) {
        // If the list view was out of screen bounds, it would allow users to nest scroll inside
        // and avoid conflicting with outer scroll.
        final RecyclerView listView = (RecyclerView) mMenuView.getChildAt(/* index= */ 0);
        if (listView.getOverScrollMode() == View.OVER_SCROLL_NEVER) {
            moveToPositionY(positionY);
        }
    }

    void moveToTopLeftPosition() {
        mIsMovedToEdge = false;
        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        moveAndPersistPosition(new PointF(draggableBounds.left, draggableBounds.top));
    }

    void moveToTopRightPosition() {
        mIsMovedToEdge = false;
        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        moveAndPersistPosition(new PointF(draggableBounds.right, draggableBounds.top));
    }

    void moveToBottomLeftPosition() {
        mIsMovedToEdge = false;
        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        moveAndPersistPosition(new PointF(draggableBounds.left, draggableBounds.bottom));
    }

    void moveToBottomRightPosition() {
        mIsMovedToEdge = false;
        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        moveAndPersistPosition(new PointF(draggableBounds.right, draggableBounds.bottom));
    }

    void moveAndPersistPosition(PointF position) {
        moveToPosition(position);
        mMenuView.onBoundsInParentChanged((int) position.x, (int) position.y);
        constrainPositionAndUpdate(position);
    }

    void flingMenuThenSpringToEdge(float x, float velocityX, float velocityY) {
        final boolean shouldMenuFlingLeft = isOnLeftSide()
                ? velocityX < ESCAPE_VELOCITY
                : velocityX < -ESCAPE_VELOCITY;

        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        final float finalPositionX = shouldMenuFlingLeft
                ? draggableBounds.left : draggableBounds.right;

        final float minimumVelocityToReachEdge =
                (finalPositionX - x) * (FLING_FRICTION_SCALAR * DEFAULT_FRICTION);

        final float startXVelocity = shouldMenuFlingLeft
                ? Math.min(minimumVelocityToReachEdge, velocityX)
                : Math.max(minimumVelocityToReachEdge, velocityX);

        flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_X,
                startXVelocity,
                FLING_FRICTION_SCALAR,
                new SpringForce()
                        .setStiffness(SPRING_STIFFNESS)
                        .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO),
                finalPositionX);

        flingThenSpringMenuWith(DynamicAnimation.TRANSLATION_Y,
                velocityY,
                FLING_FRICTION_SCALAR,
                new SpringForce()
                        .setStiffness(SPRING_STIFFNESS)
                        .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO),
                /* finalPosition= */ null);
    }

    private void flingThenSpringMenuWith(DynamicAnimation.ViewProperty property, float velocity,
            float friction, SpringForce spring, Float finalPosition) {

        final MenuPositionProperty menuPositionProperty = new MenuPositionProperty(property);
        final float currentValue = menuPositionProperty.getValue(mMenuView);
        final Rect bounds = mMenuView.getMenuDraggableBounds();
        final float min =
                property.equals(DynamicAnimation.TRANSLATION_X)
                        ? bounds.left
                        : bounds.top;
        final float max =
                property.equals(DynamicAnimation.TRANSLATION_X)
                        ? bounds.right
                        : bounds.bottom;

        final FlingAnimation flingAnimation = new FlingAnimation(mMenuView, menuPositionProperty);
        flingAnimation.setFriction(friction)
                .setStartVelocity(velocity)
                .setMinValue(Math.min(currentValue, min))
                .setMaxValue(Math.max(currentValue, max))
                .addEndListener((animation, canceled, endValue, endVelocity) -> {
                    if (canceled) {
                        if (DEBUG) {
                            Log.d(TAG, "The fling animation was canceled.");
                        }

                        return;
                    }

                    final float endPosition = finalPosition != null
                            ? finalPosition
                            : Math.max(min, Math.min(max, endValue));
                    springMenuWith(property, spring, endVelocity, endPosition);
                });

        cancelAnimation(property);
        mPositionAnimations.put(property, flingAnimation);
        flingAnimation.start();
    }

    private void springMenuWith(DynamicAnimation.ViewProperty property, SpringForce spring,
            float velocity, float finalPosition) {
        final MenuPositionProperty menuPositionProperty = new MenuPositionProperty(property);
        final SpringAnimation springAnimation =
                new SpringAnimation(mMenuView, menuPositionProperty)
                        .setSpring(spring)
                        .addEndListener((animation, canceled, endValue, endVelocity) -> {
                            if (canceled || endValue != finalPosition) {
                                return;
                            }

                            onSpringAnimationEnd(new PointF(mMenuView.getTranslationX(),
                                    mMenuView.getTranslationY()));
                        })
                        .setStartVelocity(velocity);

        cancelAnimation(property);
        mPositionAnimations.put(property, springAnimation);
        springAnimation.animateToFinalPosition(finalPosition);
    }

    /**
     * Determines whether to hide the menu to the edge of the screen with the given current
     * translation x of the menu view. It should be used when receiving the action up touch event.
     *
     * @param currentXTranslation the current translation x of the menu view.
     * @return true if the menu would be hidden to the edge, otherwise false.
     */
    boolean maybeMoveToEdgeAndHide(float currentXTranslation) {
        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();

        // If the translation x is zero, it should be at the left of the bound.
        if (currentXTranslation < draggableBounds.left
                || currentXTranslation > draggableBounds.right) {
            moveToEdgeAndHide();
            return true;
        }

        fadeOutIfEnabled();
        return false;
    }

    private boolean isOnLeftSide() {
        return mMenuView.getTranslationX() < mMenuView.getMenuDraggableBounds().centerX();
    }

    boolean isMovedToEdge() {
        return mIsMovedToEdge;
    }

    void moveToEdgeAndHide() {
        mIsMovedToEdge = true;

        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        final float endY = constrain(mMenuView.getTranslationY(), draggableBounds.top,
                draggableBounds.bottom);
        final float menuHalfWidth = mMenuView.getWidth() / 2.0f;
        final float endX = isOnLeftSide()
                ? draggableBounds.left - menuHalfWidth
                : draggableBounds.right + menuHalfWidth;
        moveAndPersistPosition(new PointF(endX, endY));

        // Keep the touch region let users could click extra space to pop up the menu view
        // from the screen edge
        mMenuView.onBoundsInParentChanged(isOnLeftSide()
                ? draggableBounds.left
                : draggableBounds.right, (int) mMenuView.getTranslationY());

        fadeOutIfEnabled();
    }

    void moveOutEdgeAndShow() {
        mIsMovedToEdge = false;

        mMenuView.onPositionChanged();
        mMenuView.onEdgeChangedIfNeeded();
    }

    void cancelAnimations() {
        cancelAnimation(DynamicAnimation.TRANSLATION_X);
        cancelAnimation(DynamicAnimation.TRANSLATION_Y);
    }

    private void cancelAnimation(DynamicAnimation.ViewProperty property) {
        if (!mPositionAnimations.containsKey(property)) {
            return;
        }

        mPositionAnimations.get(property).cancel();
    }

    void onDraggingStart() {
        mMenuView.onDraggingStart();
    }

    private void onSpringAnimationEnd(PointF position) {
        mMenuView.onBoundsInParentChanged((int) position.x, (int) position.y);
        constrainPositionAndUpdate(position);

        fadeOutIfEnabled();
    }

    private void constrainPositionAndUpdate(PointF position) {
        final Rect draggableBounds = mMenuView.getMenuDraggableBounds();
        // Have the space gap margin between the top bound and the menu view, so actually the
        // position y range needs to cut the margin.
        position.offset(-draggableBounds.left, -draggableBounds.top);

        final float percentageX = position.x < draggableBounds.centerX()
                ? MIN_PERCENT : MAX_PERCENT;

        final float percentageY = position.y < 0 || draggableBounds.height() == 0
                ? MIN_PERCENT
                : Math.min(MAX_PERCENT, position.y / draggableBounds.height());
        mMenuView.persistPositionAndUpdateEdge(new Position(percentageX, percentageY));
    }

    void updateOpacityWith(boolean isFadeEffectEnabled, float newOpacityValue) {
        mIsFadeEffectEnabled = isFadeEffectEnabled;

        mHandler.removeCallbacksAndMessages(/* token= */ null);
        mFadeOutAnimator.cancel();
        mFadeOutAnimator.setFloatValues(COMPLETELY_OPAQUE, newOpacityValue);
        mHandler.post(() -> mMenuView.setAlpha(
                mIsFadeEffectEnabled ? newOpacityValue : COMPLETELY_OPAQUE));
    }

    void fadeInNowIfEnabled() {
        if (!mIsFadeEffectEnabled) {
            return;
        }

        cancelAndRemoveCallbacksAndMessages();
        mHandler.post(() -> mMenuView.setAlpha(COMPLETELY_OPAQUE));
    }

    void fadeOutIfEnabled() {
        if (!mIsFadeEffectEnabled) {
            return;
        }

        cancelAndRemoveCallbacksAndMessages();
        mHandler.postDelayed(mFadeOutAnimator::start, FADE_EFFECT_DURATION_MS);
    }

    private void cancelAndRemoveCallbacksAndMessages() {
        mFadeOutAnimator.cancel();
        mHandler.removeCallbacksAndMessages(/* token= */ null);
    }

    private Handler createUiHandler() {
        return new Handler(requireNonNull(Looper.myLooper(), "looper must not be null"));
    }

    static class MenuPositionProperty
            extends FloatPropertyCompat<MenuView> {
        private final DynamicAnimation.ViewProperty mProperty;

        MenuPositionProperty(DynamicAnimation.ViewProperty property) {
            super(property.toString());
            mProperty = property;
        }

        @Override
        public float getValue(MenuView menuView) {
            return mProperty.getValue(menuView);
        }

        @Override
        public void setValue(MenuView menuView, float value) {
            mProperty.setValue(menuView, value);
        }
    }
}
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.annotation.FloatRange

@FloatRange(from = 0.0, to = 1.0) const val DEFAULT_OPACITY_VALUE = 0.55f
const val DEFAULT_FADE_EFFECT_IS_ENABLED = 1

/** The data class for the fade effect info of the accessibility floating menu view. */
data class MenuFadeEffectInfo(val isFadeEffectEnabled: Boolean, val opacity: Float)
+45 −0
Original line number Diff line number Diff line
@@ -16,11 +16,15 @@

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_OPACITY;
import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE;
import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;

import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.systemui.accessibility.floatingmenu.MenuFadeEffectInfoKt.DEFAULT_FADE_EFFECT_IS_ENABLED;
import static com.android.systemui.accessibility.floatingmenu.MenuFadeEffectInfoKt.DEFAULT_OPACITY_VALUE;
import static com.android.systemui.accessibility.floatingmenu.MenuViewAppearance.MenuSizeType.SMALL;

import android.annotation.FloatRange;
@@ -72,6 +76,15 @@ class MenuInfoRepository {
                }
            };

    @VisibleForTesting
    final ContentObserver mMenuFadeOutContentObserver =
            new ContentObserver(mHandler) {
                @Override
                public void onChange(boolean selfChange) {
                    mSettingsContentsCallback.onFadeEffectInfoChanged(getMenuFadeEffectInfo());
                }
            };

    MenuInfoRepository(Context context, OnSettingsContentsChanged settingsContentsChanged) {
        mContext = context;
        mSettingsContentsCallback = settingsContentsChanged;
@@ -91,6 +104,15 @@ class MenuInfoRepository {
        callback.onReady(getMenuSizeTypeFromSettings(mContext));
    }

    void loadMenuFadeEffectInfo(OnInfoReady<MenuFadeEffectInfo> callback) {
        callback.onReady(getMenuFadeEffectInfo());
    }

    private MenuFadeEffectInfo getMenuFadeEffectInfo() {
        return new MenuFadeEffectInfo(isMenuFadeEffectEnabledFromSettings(mContext),
                getMenuOpacityFromSettings(mContext));
    }

    void updateMenuSavingPosition(Position percentagePosition) {
        mPercentagePosition = percentagePosition;
        Prefs.putString(mContext, Prefs.Key.ACCESSIBILITY_FLOATING_MENU_POSITION,
@@ -119,17 +141,28 @@ class MenuInfoRepository {
                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE),
                /* notifyForDescendants */ false, mMenuSizeContentObserver,
                UserHandle.USER_CURRENT);
        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED),
                /* notifyForDescendants */ false, mMenuFadeOutContentObserver,
                UserHandle.USER_CURRENT);
        mContext.getContentResolver().registerContentObserver(
                Settings.Secure.getUriFor(ACCESSIBILITY_FLOATING_MENU_OPACITY),
                /* notifyForDescendants */ false, mMenuFadeOutContentObserver,
                UserHandle.USER_CURRENT);
    }

    void unregisterContentObservers() {
        mContext.getContentResolver().unregisterContentObserver(mMenuTargetFeaturesContentObserver);
        mContext.getContentResolver().unregisterContentObserver(mMenuSizeContentObserver);
        mContext.getContentResolver().unregisterContentObserver(mMenuFadeOutContentObserver);
    }

    interface OnSettingsContentsChanged {
        void onTargetFeaturesChanged(List<AccessibilityTarget> newTargetFeatures);

        void onSizeTypeChanged(int newSizeType);

        void onFadeEffectInfoChanged(MenuFadeEffectInfo fadeEffectInfo);
    }

    interface OnInfoReady<T> {
@@ -140,4 +173,16 @@ class MenuInfoRepository {
        return Settings.Secure.getIntForUser(context.getContentResolver(),
                ACCESSIBILITY_FLOATING_MENU_SIZE, SMALL, UserHandle.USER_CURRENT);
    }

    private static boolean isMenuFadeEffectEnabledFromSettings(Context context) {
        return Settings.Secure.getIntForUser(context.getContentResolver(),
                ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED,
                DEFAULT_FADE_EFFECT_IS_ENABLED, UserHandle.USER_CURRENT) == /* enabled */ 1;
    }

    private static float getMenuOpacityFromSettings(Context context) {
        return Settings.Secure.getFloatForUser(context.getContentResolver(),
                ACCESSIBILITY_FLOATING_MENU_OPACITY, DEFAULT_OPACITY_VALUE,
                UserHandle.USER_CURRENT);
    }
}
+131 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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 androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS;
import static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS;

import android.content.res.Resources;
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;

/**
 * An accessibility item delegate for the individual items of the list view in the
 * {@link MenuView}.
 */
class MenuItemAccessibilityDelegate extends RecyclerViewAccessibilityDelegate.ItemDelegate {
    private final MenuAnimationController mAnimationController;

    MenuItemAccessibilityDelegate(@NonNull RecyclerViewAccessibilityDelegate recyclerViewDelegate,
            MenuAnimationController animationController) {
        super(recyclerViewDelegate);
        mAnimationController = animationController;
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
        super.onInitializeAccessibilityNodeInfo(host, info);

        final Resources res = host.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 = mAnimationController.isMovedToEdge()
                ? R.id.action_move_out_edge_and_show
                : R.id.action_move_to_edge_and_hide;
        final int moveEdgeTextResId = mAnimationController.isMovedToEdge()
                ? R.string.accessibility_floating_button_action_move_out_edge_and_show
                : R.string.accessibility_floating_button_action_move_to_edge_and_hide_to_half;
        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 (action == ACTION_ACCESSIBILITY_FOCUS) {
            mAnimationController.fadeInNowIfEnabled();
        }

        if (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS) {
            mAnimationController.fadeOutIfEnabled();
        }

        if (action == R.id.action_move_top_left) {
            mAnimationController.moveToTopLeftPosition();
            return true;
        }

        if (action == R.id.action_move_top_right) {
            mAnimationController.moveToTopRightPosition();
            return true;
        }

        if (action == R.id.action_move_bottom_left) {
            mAnimationController.moveToBottomLeftPosition();
            return true;
        }

        if (action == R.id.action_move_bottom_right) {
            mAnimationController.moveToBottomRightPosition();
            return true;
        }

        if (action == R.id.action_move_to_edge_and_hide) {
            mAnimationController.moveToEdgeAndHide();
            return true;
        }

        if (action == R.id.action_move_out_edge_and_show) {
            mAnimationController.moveOutEdgeAndShow();
            return true;
        }

        return super.performAccessibilityAction(host, action, args);
    }
}
+121 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading