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

Commit 64975ae9 authored by helencheuk's avatar helencheuk
Browse files

Add hover state border line to overview task item by using the same approach...

Add hover state border line to overview task item by using the same approach used by keyboard focus state

Reviewed TAPL DD: https://docs.google.com/document/d/1OmCLgTDw3gFOMXjEvH0W1XoAe0n2J5pPdyMcAHtflMA/edit?resourcekey=0-bXle-rOnQqOR_RJBffRybQ
Fix: 249859410
Test: OverviewTaskImageTest

Change-Id: Ic9ce4e9fe90f38a4bf4be6c7deed302a12a3192a
parent 5644e3f1
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -79,6 +79,13 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
                return response;
            }

            case TestProtocol.REQUEST_GET_OVERVIEW_TASK_BORDER_WIDTH: {
                Resources res = mContext.getResources();
                response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
                        res.getDimensionPixelSize(R.dimen.keyboard_quick_switch_border_width));
                return response;
            }

            case TestProtocol.REQUEST_HAS_TIS: {
                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true);
                return response;
+7 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.view.animation.Interpolator;

import androidx.annotation.NonNull;
import androidx.annotation.Px;
import androidx.annotation.VisibleForTesting;

import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
@@ -175,6 +176,12 @@ public final class BorderAnimator {
        }
    }

    @NonNull
    @VisibleForTesting
    public AnimatedFloat getBorderAnimationProgress() {
        return mBorderAnimationProgress;
    }

    /**
     * Callback to update the border bounds when building this animation.
     */
+96 −20
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import android.widget.Toast;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;

