Merge "Bubble bar drag to dismiss" into udc-qpr-dev am: e3d4a69749
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/23879277 Change-Id: I82bd9a7499ddd73b9df80106a943a534690c3164 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<shape
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
|
||||||
|
<stroke
|
||||||
|
android:width="2dp"
|
||||||
|
android:color="@android:color/system_accent1_600" />
|
||||||
|
|
||||||
|
<solid android:color="@android:color/system_accent1_600" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="20dp"
|
||||||
|
android:height="20dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
|
||||||
|
android:fillColor="@android:color/system_neutral1_50"/>
|
||||||
|
</vector>
|
||||||
@@ -367,6 +367,13 @@
|
|||||||
<dimen name="bubblebar_icon_spacing">3dp</dimen>
|
<dimen name="bubblebar_icon_spacing">3dp</dimen>
|
||||||
<dimen name="bubblebar_icon_elevation">1dp</dimen>
|
<dimen name="bubblebar_icon_elevation">1dp</dimen>
|
||||||
|
|
||||||
|
<!-- Bubble bar dismiss view -->
|
||||||
|
<dimen name="bubblebar_dismiss_target_size">96dp</dimen>
|
||||||
|
<dimen name="bubblebar_dismiss_target_small_size">60dp</dimen>
|
||||||
|
<dimen name="bubblebar_dismiss_target_icon_size">24dp</dimen>
|
||||||
|
<dimen name="bubblebar_dismiss_target_bottom_margin">50dp</dimen>
|
||||||
|
<dimen name="bubblebar_dismiss_floating_gradient_height">548dp</dimen>
|
||||||
|
|
||||||
<!-- Launcher splash screen -->
|
<!-- Launcher splash screen -->
|
||||||
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
|
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
|
||||||
<!-- starting_surface_exit_animation_window_shift_length -->
|
<!-- starting_surface_exit_animation_window_shift_length -->
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ import com.android.launcher3.taskbar.bubbles.BubbleBarController;
|
|||||||
import com.android.launcher3.taskbar.bubbles.BubbleBarView;
|
import com.android.launcher3.taskbar.bubbles.BubbleBarView;
|
||||||
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
|
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
|
||||||
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
|
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
|
||||||
|
import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
|
||||||
|
import com.android.launcher3.taskbar.bubbles.BubbleDragController;
|
||||||
import com.android.launcher3.taskbar.bubbles.BubbleStashController;
|
import com.android.launcher3.taskbar.bubbles.BubbleStashController;
|
||||||
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
|
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
|
||||||
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
|
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
|
||||||
@@ -216,7 +218,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
|||||||
new BubbleBarController(this, bubbleBarView),
|
new BubbleBarController(this, bubbleBarView),
|
||||||
new BubbleBarViewController(this, bubbleBarView),
|
new BubbleBarViewController(this, bubbleBarView),
|
||||||
new BubbleStashController(this),
|
new BubbleStashController(this),
|
||||||
new BubbleStashedHandleViewController(this, bubbleHandleView)));
|
new BubbleStashedHandleViewController(this, bubbleHandleView),
|
||||||
|
new BubbleDragController(this),
|
||||||
|
new BubbleDismissController(this, mDragLayer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct controllers.
|
// Construct controllers.
|
||||||
|
|||||||
@@ -95,6 +95,8 @@ public class BubbleBarView extends FrameLayout {
|
|||||||
private View.OnClickListener mOnClickListener;
|
private View.OnClickListener mOnClickListener;
|
||||||
|
|
||||||
private final Rect mTempRect = new Rect();
|
private final Rect mTempRect = new Rect();
|
||||||
|
private float mRelativePivotX = 1f;
|
||||||
|
private float mRelativePivotY = 1f;
|
||||||
|
|
||||||
// An animator that represents the expansion state of the bubble bar, where 0 corresponds to the
|
// An animator that represents the expansion state of the bubble bar, where 0 corresponds to the
|
||||||
// collapsed state and 1 to the fully expanded state.
|
// collapsed state and 1 to the fully expanded state.
|
||||||
@@ -109,6 +111,9 @@ public class BubbleBarView extends FrameLayout {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private Consumer<String> mUpdateSelectedBubbleAfterCollapse;
|
private Consumer<String> mUpdateSelectedBubbleAfterCollapse;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private BubbleView mDraggedBubbleView;
|
||||||
|
|
||||||
public BubbleBarView(Context context) {
|
public BubbleBarView(Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
@@ -181,9 +186,10 @@ public class BubbleBarView extends FrameLayout {
|
|||||||
mBubbleBarBounds.right = right;
|
mBubbleBarBounds.right = right;
|
||||||
mBubbleBarBounds.bottom = bottom;
|
mBubbleBarBounds.bottom = bottom;
|
||||||
|
|
||||||
// The bubble bar handle is aligned to the bottom edge of the screen so scale towards that.
|
// The bubble bar handle is aligned according to the relative pivot,
|
||||||
setPivotX(getWidth());
|
// by default it's aligned to the bottom edge of the screen so scale towards that
|
||||||
setPivotY(getHeight());
|
setPivotX(mRelativePivotX * getWidth());
|
||||||
|
setPivotY(mRelativePivotY * getHeight());
|
||||||
|
|
||||||
// Position the views
|
// Position the views
|
||||||
updateChildrenRenderNodeProperties();
|
updateChildrenRenderNodeProperties();
|
||||||
@@ -198,6 +204,32 @@ public class BubbleBarView extends FrameLayout {
|
|||||||
return mBubbleBarBounds;
|
return mBubbleBarBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set bubble bar relative pivot value for X and Y, applied as a fraction of view width/height
|
||||||
|
* respectively. If the value is not in range of 0 to 1 it will be normalized.
|
||||||
|
* @param x relative X pivot value in range 0..1
|
||||||
|
* @param y relative Y pivot value in range 0..1
|
||||||
|
*/
|
||||||
|
public void setRelativePivot(float x, float y) {
|
||||||
|
mRelativePivotX = Float.max(Float.min(x, 1), 0);
|
||||||
|
mRelativePivotY = Float.max(Float.min(y, 1), 0);
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current relative pivot for X axis
|
||||||
|
*/
|
||||||
|
public float getRelativePivotX() {
|
||||||
|
return mRelativePivotX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current relative pivot for Y axis
|
||||||
|
*/
|
||||||
|
public float getRelativePivotY() {
|
||||||
|
return mRelativePivotY;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: (b/280605790) animate it
|
// TODO: (b/280605790) animate it
|
||||||
@Override
|
@Override
|
||||||
public void addView(View child, int index, ViewGroup.LayoutParams params) {
|
public void addView(View child, int index, ViewGroup.LayoutParams params) {
|
||||||
@@ -254,9 +286,9 @@ public class BubbleBarView extends FrameLayout {
|
|||||||
// where the bubble will end up when the animation ends
|
// where the bubble will end up when the animation ends
|
||||||
final float targetX = currentWidth - expandedWidth + expandedX;
|
final float targetX = currentWidth - expandedWidth + expandedX;
|
||||||
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
|
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
|
||||||
// if we're fully expanded, set the z level to 0
|
// if we're fully expanded, set the z level to 0 or to bubble elevation if dragged
|
||||||
if (widthState == 1f) {
|
if (widthState == 1f) {
|
||||||
bv.setZ(0);
|
bv.setZ(bv == mDraggedBubbleView ? mBubbleElevation : 0);
|
||||||
}
|
}
|
||||||
// When we're expanded, we're not stacked so we're not behind the stack
|
// When we're expanded, we're not stacked so we're not behind the stack
|
||||||
bv.setBehindStack(false, animate);
|
bv.setBehindStack(false, animate);
|
||||||
@@ -328,6 +360,14 @@ public class BubbleBarView extends FrameLayout {
|
|||||||
updateArrowForSelected(/* shouldAnimate= */ true);
|
updateArrowForSelected(/* shouldAnimate= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the dragged bubble view to correctly apply Z order. Dragged view should appear on top
|
||||||
|
*/
|
||||||
|
public void setDraggedBubble(@Nullable BubbleView view) {
|
||||||
|
mDraggedBubbleView = view;
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the arrow position to match the selected bubble.
|
* Update the arrow position to match the selected bubble.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import android.view.MotionEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.android.launcher3.R;
|
import com.android.launcher3.R;
|
||||||
import com.android.launcher3.anim.AnimatedFloat;
|
import com.android.launcher3.anim.AnimatedFloat;
|
||||||
import com.android.launcher3.taskbar.TaskbarActivityContext;
|
import com.android.launcher3.taskbar.TaskbarActivityContext;
|
||||||
@@ -54,6 +56,7 @@ public class BubbleBarViewController {
|
|||||||
// Initialized in init.
|
// Initialized in init.
|
||||||
private BubbleStashController mBubbleStashController;
|
private BubbleStashController mBubbleStashController;
|
||||||
private BubbleBarController mBubbleBarController;
|
private BubbleBarController mBubbleBarController;
|
||||||
|
private BubbleDragController mBubbleDragController;
|
||||||
private TaskbarStashController mTaskbarStashController;
|
private TaskbarStashController mTaskbarStashController;
|
||||||
private TaskbarInsetsController mTaskbarInsetsController;
|
private TaskbarInsetsController mTaskbarInsetsController;
|
||||||
private View.OnClickListener mBubbleClickListener;
|
private View.OnClickListener mBubbleClickListener;
|
||||||
@@ -85,6 +88,7 @@ public class BubbleBarViewController {
|
|||||||
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
|
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
|
||||||
mBubbleStashController = bubbleControllers.bubbleStashController;
|
mBubbleStashController = bubbleControllers.bubbleStashController;
|
||||||
mBubbleBarController = bubbleControllers.bubbleBarController;
|
mBubbleBarController = bubbleControllers.bubbleBarController;
|
||||||
|
mBubbleDragController = bubbleControllers.bubbleDragController;
|
||||||
mTaskbarStashController = controllers.taskbarStashController;
|
mTaskbarStashController = controllers.taskbarStashController;
|
||||||
mTaskbarInsetsController = controllers.taskbarInsetsController;
|
mTaskbarInsetsController = controllers.taskbarInsetsController;
|
||||||
|
|
||||||
@@ -95,6 +99,7 @@ public class BubbleBarViewController {
|
|||||||
mBubbleBarScale.updateValue(1f);
|
mBubbleBarScale.updateValue(1f);
|
||||||
mBubbleClickListener = v -> onBubbleClicked(v);
|
mBubbleClickListener = v -> onBubbleClicked(v);
|
||||||
mBubbleBarClickListener = v -> setExpanded(true);
|
mBubbleBarClickListener = v -> setExpanded(true);
|
||||||
|
mBubbleDragController.setupBubbleBarView(mBarView);
|
||||||
mBarView.setOnClickListener(mBubbleBarClickListener);
|
mBarView.setOnClickListener(mBubbleBarClickListener);
|
||||||
mBarView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
|
mBarView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
|
||||||
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
|
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
|
||||||
@@ -256,6 +261,7 @@ public class BubbleBarViewController {
|
|||||||
if (b != null) {
|
if (b != null) {
|
||||||
mBarView.addView(b.getView(), 0, new FrameLayout.LayoutParams(mIconSize, mIconSize));
|
mBarView.addView(b.getView(), 0, new FrameLayout.LayoutParams(mIconSize, mIconSize));
|
||||||
b.getView().setOnClickListener(mBubbleClickListener);
|
b.getView().setOnClickListener(mBubbleClickListener);
|
||||||
|
mBubbleDragController.setupBubbleView(b.getView());
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "addBubble, bubble was null!");
|
Log.w(TAG, "addBubble, bubble was null!");
|
||||||
}
|
}
|
||||||
@@ -307,4 +313,41 @@ public class BubbleBarViewController {
|
|||||||
mBubbleStashController.showBubbleBar(true /* expand the bubbles */);
|
mBubbleStashController.showBubbleBar(true /* expand the bubbles */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the dragged bubble view in the bubble bar view, and notifies SystemUI
|
||||||
|
* to collapse the selected bubble while it's dragged.
|
||||||
|
* @param bubbleView dragged bubble view
|
||||||
|
*/
|
||||||
|
public void onDragStart(@NonNull BubbleView bubbleView) {
|
||||||
|
mBarView.setDraggedBubble(bubbleView);
|
||||||
|
if (bubbleView.getBubble() == null) return;
|
||||||
|
mSystemUiProxy.collapseWhileDragging(bubbleView.getBubble().getKey(), true /* collapse */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the dragged bubble view in the bubble bar view, and notifies SystemUI
|
||||||
|
* to expand the selected bubble when dragging finished.
|
||||||
|
* @param bubbleView dragged bubble view
|
||||||
|
*/
|
||||||
|
public void onDragEnd(@NonNull BubbleView bubbleView) {
|
||||||
|
mBarView.setDraggedBubble(null);
|
||||||
|
if (bubbleView.getBubble() == null) return;
|
||||||
|
mSystemUiProxy.collapseWhileDragging(bubbleView.getBubble().getKey(), false /* collapse */);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when bubble was dragged into the dismiss target. Notifies System
|
||||||
|
* @param bubble dismissed bubble item
|
||||||
|
*/
|
||||||
|
public void onDismissBubbleWhileDragging(@NonNull BubbleBarItem bubble) {
|
||||||
|
mSystemUiProxy.removeBubble(bubble.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when bubble stack was dragged into the dismiss target
|
||||||
|
*/
|
||||||
|
public void onDismissAllBubblesWhileDragging() {
|
||||||
|
mSystemUiProxy.removeAllBubbles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ public class BubbleControllers {
|
|||||||
public final BubbleBarViewController bubbleBarViewController;
|
public final BubbleBarViewController bubbleBarViewController;
|
||||||
public final BubbleStashController bubbleStashController;
|
public final BubbleStashController bubbleStashController;
|
||||||
public final BubbleStashedHandleViewController bubbleStashedHandleViewController;
|
public final BubbleStashedHandleViewController bubbleStashedHandleViewController;
|
||||||
|
public final BubbleDragController bubbleDragController;
|
||||||
|
public final BubbleDismissController bubbleDismissController;
|
||||||
|
|
||||||
private final RunnableList mPostInitRunnables = new RunnableList();
|
private final RunnableList mPostInitRunnables = new RunnableList();
|
||||||
|
|
||||||
@@ -39,11 +41,15 @@ public class BubbleControllers {
|
|||||||
BubbleBarController bubbleBarController,
|
BubbleBarController bubbleBarController,
|
||||||
BubbleBarViewController bubbleBarViewController,
|
BubbleBarViewController bubbleBarViewController,
|
||||||
BubbleStashController bubbleStashController,
|
BubbleStashController bubbleStashController,
|
||||||
BubbleStashedHandleViewController bubbleStashedHandleViewController) {
|
BubbleStashedHandleViewController bubbleStashedHandleViewController,
|
||||||
|
BubbleDragController bubbleDragController,
|
||||||
|
BubbleDismissController bubbleDismissController) {
|
||||||
this.bubbleBarController = bubbleBarController;
|
this.bubbleBarController = bubbleBarController;
|
||||||
this.bubbleBarViewController = bubbleBarViewController;
|
this.bubbleBarViewController = bubbleBarViewController;
|
||||||
this.bubbleStashController = bubbleStashController;
|
this.bubbleStashController = bubbleStashController;
|
||||||
this.bubbleStashedHandleViewController = bubbleStashedHandleViewController;
|
this.bubbleStashedHandleViewController = bubbleStashedHandleViewController;
|
||||||
|
this.bubbleDragController = bubbleDragController;
|
||||||
|
this.bubbleDismissController = bubbleDismissController;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,6 +62,8 @@ public class BubbleControllers {
|
|||||||
bubbleBarViewController.init(taskbarControllers, this);
|
bubbleBarViewController.init(taskbarControllers, this);
|
||||||
bubbleStashedHandleViewController.init(taskbarControllers, this);
|
bubbleStashedHandleViewController.init(taskbarControllers, this);
|
||||||
bubbleStashController.init(taskbarControllers, this);
|
bubbleStashController.init(taskbarControllers, this);
|
||||||
|
bubbleDragController.init(/* bubbleControllers = */ this);
|
||||||
|
bubbleDismissController.init(/* bubbleControllers = */ this);
|
||||||
|
|
||||||
mPostInitRunnables.executeAllAndDestroy();
|
mPostInitRunnables.executeAllAndDestroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* 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.launcher3.taskbar.bubbles;
|
||||||
|
|
||||||
|
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.os.SystemProperties;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.dynamicanimation.animation.DynamicAnimation;
|
||||||
|
|
||||||
|
import com.android.launcher3.R;
|
||||||
|
import com.android.launcher3.taskbar.TaskbarActivityContext;
|
||||||
|
import com.android.launcher3.taskbar.TaskbarDragLayer;
|
||||||
|
import com.android.wm.shell.common.bubbles.DismissView;
|
||||||
|
import com.android.wm.shell.common.magnetictarget.MagnetizedObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls dismiss view presentation for the bubble bar dismiss functionality.
|
||||||
|
* Provides the dragged view snapping to the target dismiss area and animates it.
|
||||||
|
* When the dragged bubble/bubble stack is realised inside of the target area, it gets dismissed.
|
||||||
|
*
|
||||||
|
* @see BubbleDragController
|
||||||
|
*/
|
||||||
|
public class BubbleDismissController {
|
||||||
|
private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f;
|
||||||
|
public static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
|
||||||
|
SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
|
||||||
|
private final TaskbarActivityContext mActivity;
|
||||||
|
private final TaskbarDragLayer mDragLayer;
|
||||||
|
@Nullable
|
||||||
|
private BubbleBarViewController mBubbleBarViewController;
|
||||||
|
|
||||||
|
// Dismiss view that's attached to drag layer. It consists of the scrim view and the circular
|
||||||
|
// dismiss view used as a dismiss target.
|
||||||
|
@Nullable
|
||||||
|
private DismissView mDismissView;
|
||||||
|
|
||||||
|
// The currently magnetized object, which is being dragged and will be attracted to the magnetic
|
||||||
|
// dismiss target. This is either the stack itself, or an individual bubble.
|
||||||
|
@Nullable
|
||||||
|
private MagnetizedObject<View> mMagnetizedObject;
|
||||||
|
|
||||||
|
// The MagneticTarget instance for our circular dismiss view. This is added to the
|
||||||
|
// MagnetizedObject instances for the stack and any dragged-out bubbles.
|
||||||
|
@Nullable
|
||||||
|
private MagnetizedObject.MagneticTarget mMagneticTarget;
|
||||||
|
@Nullable
|
||||||
|
private ValueAnimator mDismissAnimator;
|
||||||
|
|
||||||
|
public BubbleDismissController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer) {
|
||||||
|
mActivity = activity;
|
||||||
|
mDragLayer = dragLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes dependencies when bubble controllers are created.
|
||||||
|
* Should be careful to only access things that were created in constructors for now, as some
|
||||||
|
* controllers may still be waiting for init().
|
||||||
|
*/
|
||||||
|
public void init(@NonNull BubbleControllers bubbleControllers) {
|
||||||
|
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the dismiss view and magnetized object that will be attracted to magnetic target.
|
||||||
|
* Should be called before handling events or showing/hiding dismiss view.
|
||||||
|
* @param magnetizedView the view to be pulled into target dismiss area
|
||||||
|
*/
|
||||||
|
public void setupDismissView(@NonNull View magnetizedView) {
|
||||||
|
setupDismissView();
|
||||||
|
setupMagnetizedObject(magnetizedView);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the touch event and pass it to the magnetized object.
|
||||||
|
* It should be called after {@code setupDismissView}
|
||||||
|
*/
|
||||||
|
public boolean handleTouchEvent(@NonNull MotionEvent event) {
|
||||||
|
return mMagnetizedObject != null && mMagnetizedObject.maybeConsumeMotionEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show dismiss view with animation
|
||||||
|
* It should be called after {@code setupDismissView}
|
||||||
|
*/
|
||||||
|
public void showDismissView() {
|
||||||
|
if (mDismissView == null) return;
|
||||||
|
mDismissView.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide dismiss view with animation
|
||||||
|
* It should be called after {@code setupDismissView}
|
||||||
|
*/
|
||||||
|
public void hideDismissView() {
|
||||||
|
if (mDismissView == null) return;
|
||||||
|
mDismissView.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismiss magnetized object when it's released in the dismiss target area
|
||||||
|
*/
|
||||||
|
private void dismissMagnetizedObject() {
|
||||||
|
if (mMagnetizedObject == null || mBubbleBarViewController == null) return;
|
||||||
|
if (mMagnetizedObject.getUnderlyingObject() instanceof BubbleView) {
|
||||||
|
BubbleView bubbleView = (BubbleView) mMagnetizedObject.getUnderlyingObject();
|
||||||
|
if (bubbleView.getBubble() != null) {
|
||||||
|
mBubbleBarViewController.onDismissBubbleWhileDragging(bubbleView.getBubble());
|
||||||
|
}
|
||||||
|
} else if (mMagnetizedObject.getUnderlyingObject() instanceof BubbleBarView) {
|
||||||
|
mBubbleBarViewController.onDismissAllBubblesWhileDragging();
|
||||||
|
}
|
||||||
|
cleanUpAnimatedViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate dismiss view when magnetized object gets stuck in the magnetic target
|
||||||
|
* @param view captured view
|
||||||
|
*/
|
||||||
|
private void animateDismissCaptured(@NonNull View view) {
|
||||||
|
cancelAnimations();
|
||||||
|
mDismissAnimator = createDismissAnimator(view);
|
||||||
|
mDismissAnimator.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animate dismiss view when magnetized object gets unstuck from the magnetic target
|
||||||
|
*/
|
||||||
|
private void animateDismissReleased() {
|
||||||
|
if (mDismissAnimator == null) return;
|
||||||
|
mDismissAnimator.removeAllListeners();
|
||||||
|
mDismissAnimator.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
cancelAnimations();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
cancelAnimations();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mDismissAnimator.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel and clear dismiss animations and reset view states
|
||||||
|
*/
|
||||||
|
private void cancelAnimations() {
|
||||||
|
if (mDismissAnimator == null) return;
|
||||||
|
ValueAnimator animator = mDismissAnimator;
|
||||||
|
mDismissAnimator = null;
|
||||||
|
animator.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up views changed during animation
|
||||||
|
*/
|
||||||
|
private void cleanUpAnimatedViews() {
|
||||||
|
// Cancel animations
|
||||||
|
cancelAnimations();
|
||||||
|
// Reset dismiss view
|
||||||
|
if (mDismissView != null) {
|
||||||
|
mDismissView.getCircle().setScaleX(1f);
|
||||||
|
mDismissView.getCircle().setScaleY(1f);
|
||||||
|
}
|
||||||
|
// Reset magnetized view
|
||||||
|
if (mMagnetizedObject != null) {
|
||||||
|
mMagnetizedObject.getUnderlyingObject().setAlpha(1f);
|
||||||
|
mMagnetizedObject.getUnderlyingObject().setScaleX(1f);
|
||||||
|
mMagnetizedObject.getUnderlyingObject().setScaleY(1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupDismissView() {
|
||||||
|
if (mDismissView != null) return;
|
||||||
|
mDismissView = new DismissView(mActivity.getApplicationContext());
|
||||||
|
BubbleDismissViewUtils.setup(mDismissView);
|
||||||
|
mDragLayer.addView(mDismissView, /* index = */ 0,
|
||||||
|
new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
||||||
|
setupMagneticTarget(mDismissView.getCircle());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupMagneticTarget(@NonNull View view) {
|
||||||
|
int magneticFieldRadius = mActivity.getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.bubblebar_dismiss_target_size);
|
||||||
|
mMagneticTarget = new MagnetizedObject.MagneticTarget(view, magneticFieldRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupMagnetizedObject(@NonNull View magnetizedView) {
|
||||||
|
mMagnetizedObject = new MagnetizedObject<>(mActivity.getApplicationContext(),
|
||||||
|
magnetizedView, DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y) {
|
||||||
|
@Override
|
||||||
|
public float getWidth(@NonNull View underlyingObject) {
|
||||||
|
return underlyingObject.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getHeight(@NonNull View underlyingObject) {
|
||||||
|
return underlyingObject.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getLocationOnScreen(@NonNull View underlyingObject, @NonNull int[] loc) {
|
||||||
|
underlyingObject.getLocationOnScreen(loc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mMagnetizedObject.setHapticsEnabled(true);
|
||||||
|
mMagnetizedObject.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
|
||||||
|
mMagnetizedObject.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
|
||||||
|
if (mMagneticTarget != null) {
|
||||||
|
mMagnetizedObject.addTarget(mMagneticTarget);
|
||||||
|
}
|
||||||
|
mMagnetizedObject.setMagnetListener(new MagnetizedObject.MagnetListener() {
|
||||||
|
@Override
|
||||||
|
public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
|
||||||
|
animateDismissCaptured(magnetizedView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
|
||||||
|
float velX, float velY, boolean wasFlungOut) {
|
||||||
|
animateDismissReleased();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
|
||||||
|
dismissMagnetizedObject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private ValueAnimator createDismissAnimator(@NonNull View magnetizedView) {
|
||||||
|
Resources resources = mActivity.getResources();
|
||||||
|
int expandedSize = resources.getDimensionPixelSize(R.dimen.bubblebar_dismiss_target_size);
|
||||||
|
int collapsedSize = resources.getDimensionPixelSize(
|
||||||
|
R.dimen.bubblebar_dismiss_target_small_size);
|
||||||
|
float minScale = (float) collapsedSize / expandedSize;
|
||||||
|
ValueAnimator animator = ValueAnimator.ofFloat(1f, minScale);
|
||||||
|
animator.addUpdateListener(animation -> {
|
||||||
|
if (mDismissView == null) return;
|
||||||
|
final float animatedValue = (float) animation.getAnimatedValue();
|
||||||
|
mDismissView.getCircle().setScaleX(animatedValue);
|
||||||
|
mDismissView.getCircle().setScaleY(animatedValue);
|
||||||
|
magnetizedView.setAlpha(animatedValue);
|
||||||
|
if (magnetizedView instanceof BubbleBarView) {
|
||||||
|
magnetizedView.setScaleX(animatedValue);
|
||||||
|
magnetizedView.setScaleY(animatedValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return animator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
@file:JvmName("BubbleDismissViewUtils")
|
||||||
|
|
||||||
|
package com.android.launcher3.taskbar.bubbles
|
||||||
|
|
||||||
|
import com.android.launcher3.R
|
||||||
|
import com.android.wm.shell.common.bubbles.DismissView
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismiss view is shared from WMShell. It requires setup with local resources.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* - Kotlin `dismissView.setup()`
|
||||||
|
* - Java `BubbleDismissViewUtils.setup(dismissView)`
|
||||||
|
*/
|
||||||
|
fun DismissView.setup() {
|
||||||
|
setup(
|
||||||
|
DismissView.Config(
|
||||||
|
targetSizeResId = R.dimen.bubblebar_dismiss_target_size,
|
||||||
|
iconSizeResId = R.dimen.bubblebar_dismiss_target_icon_size,
|
||||||
|
bottomMarginResId = R.dimen.bubblebar_dismiss_target_bottom_margin,
|
||||||
|
floatingGradientHeightResId = R.dimen.bubblebar_dismiss_floating_gradient_height,
|
||||||
|
floatingGradientColorResId = android.R.color.system_neutral1_900,
|
||||||
|
backgroundResId = R.drawable.bg_bubble_dismiss_circle,
|
||||||
|
iconResId = R.drawable.ic_bubble_dismiss_white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
* 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.launcher3.taskbar.bubbles;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.android.launcher3.taskbar.TaskbarActivityContext;
|
||||||
|
import com.android.wm.shell.common.bubbles.RelativeTouchListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls bubble bar drag to dismiss interaction.
|
||||||
|
* Interacts with {@link BubbleDismissController}, used by {@link BubbleBarViewController}.
|
||||||
|
* Supported interactions:
|
||||||
|
* - Drag a single bubble view into dismiss target to remove it.
|
||||||
|
* - Drag the bubble stack into dismiss target to remove all.
|
||||||
|
* Restores initial position of dragged view if released outside of the dismiss target.
|
||||||
|
*/
|
||||||
|
public class BubbleDragController {
|
||||||
|
private final TaskbarActivityContext mActivity;
|
||||||
|
private BubbleBarViewController mBubbleBarViewController;
|
||||||
|
private BubbleDismissController mBubbleDismissController;
|
||||||
|
|
||||||
|
public BubbleDragController(TaskbarActivityContext activity) {
|
||||||
|
mActivity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes dependencies when bubble controllers are created.
|
||||||
|
* Should be careful to only access things that were created in constructors for now, as some
|
||||||
|
* controllers may still be waiting for init().
|
||||||
|
*/
|
||||||
|
public void init(@NonNull BubbleControllers bubbleControllers) {
|
||||||
|
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
|
||||||
|
mBubbleDismissController = bubbleControllers.bubbleDismissController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the bubble view for dragging and attach touch listener to it
|
||||||
|
*/
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
public void setupBubbleView(@NonNull BubbleView bubbleView) {
|
||||||
|
// Don't setup dragging for overflow bubble view
|
||||||
|
if (bubbleView.getBubble() == null
|
||||||
|
|| !(bubbleView.getBubble() instanceof BubbleBarBubble)) return;
|
||||||
|
bubbleView.setOnTouchListener(new BaseDragListener() {
|
||||||
|
@Override
|
||||||
|
protected void onDragStart() {
|
||||||
|
super.onDragStart();
|
||||||
|
mBubbleBarViewController.onDragStart(bubbleView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDragEnd() {
|
||||||
|
super.onDragEnd();
|
||||||
|
mBubbleBarViewController.onDragEnd(bubbleView);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup the bubble bar view for dragging and attach touch listener to it
|
||||||
|
*/
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
public void setupBubbleBarView(@NonNull BubbleBarView bubbleBarView) {
|
||||||
|
PointF initialRelativePivot = new PointF();
|
||||||
|
bubbleBarView.setOnTouchListener(new BaseDragListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onDown(@NonNull View view, @NonNull MotionEvent event) {
|
||||||
|
if (bubbleBarView.isExpanded()) return false;
|
||||||
|
// Setup dragging only when bubble bar is collapsed
|
||||||
|
return super.onDown(view, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDragStart() {
|
||||||
|
super.onDragStart();
|
||||||
|
initialRelativePivot.set(bubbleBarView.getRelativePivotX(),
|
||||||
|
bubbleBarView.getRelativePivotY());
|
||||||
|
bubbleBarView.setRelativePivot(/* x = */ 0.5f, /* y = */ 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDragEnd() {
|
||||||
|
super.onDragEnd();
|
||||||
|
bubbleBarView.setRelativePivot(initialRelativePivot.x, initialRelativePivot.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base drag listener for handling a single bubble view or bubble bar view dragging.
|
||||||
|
* Controls dragging interaction and interacts with {@link BubbleDismissController}
|
||||||
|
* to coordinate dismiss view presentation.
|
||||||
|
* Lifecycle methods can be overridden do add extra setup/clean up steps
|
||||||
|
*/
|
||||||
|
private class BaseDragListener extends RelativeTouchListener {
|
||||||
|
private boolean mHandling;
|
||||||
|
private boolean mDragging;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDown(@NonNull View view, @NonNull MotionEvent event) {
|
||||||
|
mHandling = true;
|
||||||
|
mActivity.setTaskbarWindowFullscreen(true);
|
||||||
|
mBubbleDismissController.setupDismissView(view);
|
||||||
|
mBubbleDismissController.handleTouchEvent(event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMove(@NonNull View view, @NonNull MotionEvent event, float viewInitialX,
|
||||||
|
float viewInitialY, float dx, float dy) {
|
||||||
|
if (!mHandling) return;
|
||||||
|
if (!mDragging) {
|
||||||
|
// Start dragging
|
||||||
|
mDragging = true;
|
||||||
|
onDragStart();
|
||||||
|
}
|
||||||
|
if (!mBubbleDismissController.handleTouchEvent(event)) {
|
||||||
|
// Drag the view if not processed by dismiss controller
|
||||||
|
view.setTranslationX(viewInitialX + dx);
|
||||||
|
view.setTranslationY(viewInitialY + dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUp(@NonNull View view, @NonNull MotionEvent event, float viewInitialX,
|
||||||
|
float viewInitialY, float dx, float dy, float velX, float velY) {
|
||||||
|
onComplete(view, event, viewInitialX, viewInitialY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancel(@NonNull View view, @NonNull MotionEvent event, float viewInitialX,
|
||||||
|
float viewInitialY, float dx, float dy) {
|
||||||
|
onComplete(view, event, viewInitialX, viewInitialY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares dismiss view for dragging.
|
||||||
|
* This method can be overridden to add extra setup on drag start
|
||||||
|
*/
|
||||||
|
protected void onDragStart() {
|
||||||
|
mBubbleDismissController.showDismissView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up dismiss view after dragging.
|
||||||
|
* This method can be overridden to add extra setup on drag end
|
||||||
|
*/
|
||||||
|
protected void onDragEnd() {
|
||||||
|
mBubbleDismissController.hideDismissView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Complete drag handling and clean up dependencies
|
||||||
|
*/
|
||||||
|
private void onComplete(@NonNull View view, @NonNull MotionEvent event,
|
||||||
|
float viewInitialX, float viewInitialY) {
|
||||||
|
if (!mHandling) return;
|
||||||
|
if (mDragging) {
|
||||||
|
// Stop dragging
|
||||||
|
mDragging = false;
|
||||||
|
view.setTranslationX(viewInitialX);
|
||||||
|
view.setTranslationY(viewInitialY);
|
||||||
|
onDragEnd();
|
||||||
|
}
|
||||||
|
mBubbleDismissController.handleTouchEvent(event);
|
||||||
|
mActivity.setTaskbarWindowFullscreen(false);
|
||||||
|
mHandling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -661,6 +661,31 @@ public class SystemUiProxy implements ISystemUiProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells SysUI to remove the bubble with the provided key.
|
||||||
|
* @param key the key of the bubble to show.
|
||||||
|
*/
|
||||||
|
public void removeBubble(String key) {
|
||||||
|
if (mBubbles == null) return;
|
||||||
|
try {
|
||||||
|
mBubbles.removeBubble(key);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, "Failed call removeBubble");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells SysUI to remove all bubbles.
|
||||||
|
*/
|
||||||
|
public void removeAllBubbles() {
|
||||||
|
if (mBubbles == null) return;
|
||||||
|
try {
|
||||||
|
mBubbles.removeAllBubbles();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, "Failed call removeAllBubbles");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells SysUI to collapse the bubbles.
|
* Tells SysUI to collapse the bubbles.
|
||||||
*/
|
*/
|
||||||
@@ -674,6 +699,21 @@ public class SystemUiProxy implements ISystemUiProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tells SysUI to collapse/expand selected bubble view while it's dragged.
|
||||||
|
* Should be called only when the bubble bar is expanded.
|
||||||
|
* @param bubbleKey the key of the bubble to collapse/expand
|
||||||
|
* @param collapse whether to collapse/expand selected bubble
|
||||||
|
*/
|
||||||
|
public void collapseWhileDragging(@Nullable String bubbleKey, boolean collapse) {
|
||||||
|
if (mBubbles == null) return;
|
||||||
|
try {
|
||||||
|
mBubbles.collapseWhileDragging(bubbleKey, collapse);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.w(TAG, "Failed call collapseWhileDragging");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Splitscreen
|
// Splitscreen
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user