summaryrefslogtreecommitdiff
path: root/java/com/android/newbubble/BottomActionViewController.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/newbubble/BottomActionViewController.java')
-rw-r--r--java/com/android/newbubble/BottomActionViewController.java184
1 files changed, 184 insertions, 0 deletions
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;
+ }
+}