Skip to content
Snippets Groups Projects
Commit 99a965ca authored by Ats Jenk's avatar Ats Jenk
Browse files

Create a drag controller for expanded bubble bar

Tracks touch events on BubbleBarHandleView.
Moves the BubbleBarExpandedView around based on touch events.
When finger is released, snaps back to the initial position.

Bug: 283991264
Test: drag from the handle
  - observe that the view follows the finger
  - release touch, observe that the view snaps back

Change-Id: I16bc97270195dbdb753ac30d091a93c63ce6628d
parent 73b38b49
No related branches found
No related tags found
No related merge requests found
......@@ -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;
}
}
/*
* 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
}
}
......@@ -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)
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment