From f473e1d0988bb13874a0774db9cbcd66777f9150 Mon Sep 17 00:00:00 2001 From: yueg Date: Tue, 2 Jan 2018 16:23:14 -0800 Subject: Bubble v2 dismiss. Drag and drop bubble to bottom to hide or end call. Flinging to bottom does not trigger the actions. Color/text is not final. Navigation bar is not hiden and the change will be in a following CL. Bug: 67605985 Test: NewBubbleTest PiperOrigin-RevId: 180608133 Change-Id: Iff4cb32226d8fbf0f8e5319f6876a1d74c336b4a --- .../newbubble/BottomActionViewController.java | 184 +++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 java/com/android/newbubble/BottomActionViewController.java (limited to 'java/com/android/newbubble/BottomActionViewController.java') diff --git a/java/com/android/newbubble/BottomActionViewController.java b/java/com/android/newbubble/BottomActionViewController.java new file mode 100644 index 000000000..7c7105194 --- /dev/null +++ b/java/com/android/newbubble/BottomActionViewController.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2017 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.newbubble; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.support.v4.os.BuildCompat; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.view.animation.LinearInterpolator; + +/** Controller for showing and hiding bubble bottom action view. */ +final class BottomActionViewController { + + // This delay controls how long to wait before we show the target when the user first moves + // the bubble, to prevent the bottom action view from animating if the user just wants to fling + // the bubble. + private static final int SHOW_TARGET_DELAY = 100; + private static final int SHOW_TARGET_DURATION = 350; + private static final int HIDE_TARGET_DURATION = 225; + private static final float HIGHLIGHT_TARGET_SCALE = 1.5f; + + private final Context context; + private final WindowManager windowManager; + private final int gradientHeight; + private final int bottomActionViewTop; + + private View bottomActionView; + private View dismissView; + private View endCallView; + + private boolean dismissHighlighted; + private boolean endCallHighlighted; + + public BottomActionViewController(Context context) { + this.context = context; + windowManager = context.getSystemService(WindowManager.class); + gradientHeight = + context.getResources().getDimensionPixelSize(R.dimen.bubble_bottom_action_view_height); + bottomActionViewTop = context.getResources().getDisplayMetrics().heightPixels - gradientHeight; + } + + /** Creates and show the bottom action view. */ + public void createAndShowBottomActionView() { + if (bottomActionView != null) { + return; + } + + // Create a new view for the dismiss target + bottomActionView = LayoutInflater.from(context).inflate(R.layout.bottom_action_base, null); + bottomActionView.setAlpha(0); + + // Sub views + dismissView = bottomActionView.findViewById(R.id.bottom_action_dismiss_layout); + endCallView = bottomActionView.findViewById(R.id.bottom_action_end_call_layout); + + // Add the target to the window + // TODO(yueg): use TYPE_NAVIGATION_BAR_PANEL to draw over navigation bar + LayoutParams layoutParams = + new LayoutParams( + LayoutParams.MATCH_PARENT, + gradientHeight, + 0, + bottomActionViewTop, + BuildCompat.isAtLeastO() + ? LayoutParams.TYPE_APPLICATION_OVERLAY + : LayoutParams.TYPE_SYSTEM_OVERLAY, + LayoutParams.FLAG_LAYOUT_IN_SCREEN + | LayoutParams.FLAG_NOT_TOUCHABLE + | LayoutParams.FLAG_NOT_FOCUSABLE, + PixelFormat.TRANSLUCENT); + layoutParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; + windowManager.addView(bottomActionView, layoutParams); + bottomActionView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN); + bottomActionView + .getRootView() + .setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN); + + // Shows the botton action view + bottomActionView + .animate() + .alpha(1f) + .setInterpolator(new LinearInterpolator()) + .setStartDelay(SHOW_TARGET_DELAY) + .setDuration(SHOW_TARGET_DURATION) + .start(); + } + + /** Hides and destroys the bottom action view. */ + public void destroyBottomActionView() { + if (bottomActionView == null) { + return; + } + bottomActionView + .animate() + .alpha(0f) + .setInterpolator(new LinearInterpolator()) + .setDuration(HIDE_TARGET_DURATION) + .withEndAction( + () -> { + // Use removeViewImmediate instead of removeView to avoid view flashing before removed + windowManager.removeViewImmediate(bottomActionView); + bottomActionView = null; + }) + .start(); + } + + /** + * Change highlight state of dismiss view and end call view according to current touch point. + * Highlight the view with touch point moving into its boundary. Unhighlight the view with touch + * point moving out of its boundary. + * + * @param x x position of current touch point + * @param y y position of current touch point + */ + public void highlightIfHover(float x, float y) { + if (bottomActionView == null) { + return; + } + final int middle = context.getResources().getDisplayMetrics().widthPixels / 2; + boolean shouldHighlightDismiss = y > bottomActionViewTop && x < middle; + boolean shouldHighlightEndCall = y > bottomActionViewTop && x >= middle; + + if (!shouldHighlightDismiss && dismissHighlighted) { + // Unhighlight dismiss + dismissView.animate().scaleX(1f).scaleY(1f).setDuration(HIDE_TARGET_DURATION).start(); + dismissHighlighted = false; + } else if (!shouldHighlightEndCall && endCallHighlighted) { + // Unhighlight end call + endCallView.animate().scaleX(1f).scaleY(1f).setDuration(HIDE_TARGET_DURATION).start(); + endCallHighlighted = false; + } + + if (shouldHighlightDismiss && !dismissHighlighted) { + // Highlight dismiss + dismissView + .animate() + .scaleX(HIGHLIGHT_TARGET_SCALE) + .scaleY(HIGHLIGHT_TARGET_SCALE) + .setDuration(SHOW_TARGET_DURATION) + .start(); + dismissHighlighted = true; + } else if (shouldHighlightEndCall && !endCallHighlighted) { + // Highlight end call + endCallView + .animate() + .scaleX(HIGHLIGHT_TARGET_SCALE) + .scaleY(HIGHLIGHT_TARGET_SCALE) + .setDuration(SHOW_TARGET_DURATION) + .start(); + endCallHighlighted = true; + } + } + + public boolean isDismissHighlighted() { + return dismissHighlighted; + } + + public boolean isEndCallHighlighted() { + return endCallHighlighted; + } +} -- cgit v1.2.3