summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--InCallUI/res/layout/primary_call_info.xml9
-rw-r--r--InCallUI/res/values/styles.xml42
-rw-r--r--InCallUI/src/com/android/incallui/CallCardFragment.java69
-rw-r--r--InCallUI/src/com/android/incallui/CallCardPresenter.java4
-rw-r--r--InCallUI/src/com/android/incallui/CircularRevealActivity.java179
-rw-r--r--InCallUI/src/com/android/incallui/CircularRevealFragment.java159
-rw-r--r--InCallUI/src/com/android/incallui/InCallActivity.java10
-rw-r--r--InCallUI/src/com/android/incallui/InCallPresenter.java146
-rw-r--r--InCallUI/src/com/android/incallui/StatusBarNotifier.java3
9 files changed, 251 insertions, 370 deletions
diff --git a/InCallUI/res/layout/primary_call_info.xml b/InCallUI/res/layout/primary_call_info.xml
index 71369d479..cb9cc2498 100644
--- a/InCallUI/res/layout/primary_call_info.xml
+++ b/InCallUI/res/layout/primary_call_info.xml
@@ -109,7 +109,8 @@
android:textColor="@color/incall_call_banner_subtext_color"
android:textSize="@dimen/call_label_text_size"
android:singleLine="true"
- android:textDirection="ltr" />
+ android:textDirection="ltr"
+ android:visibility="gone" />
<TextView android:id="@+id/phoneNumber"
android:layout_width="match_parent"
@@ -118,7 +119,8 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/incall_call_banner_subtext_color"
android:textSize="@dimen/call_label_text_size"
- android:singleLine="true" />
+ android:singleLine="true"
+ android:visibility="gone" />
</LinearLayout>
@@ -145,6 +147,7 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/incall_call_banner_text_color"
android:maxLines="1"
- android:ellipsize="end" />
+ android:ellipsize="end"
+ android:visibility="gone" />
</LinearLayout> <!-- End of call_banner -->
diff --git a/InCallUI/res/values/styles.xml b/InCallUI/res/values/styles.xml
index e16d72cb4..dba7cc375 100644
--- a/InCallUI/res/values/styles.xml
+++ b/InCallUI/res/values/styles.xml
@@ -70,43 +70,12 @@
<item name="android:textOff">@null</item>
</style>
- <style name="InCallAnimationStyle" parent="@android:style/Animation.Activity">
- <!-- Suppress task-to-task animation happening during the transition from
- OutgoingCallBroadcaster (and SipOptionHandler) to InCallActivity.
- The transition unexpectedly happens during the transition (inside the phone task),
- because InCallActivity is using android:launchMode="singleInstance".
-
- - taskOpenEnterAnimation/taskOpenExitAnimation is used for the first time
- InCallActivity instance is created.
-
- - taskToFrontEnterAnimation/taskToFrontExitAnimation is used when InCallActivity
- is already available.
- (Note that InCallActivity won't be destroyed once it is created)
-
- TODO: try removing the flag instead -->
- <item name="android:taskOpenEnterAnimation">@null</item>
- <item name="android:taskOpenExitAnimation">@anim/activity_open_exit</item>
- <item name="android:taskToFrontEnterAnimation">@anim/activity_open_enter</item>
- <item name="android:taskToFrontExitAnimation">@anim/activity_open_exit</item>
- </style>
-
- <style name="OutgoingCallAnimationStyle" parent="@android:style/Animation.Activity">
- <item name="android:taskOpenEnterAnimation">@null</item>
- <item name="android:taskOpenExitAnimation">@null</item>
- <item name="android:activityOpenEnterAnimation">@null</item>
- <item name="android:activityOpenExitAnimation">@null</item>
- <item name="android:activityCloseEnterAnimation">@null</item>
- <item name="android:activityCloseExitAnimation">@null</item>
- <item name="android:taskToFrontEnterAnimation">@null</item>
- <item name="android:taskToFrontExitAnimation">@null</item>
- </style>
-
<!-- Theme for the InCallActivity activity. Should have a transparent background for the
circular reveal animation for a new outgoing call to work correctly. We don't just use
Theme.Black.NoTitleBar directly, since we want any popups or dialogs from the
InCallActivity to have the correct Material style. -->
<style name="Theme.InCallScreen" parent="@android:style/Theme.Material.Light">
- <item name="android:windowAnimationStyle">@style/InCallAnimationStyle</item>
+ <item name="android:windowAnimationStyle">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
@@ -118,15 +87,6 @@
<item name="android:buttonStyleToggle">@style/InCallCompoundButton</item>
</style>
- <style name="Theme.CircularRevealAnimation" parent="@android:style/Theme.Material.Light">
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowContentOverlay">@null</item>
- <item name="android:windowNoTitle">true</item>
- <item name="android:colorPrimaryDark">@color/dialer_theme_color_dark</item>
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:windowAnimationStyle">@null</item>
- </style>
-
<style name="InCallPopupMenuStyle" parent="@android:style/Theme.Material.Light">
<item name="android:textColorPrimary">@color/popup_menu_color</item>
</style>
diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java
index 649176ce9..00e619609 100644
--- a/InCallUI/src/com/android/incallui/CallCardFragment.java
+++ b/InCallUI/src/com/android/incallui/CallCardFragment.java
@@ -24,7 +24,6 @@ import android.animation.ObjectAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Point;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -33,11 +32,9 @@ import android.telecom.VideoProfile;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.text.format.DateUtils;
-import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
-import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.ViewTreeObserver;
@@ -51,7 +48,6 @@ import android.widget.TextView;
import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
import com.android.contacts.common.widget.FloatingActionButtonController;
-import com.android.incallui.service.PhoneNumberService;
import com.android.phone.common.animation.AnimUtils;
import java.util.List;
@@ -63,7 +59,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
implements CallCardPresenter.CallCardUi {
private AnimatorSet mAnimatorSet;
- private int mRevealAnimationDuration;
private int mShrinkAnimationDuration;
private int mFabNormalDiameter;
private int mFabSmallDiameter;
@@ -108,9 +103,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
private ImageButton mFloatingActionButton;
private int mFloatingActionButtonVerticalOffset;
- // Cached DisplayMetrics density.
- private float mDensity;
-
private float mTranslationOffset;
private Animation mPulseAnimation;
@@ -132,7 +124,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mRevealAnimationDuration = getResources().getInteger(R.integer.reveal_animation_duration);
mShrinkAnimationDuration = getResources().getInteger(R.integer.shrink_animation_duration);
mVideoAnimationDuration = getResources().getInteger(R.integer.video_animation_duration);
mFloatingActionButtonVerticalOffset = getResources().getDimensionPixelOffset(
@@ -156,9 +147,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- super.onCreateView(inflater, container, savedInstanceState);
-
- mDensity = getResources().getDisplayMetrics().density;
mTranslationOffset =
getResources().getDimensionPixelSize(R.dimen.call_card_anim_translate_y_offset);
@@ -230,6 +218,9 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
mPrimaryName.setElegantTextHeight(false);
mCallStateLabel.setElegantTextHeight(false);
+
+ final LayoutTransition transition = mPrimaryCallInfo.getLayoutTransition();
+ transition.enableTransitionType(LayoutTransition.CHANGING);
}
@Override
@@ -425,7 +416,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
public void setPrimary(String number, String name, boolean nameIsNumber, String label,
Drawable photo, boolean isSipCall) {
Log.d(this, "Setting primary call");
-
// set the name field.
setPrimaryName(name, nameIsNumber);
@@ -842,13 +832,14 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
}
}
- public void animateForNewOutgoingCall(final Point touchPoint,
- final boolean showCircularReveal) {
+ @Override
+ public void animateForNewOutgoingCall() {
final ViewGroup parent = (ViewGroup) mPrimaryCallCardContainer.getParent();
final ViewTreeObserver observer = getView().getViewTreeObserver();
- mPrimaryCallInfo.getLayoutTransition().disableTransitionType(LayoutTransition.CHANGING);
+ final LayoutTransition transition = mPrimaryCallInfo.getLayoutTransition();
+ transition.disableTransitionType(LayoutTransition.CHANGING);
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
@@ -862,21 +853,21 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
final LayoutIgnoringListener listener = new LayoutIgnoringListener();
mPrimaryCallCardContainer.addOnLayoutChangeListener(listener);
- // Prepare the state of views before the circular reveal animation
+ // Prepare the state of views before the slide animation
final int originalHeight = mPrimaryCallCardContainer.getHeight();
mPrimaryCallCardContainer.setBottom(parent.getHeight());
// Set up FAB.
mFloatingActionButtonContainer.setVisibility(View.GONE);
mFloatingActionButtonController.setScreenWidth(parent.getWidth());
+
mCallButtonsContainer.setAlpha(0);
mCallStateLabel.setAlpha(0);
mPrimaryName.setAlpha(0);
mCallTypeLabel.setAlpha(0);
mCallNumberAndLabel.setAlpha(0);
- final Animator animator = getOutgoingCallAnimator(touchPoint,
- parent.getHeight(), originalHeight, showCircularReveal);
+ final Animator animator = getShrinkAnimator(parent.getHeight(), originalHeight);
animator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -990,41 +981,6 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
return shrinkAnimator;
}
- private Animator getRevealAnimator(Point touchPoint) {
- final Activity activity = getActivity();
- final View view = activity.getWindow().getDecorView();
- final Display display = activity.getWindowManager().getDefaultDisplay();
- final Point size = new Point();
- display.getSize(size);
-
- int startX = size.x / 2;
- int startY = size.y / 2;
- if (touchPoint != null) {
- startX = touchPoint.x;
- startY = touchPoint.y;
- }
-
- final Animator valueAnimator = ViewAnimationUtils.createCircularReveal(view,
- startX, startY, 0, Math.max(size.x, size.y));
- valueAnimator.setDuration(mRevealAnimationDuration);
- return valueAnimator;
- }
-
- private Animator getOutgoingCallAnimator(Point touchPoint, int startHeight, int endHeight,
- boolean showCircularReveal) {
-
- final Animator shrinkAnimator = getShrinkAnimator(startHeight, endHeight);
-
- if (!showCircularReveal) {
- return shrinkAnimator;
- }
-
- final Animator revealAnimator = getRevealAnimator(touchPoint);
- final AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playSequentially(revealAnimator, shrinkAnimator);
- return animatorSet;
- }
-
private void assignTranslateAnimation(View view, int offset) {
view.setTranslationY(mTranslationOffset * offset);
view.animate().translationY(0).alpha(1).withLayer()
@@ -1045,7 +1001,10 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr
setViewStatePostAnimation(mCallStateIcon);
mPrimaryCallCardContainer.removeOnLayoutChangeListener(layoutChangeListener);
- mPrimaryCallInfo.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
+
+ final LayoutTransition transition = mPrimaryCallInfo.getLayoutTransition();
+ transition.enableTransitionType(LayoutTransition.CHANGING);
+
mFloatingActionButtonController.scaleIn(AnimUtils.NO_DELAY);
}
diff --git a/InCallUI/src/com/android/incallui/CallCardPresenter.java b/InCallUI/src/com/android/incallui/CallCardPresenter.java
index cb378a687..ab93c2d8e 100644
--- a/InCallUI/src/com/android/incallui/CallCardPresenter.java
+++ b/InCallUI/src/com/android/incallui/CallCardPresenter.java
@@ -17,6 +17,8 @@
package com.android.incallui;
import android.Manifest;
+import android.app.Activity;
+import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -34,6 +36,7 @@ import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import com.android.incallui.CircularRevealFragment.OnCircularRevealCompleteListener;
import com.android.incallui.ContactInfoCache.ContactCacheEntry;
import com.android.incallui.ContactInfoCache.ContactInfoCacheCallback;
import com.android.incallui.InCallPresenter.InCallDetailsListener;
@@ -743,5 +746,6 @@ public class CallCardPresenter extends Presenter<CallCardPresenter.CallCardUi>
void setProgressSpinnerVisible(boolean visible);
void showManageConferenceCallButton(boolean visible);
boolean isManageConferenceVisible();
+ void animateForNewOutgoingCall();
}
}
diff --git a/InCallUI/src/com/android/incallui/CircularRevealActivity.java b/InCallUI/src/com/android/incallui/CircularRevealActivity.java
deleted file mode 100644
index 4dc58baa8..000000000
--- a/InCallUI/src/com/android/incallui/CircularRevealActivity.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2014 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.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Outline;
-import android.graphics.Point;
-import android.os.Bundle;
-import android.support.v4.content.LocalBroadcastManager;
-import android.view.Display;
-import android.view.View;
-import android.view.ViewAnimationUtils;
-import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnPreDrawListener;
-
-import com.android.contacts.common.interactions.TouchPointManager;
-import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
-
-/**
- * Lightweight activity used to display a circular reveal while InCallActivity is starting up.
- * A BroadcastReceiver is used to listen to broadcasts from a LocalBroadcastManager to finish
- * the activity at suitable times.
- */
-public class CircularRevealActivity extends Activity {
- private static final int REVEAL_DURATION = 333;
- public static final String EXTRA_THEME_COLORS = "extra_theme_colors";
- public static final String ACTION_CLEAR_DISPLAY = "action_clear_display";
-
- final BroadcastReceiver mClearDisplayReceiver = new BroadcastReceiver( ) {
- @Override
- public void onReceive(Context context, Intent intent) {
- clearDisplay();
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- overridePendingTransition(0, 0);
- setContentView(R.layout.outgoing_call_animation);
- prepareDecorViewFromIntent(getIntent());
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- if (!InCallPresenter.getInstance().isServiceBound()) {
- clearDisplay();
- }
- final IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_CLEAR_DISPLAY);
- LocalBroadcastManager.getInstance(this).registerReceiver(mClearDisplayReceiver, filter);
- }
-
- @Override
- protected void onStop() {
- LocalBroadcastManager.getInstance(this).unregisterReceiver(mClearDisplayReceiver);
- super.onStop();
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- setIntent(intent);
- prepareDecorViewFromIntent(intent);
- }
-
- private void prepareDecorViewFromIntent(Intent intent) {
- final Point touchPoint = intent.getParcelableExtra(TouchPointManager.TOUCH_POINT);
- final MaterialPalette palette = intent.getParcelableExtra(EXTRA_THEME_COLORS);
- setupDecorView(touchPoint, palette);
- }
-
- private void setupDecorView(final Point touchPoint, MaterialPalette palette) {
- final View view = getWindow().getDecorView();
-
- // The circle starts from an initial size of 0 so clip it such that it is invisible. When
- // the animation later starts, this clip will be clobbered by the circular reveal clip.
- // See ViewAnimationUtils.createCircularReveal.
- view.setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- // Using (0, 0, 0, 0) will not work since the outline will simply be treated as
- // an empty outline.
- outline.setOval(-1, -1, 0, 0);
- }
- });
- view.setClipToOutline(true);
-
- if (palette != null) {
- view.findViewById(R.id.outgoing_call_animation_circle).setBackgroundColor(
- palette.mPrimaryColor);
- getWindow().setStatusBarColor(palette.mSecondaryColor);
- }
-
- view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- final ViewTreeObserver vto = view.getViewTreeObserver();
- if (vto.isAlive()) {
- vto.removeOnPreDrawListener(this);
- }
- final Animator animator = getRevealAnimator(touchPoint);
- // Since this animator is a RenderNodeAnimator (native animator), add an arbitary
- // start delay to force the onAnimationStart callback to happen later on the UI
- // thread. Otherwise it would happen right away inside animator.start()
- animator.setStartDelay(5);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- InCallPresenter.getInstance().onCircularRevealStarted(
- CircularRevealActivity.this);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- view.setClipToOutline(false);
- super.onAnimationEnd(animation);
- }
- });
- animator.start();
- return false;
- }
- });
- }
-
- private void clearDisplay() {
- getWindow().getDecorView().setVisibility(View.INVISIBLE);
- finish();
- }
-
- @Override
- public void onBackPressed() {
- return;
- }
-
- public static void sendClearDisplayBroadcast(Context context) {
- LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(ACTION_CLEAR_DISPLAY));
- }
-
- private Animator getRevealAnimator(Point touchPoint) {
- final View view = getWindow().getDecorView();
- final Display display = getWindowManager().getDefaultDisplay();
- final Point size = new Point();
- display.getSize(size);
-
- int startX = size.x / 2;
- int startY = size.y / 2;
- if (touchPoint != null) {
- startX = touchPoint.x;
- startY = touchPoint.y;
- }
-
- final Animator valueAnimator = ViewAnimationUtils.createCircularReveal(view,
- startX, startY, 0, Math.max(size.x, size.y));
- valueAnimator.setDuration(REVEAL_DURATION);
- return valueAnimator;
- }
-}
diff --git a/InCallUI/src/com/android/incallui/CircularRevealFragment.java b/InCallUI/src/com/android/incallui/CircularRevealFragment.java
new file mode 100644
index 000000000..c2821792b
--- /dev/null
+++ b/InCallUI/src/com/android/incallui/CircularRevealFragment.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 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.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.graphics.Outline;
+import android.graphics.Point;
+import android.os.Bundle;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+
+import com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette;
+
+public class CircularRevealFragment extends Fragment {
+ static final String TAG = "CircularRevealFragment";
+
+ private Point mTouchPoint;
+ private OnCircularRevealCompleteListener mListener;
+ private boolean mAnimationStarted;
+
+ interface OnCircularRevealCompleteListener {
+ public void onCircularRevealComplete(FragmentManager fm);
+ }
+
+ public static void startCircularReveal(FragmentManager fm, Point touchPoint,
+ OnCircularRevealCompleteListener listener) {
+ fm.beginTransaction().add(R.id.main, new CircularRevealFragment(touchPoint, listener), TAG)
+ .commitAllowingStateLoss();
+ }
+
+ public static void endCircularReveal(FragmentManager fm) {
+ final Fragment fragment = fm.findFragmentByTag(TAG);
+ if (fragment != null) {
+ fm.beginTransaction().remove(fragment).commitAllowingStateLoss();
+ }
+ }
+
+ /**
+ * Empty constructor used only by the {@link FragmentManager}.
+ */
+ public CircularRevealFragment() {}
+
+ public CircularRevealFragment(Point touchPoint, OnCircularRevealCompleteListener listener) {
+ mTouchPoint = touchPoint;
+ mListener = listener;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (!mAnimationStarted) {
+ // Only run the animation once for each instance of the fragment
+ startOutgoingAnimation(InCallPresenter.getInstance().getThemeColors());
+ }
+ mAnimationStarted = true;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.outgoing_call_animation, container, false);
+ }
+
+ public void startOutgoingAnimation(MaterialPalette palette) {
+ final Activity activity = getActivity();
+ if (activity == null) {
+ Log.w(this, "Asked to do outgoing call animation when not attached");
+ return;
+ }
+
+ final View view = activity.getWindow().getDecorView();
+
+ // The circle starts from an initial size of 0 so clip it such that it is invisible.
+ // Otherwise the first frame is drawn with a fully opaque screen which causes jank. When
+ // the animation later starts, this clip will be clobbered by the circular reveal clip.
+ // See ViewAnimationUtils.createCircularReveal.
+ view.setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ // Using (0, 0, 0, 0) will not work since the outline will simply be treated as
+ // an empty outline.
+ outline.setOval(-1, -1, 0, 0);
+ }
+ });
+ view.setClipToOutline(true);
+
+ if (palette != null) {
+ view.findViewById(R.id.outgoing_call_animation_circle).setBackgroundColor(
+ palette.mPrimaryColor);
+ activity.getWindow().setStatusBarColor(palette.mSecondaryColor);
+ }
+
+ view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ final ViewTreeObserver vto = view.getViewTreeObserver();
+ if (vto.isAlive()) {
+ vto.removeOnPreDrawListener(this);
+ }
+ final Animator animator = getRevealAnimator(mTouchPoint);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setClipToOutline(false);
+ if (mListener != null) {
+ mListener.onCircularRevealComplete(getFragmentManager());
+ }
+ }
+ });
+ animator.start();
+ return false;
+ }
+ });
+ }
+
+ private Animator getRevealAnimator(Point touchPoint) {
+ final Activity activity = getActivity();
+ final View view = activity.getWindow().getDecorView();
+ final Display display = activity.getWindowManager().getDefaultDisplay();
+ final Point size = new Point();
+ display.getSize(size);
+
+ int startX = size.x / 2;
+ int startY = size.y / 2;
+ if (touchPoint != null) {
+ startX = touchPoint.x;
+ startY = touchPoint.y;
+ }
+
+ final Animator valueAnimator = ViewAnimationUtils.createCircularReveal(view,
+ startX, startY, 0, Math.max(size.x, size.y));
+ valueAnimator.setDuration(getResources().getInteger(R.integer.reveal_animation_duration));
+ return valueAnimator;
+ }
+}
diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java
index 32bee93a7..f692627a1 100644
--- a/InCallUI/src/com/android/incallui/InCallActivity.java
+++ b/InCallUI/src/com/android/incallui/InCallActivity.java
@@ -66,7 +66,6 @@ public class InCallActivity extends Activity {
public static final String SHOW_DIALPAD_EXTRA = "InCallActivity.show_dialpad";
public static final String DIALPAD_TEXT_EXTRA = "InCallActivity.dialpad_text";
public static final String NEW_OUTGOING_CALL_EXTRA = "InCallActivity.new_outgoing_call";
- public static final String SHOW_CIRCULAR_REVEAL_EXTRA = "InCallActivity.show_circular_reveal";
private CallButtonFragment mCallButtonFragment;
private CallCardFragment mCallCardFragment;
@@ -489,12 +488,9 @@ public class InCallActivity extends Activity {
}
}
- // This is only true in the case where an outgoing call is initiated by tapping
- // on the "Select account dialog", in which case we skip the initial animation. In
- // most other cases the circular reveal is done by OutgoingCallAnimationActivity.
- final boolean showCircularReveal =
- intent.getBooleanExtra(SHOW_CIRCULAR_REVEAL_EXTRA, false);
- mCallCardFragment.animateForNewOutgoingCall(touchPoint, showCircularReveal);
+ // Start animation for new outgoing call
+ CircularRevealFragment.startCircularReveal(getFragmentManager(), touchPoint,
+ InCallPresenter.getInstance());
// InCallActivity is responsible for disconnecting a new outgoing call if there
// is no way of making it (i.e. no valid call capable accounts)
diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java
index ce6d439d1..82ce58c11 100644
--- a/InCallUI/src/com/android/incallui/InCallPresenter.java
+++ b/InCallUI/src/com/android/incallui/InCallPresenter.java
@@ -16,14 +16,13 @@
package com.android.incallui;
-import android.app.Activity;
+import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccount;
import android.telecom.Phone;
@@ -57,7 +56,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
* that want to listen in on the in-call state changes.
* TODO: This class has become more of a state machine at this point. Consider renaming.
*/
-public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
+public class InCallPresenter implements CallList.Listener, InCallPhoneListener,
+ CircularRevealFragment.OnCircularRevealCompleteListener {
private static final String EXTRA_FIRST_TIME_SHOWN =
"com.android.incallui.intent.extra.FIRST_TIME_SHOWN";
@@ -97,6 +97,16 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
private boolean mAccountSelectionCancelled = false;
private InCallCameraManager mInCallCameraManager = null;
+ /**
+ * Whether or not we are currently bound and waiting for Telecom to send us a new call.
+ */
+ private boolean mBoundAndWaitingForOutgoingCall;
+ /**
+ * If there is no actual call currently in the call list, this will be used as a fallback
+ * to determine the theme color for InCallUI.
+ */
+ private PhoneAccountHandle mPendingPhoneAccountHandle;
+
private final Phone.Listener mPhoneListener = new Phone.Listener() {
@Override
public void onBringToForeground(Phone phone, boolean showDialpad) {
@@ -105,6 +115,9 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
}
@Override
public void onCallAdded(Phone phone, android.telecom.Call call) {
+ // Since a call has been added we are no longer waiting for Telecom to send us a
+ // call.
+ setBoundAndWaitingForOutgoingCall(false, null);
call.addListener(mCallListener);
}
@Override
@@ -156,20 +169,6 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
*/
private boolean mIsActivityPreviouslyStarted = false;
-
- /**
- * Whether or not to wait for the circular reveal animation to be started, to avoid stopping
- * the circular reveal animation activity before the animation is initiated.
- */
- private boolean mWaitForRevealAnimationStart = false;
-
- /**
- * Whether or not the CircularRevealAnimationActivity has started.
- */
- private boolean mCircularRevealActivityStarted = false;
-
- private boolean mShowDialpadOnStart = false;
-
/**
* Whether or not InCallService is bound to Telecom.
*/
@@ -177,8 +176,6 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
private Phone mPhone;
- private Handler mHandler = new Handler();
-
/** Display colors for the UI. Consists of a primary color and secondary (darker) color */
private MaterialPalette mThemeColors;
@@ -261,13 +258,6 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
}
private void attemptFinishActivity() {
- mWaitForRevealAnimationStart = false;
-
- Context context = mContext != null ? mContext : mInCallActivity;
- if (context != null) {
- CircularRevealActivity.sendClearDisplayBroadcast(context);
- }
-
final boolean doFinish = (mInCallActivity != null && isActivityStarted());
Log.i(this, "Hide in call UI: " + doFinish);
if (doFinish) {
@@ -457,7 +447,7 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
/**
* Given the call list, return the state in which the in-call screen should be.
*/
- public static InCallState getPotentialStateFromCallList(CallList callList) {
+ public InCallState getPotentialStateFromCallList(CallList callList) {
InCallState newState = InCallState.NO_CALLS;
@@ -479,9 +469,40 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
newState = InCallState.INCALL;
}
+ if (newState == InCallState.NO_CALLS) {
+ if (mBoundAndWaitingForOutgoingCall) {
+ return InCallState.OUTGOING;
+ }
+ }
+
return newState;
}
+ public boolean isBoundAndWaitingForOutgoingCall() {
+ return mBoundAndWaitingForOutgoingCall;
+ }
+
+ public void setBoundAndWaitingForOutgoingCall(boolean isBound, PhoneAccountHandle handle) {
+ // NOTE: It is possible for there to be a race and have handle become null before
+ // the circular reveal starts. This should not cause any problems because CallCardFragment
+ // should fallback to the actual call in the CallList at that point in time to determine
+ // the theme color.
+ Log.i(this, "setBoundAndWaitingForOutgoingCall: " + isBound);
+ mBoundAndWaitingForOutgoingCall = isBound;
+ mPendingPhoneAccountHandle = handle;
+ if (isBound && mInCallState == InCallState.NO_CALLS) {
+ mInCallState = InCallState.OUTGOING;
+ }
+ }
+
+ @Override
+ public void onCircularRevealComplete(FragmentManager fm) {
+ if (mInCallActivity != null) {
+ mInCallActivity.getCallCardFragment().animateForNewOutgoingCall();
+ CircularRevealFragment.endCircularReveal(mInCallActivity.getFragmentManager());
+ }
+ }
+
public void addIncomingCallListener(IncomingCallListener listener) {
Preconditions.checkNotNull(listener);
mIncomingCallListeners.add(listener);
@@ -714,8 +735,6 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
if (showing) {
mIsActivityPreviouslyStarted = true;
- } else {
- CircularRevealActivity.sendClearDisplayBroadcast(mContext);
}
for (InCallUiListener listener : mInCallUiListeners) {
@@ -1125,35 +1144,8 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
}
public void showInCall(final boolean showDialpad, final boolean newOutgoingCall) {
- if (mCircularRevealActivityStarted) {
- mWaitForRevealAnimationStart = true;
- mShowDialpadOnStart = showDialpad;
- Log.i(this, "Waiting for circular reveal completion to show InCallActivity");
- } else {
- Log.i(this, "Showing InCallActivity immediately");
- mContext.startActivity(getInCallIntent(showDialpad, newOutgoingCall,
- newOutgoingCall /* showCircularReveal */));
- }
- }
-
- public void onCircularRevealStarted(final Activity activity) {
- mCircularRevealActivityStarted = false;
- if (mWaitForRevealAnimationStart) {
- mWaitForRevealAnimationStart = false;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Log.i(this, "Showing InCallActivity after circular reveal");
- final Intent intent =
- getInCallIntent(mShowDialpadOnStart, true, false, false);
- activity.startActivity(intent);
- mShowDialpadOnStart = false;
- }
- });
- } else if (!mServiceBound) {
- CircularRevealActivity.sendClearDisplayBroadcast(mContext);
- return;
- }
+ Log.i(this, "Showing InCallActivity");
+ mContext.startActivity(getInCallIntent(showDialpad, newOutgoingCall));
}
public void onServiceBind() {
@@ -1161,6 +1153,7 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
}
public void onServiceUnbind() {
+ InCallPresenter.getInstance().setBoundAndWaitingForOutgoingCall(false, null);
mServiceBound = false;
}
@@ -1185,43 +1178,26 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
final PhoneAccountHandle accountHandle =
intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
- final MaterialPalette colors = getColorsFromPhoneAccountHandle(accountHandle);
final Point touchPoint = extras.getParcelable(TouchPointManager.TOUCH_POINT);
- mCircularRevealActivityStarted = true;
- mContext.startActivity(getAnimationIntent(touchPoint, colors));
- }
-
- private Intent getAnimationIntent(Point touchPoint, MaterialPalette palette) {
- final Intent intent = new Intent(mContext, CircularRevealActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
- intent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint);
- intent.putExtra(CircularRevealActivity.EXTRA_THEME_COLORS, palette);
- return intent;
- }
+ InCallPresenter.getInstance().setBoundAndWaitingForOutgoingCall(true, accountHandle);
- public Intent getInCallIntent(boolean showDialpad, boolean newOutgoingCall,
- boolean showCircularReveal) {
- return getInCallIntent(showDialpad, newOutgoingCall, showCircularReveal, true);
+ final Intent incallIntent = getInCallIntent(false, true);
+ incallIntent.putExtra(TouchPointManager.TOUCH_POINT, touchPoint);
+ mContext.startActivity(incallIntent);
}
- public Intent getInCallIntent(boolean showDialpad, boolean newOutgoingCall,
- boolean showCircularReveal, boolean newTask) {
+ public Intent getInCallIntent(boolean showDialpad, boolean newOutgoingCall) {
final Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
- | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
- if (newTask) {
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
+ | Intent.FLAG_ACTIVITY_NO_USER_ACTION
+ | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(mContext, InCallActivity.class);
if (showDialpad) {
intent.putExtra(InCallActivity.SHOW_DIALPAD_EXTRA, true);
}
intent.putExtra(InCallActivity.NEW_OUTGOING_CALL_EXTRA, newOutgoingCall);
- intent.putExtra(InCallActivity.SHOW_CIRCULAR_REVEAL_EXTRA, showCircularReveal);
return intent;
}
@@ -1359,7 +1335,11 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener {
}
private MaterialPalette getColorsFromCall(Call call) {
- return getColorsFromPhoneAccountHandle(call == null ? null : call.getAccountHandle());
+ if (call == null) {
+ return getColorsFromPhoneAccountHandle(mPendingPhoneAccountHandle);
+ } else {
+ return getColorsFromPhoneAccountHandle(call.getAccountHandle());
+ }
}
private MaterialPalette getColorsFromPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
index 99392d9fd..89192f882 100644
--- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java
+++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java
@@ -627,8 +627,7 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener {
private PendingIntent createLaunchPendingIntent() {
final Intent intent = InCallPresenter.getInstance().getInCallIntent(
- false /* showDialpad */, false /* newOutgoingCall */,
- false /* showCircularReveal */);
+ false /* showDialpad */, false /* newOutgoingCall */);
// PendingIntent that can be used to launch the InCallActivity. The
// system fires off this intent if the user pulls down the windowshade