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

Commit b9a5c455 authored by Vinit Nayak's avatar Vinit Nayak Committed by Android (Google) Code Review
Browse files

Merge "Show split select instructions toast when starting split on workspace" into udc-qpr-dev

parents 5c825f4c 5f090915
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -24,12 +24,15 @@
    android:paddingTop="@dimen/split_instructions_vertical_padding"
    android:paddingBottom="@dimen/split_instructions_vertical_padding"
    android:elevation="@dimen/split_instructions_elevation"
    android:visibility="gone">
    android:visibility="gone"
    android:importantForAccessibility="yes">
    <androidx.appcompat.widget.AppCompatTextView
        android:id="@+id/split_instructions_text"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:gravity="center"
        android:textColor="?androidprv:attr/textColorOnAccent"
        android:drawableEnd="@drawable/ic_split_horizontal"
        android:drawablePadding="@dimen/split_instructions_drawable_padding"
        android:text="@string/toast_split_select_app" />
</com.android.quickstep.views.SplitInstructionsView>
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -230,6 +230,7 @@
    <string name="action_split">Split</string>
    <!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
    <string name="toast_split_select_app">Tap another app to use split screen</string>
    <string name="toast_split_select_cont_desc">Exit split screen selection</string>
    <!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
    <string name="toast_split_app_unsupported">Choose another app to use split screen</string>
    <!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
+5 −11
Original line number Diff line number Diff line
@@ -544,17 +544,9 @@ public class QuickstepLauncher extends Launcher {

        ArrayList<TouchController> list = new ArrayList<>();
        list.add(getDragController());
        Consumer<AnimatorSet> splitAnimator = animatorSet -> {
            AnimatorSet anim = mSplitSelectStateController.getSplitAnimationController()
                    .createPlaceholderDismissAnim(QuickstepLauncher.this);
            anim.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mSplitSelectStateController.resetState();
                }
            });
            animatorSet.play(anim);
        };
        Consumer<AnimatorSet> splitAnimator = animatorSet ->
                animatorSet.play(mSplitSelectStateController.getSplitAnimationController()
                        .createPlaceholderDismissAnim(this));
        switch (mode) {
            case NO_BUTTON:
                list.add(new NoButtonQuickSwitchTouchController(this));
@@ -673,6 +665,8 @@ public class QuickstepLauncher extends Launcher {
                mSplitSelectStateController.resetState();
            }
        });
        anim.add(mSplitSelectStateController.getSplitAnimationController()
                .getShowSplitInstructionsAnim(this).buildAnim());
        anim.buildAnim().start();
    }

+46 −11
Original line number Diff line number Diff line
@@ -26,15 +26,17 @@ import android.graphics.Rect
import android.graphics.RectF
import android.graphics.drawable.Drawable
import android.view.View
import com.android.app.animation.Interpolators
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Launcher
import com.android.launcher3.Utilities
import com.android.launcher3.anim.PendingAnimation
import com.android.launcher3.dragndrop.DragLayer
import com.android.launcher3.statemanager.StatefulActivity
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
import com.android.launcher3.views.BaseDragLayer
import com.android.quickstep.views.FloatingTaskView
import com.android.quickstep.views.IconView
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.SplitInstructionsView
import com.android.quickstep.views.TaskThumbnailView
import com.android.quickstep.views.TaskView
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
@@ -58,6 +60,8 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
        )
    }

    var splitInstructionsView: SplitInstructionsView? = null

    /**
     * Returns different elements to animate for the initial split selection animation
     * depending on the state of the surface from which the split was initiated
@@ -188,31 +192,26 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
    }

    /** Does not play any animation if user is not currently in split selection state. */
    fun playPlaceholderDismissAnim(launcher: Launcher) {
    fun playPlaceholderDismissAnim(launcher: StatefulActivity<*>) {
        if (!splitSelectStateController.isSplitSelectActive) {
            return
        }

        val anim = createPlaceholderDismissAnim(launcher)
        anim.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                splitSelectStateController.resetState()
            }
        })
        anim.start()
    }

    /** Returns [AnimatorSet] which slides initial split placeholder view offscreen. */
    fun createPlaceholderDismissAnim(launcher: Launcher) : AnimatorSet {
    fun createPlaceholderDismissAnim(launcher: StatefulActivity<*>) : AnimatorSet {
        val animatorSet = AnimatorSet()
        val recentsView : RecentsView<*, *> = launcher.getOverviewPanel()
        val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView
                ?: return animatorSet

        // We are in split selection state currently, transitioning to another state
        val dragLayer: DragLayer = launcher.dragLayer
        val dragLayer: BaseDragLayer<*> = launcher.dragLayer
        val onScreenRectF = RectF()
        Utilities.getBoundsForViewInDragLayer(launcher.dragLayer, floatingTask,
        Utilities.getBoundsForViewInDragLayer(dragLayer, floatingTask,
                Rect(0, 0, floatingTask.width, floatingTask.height),
                false, null, onScreenRectF)
        // Get the part of the floatingTask that intersects with the DragLayer (i.e. the
@@ -233,6 +232,42 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC
                                floatingTask.stagePosition,
                                launcher.deviceProfile
                        )))
        animatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                splitSelectStateController.resetState()
                safeRemoveViewFromDragLayer(launcher, splitInstructionsView)
            }
        })
        return animatorSet
    }

    /**
     * Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second
     * app for splitscreen
     */
    fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>) : PendingAnimation {
        safeRemoveViewFromDragLayer(launcher, splitInstructionsView)
        splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(launcher)
        val timings = AnimUtils.getDeviceOverviewToSplitTimings(launcher.deviceProfile.isTablet)
        val anim = PendingAnimation(100 /*duration */)
        anim.setViewAlpha(splitInstructionsView, 1f,
                Interpolators.clampToProgress(Interpolators.LINEAR,
                        timings.instructionsContainerFadeInStartOffset,
                        timings.instructionsContainerFadeInEndOffset))
        anim.setViewAlpha(splitInstructionsView!!.textView, 1f,
                Interpolators.clampToProgress(Interpolators.LINEAR,
                        timings.instructionsTextFadeInStartOffset,
                        timings.instructionsTextFadeInEndOffset))
        anim.addFloat(splitInstructionsView, SplitInstructionsView.UNFOLD, 0.1f, 1f,
                Interpolators.clampToProgress(Interpolators.EMPHASIZED_DECELERATE,
                        timings.instructionsUnfoldStartOffset,
                        timings.instructionsUnfoldEndOffset))
        return anim
    }

    private fun safeRemoveViewFromDragLayer(launcher: StatefulActivity<*>, view: View?) {
        if (view != null) {
            launcher.dragLayer.removeView(view)
        }
    }
}
+73 −4
Original line number Diff line number Diff line
@@ -17,15 +17,21 @@
package com.android.quickstep.views;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;

