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

Commit dd63e5df authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Create a drag controller for expanded bubble bar" into main

parents 87f82bb9 99a965ca
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
    private boolean mIsOverflow;
    private BubbleTaskViewHelper mBubbleTaskViewHelper;
    private BubbleBarMenuViewController mMenuViewController;
    private BubbleBarExpandedViewDragController mDragController;
    private @Nullable Supplier<Rect> mLayerBoundsSupplier;
    private @Nullable Listener mListener;

@@ -180,6 +181,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
        mHandleView.setOnClickListener(view -> {
            mMenuViewController.showMenu(true /* animated */);
        });

        mDragController = new BubbleBarExpandedViewDragController(this);
    }

    public BubbleBarHandleView getHandleView() {
@@ -386,4 +389,11 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
            setContentVisibility(mIsContentVisible);
        }
    }

    /**
     * Check whether the view is animating
     */
    public boolean isAnimating() {
        return mIsAnimating;
    }
}
+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.wm.shell.bubbles.bar

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.graphics.PointF
import android.view.MotionEvent
import android.view.View
import com.android.wm.shell.animation.Interpolators
import com.android.wm.shell.common.bubbles.RelativeTouchListener

/** Controller for handling drag interactions with [BubbleBarExpandedView] */
class BubbleBarExpandedViewDragController(private val expandedView: BubbleBarExpandedView) {

    init {
        expandedView.handleView.setOnTouchListener(HandleDragListener())
    }

    private fun resetExpandedViewPosition(initialX: Float, initialY: Float) {
        val listener = object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator) {
                expandedView.isAnimating = true
            }

            override fun onAnimationEnd(animation: Animator) {
                expandedView.isAnimating = false
            }
        }
        expandedView.animate()
            .translationX(initialX)
            .translationY(initialY)
            .setDuration(RESET_POSITION_ANIM_DURATION)
            .setInterpolator(Interpolators.EMPHASIZED_DECELERATE)
            .setListener(listener)
            .start()
    }

    private inner class HandleDragListener : RelativeTouchListener() {

        private val expandedViewRestPosition = PointF()

        override fun onDown(v: View, ev: MotionEvent): Boolean {
            // While animating, don't allow new touch events
            if (expandedView.isAnimating) {
                return false
            }
            expandedViewRestPosition.x = expandedView.translationX
            expandedViewRestPosition.y = expandedView.translationY
            return true
        }

        override fun onMove(
            v: View,
            ev: MotionEvent,
            viewInitialX: Float,
            viewInitialY: Float,
            dx: Float,
            dy: Float
        ) {
            expandedView.translationX = expandedViewRestPosition.x + dx
            expandedView.translationY = expandedViewRestPosition.y + dy
        }

        override fun onUp(
            v: View,
            ev: MotionEvent,
            viewInitialX: Float,
            viewInitialY: Float,
            dx: Float,
            dy: Float,
            velX: Float,
            velY: Float
        ) {
            resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y)
        }

        override fun onCancel(v: View, ev: MotionEvent, viewInitialX: Float, viewInitialY: Float) {
            resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y)
        }
    }

    companion object {
        const val RESET_POSITION_ANIM_DURATION = 300L
    }
}
+17 −5
Original line number Diff line number Diff line
@@ -78,8 +78,15 @@ abstract class RelativeTouchListener : View.OnTouchListener {
        velY: Float
    )

    open fun onCancel(
        v: View,
        ev: MotionEvent,
        viewInitialX: Float,
        viewInitialY: Float
    ) {}

    /** The raw coordinates of the last ACTION_DOWN event. */
    private val touchDown = PointF()
    private var touchDown: PointF? = null

    /** The coordinates of the view, at the time of the last ACTION_DOWN event. */
    private val viewPositionOnTouchDown = PointF()
@@ -91,12 +98,11 @@ abstract class RelativeTouchListener : View.OnTouchListener {

    private var performedLongClick = false

    @Suppress("UNCHECKED_CAST")
    override fun onTouch(v: View, ev: MotionEvent): Boolean {
        addMovement(ev)

        val dx = ev.rawX - touchDown.x
        val dy = ev.rawY - touchDown.y
        val dx = touchDown?.let { ev.rawX - it.x } ?: 0f
        val dy = touchDown?.let { ev.rawY - it.y } ?: 0f

        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
@@ -108,7 +114,7 @@ abstract class RelativeTouchListener : View.OnTouchListener {
                // last gesture.
                touchSlop = ViewConfiguration.get(v.context).scaledTouchSlop

                touchDown.set(ev.rawX, ev.rawY)
                touchDown = PointF(ev.rawX, ev.rawY)
                viewPositionOnTouchDown.set(v.translationX, v.translationY)

                performedLongClick = false
@@ -120,6 +126,7 @@ abstract class RelativeTouchListener : View.OnTouchListener {
            }

            MotionEvent.ACTION_MOVE -> {
                if (touchDown == null) return false
                if (!movedEnough && hypot(dx, dy) > touchSlop && !performedLongClick) {
                    movedEnough = true
                    v.handler?.removeCallbacksAndMessages(null)
@@ -131,6 +138,7 @@ abstract class RelativeTouchListener : View.OnTouchListener {
            }

            MotionEvent.ACTION_UP -> {
                if (touchDown == null) return false
                if (movedEnough) {
                    velocityTracker.computeCurrentVelocity(1000 /* units */)
                    onUp(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y, dx, dy,
@@ -143,12 +151,16 @@ abstract class RelativeTouchListener : View.OnTouchListener {

                velocityTracker.clear()
                movedEnough = false
                touchDown = null
            }

            MotionEvent.ACTION_CANCEL -> {
                if (touchDown == null) return false
                v.handler?.removeCallbacksAndMessages(null)
                velocityTracker.clear()
                movedEnough = false
                touchDown = null
                onCancel(v, ev, viewPositionOnTouchDown.x, viewPositionOnTouchDown.y)
            }
        }