diff options
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 6c582131b..9dc703a2e 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 318d8695e..0343ed6ca 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 @@ -155,20 +168,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. */ @@ -176,8 +175,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; @@ -260,13 +257,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) { @@ -455,7 +445,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; @@ -477,9 +467,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); @@ -712,8 +733,6 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { if (showing) { mIsActivityPreviouslyStarted = true; - } else { - CircularRevealActivity.sendClearDisplayBroadcast(mContext); } for (InCallUiListener listener : mInCallUiListeners) { @@ -1114,35 +1133,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() { @@ -1150,6 +1142,7 @@ public class InCallPresenter implements CallList.Listener, InCallPhoneListener { } public void onServiceUnbind() { + InCallPresenter.getInstance().setBoundAndWaitingForOutgoingCall(false, null); mServiceBound = false; } @@ -1174,43 +1167,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; } @@ -1348,7 +1324,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 |