summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
authoryueg <yueg@google.com>2018-02-02 17:28:02 -0800
committerCopybara-Service <copybara-piper@google.com>2018-02-05 16:33:16 -0800
commitbeaaff27e6ea36ddab00ccf259bb73a18208f5c2 (patch)
tree5757287797756cc443b25e2007244f0cbee75a44 /java
parent3c7c669918e58f301f27b4d9cbb7d80a7b4ebabc (diff)
Remove bubble v1.
Bug: 67605985 Test: manual PiperOrigin-RevId: 184358120 Change-Id: I17288da2b059f18bd51247e27aa174c7994e6f05
Diffstat (limited to 'java')
-rw-r--r--java/com/android/bubble/AndroidManifest.xml22
-rw-r--r--java/com/android/bubble/Bubble.java977
-rw-r--r--java/com/android/bubble/BubbleInfo.java123
-rw-r--r--java/com/android/bubble/ChangeOnScreenBounds.java191
-rw-r--r--java/com/android/bubble/CheckableImageButton.java101
-rw-r--r--java/com/android/bubble/MoveHandler.java280
-rw-r--r--java/com/android/bubble/WindowRoot.java74
-rw-r--r--java/com/android/bubble/res/color/bubble_checkable_mask.xml21
-rw-r--r--java/com/android/bubble/res/color/bubble_icon_tint_states.xml21
-rw-r--r--java/com/android/bubble/res/drawable/bubble_background_pill_ltr.xml23
-rw-r--r--java/com/android/bubble/res/drawable/bubble_background_pill_rtl.xml23
-rw-r--r--java/com/android/bubble/res/drawable/bubble_ripple_checkable_circle.xml30
-rw-r--r--java/com/android/bubble/res/drawable/bubble_ripple_circle.xml26
-rw-r--r--java/com/android/bubble/res/layout/bubble_base.xml192
-rw-r--r--java/com/android/bubble/res/values-car/values.xml25
-rw-r--r--java/com/android/bubble/res/values/colors.xml20
-rw-r--r--java/com/android/bubble/res/values/values.xml30
-rw-r--r--java/com/android/incallui/AndroidManifest.xml3
-rw-r--r--java/com/android/incallui/InCallActivity.java6
-rw-r--r--java/com/android/incallui/InCallServiceImpl.java8
-rw-r--r--java/com/android/incallui/ReturnToCallActionReceiver.java138
-rw-r--r--java/com/android/incallui/ReturnToCallController.java280
-rw-r--r--java/com/android/incallui/StatusBarNotifier.java4
23 files changed, 2 insertions, 2616 deletions
diff --git a/java/com/android/bubble/AndroidManifest.xml b/java/com/android/bubble/AndroidManifest.xml
deleted file mode 100644
index 80efe5caa..000000000
--- a/java/com/android/bubble/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
- ~ 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
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.bubble">
-
- <uses-sdk android:minSdkVersion="21"/>
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
-</manifest>
diff --git a/java/com/android/bubble/Bubble.java b/java/com/android/bubble/Bubble.java
deleted file mode 100644
index a25316f5b..000000000
--- a/java/com/android/bubble/Bubble.java
+++ /dev/null
@@ -1,977 +0,0 @@
-/*
- * 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.bubble;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.annotation.SuppressLint;
-import android.app.PendingIntent.CanceledException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.RippleDrawable;
-import android.net.Uri;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.os.Handler;
-import android.provider.Settings;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.graphics.ColorUtils;
-import android.support.v4.os.BuildCompat;
-import android.support.v4.view.animation.FastOutLinearInInterpolator;
-import android.support.v4.view.animation.LinearOutSlowInInterpolator;
-import android.transition.TransitionManager;
-import android.transition.TransitionValues;
-import android.view.ContextThemeWrapper;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.view.ViewPropertyAnimator;
-import android.view.ViewTreeObserver.OnPreDrawListener;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.animation.AnticipateInterpolator;
-import android.view.animation.OvershootInterpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.ViewAnimator;
-import com.android.bubble.BubbleInfo.Action;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Creates and manages a bubble window from information in a {@link BubbleInfo}. Before creating, be
- * sure to check whether bubbles may be shown using {@link #canShowBubbles(Context)} and request
- * permission if necessary ({@link #getRequestPermissionIntent(Context)} is provided for
- * convenience)
- */
-public class Bubble {
- // This class has some odd behavior that is not immediately obvious in order to avoid jank when
- // resizing. See http://go/bubble-resize for details.
-
- // How long text should show after showText(CharSequence) is called
- private static final int SHOW_TEXT_DURATION_MILLIS = 3000;
- // How long the new window should show before destroying the old one during resize operations.
- // This ensures the new window has had time to draw first.
- private static final int WINDOW_REDRAW_DELAY_MILLIS = 50;
-
- private static Boolean canShowBubblesForTesting = null;
-
- private final Context context;
- private final WindowManager windowManager;
-
- private final Handler handler;
- private LayoutParams windowParams;
-
- // Initialized in factory method
- @SuppressWarnings("NullableProblems")
- @NonNull
- private BubbleInfo currentInfo;
-
- @Visibility private int visibility;
- @VisibleForTesting boolean expanded;
- private boolean textShowing;
- private boolean hideAfterText;
- private CharSequence textAfterShow;
- private int collapseEndAction;
-
- @VisibleForTesting ViewHolder viewHolder;
- private ViewPropertyAnimator collapseAnimation;
- @VisibleForTesting Integer overrideGravity;
- private ViewPropertyAnimator exitAnimator;
-
- private final Runnable collapseRunnable =
- new Runnable() {
- @Override
- public void run() {
- textShowing = false;
- if (hideAfterText) {
- // Always reset here since text shouldn't keep showing.
- hideAndReset();
- } else {
- doResize(
- () -> viewHolder.getPrimaryButton().setDisplayedChild(ViewHolder.CHILD_INDEX_ICON));
- }
- }
- };
-
- private BubbleExpansionStateListener bubbleExpansionStateListener;
-
- /** Type of action after bubble collapse */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({CollapseEnd.NOTHING, CollapseEnd.HIDE})
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- public @interface CollapseEnd {
- int NOTHING = 0;
- int HIDE = 1;
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({Visibility.ENTERING, Visibility.SHOWING, Visibility.EXITING, Visibility.HIDDEN})
- private @interface Visibility {
- int HIDDEN = 0;
- int ENTERING = 1;
- int SHOWING = 2;
- int EXITING = 3;
- }
-
- /** Indicate bubble expansion state. */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({ExpansionState.START_EXPANDING, ExpansionState.START_COLLAPSING})
- public @interface ExpansionState {
- // TODO(yueg): add more states when needed
- int START_EXPANDING = 0;
- int START_COLLAPSING = 1;
- }
-
- /**
- * Determines whether bubbles can be shown based on permissions obtained. This should be checked
- * before attempting to create a Bubble.
- *
- * @return true iff bubbles are able to be shown.
- * @see Settings#canDrawOverlays(Context)
- */
- public static boolean canShowBubbles(@NonNull Context context) {
- return canShowBubblesForTesting != null
- ? canShowBubblesForTesting
- : VERSION.SDK_INT < VERSION_CODES.M || Settings.canDrawOverlays(context);
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- public static void setCanShowBubblesForTesting(boolean canShowBubbles) {
- canShowBubblesForTesting = canShowBubbles;
- }
-
- /** Returns an Intent to request permission to show overlays */
- @NonNull
- public static Intent getRequestPermissionIntent(@NonNull Context context) {
- return new Intent(
- Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
- Uri.fromParts("package", context.getPackageName(), null));
- }
-
- /** Creates instances of Bubble. The default implementation just calls the constructor. */
- @VisibleForTesting
- public interface BubbleFactory {
- Bubble createBubble(@NonNull Context context, @NonNull Handler handler);
- }
-
- private static BubbleFactory bubbleFactory = Bubble::new;
-
- public static Bubble createBubble(@NonNull Context context, @NonNull BubbleInfo info) {
- Bubble bubble = bubbleFactory.createBubble(context, new Handler());
- bubble.setBubbleInfo(info);
- return bubble;
- }
-
- @VisibleForTesting
- public static void setBubbleFactory(@NonNull BubbleFactory bubbleFactory) {
- Bubble.bubbleFactory = bubbleFactory;
- }
-
- @VisibleForTesting
- public static void resetBubbleFactory() {
- Bubble.bubbleFactory = Bubble::new;
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- Bubble(@NonNull Context context, @NonNull Handler handler) {
- context = new ContextThemeWrapper(context, R.style.Theme_AppCompat);
- this.context = context;
- this.handler = handler;
- windowManager = context.getSystemService(WindowManager.class);
-
- viewHolder = new ViewHolder(context);
- }
-
- /** Expands the main bubble menu. */
- public void expand(boolean isUserAction) {
- if (bubbleExpansionStateListener != null) {
- bubbleExpansionStateListener.onBubbleExpansionStateChanged(
- ExpansionState.START_EXPANDING, isUserAction);
- }
- doResize(
- () -> {
- onLeftRightSwitch(isDrawingFromRight());
- viewHolder.setDrawerVisibility(View.VISIBLE);
- });
- View expandedView = viewHolder.getExpandedView();
- expandedView
- .getViewTreeObserver()
- .addOnPreDrawListener(
- new OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- expandedView.getViewTreeObserver().removeOnPreDrawListener(this);
- expandedView.setTranslationX(
- isDrawingFromRight() ? expandedView.getWidth() : -expandedView.getWidth());
- expandedView
- .animate()
- .setInterpolator(new LinearOutSlowInInterpolator())
- .translationX(0);
- return false;
- }
- });
- setFocused(true);
- expanded = true;
- }
-
- /**
- * Make the bubble visible. Will show a short entrance animation as it enters. If the bubble is
- * already showing this method does nothing.
- */
- public void show() {
- if (collapseEndAction == CollapseEnd.HIDE) {
- // If show() was called while collapsing, make sure we don't hide after.
- collapseEndAction = CollapseEnd.NOTHING;
- }
- if (visibility == Visibility.SHOWING || visibility == Visibility.ENTERING) {
- return;
- }
-
- hideAfterText = false;
-
- if (windowParams == null) {
- // Apps targeting O+ must use TYPE_APPLICATION_OVERLAY, which is not available prior to O.
- @SuppressWarnings("deprecation")
- @SuppressLint("InlinedApi")
- int type =
- BuildCompat.isAtLeastO()
- ? LayoutParams.TYPE_APPLICATION_OVERLAY
- : LayoutParams.TYPE_PHONE;
-
- windowParams =
- new LayoutParams(
- type,
- LayoutParams.FLAG_NOT_TOUCH_MODAL
- | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | LayoutParams.FLAG_NOT_FOCUSABLE
- | LayoutParams.FLAG_LAYOUT_NO_LIMITS,
- PixelFormat.TRANSLUCENT);
- windowParams.gravity = Gravity.TOP | Gravity.LEFT;
- windowParams.x = context.getResources().getDimensionPixelOffset(R.dimen.bubble_safe_margin_x);
- windowParams.y = currentInfo.getStartingYPosition();
- windowParams.height = LayoutParams.WRAP_CONTENT;
- windowParams.width = LayoutParams.WRAP_CONTENT;
- }
-
- if (exitAnimator != null) {
- exitAnimator.cancel();
- exitAnimator = null;
- } else {
- windowManager.addView(viewHolder.getRoot(), windowParams);
- viewHolder.getPrimaryButton().setScaleX(0);
- viewHolder.getPrimaryButton().setScaleY(0);
- }
-
- viewHolder.setChildClickable(true);
- visibility = Visibility.ENTERING;
- viewHolder
- .getPrimaryButton()
- .animate()
- .setInterpolator(new OvershootInterpolator())
- .scaleX(1)
- .scaleY(1)
- .withEndAction(
- () -> {
- visibility = Visibility.SHOWING;
- // Show the queued up text, if available.
- if (textAfterShow != null) {
- showText(textAfterShow);
- textAfterShow = null;
- }
- })
- .start();
-
- updatePrimaryIconAnimation();
- }
-
- /** Hide the bubble. */
- public void hide() {
- if (hideAfterText) {
- // hideAndReset() will be called after showing text, do nothing here.
- return;
- }
- hideHelper(this::defaultAfterHidingAnimation);
- }
-
- /** Hide the bubble and reset {@viewHolder} to initial state */
- public void hideAndReset() {
- hideHelper(
- () -> {
- defaultAfterHidingAnimation();
- reset();
- });
- }
-
- /** Returns whether the bubble is currently visible */
- public boolean isVisible() {
- return visibility == Visibility.SHOWING
- || visibility == Visibility.ENTERING
- || visibility == Visibility.EXITING;
- }
-
- /**
- * Set the info for this Bubble to display
- *
- * @param bubbleInfo the BubbleInfo to display in this Bubble.
- */
- public void setBubbleInfo(@NonNull BubbleInfo bubbleInfo) {
- currentInfo = bubbleInfo;
- update();
- }
-
- /**
- * Update the state and behavior of actions.
- *
- * @param actions the new state of the bubble's actions
- */
- public void updateActions(@NonNull List<Action> actions) {
- currentInfo = BubbleInfo.from(currentInfo).setActions(actions).build();
- updateButtonStates();
- }
-
- /** Returns the currently displayed BubbleInfo */
- public BubbleInfo getBubbleInfo() {
- return currentInfo;
- }
-
- /**
- * Display text in the main bubble. The bubble's drawer is not expandable while text is showing,
- * and the drawer will be closed if already open.
- *
- * @param text the text to display to the user
- */
- public void showText(@NonNull CharSequence text) {
- textShowing = true;
- if (expanded) {
- startCollapse(CollapseEnd.NOTHING, false);
- doShowText(text);
- } else {
- // Need to transition from old bounds to new bounds manually
- ChangeOnScreenBounds transition = new ChangeOnScreenBounds();
- // Prepare and capture start values
- TransitionValues startValues = new TransitionValues();
- startValues.view = viewHolder.getPrimaryButton();
- transition.addTarget(startValues.view);
- transition.captureStartValues(startValues);
-
- // If our view is not laid out yet, postpone showing the text.
- if (startValues.values.isEmpty()) {
- textAfterShow = text;
- return;
- }
-
- doResize(
- () -> {
- doShowText(text);
- // Hide the text so we can animate it in
- viewHolder.getPrimaryText().setAlpha(0);
-
- ViewAnimator primaryButton = viewHolder.getPrimaryButton();
- // Cancel the automatic transition scheduled in doShowText
- TransitionManager.endTransitions((ViewGroup) primaryButton.getParent());
- primaryButton
- .getViewTreeObserver()
- .addOnPreDrawListener(
- new OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- primaryButton.getViewTreeObserver().removeOnPreDrawListener(this);
-
- // Prepare and capture end values, always use the size of primaryText since
- // its invisibility makes primaryButton smaller than expected
- TransitionValues endValues = new TransitionValues();
- endValues.values.put(
- ChangeOnScreenBounds.PROPNAME_WIDTH,
- viewHolder.getPrimaryText().getWidth());
- endValues.values.put(
- ChangeOnScreenBounds.PROPNAME_HEIGHT,
- viewHolder.getPrimaryText().getHeight());
- endValues.view = primaryButton;
- transition.addTarget(endValues.view);
- transition.captureEndValues(endValues);
-
- // animate the primary button bounds change
- Animator bounds =
- transition.createAnimator(primaryButton, startValues, endValues);
-
- // Animate the text in
- Animator alpha =
- ObjectAnimator.ofFloat(viewHolder.getPrimaryText(), View.ALPHA, 1f);
-
- AnimatorSet set = new AnimatorSet();
- set.play(bounds).before(alpha);
- set.start();
- return false;
- }
- });
- });
- }
- handler.removeCallbacks(collapseRunnable);
- handler.postDelayed(collapseRunnable, SHOW_TEXT_DURATION_MILLIS);
- }
-
- public void setBubbleExpansionStateListener(
- BubbleExpansionStateListener bubbleExpansionStateListener) {
- this.bubbleExpansionStateListener = bubbleExpansionStateListener;
- }
-
- @Nullable
- Integer getGravityOverride() {
- return overrideGravity;
- }
-
- void onMoveStart() {
- startCollapse(CollapseEnd.NOTHING, true);
- viewHolder
- .getPrimaryButton()
- .animate()
- .translationZ(
- context.getResources().getDimensionPixelOffset(R.dimen.bubble_move_elevation_change));
- }
-
- void onMoveFinish() {
- viewHolder.getPrimaryButton().animate().translationZ(0);
- // If it's GONE, no resize is necessary. If it's VISIBLE, it will get cleaned up when the
- // collapse animation finishes
- if (viewHolder.getExpandedView().getVisibility() == View.INVISIBLE) {
- doResize(null);
- }
- }
-
- void primaryButtonClick() {
- // Send primary intent if not to expand.
- if (expanded || textShowing || currentInfo.getActions().isEmpty()) {
- try {
- currentInfo.getPrimaryIntent().send();
- } catch (CanceledException e) {
- throw new RuntimeException(e);
- }
- return;
- }
-
- expand(true);
- }
-
- void onLeftRightSwitch(boolean onRight) {
- if (viewHolder.isMoving()) {
- if (viewHolder.getExpandedView().getVisibility() == View.GONE) {
- // If the drawer is not part of the layout we don't need to do anything. Layout flips will
- // happen if necessary when opening the drawer.
- return;
- }
- }
-
- viewHolder
- .getRoot()
- .setLayoutDirection(onRight ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
- View primaryContainer = viewHolder.getRoot().findViewById(R.id.bubble_primary_container);
- ViewGroup.LayoutParams layoutParams = primaryContainer.getLayoutParams();
- ((FrameLayout.LayoutParams) layoutParams).gravity = onRight ? Gravity.RIGHT : Gravity.LEFT;
- primaryContainer.setLayoutParams(layoutParams);
- }
-
- LayoutParams getWindowParams() {
- return windowParams;
- }
-
- View getRootView() {
- return viewHolder.getRoot();
- }
-
- /**
- * Hide the bubble if visible. Will run a short exit animation and before hiding, and {@code
- * afterHiding} after hiding. If the bubble is currently showing text, will hide after the text is
- * done displaying. If the bubble is not visible this method does nothing.
- */
- private void hideHelper(Runnable afterHiding) {
- if (visibility == Visibility.HIDDEN || visibility == Visibility.EXITING) {
- return;
- }
-
- // Make bubble non clickable to prevent further buggy actions
- viewHolder.setChildClickable(false);
-
- if (textShowing) {
- hideAfterText = true;
- return;
- }
-
- if (collapseAnimation != null) {
- collapseEndAction = CollapseEnd.HIDE;
- return;
- }
-
- if (expanded) {
- startCollapse(CollapseEnd.HIDE, false);
- return;
- }
-
- visibility = Visibility.EXITING;
- exitAnimator =
- viewHolder
- .getPrimaryButton()
- .animate()
- .setInterpolator(new AnticipateInterpolator())
- .scaleX(0)
- .scaleY(0)
- .withEndAction(afterHiding);
- exitAnimator.start();
- }
-
- private void reset() {
- viewHolder = new ViewHolder(viewHolder.getRoot().getContext());
- update();
- }
-
- private void update() {
- RippleDrawable backgroundRipple =
- (RippleDrawable)
- context.getResources().getDrawable(R.drawable.bubble_ripple_circle, context.getTheme());
- int primaryTint =
- ColorUtils.compositeColors(
- context.getColor(R.color.bubble_primary_background_darken),
- currentInfo.getPrimaryColor());
- backgroundRipple.getDrawable(0).setTint(primaryTint);
- viewHolder.getPrimaryButton().setBackground(backgroundRipple);
-
- for (CheckableImageButton button : viewHolder.getActionButtons()) {
- setBackgroundDrawable(button, primaryTint);
- }
-
- int numButtons = currentInfo.getActions().size();
- for (CheckableImageButton button : viewHolder.getThirdButtons()) {
- button.setVisibility(numButtons < 3 ? View.GONE : View.VISIBLE);
- }
- for (CheckableImageButton button : viewHolder.getSecondButtons()) {
- button.setVisibility(numButtons < 2 ? View.GONE : View.VISIBLE);
- }
-
- viewHolder.getPrimaryIcon().setImageIcon(currentInfo.getPrimaryIcon());
- updatePrimaryIconAnimation();
- for (View expandedView : viewHolder.getExpandedViews()) {
- expandedView.setBackgroundTintList(ColorStateList.valueOf(currentInfo.getPrimaryColor()));
- }
-
- updateButtonStates();
- }
-
- private void updatePrimaryIconAnimation() {
- Drawable drawable = viewHolder.getPrimaryIcon().getDrawable();
- if (drawable instanceof Animatable) {
- if (isVisible()) {
- ((Animatable) drawable).start();
- } else {
- ((Animatable) drawable).stop();
- }
- }
- }
-
- private void setBackgroundDrawable(CheckableImageButton view, @ColorInt int color) {
- RippleDrawable itemRipple =
- (RippleDrawable)
- context
- .getResources()
- .getDrawable(R.drawable.bubble_ripple_checkable_circle, context.getTheme());
- itemRipple.getDrawable(0).setTint(color);
- view.setBackground(itemRipple);
- }
-
- private void updateButtonStates() {
- int numButtons = currentInfo.getActions().size();
-
- if (numButtons >= 1) {
- for (CheckableImageButton button : viewHolder.getFirstButtons()) {
- configureButton(currentInfo.getActions().get(0), button);
- }
- if (numButtons >= 2) {
- for (CheckableImageButton button : viewHolder.getSecondButtons()) {
- configureButton(currentInfo.getActions().get(1), button);
- }
- if (numButtons >= 3) {
- for (CheckableImageButton button : viewHolder.getThirdButtons()) {
- configureButton(currentInfo.getActions().get(2), button);
- }
- }
- }
- }
- }
-
- private void doShowText(@NonNull CharSequence text) {
- TransitionManager.beginDelayedTransition((ViewGroup) viewHolder.getPrimaryButton().getParent());
- viewHolder.getPrimaryText().setText(text);
- viewHolder.getPrimaryButton().setDisplayedChild(ViewHolder.CHILD_INDEX_TEXT);
- }
-
- private void configureButton(Action action, CheckableImageButton button) {
- action
- .getIcon()
- .loadDrawableAsync(
- context,
- d -> {
- button.setImageIcon(action.getIcon());
- button.setContentDescription(action.getName());
- button.setChecked(action.isChecked());
- button.setEnabled(action.isEnabled());
- },
- handler);
- button.setOnClickListener(v -> doAction(action));
- }
-
- private void doAction(Action action) {
- try {
- action.getIntent().send();
- } catch (CanceledException e) {
- throw new RuntimeException(e);
- }
- }
-
- private void doResize(@Nullable Runnable operation) {
- // If we're resizing on the right side of the screen, there is an implicit move operation
- // necessary. The WindowManager does not sync the move and resize operations, so serious jank
- // would occur. To fix this, instead of resizing the window, we create a new one and destroy
- // the old one. There is a short delay before destroying the old view to ensure the new one has
- // had time to draw.
- ViewHolder oldViewHolder = viewHolder;
- if (isDrawingFromRight()) {
- viewHolder = new ViewHolder(oldViewHolder.getRoot().getContext());
- update();
- viewHolder
- .getPrimaryButton()
- .setDisplayedChild(oldViewHolder.getPrimaryButton().getDisplayedChild());
- viewHolder.getPrimaryText().setText(oldViewHolder.getPrimaryText().getText());
- }
-
- if (operation != null) {
- operation.run();
- }
-
- if (isDrawingFromRight()) {
- swapViewHolders(oldViewHolder);
- }
- }
-
- private void swapViewHolders(ViewHolder oldViewHolder) {
- oldViewHolder.getShadowProvider().setVisibility(View.GONE);
- ViewGroup root = viewHolder.getRoot();
- windowManager.addView(root, windowParams);
- root.getViewTreeObserver()
- .addOnPreDrawListener(
- new OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- root.getViewTreeObserver().removeOnPreDrawListener(this);
- // Wait a bit before removing the old view; make sure the new one has drawn over it.
- handler.postDelayed(
- () -> windowManager.removeView(oldViewHolder.getRoot()),
- WINDOW_REDRAW_DELAY_MILLIS);
- return true;
- }
- });
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- public void startCollapse(@CollapseEnd int endAction, boolean isUserAction) {
- View expandedView = viewHolder.getExpandedView();
- if (expandedView.getVisibility() != View.VISIBLE || collapseAnimation != null) {
- // Drawer is already collapsed or animation is running.
- return;
- }
-
- overrideGravity = isDrawingFromRight() ? Gravity.RIGHT : Gravity.LEFT;
- setFocused(false);
-
- if (collapseEndAction == CollapseEnd.NOTHING) {
- collapseEndAction = endAction;
- }
- if (bubbleExpansionStateListener != null && collapseEndAction == CollapseEnd.NOTHING) {
- bubbleExpansionStateListener.onBubbleExpansionStateChanged(
- ExpansionState.START_COLLAPSING, isUserAction);
- }
- collapseAnimation =
- expandedView
- .animate()
- .translationX(isDrawingFromRight() ? expandedView.getWidth() : -expandedView.getWidth())
- .setInterpolator(new FastOutLinearInInterpolator())
- .withEndAction(
- () -> {
- collapseAnimation = null;
- expanded = false;
-
- if (textShowing) {
- // Will do resize once the text is done.
- return;
- }
-
- // Hide the drawer and resize if possible.
- viewHolder.setDrawerVisibility(View.INVISIBLE);
- if (!viewHolder.isMoving() || !isDrawingFromRight()) {
- doResize(() -> viewHolder.setDrawerVisibility(View.GONE));
- }
-
- // If this collapse was to come before a hide, do it now.
- if (collapseEndAction == CollapseEnd.HIDE) {
- hide();
- }
- collapseEndAction = CollapseEnd.NOTHING;
-
- // Resume normal gravity after any resizing is done.
- handler.postDelayed(
- () -> {
- overrideGravity = null;
- if (!viewHolder.isMoving()) {
- viewHolder.undoGravityOverride();
- }
- },
- // Need to wait twice as long for resize and layout
- WINDOW_REDRAW_DELAY_MILLIS * 2);
- });
- }
-
- private boolean isDrawingFromRight() {
- return (windowParams.gravity & Gravity.RIGHT) == Gravity.RIGHT;
- }
-
- private void setFocused(boolean focused) {
- if (focused) {
- windowParams.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE;
- } else {
- windowParams.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
- }
- windowManager.updateViewLayout(getRootView(), windowParams);
- }
-
- private void defaultAfterHidingAnimation() {
- exitAnimator = null;
- windowManager.removeView(viewHolder.getRoot());
- visibility = Visibility.HIDDEN;
-
- updatePrimaryIconAnimation();
- }
-
- @VisibleForTesting
- class ViewHolder {
-
- public static final int CHILD_INDEX_ICON = 0;
- public static final int CHILD_INDEX_TEXT = 1;
-
- private MoveHandler moveHandler;
- private final WindowRoot root;
- private final ViewAnimator primaryButton;
- private final ImageView primaryIcon;
- private final TextView primaryText;
-
- private final CheckableImageButton firstButton;
- private final CheckableImageButton firstButtonRtl;
- private final CheckableImageButton secondButton;
- private final CheckableImageButton secondButtonRtl;
- private final CheckableImageButton thirdButton;
- private final CheckableImageButton thirdButtonRtl;
- private final View expandedView;
- private final View expandedViewRtl;
- private final View shadowProvider;
- private final View shadowProviderRtl;
-
- public ViewHolder(Context context) {
- // Window root is not in the layout file so that the inflater has a view to inflate into
- this.root = new WindowRoot(context);
- LayoutInflater inflater = LayoutInflater.from(root.getContext());
- View contentView = inflater.inflate(R.layout.bubble_base, root, true);
- expandedView = contentView.findViewById(R.id.bubble_expanded_layout);
- expandedViewRtl = contentView.findViewById(R.id.bubble_expanded_layout_rtl);
- primaryButton = contentView.findViewById(R.id.bubble_button_primary);
- primaryIcon = contentView.findViewById(R.id.bubble_icon_primary);
- primaryText = contentView.findViewById(R.id.bubble_text);
- shadowProvider = contentView.findViewById(R.id.bubble_drawer_shadow_provider);
- shadowProviderRtl = contentView.findViewById(R.id.bubble_drawer_shadow_provider_rtl);
-
- firstButton = contentView.findViewById(R.id.bubble_icon_first);
- firstButtonRtl = contentView.findViewById(R.id.bubble_icon_first_rtl);
- secondButton = contentView.findViewById(R.id.bubble_icon_second);
- secondButtonRtl = contentView.findViewById(R.id.bubble_icon_second_rtl);
- thirdButton = contentView.findViewById(R.id.bubble_icon_third);
- thirdButtonRtl = contentView.findViewById(R.id.bubble_icon_third_rtl);
-
- root.setOnBackPressedListener(
- () -> {
- if (visibility == Visibility.SHOWING && expanded) {
- startCollapse(CollapseEnd.NOTHING, true);
- return true;
- }
- return false;
- });
- root.setOnConfigurationChangedListener(
- (configuration) -> {
- // The values in the current MoveHandler may be stale, so replace it. Then ensure the
- // Window is in bounds
- moveHandler = new MoveHandler(primaryButton, Bubble.this);
- moveHandler.snapToBounds();
- });
- root.setOnTouchListener(
- (v, event) -> {
- if (expanded && event.getActionMasked() == MotionEvent.ACTION_OUTSIDE) {
- startCollapse(CollapseEnd.NOTHING, true);
- return true;
- }
- return false;
- });
- expandedView
- .getViewTreeObserver()
- .addOnDrawListener(
- () -> {
- int translationX = (int) expandedView.getTranslationX();
- int parentOffset =
- ((MarginLayoutParams) ((ViewGroup) expandedView.getParent()).getLayoutParams())
- .leftMargin;
- int minRight =
- shadowProvider.getLeft()
- + context.getResources().getDimensionPixelSize(R.dimen.bubble_size);
- shadowProvider.setRight(
- Math.max(minRight, expandedView.getRight() + translationX + parentOffset));
- });
- expandedViewRtl
- .getViewTreeObserver()
- .addOnDrawListener(
- () -> {
- int translationX = (int) expandedViewRtl.getTranslationX();
- int parentOffset =
- ((MarginLayoutParams)
- ((ViewGroup) expandedViewRtl.getParent()).getLayoutParams())
- .leftMargin;
- int maxLeft =
- shadowProviderRtl.getRight()
- - context.getResources().getDimensionPixelSize(R.dimen.bubble_size);
- shadowProviderRtl.setLeft(
- Math.min(maxLeft, expandedViewRtl.getLeft() + translationX + parentOffset));
- });
- moveHandler = new MoveHandler(primaryButton, Bubble.this);
- }
-
- private void setChildClickable(boolean clickable) {
- for (CheckableImageButton button : getActionButtons()) {
- button.setClickable(clickable);
- }
-
- primaryButton.setOnTouchListener(clickable ? moveHandler : null);
- }
-
- public ViewGroup getRoot() {
- return root;
- }
-
- public ViewAnimator getPrimaryButton() {
- return primaryButton;
- }
-
- public ImageView getPrimaryIcon() {
- return primaryIcon;
- }
-
- public TextView getPrimaryText() {
- return primaryText;
- }
-
- /** Get list of all the action buttons from both LTR/RTL drawers. */
- public List<CheckableImageButton> getActionButtons() {
- return Arrays.asList(
- firstButton, firstButtonRtl, secondButton, secondButtonRtl, thirdButton, thirdButtonRtl);
- }
-
- /** Get the first action button used in the current orientation drawer. */
- public CheckableImageButton getFirstButton() {
- return isDrawingFromRight() ? firstButtonRtl : firstButton;
- }
-
- /** Get both of the first action buttons from both LTR/RTL drawers. */
- public List<CheckableImageButton> getFirstButtons() {
- return Arrays.asList(firstButton, firstButtonRtl);
- }
-
- /** Get the second action button used in the current orientation drawer. */
- public CheckableImageButton getSecondButton() {
- return isDrawingFromRight() ? secondButtonRtl : secondButton;
- }
-
- /** Get both of the second action buttons from both LTR/RTL drawers. */
- public List<CheckableImageButton> getSecondButtons() {
- return Arrays.asList(secondButton, secondButtonRtl);
- }
-
- /** Get the third action button used in the current orientation drawer. */
- public CheckableImageButton getThirdButton() {
- return isDrawingFromRight() ? thirdButtonRtl : thirdButton;
- }
-
- /** Get both of the third action buttons from both LTR/RTL drawers. */
- public List<CheckableImageButton> getThirdButtons() {
- return Arrays.asList(thirdButton, thirdButtonRtl);
- }
-
- /** Get the correct expanded view used in current bubble orientation. */
- public View getExpandedView() {
- return isDrawingFromRight() ? expandedViewRtl : expandedView;
- }
-
- /** Get both views of the LTR and RTL drawers. */
- public List<View> getExpandedViews() {
- return Arrays.asList(expandedView, expandedViewRtl);
- }
-
- /** Get the correct shadow provider view used in current bubble orientation. */
- public View getShadowProvider() {
- return isDrawingFromRight() ? shadowProviderRtl : shadowProvider;
- }
-
- public void setDrawerVisibility(int visibility) {
- if (isDrawingFromRight()) {
- expandedViewRtl.setVisibility(visibility);
- shadowProviderRtl.setVisibility(visibility);
- } else {
- expandedView.setVisibility(visibility);
- shadowProvider.setVisibility(visibility);
- }
- }
-
- public boolean isMoving() {
- return moveHandler.isMoving();
- }
-
- public void undoGravityOverride() {
- moveHandler.undoGravityOverride();
- }
- }
-
- /** Listener for bubble expansion state change. */
- public interface BubbleExpansionStateListener {
- void onBubbleExpansionStateChanged(@ExpansionState int expansionState, boolean isUserAction);
- }
-}
diff --git a/java/com/android/bubble/BubbleInfo.java b/java/com/android/bubble/BubbleInfo.java
deleted file mode 100644
index b4f81b38c..000000000
--- a/java/com/android/bubble/BubbleInfo.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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.bubble;
-
-import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
-import android.support.annotation.Px;
-import com.google.auto.value.AutoValue;
-import java.util.Collections;
-import java.util.List;
-
-/** Info for displaying a {@link Bubble} */
-@AutoValue
-public abstract class BubbleInfo {
- @ColorInt
- public abstract int getPrimaryColor();
-
- @NonNull
- public abstract Icon getPrimaryIcon();
-
- @NonNull
- public abstract PendingIntent getPrimaryIntent();
-
- @Px
- public abstract int getStartingYPosition();
-
- @NonNull
- public abstract List<Action> getActions();
-
- public static Builder builder() {
- return new AutoValue_BubbleInfo.Builder().setActions(Collections.emptyList());
- }
-
- public static Builder from(@NonNull BubbleInfo bubbleInfo) {
- return builder()
- .setPrimaryIntent(bubbleInfo.getPrimaryIntent())
- .setPrimaryColor(bubbleInfo.getPrimaryColor())
- .setPrimaryIcon(bubbleInfo.getPrimaryIcon())
- .setStartingYPosition(bubbleInfo.getStartingYPosition())
- .setActions(bubbleInfo.getActions());
- }
-
- /** Builder for {@link BubbleInfo} */
- @AutoValue.Builder
- public abstract static class Builder {
-
- public abstract Builder setPrimaryColor(@ColorInt int primaryColor);
-
- public abstract Builder setPrimaryIcon(@NonNull Icon primaryIcon);
-
- public abstract Builder setPrimaryIntent(@NonNull PendingIntent primaryIntent);
-
- public abstract Builder setStartingYPosition(@Px int startingYPosition);
-
- public abstract Builder setActions(List<Action> actions);
-
- public abstract BubbleInfo build();
- }
-
- /** Represents actions to be shown in the bubble when expanded */
- @AutoValue
- public abstract static class Action {
-
- @NonNull
- public abstract Icon getIcon();
-
- @NonNull
- public abstract CharSequence getName();
-
- @NonNull
- public abstract PendingIntent getIntent();
-
- public abstract boolean isEnabled();
-
- public abstract boolean isChecked();
-
- public static Builder builder() {
- return new AutoValue_BubbleInfo_Action.Builder().setEnabled(true).setChecked(false);
- }
-
- public static Builder from(@NonNull Action action) {
- return builder()
- .setIntent(action.getIntent())
- .setChecked(action.isChecked())
- .setEnabled(action.isEnabled())
- .setName(action.getName())
- .setIcon(action.getIcon());
- }
-
- /** Builder for {@link Action} */
- @AutoValue.Builder
- public abstract static class Builder {
-
- public abstract Builder setIcon(@NonNull Icon icon);
-
- public abstract Builder setName(@NonNull CharSequence name);
-
- public abstract Builder setIntent(@NonNull PendingIntent intent);
-
- public abstract Builder setEnabled(boolean enabled);
-
- public abstract Builder setChecked(boolean checked);
-
- public abstract Action build();
- }
- }
-}
diff --git a/java/com/android/bubble/ChangeOnScreenBounds.java b/java/com/android/bubble/ChangeOnScreenBounds.java
deleted file mode 100644
index 0a7adf637..000000000
--- a/java/com/android/bubble/ChangeOnScreenBounds.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * 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.bubble;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.graphics.Path;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.support.annotation.VisibleForTesting;
-import android.transition.Transition;
-import android.transition.TransitionValues;
-import android.util.Property;
-import android.view.View;
-import android.view.ViewGroup;
-
-/** Similar to {@link android.transition.ChangeBounds ChangeBounds} but works across windows */
-public class ChangeOnScreenBounds extends Transition {
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String PROPNAME_BOUNDS = "bubble:changeScreenBounds:bounds";
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String PROPNAME_SCREEN_X = "bubble:changeScreenBounds:screenX";
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- static final String PROPNAME_SCREEN_Y = "bubble:changeScreenBounds:screenY";
-
- static final String PROPNAME_WIDTH = "bubble:changeScreenBounds:width";
- static final String PROPNAME_HEIGHT = "bubble:changeScreenBounds:height";
-
- private static final Property<ViewBounds, PointF> TOP_LEFT_PROPERTY =
- new Property<ViewBounds, PointF>(PointF.class, "topLeft") {
- @Override
- public void set(ViewBounds viewBounds, PointF topLeft) {
- viewBounds.setTopLeft(topLeft);
- }
-
- @Override
- public PointF get(ViewBounds viewBounds) {
- return null;
- }
- };
-
- private static final Property<ViewBounds, PointF> BOTTOM_RIGHT_PROPERTY =
- new Property<ViewBounds, PointF>(PointF.class, "bottomRight") {
- @Override
- public void set(ViewBounds viewBounds, PointF bottomRight) {
- viewBounds.setBottomRight(bottomRight);
- }
-
- @Override
- public PointF get(ViewBounds viewBounds) {
- return null;
- }
- };
- private final int[] tempLocation = new int[2];
-
- @Override
- public void captureStartValues(TransitionValues transitionValues) {
- captureValuesWithSize(transitionValues);
- }
-
- @Override
- public void captureEndValues(TransitionValues transitionValues) {
- captureValuesWithSize(transitionValues);
- }
-
- /**
- * Capture location (left and top) from {@code values.view} and size (width and height) from
- * {@code values.values}. If size is not set, use the size of {@code values.view}.
- */
- private void captureValuesWithSize(TransitionValues values) {
- View view = values.view;
-
- if (view.isLaidOut() || view.getWidth() != 0 || view.getHeight() != 0) {
- Integer width = (Integer) values.values.get(PROPNAME_WIDTH);
- Integer height = (Integer) values.values.get(PROPNAME_HEIGHT);
-
- values.values.put(
- PROPNAME_BOUNDS,
- new Rect(
- view.getLeft(),
- view.getTop(),
- width == null ? view.getRight() : view.getLeft() + width,
- height == null ? view.getBottom() : view.getTop() + height));
- values.view.getLocationOnScreen(tempLocation);
- values.values.put(PROPNAME_SCREEN_X, tempLocation[0]);
- values.values.put(PROPNAME_SCREEN_Y, tempLocation[1]);
- }
- }
-
- @Override
- public Animator createAnimator(
- ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
- Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
- Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
-
- if (startBounds == null || endBounds == null) {
- // start or end values were not captured, so don't animate.
- return null;
- }
-
- // Offset the startBounds by the difference in screen position
- int startScreenX = (Integer) startValues.values.get(PROPNAME_SCREEN_X);
- int startScreenY = (Integer) startValues.values.get(PROPNAME_SCREEN_Y);
- int endScreenX = (Integer) endValues.values.get(PROPNAME_SCREEN_X);
- int endScreenY = (Integer) endValues.values.get(PROPNAME_SCREEN_Y);
- startBounds.offset(startScreenX - endScreenX, startScreenY - endScreenY);
-
- final int startLeft = startBounds.left;
- final int endLeft = endBounds.left;
- final int startTop = startBounds.top;
- final int endTop = endBounds.top;
- final int startRight = startBounds.right;
- final int endRight = endBounds.right;
- final int startBottom = startBounds.bottom;
- final int endBottom = endBounds.bottom;
- ViewBounds viewBounds = new ViewBounds(endValues.view);
- viewBounds.setTopLeft(new PointF(startLeft, startTop));
- viewBounds.setBottomRight(new PointF(startRight, startBottom));
-
- // Animate the top left and bottom right corners along a path
- Path topLeftPath = getPathMotion().getPath(startLeft, startTop, endLeft, endTop);
- ObjectAnimator topLeftAnimator =
- ObjectAnimator.ofObject(viewBounds, TOP_LEFT_PROPERTY, null, topLeftPath);
-
- Path bottomRightPath = getPathMotion().getPath(startRight, startBottom, endRight, endBottom);
- ObjectAnimator bottomRightAnimator =
- ObjectAnimator.ofObject(viewBounds, BOTTOM_RIGHT_PROPERTY, null, bottomRightPath);
- AnimatorSet set = new AnimatorSet();
- set.playTogether(topLeftAnimator, bottomRightAnimator);
- return set;
- }
-
- private static class ViewBounds {
- private int left;
- private int top;
- private int right;
- private int bottom;
- private final View view;
- private int topLeftCalls;
- private int bottomRightCalls;
-
- public ViewBounds(View view) {
- this.view = view;
- }
-
- public void setTopLeft(PointF topLeft) {
- left = Math.round(topLeft.x);
- top = Math.round(topLeft.y);
- topLeftCalls++;
- if (topLeftCalls == bottomRightCalls) {
- updateLeftTopRightBottom();
- }
- }
-
- public void setBottomRight(PointF bottomRight) {
- right = Math.round(bottomRight.x);
- bottom = Math.round(bottomRight.y);
- bottomRightCalls++;
- if (topLeftCalls == bottomRightCalls) {
- updateLeftTopRightBottom();
- }
- }
-
- private void updateLeftTopRightBottom() {
- view.setLeft(left);
- view.setTop(top);
- view.setRight(right);
- view.setBottom(bottom);
- topLeftCalls = 0;
- bottomRightCalls = 0;
- }
- }
-}
diff --git a/java/com/android/bubble/CheckableImageButton.java b/java/com/android/bubble/CheckableImageButton.java
deleted file mode 100644
index dd9acced8..000000000
--- a/java/com/android/bubble/CheckableImageButton.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.bubble;
-
-import android.content.Context;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.widget.AppCompatImageButton;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.Checkable;
-
-/**
- * An {@link android.widget.ImageButton ImageButton} that implements {@link Checkable} and
- * propagates the checkable state
- */
-public class CheckableImageButton extends AppCompatImageButton implements Checkable {
-
- // Copied without modification from AppCompat library
-
- private static final int[] DRAWABLE_STATE_CHECKED = new int[] {android.R.attr.state_checked};
-
- private boolean mChecked;
-
- public CheckableImageButton(Context context) {
- this(context, null);
- }
-
- public CheckableImageButton(Context context, AttributeSet attrs) {
- this(context, attrs, android.R.attr.imageButtonStyle);
- }
-
- public CheckableImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- ViewCompat.setAccessibilityDelegate(
- this,
- new AccessibilityDelegateCompat() {
- @Override
- public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
- super.onInitializeAccessibilityEvent(host, event);
- event.setChecked(isChecked());
- }
-
- @Override
- public void onInitializeAccessibilityNodeInfo(
- View host, AccessibilityNodeInfoCompat info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- info.setCheckable(true);
- info.setChecked(isChecked());
- }
- });
- }
-
- @Override
- public void setChecked(boolean checked) {
- if (mChecked != checked) {
- mChecked = checked;
- refreshDrawableState();
- sendAccessibilityEvent(AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED);
- }
- }
-
- @Override
- public boolean isChecked() {
- return mChecked;
- }
-
- @Override
- public void toggle() {
- setChecked(!mChecked);
- }
-
- @Override
- public int[] onCreateDrawableState(int extraSpace) {
- if (mChecked) {
- return mergeDrawableStates(
- super.onCreateDrawableState(extraSpace + DRAWABLE_STATE_CHECKED.length),
- DRAWABLE_STATE_CHECKED);
- } else {
- return super.onCreateDrawableState(extraSpace);
- }
- }
-}
diff --git a/java/com/android/bubble/MoveHandler.java b/java/com/android/bubble/MoveHandler.java
deleted file mode 100644
index 06efbd4b8..000000000
--- a/java/com/android/bubble/MoveHandler.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * 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.bubble;
-
-import android.content.Context;
-import android.graphics.Point;
-import android.support.animation.FloatPropertyCompat;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.NonNull;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.View.OnTouchListener;
-import android.view.ViewConfiguration;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.widget.Scroller;
-
-/** Handles touches and manages moving the bubble in response */
-class MoveHandler implements OnTouchListener {
-
- // Amount the ViewConfiguration's minFlingVelocity will be scaled by for our own minVelocity
- private static final int MIN_FLING_VELOCITY_FACTOR = 8;
- // The friction multiplier to control how slippery the bubble is when flung
- private static final float SCROLL_FRICTION_MULTIPLIER = 4f;
-
- private final Context context;
- private final WindowManager windowManager;
- private final Bubble bubble;
- private final int minX;
- private final int minY;
- private final int maxX;
- private final int maxY;
- private final int bubbleSize;
- private final int shadowPaddingSize;
- private final float touchSlopSquared;
-
- private boolean isMoving;
- private float firstX;
- private float firstY;
-
- private SpringAnimation moveXAnimation;
- private SpringAnimation moveYAnimation;
- private VelocityTracker velocityTracker;
- private Scroller scroller;
-
- private static float clamp(float value, float min, float max) {
- return Math.min(max, Math.max(min, value));
- }
-
- // Handles the left/right gravity conversion and centering
- private final FloatPropertyCompat<WindowManager.LayoutParams> xProperty =
- new FloatPropertyCompat<LayoutParams>("xProperty") {
- @Override
- public float getValue(LayoutParams windowParams) {
- int realX = windowParams.x;
- realX = realX + bubbleSize / 2;
- realX = realX + shadowPaddingSize;
- if (relativeToRight(windowParams)) {
- int displayWidth = context.getResources().getDisplayMetrics().widthPixels;
- realX = displayWidth - realX;
- }
- return clamp(realX, minX, maxX);
- }
-
- @Override
- public void setValue(LayoutParams windowParams, float value) {
- boolean wasOnRight = (windowParams.gravity & Gravity.RIGHT) == Gravity.RIGHT;
- int displayWidth = context.getResources().getDisplayMetrics().widthPixels;
- boolean onRight;
- Integer gravityOverride = bubble.getGravityOverride();
- if (gravityOverride == null) {
- onRight = value > displayWidth / 2;
- } else {
- onRight = (gravityOverride & Gravity.RIGHT) == Gravity.RIGHT;
- }
- int centeringOffset = bubbleSize / 2 + shadowPaddingSize;
- windowParams.x =
- (int) (onRight ? (displayWidth - value - centeringOffset) : value - centeringOffset);
- windowParams.gravity = Gravity.TOP | (onRight ? Gravity.RIGHT : Gravity.LEFT);
- if (wasOnRight != onRight) {
- bubble.onLeftRightSwitch(onRight);
- }
- if (bubble.isVisible()) {
- windowManager.updateViewLayout(bubble.getRootView(), windowParams);
- }
- }
- };
-
- private final FloatPropertyCompat<WindowManager.LayoutParams> yProperty =
- new FloatPropertyCompat<LayoutParams>("yProperty") {
- @Override
- public float getValue(LayoutParams object) {
- return clamp(object.y + bubbleSize + shadowPaddingSize, minY, maxY);
- }
-
- @Override
- public void setValue(LayoutParams object, float value) {
- object.y = (int) value - bubbleSize - shadowPaddingSize;
- if (bubble.isVisible()) {
- windowManager.updateViewLayout(bubble.getRootView(), object);
- }
- }
- };
-
- public MoveHandler(@NonNull View targetView, @NonNull Bubble bubble) {
- this.bubble = bubble;
- context = targetView.getContext();
- windowManager = context.getSystemService(WindowManager.class);
-
- bubbleSize = context.getResources().getDimensionPixelSize(R.dimen.bubble_size);
- shadowPaddingSize =
- context.getResources().getDimensionPixelOffset(R.dimen.bubble_shadow_padding_size);
- minX =
- context.getResources().getDimensionPixelOffset(R.dimen.bubble_safe_margin_x)
- + bubbleSize / 2;
- minY =
- context.getResources().getDimensionPixelOffset(R.dimen.bubble_safe_margin_y)
- + bubbleSize / 2;
- maxX = context.getResources().getDisplayMetrics().widthPixels - minX;
- maxY = context.getResources().getDisplayMetrics().heightPixels - minY;
-
- // Squared because it will be compared against the square of the touch delta. This is more
- // efficient than needing to take a square root.
- touchSlopSquared = (float) Math.pow(ViewConfiguration.get(context).getScaledTouchSlop(), 2);
-
- targetView.setOnTouchListener(this);
- }
-
- public boolean isMoving() {
- return isMoving;
- }
-
- public void undoGravityOverride() {
- LayoutParams windowParams = bubble.getWindowParams();
- xProperty.setValue(windowParams, xProperty.getValue(windowParams));
- }
-
- public void snapToBounds() {
- ensureSprings();
-
- moveXAnimation.animateToFinalPosition(relativeToRight(bubble.getWindowParams()) ? maxX : minX);
- moveYAnimation.animateToFinalPosition(yProperty.getValue(bubble.getWindowParams()));
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- float eventX = event.getRawX();
- float eventY = event.getRawY();
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- firstX = eventX;
- firstY = eventY;
- velocityTracker = VelocityTracker.obtain();
- break;
- case MotionEvent.ACTION_MOVE:
- if (isMoving || hasExceededTouchSlop(event)) {
- if (!isMoving) {
- isMoving = true;
- bubble.onMoveStart();
- }
-
- ensureSprings();
-
- moveXAnimation.animateToFinalPosition(clamp(eventX, minX, maxX));
- moveYAnimation.animateToFinalPosition(clamp(eventY, minY, maxY));
- }
-
- velocityTracker.addMovement(event);
- break;
- case MotionEvent.ACTION_UP:
- if (isMoving) {
- ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
- velocityTracker.computeCurrentVelocity(
- 1000, viewConfiguration.getScaledMaximumFlingVelocity());
- float xVelocity = velocityTracker.getXVelocity();
- float yVelocity = velocityTracker.getYVelocity();
- boolean isFling = isFling(xVelocity, yVelocity);
-
- if (isFling) {
- Point target =
- findTarget(
- xVelocity,
- yVelocity,
- (int) xProperty.getValue(bubble.getWindowParams()),
- (int) yProperty.getValue(bubble.getWindowParams()));
-
- moveXAnimation.animateToFinalPosition(target.x);
- moveYAnimation.animateToFinalPosition(target.y);
- } else {
- snapX();
- }
- isMoving = false;
- bubble.onMoveFinish();
- } else {
- v.performClick();
- bubble.primaryButtonClick();
- }
- break;
- default: // fall out
- }
- return true;
- }
-
- private void ensureSprings() {
- if (moveXAnimation == null) {
- moveXAnimation = new SpringAnimation(bubble.getWindowParams(), xProperty);
- moveXAnimation.setSpring(new SpringForce());
- moveXAnimation.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY);
- }
-
- if (moveYAnimation == null) {
- moveYAnimation = new SpringAnimation(bubble.getWindowParams(), yProperty);
- moveYAnimation.setSpring(new SpringForce());
- moveYAnimation.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY);
- }
- }
-
- private Point findTarget(float xVelocity, float yVelocity, int startX, int startY) {
- if (scroller == null) {
- scroller = new Scroller(context);
- scroller.setFriction(ViewConfiguration.getScrollFriction() * SCROLL_FRICTION_MULTIPLIER);
- }
-
- // Find where a fling would end vertically
- scroller.fling(startX, startY, (int) xVelocity, (int) yVelocity, minX, maxX, minY, maxY);
- int targetY = scroller.getFinalY();
- scroller.abortAnimation();
-
- // If the x component of the velocity is above the minimum fling velocity, use velocity to
- // determine edge. Otherwise use its starting position
- boolean pullRight = isFling(xVelocity, 0) ? xVelocity > 0 : isOnRightHalf(startX);
- return new Point(pullRight ? maxX : minX, targetY);
- }
-
- private boolean isFling(float xVelocity, float yVelocity) {
- int minFlingVelocity =
- ViewConfiguration.get(context).getScaledMinimumFlingVelocity() * MIN_FLING_VELOCITY_FACTOR;
- return getMagnitudeSquared(xVelocity, yVelocity) > minFlingVelocity * minFlingVelocity;
- }
-
- private boolean isOnRightHalf(float currentX) {
- return currentX > (minX + maxX) / 2;
- }
-
- private void snapX() {
- // Check if x value is closer to min or max
- boolean pullRight = isOnRightHalf(xProperty.getValue(bubble.getWindowParams()));
- moveXAnimation.animateToFinalPosition(pullRight ? maxX : minX);
- }
-
- private boolean relativeToRight(LayoutParams windowParams) {
- return (windowParams.gravity & Gravity.RIGHT) == Gravity.RIGHT;
- }
-
- private boolean hasExceededTouchSlop(MotionEvent event) {
- return getMagnitudeSquared(event.getRawX() - firstX, event.getRawY() - firstY)
- > touchSlopSquared;
- }
-
- private float getMagnitudeSquared(float deltaX, float deltaY) {
- return deltaX * deltaX + deltaY * deltaY;
- }
-}
diff --git a/java/com/android/bubble/WindowRoot.java b/java/com/android/bubble/WindowRoot.java
deleted file mode 100644
index b9024c413..000000000
--- a/java/com/android/bubble/WindowRoot.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.bubble;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.support.annotation.NonNull;
-import android.view.KeyEvent;
-import android.widget.FrameLayout;
-
-/**
- * ViewGroup that handles some overlay window concerns. Allows back button and configuration change
- * events to be listened for via interfaces.
- */
-public class WindowRoot extends FrameLayout {
-
- /** Callback for when the back button is pressed while this window is in focus */
- public interface OnBackPressedListener {
- boolean onBackPressed();
- }
-
- /** Callback for when the Configuration changes for this window */
- public interface OnConfigurationChangedListener {
- void onConfigurationChanged(Configuration newConfiguration);
- }
-
- private OnBackPressedListener backPressedListener;
- private OnConfigurationChangedListener configurationChangedListener;
-
- public WindowRoot(@NonNull Context context) {
- super(context);
- }
-
- public void setOnBackPressedListener(OnBackPressedListener listener) {
- backPressedListener = listener;
- }
-
- public void setOnConfigurationChangedListener(OnConfigurationChangedListener listener) {
- configurationChangedListener = listener;
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && backPressedListener != null) {
- if (event.getAction() == KeyEvent.ACTION_UP) {
- return backPressedListener.onBackPressed();
- }
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
-
- @Override
- public void dispatchConfigurationChanged(Configuration newConfig) {
- super.dispatchConfigurationChanged(newConfig);
- if (configurationChangedListener != null) {
- configurationChangedListener.onConfigurationChanged(newConfig);
- }
- }
-}
diff --git a/java/com/android/bubble/res/color/bubble_checkable_mask.xml b/java/com/android/bubble/res/color/bubble_checkable_mask.xml
deleted file mode 100644
index f9416ab57..000000000
--- a/java/com/android/bubble/res/color/bubble_checkable_mask.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/white" android:state_checked="true"/>
- <item android:color="@android:color/transparent"/>
-</selector>
diff --git a/java/com/android/bubble/res/color/bubble_icon_tint_states.xml b/java/com/android/bubble/res/color/bubble_icon_tint_states.xml
deleted file mode 100644
index 33ca1fdc5..000000000
--- a/java/com/android/bubble/res/color/bubble_icon_tint_states.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="#80FFFFFF" android:state_enabled="false"/>
- <item android:color="@android:color/white"/>
-</selector>
diff --git a/java/com/android/bubble/res/drawable/bubble_background_pill_ltr.xml b/java/com/android/bubble/res/drawable/bubble_background_pill_ltr.xml
deleted file mode 100644
index 77c813a75..000000000
--- a/java/com/android/bubble/res/drawable/bubble_background_pill_ltr.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <corners
- android:bottomRightRadius="@dimen/bubble_size"
- android:topRightRadius="@dimen/bubble_size"/>
- <solid android:color="@android:color/white"/>
-</shape>
diff --git a/java/com/android/bubble/res/drawable/bubble_background_pill_rtl.xml b/java/com/android/bubble/res/drawable/bubble_background_pill_rtl.xml
deleted file mode 100644
index 9e2542154..000000000
--- a/java/com/android/bubble/res/drawable/bubble_background_pill_rtl.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <corners
- android:bottomLeftRadius="@dimen/bubble_size"
- android:topLeftRadius="@dimen/bubble_size"/>
- <solid android:color="@android:color/white"/>
-</shape>
diff --git a/java/com/android/bubble/res/drawable/bubble_ripple_checkable_circle.xml b/java/com/android/bubble/res/drawable/bubble_ripple_checkable_circle.xml
deleted file mode 100644
index 85e0b24f3..000000000
--- a/java/com/android/bubble/res/drawable/bubble_ripple_checkable_circle.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:colorControlHighlight">
- <item>
- <shape android:shape="oval">
- <solid android:color="@color/bubble_checkable_mask"/>
- </shape>
- </item>
- <item android:id="@android:id/mask">
- <shape android:shape="oval">
- <solid android:color="@android:color/white"/>
- </shape>
- </item>
-</ripple>
diff --git a/java/com/android/bubble/res/drawable/bubble_ripple_circle.xml b/java/com/android/bubble/res/drawable/bubble_ripple_circle.xml
deleted file mode 100644
index 8d5cf0bb5..000000000
--- a/java/com/android/bubble/res/drawable/bubble_ripple_circle.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:colorControlHighlight">
- <item>
- <shape>
- <corners android:radius="@dimen/bubble_size"/>
- <solid android:color="@android:color/white"/>
- </shape>
- </item>
-</ripple>
diff --git a/java/com/android/bubble/res/layout/bubble_base.xml b/java/com/android/bubble/res/layout/bubble_base.xml
deleted file mode 100644
index 9f88e7083..000000000
--- a/java/com/android/bubble/res/layout/bubble_base.xml
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clipToPadding="false"
- tools:theme="@style/Theme.AppCompat">
- <View
- android:id="@+id/bubble_drawer_shadow_provider"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginTop="@dimen/bubble_shadow_padding_size"
- android:layout_marginBottom="@dimen/bubble_shadow_padding_size"
- android:layout_marginStart="@dimen/bubble_shadow_padding_size"
- android:background="@drawable/bubble_ripple_circle"
- android:backgroundTint="@android:color/transparent"
- android:elevation="10dp"
- android:visibility="invisible"
- />
- <View
- android:id="@+id/bubble_drawer_shadow_provider_rtl"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginTop="@dimen/bubble_shadow_padding_size"
- android:layout_marginBottom="@dimen/bubble_shadow_padding_size"
- android:layout_marginRight="@dimen/bubble_shadow_padding_size"
- android:layout_gravity="right"
- android:background="@drawable/bubble_ripple_circle"
- android:backgroundTint="@android:color/transparent"
- android:elevation="10dp"
- android:visibility="invisible"
- />
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/bubble_drawer_margin"
- android:elevation="10dp"
- android:paddingTop="@dimen/bubble_shadow_padding_size"
- android:paddingBottom="@dimen/bubble_shadow_padding_size"
- android:paddingEnd="@dimen/bubble_shadow_padding_size">
-
- <LinearLayout
- android:id="@+id/bubble_expanded_layout"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="@dimen/bubble_drawer_padding_start"
- android:paddingEnd="@dimen/bubble_drawer_padding_end"
- android:background="@drawable/bubble_background_pill_ltr"
- android:layoutDirection="ltr"
- android:orientation="horizontal"
- android:visibility="gone"
- tools:backgroundTint="#FF0000FF"
- tools:visibility="visible">
- <com.android.bubble.CheckableImageButton
- android:id="@+id/bubble_icon_first"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginStart="4dp"
- android:padding="@dimen/bubble_icon_padding"
- android:tint="@color/bubble_icon_tint_states"
- android:tintMode="src_in"
- tools:background="@drawable/bubble_ripple_checkable_circle"
- tools:src="@android:drawable/ic_lock_idle_lock"/>
- <com.android.bubble.CheckableImageButton
- android:id="@+id/bubble_icon_second"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginStart="4dp"
- android:padding="@dimen/bubble_icon_padding"
- android:tint="@color/bubble_icon_tint_states"
- android:tintMode="src_in"
- tools:background="@drawable/bubble_ripple_checkable_circle"
- tools:src="@android:drawable/ic_input_add"/>
- <com.android.bubble.CheckableImageButton
- android:id="@+id/bubble_icon_third"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginStart="4dp"
- android:padding="@dimen/bubble_icon_padding"
- android:tint="@color/bubble_icon_tint_states"
- android:tintMode="src_in"
- tools:background="@drawable/bubble_ripple_checkable_circle"
- tools:src="@android:drawable/ic_menu_call"/>
- </LinearLayout>
- </FrameLayout>
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="@dimen/bubble_drawer_margin"
- android:elevation="10dp"
- android:paddingTop="@dimen/bubble_shadow_padding_size"
- android:paddingBottom="@dimen/bubble_shadow_padding_size"
- android:paddingLeft="@dimen/bubble_shadow_padding_size">
- <LinearLayout
- android:id="@+id/bubble_expanded_layout_rtl"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingRight="@dimen/bubble_drawer_padding_start"
- android:paddingLeft="@dimen/bubble_drawer_padding_end"
- android:background="@drawable/bubble_background_pill_rtl"
- android:layoutDirection="rtl"
- android:orientation="horizontal"
- android:visibility="gone"
- tools:backgroundTint="#FF0000FF"
- tools:visibility="invisible">
- <com.android.bubble.CheckableImageButton
- android:id="@+id/bubble_icon_first_rtl"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginRight="4dp"
- android:padding="@dimen/bubble_icon_padding"
- android:tint="@color/bubble_icon_tint_states"
- android:tintMode="src_in"
- tools:background="@drawable/bubble_ripple_checkable_circle"
- tools:src="@android:drawable/ic_lock_idle_lock"/>
- <com.android.bubble.CheckableImageButton
- android:id="@+id/bubble_icon_second_rtl"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginRight="4dp"
- android:padding="@dimen/bubble_icon_padding"
- android:tint="@color/bubble_icon_tint_states"
- android:tintMode="src_in"
- tools:background="@drawable/bubble_ripple_checkable_circle"
- tools:src="@android:drawable/ic_input_add"/>
- <com.android.bubble.CheckableImageButton
- android:id="@+id/bubble_icon_third_rtl"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:layout_marginRight="4dp"
- android:padding="@dimen/bubble_icon_padding"
- android:tint="@color/bubble_icon_tint_states"
- android:tintMode="src_in"
- tools:background="@drawable/bubble_ripple_checkable_circle"
- tools:src="@android:drawable/ic_menu_call"/>
- </LinearLayout>
- </FrameLayout>
- <FrameLayout
- android:id="@+id/bubble_primary_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="start"
- android:animateLayoutChanges="true"
- android:clipChildren="false"
- android:clipToPadding="false"
- android:elevation="12dp">
- <ViewAnimator
- android:id="@+id/bubble_button_primary"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="@dimen/bubble_shadow_padding_size"
- android:background="@drawable/bubble_ripple_circle"
- android:measureAllChildren="false"
- tools:backgroundTint="#FF0000AA">
- <ImageView
- android:id="@+id/bubble_icon_primary"
- android:layout_width="@dimen/bubble_size"
- android:layout_height="@dimen/bubble_size"
- android:padding="@dimen/bubble_icon_padding"
- android:tint="@android:color/white"
- android:tintMode="src_in"
- tools:src="@android:drawable/ic_btn_speak_now"/>
- <TextView
- android:id="@+id/bubble_text"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/bubble_size"
- android:paddingStart="@dimen/bubble_icon_padding"
- android:paddingEnd="@dimen/bubble_icon_padding"
- android:gravity="center"
- android:minWidth="@dimen/bubble_size"
- android:textAppearance="@style/TextAppearance.AppCompat"
- tools:text="Call ended"/>
- </ViewAnimator>
- </FrameLayout>
-
-</FrameLayout>
diff --git a/java/com/android/bubble/res/values-car/values.xml b/java/com/android/bubble/res/values-car/values.xml
deleted file mode 100644
index 47f20a1bf..000000000
--- a/java/com/android/bubble/res/values-car/values.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-
-<resources>
- <dimen name="bubble_size">64dp</dimen>
- <dimen name="bubble_drawer_margin">50dp</dimen>
- <dimen name="bubble_drawer_padding_start">38dp</dimen>
- <dimen name="bubble_drawer_padding_end">12dp</dimen>
-</resources>
-
diff --git a/java/com/android/bubble/res/values/colors.xml b/java/com/android/bubble/res/values/colors.xml
deleted file mode 100644
index 97545faf3..000000000
--- a/java/com/android/bubble/res/values/colors.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-<resources>
- <color name="bubble_primary_background_darken">#33000000</color>
-</resources>
diff --git a/java/com/android/bubble/res/values/values.xml b/java/com/android/bubble/res/values/values.xml
deleted file mode 100644
index 6066e18c3..000000000
--- a/java/com/android/bubble/res/values/values.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ 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
- -->
-
-
-<resources>
- <dimen name="bubble_safe_margin_x">16dp</dimen>
- <dimen name="bubble_safe_margin_y">64dp</dimen>
- <dimen name="bubble_size">56dp</dimen>
- <dimen name="bubble_drawer_margin">48dp</dimen>
- <dimen name="bubble_drawer_padding_start">32dp</dimen>
- <dimen name="bubble_drawer_padding_end">8dp</dimen>
- <dimen name="bubble_icon_padding">16dp</dimen>
- <dimen name="bubble_move_elevation_change">4dp</dimen>
- <dimen name="bubble_shadow_padding_size">16dp</dimen>
-</resources>
-
diff --git a/java/com/android/incallui/AndroidManifest.xml b/java/com/android/incallui/AndroidManifest.xml
index 3d5aa1ceb..eb080bc82 100644
--- a/java/com/android/incallui/AndroidManifest.xml
+++ b/java/com/android/incallui/AndroidManifest.xml
@@ -114,9 +114,6 @@
<receiver
android:exported="false"
- android:name=".ReturnToCallActionReceiver"/>
- <receiver
- android:exported="false"
android:name=".NewReturnToCallActionReceiver"/>
</application>
diff --git a/java/com/android/incallui/InCallActivity.java b/java/com/android/incallui/InCallActivity.java
index 535b894f6..8769be5d9 100644
--- a/java/com/android/incallui/InCallActivity.java
+++ b/java/com/android/incallui/InCallActivity.java
@@ -60,7 +60,6 @@ import com.android.dialer.common.concurrent.ThreadUtil;
import com.android.dialer.compat.ActivityCompat;
import com.android.dialer.compat.CompatUtils;
import com.android.dialer.configprovider.ConfigProviderBindings;
-import com.android.dialer.logging.DialerImpression;
import com.android.dialer.logging.Logger;
import com.android.dialer.logging.LoggingBindings;
import com.android.dialer.logging.ScreenEvent;
@@ -173,11 +172,6 @@ public class InCallActivity extends TransactionSafeFragmentActivity
Trace.beginSection("InCallActivity.onCreate");
super.onCreate(bundle);
- if (getIntent().getBooleanExtra(ReturnToCallController.RETURN_TO_CALL_EXTRA_KEY, false)) {
- Logger.get(this).logImpression(DialerImpression.Type.BUBBLE_PRIMARY_BUTTON_RETURN_TO_CALL);
- getIntent().removeExtra(ReturnToCallController.RETURN_TO_CALL_EXTRA_KEY);
- }
-
if (bundle != null) {
didShowAnswerScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_ANSWER_SCREEN);
didShowInCallScreen = bundle.getBoolean(KeysForSavedInstance.DID_SHOW_IN_CALL_SCREEN);
diff --git a/java/com/android/incallui/InCallServiceImpl.java b/java/com/android/incallui/InCallServiceImpl.java
index c4d6d064f..a7095f818 100644
--- a/java/com/android/incallui/InCallServiceImpl.java
+++ b/java/com/android/incallui/InCallServiceImpl.java
@@ -40,7 +40,6 @@ import com.android.incallui.speakeasy.SpeakEasyComponent;
*/
public class InCallServiceImpl extends InCallService {
- private ReturnToCallController returnToCallController;
private NewReturnToCallController newReturnToCallController;
private CallList.Listener feedbackListener;
// We only expect there to be one speakEasyCallManager to be instantiated at a time.
@@ -112,9 +111,6 @@ public class InCallServiceImpl extends InCallService {
InCallPresenter.getInstance().onServiceBind();
InCallPresenter.getInstance().maybeStartRevealAnimation(intent);
TelecomAdapter.getInstance().setInCallService(this);
- if (ReturnToCallController.isEnabled(this)) {
- returnToCallController = new ReturnToCallController(this);
- }
if (NewReturnToCallController.isEnabled(this)) {
newReturnToCallController =
new NewReturnToCallController(this, ContactInfoCache.getInstance(context));
@@ -145,10 +141,6 @@ public class InCallServiceImpl extends InCallService {
// Tear down the InCall system
InCallPresenter.getInstance().tearDown();
TelecomAdapter.getInstance().clearInCallService();
- if (returnToCallController != null) {
- returnToCallController.tearDown();
- returnToCallController = null;
- }
if (newReturnToCallController != null) {
newReturnToCallController.tearDown();
newReturnToCallController = null;
diff --git a/java/com/android/incallui/ReturnToCallActionReceiver.java b/java/com/android/incallui/ReturnToCallActionReceiver.java
deleted file mode 100644
index c37b0b816..000000000
--- a/java/com/android/incallui/ReturnToCallActionReceiver.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.incallui;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.telecom.CallAudioState;
-import com.android.dialer.common.Assert;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.logging.DialerImpression;
-import com.android.dialer.logging.Logger;
-import com.android.incallui.audiomode.AudioModeProvider;
-import com.android.incallui.call.CallList;
-import com.android.incallui.call.DialerCall;
-import com.android.incallui.call.TelecomAdapter;
-
-/** Handles clicks on the return-to-call bubble */
-public class ReturnToCallActionReceiver extends BroadcastReceiver {
-
- public static final String ACTION_TOGGLE_SPEAKER = "toggleSpeaker";
- public static final String ACTION_SHOW_AUDIO_ROUTE_SELECTOR = "showAudioRouteSelector";
- public static final String ACTION_TOGGLE_MUTE = "toggleMute";
- public static final String ACTION_END_CALL = "endCall";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- switch (intent.getAction()) {
- case ACTION_TOGGLE_SPEAKER:
- toggleSpeaker(context);
- break;
- case ACTION_SHOW_AUDIO_ROUTE_SELECTOR:
- showAudioRouteSelector(context);
- break;
- case ACTION_TOGGLE_MUTE:
- toggleMute(context);
- break;
- case ACTION_END_CALL:
- endCall(context);
- break;
- default:
- throw Assert.createIllegalStateFailException(
- "Invalid intent action: " + intent.getAction());
- }
- }
-
- private void toggleSpeaker(Context context) {
- CallAudioState audioState = AudioModeProvider.getInstance().getAudioState();
-
- if ((audioState.getSupportedRouteMask() & CallAudioState.ROUTE_BLUETOOTH)
- == CallAudioState.ROUTE_BLUETOOTH) {
- LogUtil.w(
- "ReturnToCallActionReceiver.toggleSpeaker",
- "toggleSpeaker() called when bluetooth available."
- + " Probably should have shown audio route selector");
- }
-
- DialerCall call = getCall();
-
- int newRoute;
- if (audioState.getRoute() == CallAudioState.ROUTE_SPEAKER) {
- newRoute = CallAudioState.ROUTE_WIRED_OR_EARPIECE;
- Logger.get(context)
- .logCallImpression(
- DialerImpression.Type.BUBBLE_TURN_ON_WIRED_OR_EARPIECE,
- call != null ? call.getUniqueCallId() : "",
- call != null ? call.getTimeAddedMs() : 0);
- } else {
- newRoute = CallAudioState.ROUTE_SPEAKER;
- Logger.get(context)
- .logCallImpression(
- DialerImpression.Type.BUBBLE_TURN_ON_SPEAKERPHONE,
- call != null ? call.getUniqueCallId() : "",
- call != null ? call.getTimeAddedMs() : 0);
- }
- TelecomAdapter.getInstance().setAudioRoute(newRoute);
- }
-
- public void showAudioRouteSelector(Context context) {
- Intent intent = new Intent(context, AudioRouteSelectorActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
- context.startActivity(intent);
- }
-
- private void toggleMute(Context context) {
- DialerCall call = getCall();
- boolean shouldMute = !AudioModeProvider.getInstance().getAudioState().isMuted();
- Logger.get(context)
- .logCallImpression(
- shouldMute
- ? DialerImpression.Type.BUBBLE_MUTE_CALL
- : DialerImpression.Type.BUBBLE_UNMUTE_CALL,
- call != null ? call.getUniqueCallId() : "",
- call != null ? call.getTimeAddedMs() : 0);
- TelecomAdapter.getInstance().mute(shouldMute);
- }
-
- private void endCall(Context context) {
- DialerCall call = getCall();
-
- Logger.get(context)
- .logCallImpression(
- DialerImpression.Type.BUBBLE_END_CALL,
- call != null ? call.getUniqueCallId() : "",
- call != null ? call.getTimeAddedMs() : 0);
- if (call != null) {
- call.disconnect();
- }
- }
-
- private DialerCall getCall() {
- CallList callList = InCallPresenter.getInstance().getCallList();
- if (callList != null) {
- DialerCall call = callList.getOutgoingCall();
- if (call == null) {
- call = callList.getActiveOrBackgroundCall();
- }
- if (call != null) {
- return call;
- }
- }
- return null;
- }
-}
diff --git a/java/com/android/incallui/ReturnToCallController.java b/java/com/android/incallui/ReturnToCallController.java
deleted file mode 100644
index 58d868818..000000000
--- a/java/com/android/incallui/ReturnToCallController.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * 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.incallui;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.drawable.Icon;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
-import android.telecom.CallAudioState;
-import com.android.bubble.Bubble;
-import com.android.bubble.Bubble.BubbleExpansionStateListener;
-import com.android.bubble.Bubble.ExpansionState;
-import com.android.bubble.BubbleInfo;
-import com.android.bubble.BubbleInfo.Action;
-import com.android.dialer.common.LogUtil;
-import com.android.dialer.configprovider.ConfigProviderBindings;
-import com.android.dialer.logging.DialerImpression;
-import com.android.dialer.logging.Logger;
-import com.android.dialer.telecom.TelecomUtil;
-import com.android.incallui.InCallPresenter.InCallUiListener;
-import com.android.incallui.audiomode.AudioModeProvider;
-import com.android.incallui.audiomode.AudioModeProvider.AudioModeListener;
-import com.android.incallui.call.CallList;
-import com.android.incallui.call.CallList.Listener;
-import com.android.incallui.call.DialerCall;
-import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo;
-import com.android.incallui.speakerbuttonlogic.SpeakerButtonInfo.IconSize;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Listens for events relevant to the return-to-call bubble and updates the bubble's state as
- * necessary
- */
-public class ReturnToCallController implements InCallUiListener, Listener, AudioModeListener {
-
- public static final String RETURN_TO_CALL_EXTRA_KEY = "RETURN_TO_CALL_BUBBLE";
-
- private final Context context;
-
- @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
- Bubble bubble;
-
- private CallAudioState audioState;
-
- private final PendingIntent toggleSpeaker;
- private final PendingIntent showSpeakerSelect;
- private final PendingIntent toggleMute;
- private final PendingIntent endCall;
-
- public static boolean isEnabled(Context context) {
- return ConfigProviderBindings.get(context).getBoolean("enable_return_to_call_bubble", false);
- }
-
- public ReturnToCallController(Context context) {
- this.context = context;
-
- toggleSpeaker = createActionIntent(ReturnToCallActionReceiver.ACTION_TOGGLE_SPEAKER);
- showSpeakerSelect =
- createActionIntent(ReturnToCallActionReceiver.ACTION_SHOW_AUDIO_ROUTE_SELECTOR);
- toggleMute = createActionIntent(ReturnToCallActionReceiver.ACTION_TOGGLE_MUTE);
- endCall = createActionIntent(ReturnToCallActionReceiver.ACTION_END_CALL);
-
- InCallPresenter.getInstance().addInCallUiListener(this);
- CallList.getInstance().addListener(this);
- AudioModeProvider.getInstance().addListener(this);
- audioState = AudioModeProvider.getInstance().getAudioState();
- }
-
- public void tearDown() {
- hide();
- InCallPresenter.getInstance().removeInCallUiListener(this);
- CallList.getInstance().removeListener(this);
- AudioModeProvider.getInstance().removeListener(this);
- }
-
- @Override
- public void onUiShowing(boolean showing) {
- if (showing) {
- hide();
- } else {
- if (TelecomUtil.isInManagedCall(context)) {
- show();
- }
- }
- }
-
- private void hide() {
- if (bubble != null) {
- bubble.hide();
- } else {
- LogUtil.i("ReturnToCallController.hide", "hide() called without calling show()");
- }
- }
-
- private void hideAndReset() {
- if (bubble != null) {
- bubble.hideAndReset();
- } else {
- LogUtil.i("ReturnToCallController.reset", "reset() called without calling show()");
- }
- }
-
- private void show() {
- if (bubble == null) {
- bubble = startNewBubble();
- } else {
- bubble.show();
- }
- }
-
- @VisibleForTesting
- public Bubble startNewBubble() {
- if (!Bubble.canShowBubbles(context)) {
- LogUtil.i("ReturnToCallController.startNewBubble", "can't show bubble, no permission");
- return null;
- }
- Bubble returnToCallBubble = Bubble.createBubble(context, generateBubbleInfo());
- returnToCallBubble.setBubbleExpansionStateListener(
- new BubbleExpansionStateListener() {
- @Override
- public void onBubbleExpansionStateChanged(
- @ExpansionState int expansionState, boolean isUserAction) {
- if (!isUserAction) {
- return;
- }
-
- DialerCall call = CallList.getInstance().getActiveOrBackgroundCall();
- switch (expansionState) {
- case ExpansionState.START_EXPANDING:
- if (call != null) {
- Logger.get(context)
- .logCallImpression(
- DialerImpression.Type.BUBBLE_PRIMARY_BUTTON_EXPAND,
- call.getUniqueCallId(),
- call.getTimeAddedMs());
- } else {
- Logger.get(context)
- .logImpression(DialerImpression.Type.BUBBLE_PRIMARY_BUTTON_EXPAND);
- }
- break;
- case ExpansionState.START_COLLAPSING:
- if (call != null) {
- Logger.get(context)
- .logCallImpression(
- DialerImpression.Type.BUBBLE_COLLAPSE_BY_USER,
- call.getUniqueCallId(),
- call.getTimeAddedMs());
- } else {
- Logger.get(context).logImpression(DialerImpression.Type.BUBBLE_COLLAPSE_BY_USER);
- }
- break;
- default:
- break;
- }
- }
- });
- returnToCallBubble.show();
- return returnToCallBubble;
- }
-
- @Override
- public void onIncomingCall(DialerCall call) {}
-
- @Override
- public void onUpgradeToVideo(DialerCall call) {}
-
- @Override
- public void onSessionModificationStateChange(DialerCall call) {}
-
- @Override
- public void onCallListChange(CallList callList) {}
-
- @Override
- public void onDisconnect(DialerCall call) {
- if (call.wasParentCall()) {
- // It's disconnected after the last child call is disconnected, and we already did everything
- // for the last child.
- LogUtil.i(
- "ReturnToCallController.onDisconnect", "being called for a parent call and do nothing");
- return;
- }
- if (bubble != null
- && bubble.isVisible()
- && (!TelecomUtil.isInManagedCall(context)
- || CallList.getInstance().getActiveOrBackgroundCall() != null)) {
- bubble.showText(context.getText(R.string.incall_call_ended));
- }
- // For conference call, we should hideAndReset for the last disconnected child call while the
- // parent call is still there.
- if (!CallList.getInstance().hasNonParentActiveOrBackgroundCall()) {
- hideAndReset();
- }
- }
-
- @Override
- public void onWiFiToLteHandover(DialerCall call) {}
-
- @Override
- public void onHandoverToWifiFailed(DialerCall call) {}
-
- @Override
- public void onInternationalCallOnWifi(@NonNull DialerCall call) {}
-
- @Override
- public void onAudioStateChanged(CallAudioState audioState) {
- this.audioState = audioState;
- if (bubble != null) {
- bubble.updateActions(generateActions());
- }
- }
-
- private BubbleInfo generateBubbleInfo() {
- Intent activityIntent = InCallActivity.getIntent(context, false, false, false);
- activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- activityIntent.putExtra(RETURN_TO_CALL_EXTRA_KEY, true);
- return BubbleInfo.builder()
- .setPrimaryColor(context.getResources().getColor(R.color.dialer_theme_color, null))
- .setPrimaryIcon(Icon.createWithResource(context, R.drawable.on_going_call))
- .setStartingYPosition(
- context.getResources().getDimensionPixelOffset(R.dimen.return_to_call_initial_offset_y))
- .setPrimaryIntent(
- PendingIntent.getActivity(
- context, InCallActivity.PendingIntentRequestCodes.BUBBLE, activityIntent, 0))
- .setActions(generateActions())
- .build();
- }
-
- @NonNull
- private List<Action> generateActions() {
- List<Action> actions = new ArrayList<>();
- SpeakerButtonInfo speakerButtonInfo = new SpeakerButtonInfo(audioState, IconSize.SIZE_24_DP);
-
- actions.add(
- Action.builder()
- .setIcon(Icon.createWithResource(context, speakerButtonInfo.icon))
- .setName(context.getText(speakerButtonInfo.label))
- .setChecked(speakerButtonInfo.isChecked)
- .setIntent(speakerButtonInfo.checkable ? toggleSpeaker : showSpeakerSelect)
- .build());
-
- actions.add(
- Action.builder()
- .setIcon(Icon.createWithResource(context, R.drawable.quantum_ic_mic_off_white_24))
- .setName(context.getText(R.string.incall_label_mute))
- .setChecked(audioState.isMuted())
- .setIntent(toggleMute)
- .build());
- actions.add(
- Action.builder()
- .setIcon(Icon.createWithResource(context, R.drawable.quantum_ic_call_end_vd_theme_24))
- .setName(context.getText(R.string.incall_label_end_call))
- .setIntent(endCall)
- .build());
- return actions;
- }
-
- @NonNull
- private PendingIntent createActionIntent(String action) {
- Intent toggleSpeaker = new Intent(context, ReturnToCallActionReceiver.class);
- toggleSpeaker.setAction(action);
- return PendingIntent.getBroadcast(context, 0, toggleSpeaker, 0);
- }
-}
diff --git a/java/com/android/incallui/StatusBarNotifier.java b/java/com/android/incallui/StatusBarNotifier.java
index 960fd14df..87f332a1d 100644
--- a/java/com/android/incallui/StatusBarNotifier.java
+++ b/java/com/android/incallui/StatusBarNotifier.java
@@ -657,8 +657,8 @@ public class StatusBarNotifier
} else if (call.hasProperty(Details.PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
return R.drawable.quantum_ic_phone_locked_vd_theme_24;
}
- // If ReturnToCall is enabled, use the static icon. The animated one will show in the bubble.
- if (ReturnToCallController.isEnabled(context) || NewReturnToCallController.isEnabled(context)) {
+ // If NewReturnToCall is enabled, use the static icon. The animated one will show in the bubble.
+ if (NewReturnToCallController.isEnabled(context)) {
return R.drawable.quantum_ic_call_vd_theme_24;
} else {
return R.drawable.on_going_call;