import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatTextView;

import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StatefulActivity;

/**
@@ -65,7 +71,7 @@ public class SplitInstructionsView extends FrameLayout {
        mLauncher = (StatefulActivity) context;
    }

    static SplitInstructionsView getSplitInstructionsView(StatefulActivity launcher) {
    public static SplitInstructionsView getSplitInstructionsView(StatefulActivity launcher) {
        ViewGroup dragLayer = launcher.getDragLayer();
        final SplitInstructionsView splitInstructionsView =
                (SplitInstructionsView) launcher.getLayoutInflater().inflate(
@@ -73,9 +79,7 @@ public class SplitInstructionsView extends FrameLayout {
                        dragLayer,
                        false
                );

        splitInstructionsView.mTextView = splitInstructionsView.findViewById(
                R.id.split_instructions_text);
        splitInstructionsView.init();

        // Since textview overlays base view, and we sometimes manipulate the alpha of each
        // simultaneously, force overlapping rendering to false prevents redrawing of pixels,
@@ -92,6 +96,71 @@ public class SplitInstructionsView extends FrameLayout {
        ensureProperRotation();
    }

    private void init() {
        mTextView = findViewById(R.id.split_instructions_text);

        if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
            mTextView.setCompoundDrawables(null, null, null, null);
            return;
        }

        mTextView.setOnTouchListener((v, event) -> {
            if (isTouchInsideRightCompoundDrawable(event)) {
                if (event.getAction() == MotionEvent.ACTION_UP) {
                    exitSplitSelection();
                }
                return true;
            }
            return false;
        });
    }

    private void exitSplitSelection() {
        ((RecentsView) mLauncher.getOverviewPanel()).getSplitSelectController()
                .getSplitAnimationController().playPlaceholderDismissAnim(mLauncher);
        mLauncher.getStateManager().goToState(LauncherState.NORMAL);
    }

    private boolean isTouchInsideRightCompoundDrawable(MotionEvent event) {
        // Get the right compound drawable of the TextView.
        Drawable rightDrawable = mTextView.getCompoundDrawablesRelative()[2];

        // Check if the touch event intersects with the drawable's bounds.
        if (rightDrawable != null) {
            // We can get away w/o caring about the Y bounds since it's such a small view, if it's
            // above/below the drawable just assume they meant to touch it. ¯\_(ツ)_/¯
            return  event.getX() >= (mTextView.getWidth() - rightDrawable.getBounds().width());
        } else {
            return false;
        }
    }

    @Override
    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfo(info);
        if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
            return;
        }

        info.addAction(new AccessibilityNodeInfo.AccessibilityAction(
                R.string.toast_split_select_cont_desc,
                getResources().getString(R.string.toast_split_select_cont_desc)
        ));
    }

    @Override
    public boolean performAccessibilityAction(int action, Bundle arguments) {
        if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
            return super.performAccessibilityAction(action, arguments);
        }

        if (action == R.string.toast_split_select_cont_desc) {
            exitSplitSelection();
            return true;
        }
        return super.performAccessibilityAction(action, arguments);
    }

    void ensureProperRotation() {
        ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler()
                .setSplitInstructionsParams(
Loading