import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherSettings;
@@ -411,7 +412,11 @@ public class TaskView extends FrameLayout implements Reusable {

    private boolean mIsClickableAsLiveTile = true;

    @Nullable private final BorderAnimator mBorderAnimator;
    @Nullable private BorderAnimator mBorderAnimator;

    private final boolean mCursorHoverStatesEnabled;

    private final boolean mKeyboardFocusHighlightEnabled;

    public TaskView(Context context) {
        this(context, null);
@@ -434,17 +439,19 @@ public class TaskView extends FrameLayout implements Reusable {
        mCurrentFullscreenParams = new FullscreenDrawParams(context);
        mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);

        boolean keyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
        mKeyboardFocusHighlightEnabled = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
                || DesktopTaskView.DESKTOP_MODE_SUPPORTED;
        mCursorHoverStatesEnabled = FeatureFlags.ENABLE_CURSOR_HOVER_STATES.get();
        if (mCursorHoverStatesEnabled) {
            setOnHoverListener(this::onHover);
        }

        setWillNotDraw(!keyboardFocusHighlightEnabled);
        setWillNotDraw(!mKeyboardFocusHighlightEnabled && !mCursorHoverStatesEnabled);

        if (mKeyboardFocusHighlightEnabled || mCursorHoverStatesEnabled) {
            TypedArray ta = context.obtainStyledAttributes(
                    attrs, R.styleable.TaskView, defStyleAttr, defStyleRes);

        mBorderAnimator = !keyboardFocusHighlightEnabled
                ? null
                : new BorderAnimator(
            mBorderAnimator = new BorderAnimator(
                    /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
                    /* borderColor= */ ta.getColor(
                    R.styleable.TaskView_borderColor, DEFAULT_BORDER_COLOR),
@@ -455,6 +462,7 @@ public class TaskView extends FrameLayout implements Reusable {
                    /* targetView= */ this));
            ta.recycle();
        }
    }

    protected void updateBorderBounds(Rect bounds) {
        bounds.set(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
@@ -496,6 +504,12 @@ public class TaskView extends FrameLayout implements Reusable {
        return stubInfo;
    }

    @Nullable
    @VisibleForTesting
    public BorderAnimator getBorderAnimator() {
        return mBorderAnimator;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
@@ -507,11 +521,22 @@ public class TaskView extends FrameLayout implements Reusable {
    @Override
    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
        if (mBorderAnimator != null) {
        if (mKeyboardFocusHighlightEnabled) {
            mBorderAnimator.buildAnimator(gainFocus).start();
        }
    }

    @Override
    public boolean onInterceptHoverEvent(MotionEvent event) {
        if (mCursorHoverStatesEnabled) {
            // avoid triggering hover event on child elements which would cause HOVER_EXIT for this
            // task view
            return true;
        } else {
            return super.onInterceptHoverEvent(event);
        }
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
@@ -750,6 +775,57 @@ public class TaskView extends FrameLayout implements Reusable {
                .log(LAUNCHER_TASK_LAUNCH_TAP);
    }

    private boolean onHover(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_HOVER_MOVE:
                if (mKeyboardFocusHighlightEnabled && !isFocused()) {
                    // existing focus is on another task selected by keyboard,
                    // cursor then moves inside this task thumbnail and steals the focus
                    requestFocusAndExitTouchMode(v);
                }
                return true;
            case MotionEvent.ACTION_HOVER_ENTER:
                if (mKeyboardFocusHighlightEnabled) {
                    if (isFocused()) {
                        // the task is already focused with border, no action is needed
                        return true;
                    } else {
                        requestFocusAndExitTouchMode(v);
                    }
                } else {
                    // mKeyboardFocusHighlightEnabled is turned off so it only shows hover
                    // state animation but not steals the focus
                    mBorderAnimator.buildAnimator(true).start();
                }
                return true;
            case MotionEvent.ACTION_HOVER_EXIT:
                if (mKeyboardFocusHighlightEnabled) {
                    // clearFocus() does not work here because parent element is not focusable
                    // so it changes to touch mode to clear focus
                    v.getViewRootImpl().touchModeChanged(true);
                } else {
                    // just show the disappearing animation but not change the focus when
                    // mKeyboardFocusHighlightEnabled is off
                    mBorderAnimator.buildAnimator(false).start();
                }
                return true;
            default:
                return false;
        }
    }

    private void requestFocusAndExitTouchMode(View v) {
        if (isInTouchMode()) {
            // Tasks are not focusable in touch mode by default. As hover state would steal focus
            // when both mKeyboardFocusHighlightEnabled and mCursorHoverStatesEnabled are on,
            // touch mode needs to be set to false when hovering so it can steal focus to current
            // task and show border animation as hover state
            v.getViewRootImpl().touchModeChanged(false);
        }

        requestFocus();
    }

    /**
     * @return {@code true} if user is already in split select mode and this tap was to choose the
     *         second app. {@code false} otherwise
+4 −0
Original line number Diff line number Diff line
@@ -140,6 +140,10 @@ public final class TestProtocol {
    public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
            "get-grid-task-size-rect-for-tablet";
    public static final String REQUEST_GET_OVERVIEW_PAGE_SPACING = "get-overview-page-spacing";

    public static final String REQUEST_GET_OVERVIEW_TASK_BORDER_WIDTH =
            "get-overview-task-border-width";

    public static final String REQUEST_ENABLE_ROTATION = "enable_rotation";
    public static final String REQUEST_ENABLE_SUGGESTION = "enable-suggestion";
    public static final String REQUEST_MODEL_QUEUE_CLEARED = "model-queue-cleared";
+5 −0
Original line number Diff line number Diff line
@@ -375,6 +375,11 @@ public final class LauncherInstrumentation {
                .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
    }

    public int getOverviewTaskBorderWidth() {
        return getTestInfo(TestProtocol.REQUEST_GET_OVERVIEW_TASK_BORDER_WIDTH)
                .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
    }

    int getFocusedTaskHeightForTablet() {
        return getTestInfo(TestProtocol.REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET).getInt(
                TestProtocol.TEST_INFO_RESPONSE_FIELD);
Loading