diff options
author | Yorke Lee <yorkelee@google.com> | 2014-05-15 09:35:23 -0700 |
---|---|---|
committer | Yorke Lee <yorkelee@google.com> | 2014-05-15 14:41:06 -0700 |
commit | 8ef5cf3987ab9f7988d0ce7b033270095e05481d (patch) | |
tree | 62c1473a39bb8e7c3e62fdfb7226322b602ceeb0 | |
parent | cb2f51bf1acf387f391ca9c8cae8a2344eb2936a (diff) |
First pass at Dialer to InCall transition
* Modify InCallActivity to perform an animation only on a new outgoing
call
* Add an animated scrim to call_card.xml that serves as the backdrop
of the full screen animated reveal
* Add resize animation
* Add circular reveal animation
Bug: 14820894
Change-Id: Iaa7e87e8a96dcd269e444a40eadac9d912625c01
-rw-r--r-- | InCallUI/res/layout/call_button_fragment.xml | 1 | ||||
-rw-r--r-- | InCallUI/res/layout/call_card.xml | 174 | ||||
-rw-r--r-- | InCallUI/res/layout/primary_call_info.xml | 5 | ||||
-rw-r--r-- | InCallUI/res/values/styles.xml | 9 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/CallCardFragment.java | 106 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/InCallActivity.java | 7 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/InCallPresenter.java | 13 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/StatusBarNotifier.java | 3 | ||||
-rw-r--r-- | InCallUI/src/com/android/incallui/animation/ResizeAnimation.java | 52 |
9 files changed, 280 insertions, 90 deletions
diff --git a/InCallUI/res/layout/call_button_fragment.xml b/InCallUI/res/layout/call_button_fragment.xml index b455241d8..cf21b1dd9 100644 --- a/InCallUI/res/layout/call_button_fragment.xml +++ b/InCallUI/res/layout/call_button_fragment.xml @@ -33,7 +33,6 @@ android:id="@+id/bottomButtons" android:orientation="vertical" android:layout_width="match_parent" - android:background="#0000ff" android:layout_margin="0dp" android:padding="0dp" android:layout_height="wrap_content" diff --git a/InCallUI/res/layout/call_card.xml b/InCallUI/res/layout/call_card.xml index f2e5b1865..bb12725ff 100644 --- a/InCallUI/res/layout/call_card.xml +++ b/InCallUI/res/layout/call_card.xml @@ -16,102 +16,128 @@ ~ limitations under the License --> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/call_card" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" > - - <!-- The main content of the CallCard is either one or two "call info" - blocks, depending on whether one or two lines are in use. + android:layout_height="match_parent" > + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" > - The call_info blocks are stacked vertically inside a CallCard (LinearLayout), - each with layout_weight="1". If only one line is in use (i.e. the - common case) then the 2nd call info will be GONE and thus the 1st one - will expand to fill the full height of the CallCard. --> + <!-- The main content of the CallCard is either one or two "call info" + blocks, depending on whether one or two lines are in use. - <!-- Primary "call card" block, for the foreground call. --> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="5" > + The call_info blocks are stacked vertically inside a CallCard (LinearLayout), + each with layout_weight="1". If only one line is in use (i.e. the + common case) then the 2nd call info will be GONE and thus the 1st one + will expand to fill the full height of the CallCard. --> - <LinearLayout + <!-- Primary "call card" block, for the foreground call. --> + <FrameLayout android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical" > + android:layout_height="0dp" + android:layout_weight="5" > <LinearLayout android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" - android:translationZ="@dimen/primary_call_translation_z" > - - <include android:id="@+id/primary_call_info" - layout="@layout/primary_call_info" /> + android:layout_height="match_parent" + android:orientation="vertical" > - <fragment android:name="com.android.incallui.CallButtonFragment" - android:id="@+id/callButtonFragment" + <LinearLayout + android:id="@+id/primary_call_info_container" android:layout_width="match_parent" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content" + android:orientation="vertical" + android:translationZ="@dimen/primary_call_translation_z" + android:background="@color/incall_call_banner_background_color" + > - </LinearLayout> + <include layout="@layout/primary_call_info" /> - <FrameLayout - android:layout_width="match_parent" - android:layout_height="match_parent" > + <fragment android:name="com.android.incallui.CallButtonFragment" + android:id="@+id/callButtonFragment" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> - <!-- Contact photo for primary call info --> - <ImageView android:id="@+id/photo" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="top|center_horizontal" - android:scaleType="centerCrop" - android:contentDescription="@string/contactPhoto" - android:src="@drawable/picture_unknown"/> - - <fragment android:name="com.android.incallui.DialpadFragment" - android:id="@+id/dialpadFragment" - android:layout_width="match_parent" - android:layout_height="match_parent" /> + </LinearLayout> - <fragment android:name="com.android.incallui.AnswerFragment" - android:id="@+id/answerFragment" + <FrameLayout android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_alignParentBottom="true" - android:layout_centerHorizontal="true" - android:gravity="top" - android:layout_gravity="bottom|center_horizontal" - android:layout_marginBottom="@dimen/glowpadview_margin_bottom" - android:visibility="gone" /> + android:layout_height="match_parent" > + + <!-- Contact photo for primary call info --> + <ImageView android:id="@+id/photo" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="top|center_horizontal" + android:scaleType="centerCrop" + android:contentDescription="@string/contactPhoto" + android:src="@drawable/picture_unknown"/> + + <fragment android:name="com.android.incallui.DialpadFragment" + android:id="@+id/dialpadFragment" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <fragment android:name="com.android.incallui.AnswerFragment" + android:id="@+id/answerFragment" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_alignParentBottom="true" + android:layout_centerHorizontal="true" + android:gravity="top" + android:layout_gravity="bottom|center_horizontal" + android:layout_marginBottom="@dimen/glowpadview_margin_bottom" + android:visibility="gone" /> + + </FrameLayout> - </FrameLayout> + </LinearLayout> - </LinearLayout> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center"> - <FrameLayout - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="bottom|center"> - - <ImageButton android:id="@+id/endButton" - android:layout_width="@dimen/floating_action_button_width" - android:layout_height="@dimen/floating_action_button_height" - android:layout_marginBottom="@dimen/end_call_button_margin_bottom" - android:background="@drawable/end_call_background" - android:src="@drawable/fab_ic_end_call" - android:contentDescription="@string/onscreenEndCallText" /> + <ImageButton android:id="@+id/endButton" + android:layout_width="@dimen/floating_action_button_width" + android:layout_height="@dimen/floating_action_button_height" + android:layout_marginBottom="@dimen/end_call_button_margin_bottom" + android:background="@drawable/end_call_background" + android:src="@drawable/fab_ic_end_call" + android:contentDescription="@string/onscreenEndCallText" /> + </FrameLayout> </FrameLayout> - </FrameLayout> + <!-- Secondary "Call info" block, for the background ("on hold") call. --> + <ViewStub android:id="@+id/secondary_call_info" + android:layout="@layout/secondary_call_info" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" /> + + </LinearLayout> - <!-- Secondary "Call info" block, for the background ("on hold") call. --> - <ViewStub android:id="@+id/secondary_call_info" - android:layout="@layout/secondary_call_info" + <!-- Animated scrim that fills the whole screen and then shrinks to show call details --> + <LinearLayout + android:id="@+id/animated_scrim" android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" /> + android:layout_height="match_parent" + android:visibility="gone" + android:orientation="vertical"> + + <Space + android:id="@+id/animated_scrim_spacer" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="0" /> + <View + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:background="@color/incall_call_banner_background_color" /> + </LinearLayout> -</LinearLayout> +</FrameLayout> diff --git a/InCallUI/res/layout/primary_call_info.xml b/InCallUI/res/layout/primary_call_info.xml index db18e4dfa..d7a2b9d79 100644 --- a/InCallUI/res/layout/primary_call_info.xml +++ b/InCallUI/res/layout/primary_call_info.xml @@ -18,7 +18,7 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" > <LinearLayout android:layout_width="match_parent" @@ -38,8 +38,7 @@ android:paddingStart="@dimen/call_banner_side_padding" android:paddingEnd="@dimen/call_banner_side_padding" android:paddingTop="@dimen/call_banner_primary_call_top_padding" - android:paddingBottom="@dimen/call_banner_top_bottom_padding" - android:background="@color/incall_call_banner_background_color"> + android:paddingBottom="@dimen/call_banner_top_bottom_padding" > <!-- Name (or the phone number, if we don't have a name to display). --> <LinearLayout android:id="@+id/stateAndName" diff --git a/InCallUI/res/values/styles.xml b/InCallUI/res/values/styles.xml index c5b5d4722..747a324e4 100644 --- a/InCallUI/res/values/styles.xml +++ b/InCallUI/res/values/styles.xml @@ -112,13 +112,16 @@ <item name="android:taskToFrontExitAnimation">@anim/activity_open_exit</item> </style> - <!-- Theme for the InCallActivity activity. This gives us a totally black - window background instead of the default dark grey. (We don't just use + <!-- 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 holo style. --> <style name="Theme.InCallScreen" parent="@android:style/Theme.Holo.NoActionBar"> - <item name="android:windowBackground">@android:color/black</item> <item name="android:windowAnimationStyle">@style/InCallAnimationStyle</item> + <item name="android:windowIsTranslucent">true</item> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowContentOverlay">@null</item> + <item name="android:windowNoTitle">true</item> </style> <style name="PrimaryCallInfoPrimaryCallBanner"> diff --git a/InCallUI/src/com/android/incallui/CallCardFragment.java b/InCallUI/src/com/android/incallui/CallCardFragment.java index bd4864161..5998a3f88 100644 --- a/InCallUI/src/com/android/incallui/CallCardFragment.java +++ b/InCallUI/src/com/android/incallui/CallCardFragment.java @@ -16,23 +16,34 @@ package com.android.incallui; +import android.animation.Animator.AnimatorListener; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.app.Activity; import android.content.Context; +import android.graphics.Point; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.telephony.DisconnectCause; import android.text.TextUtils; -import android.view.Gravity; +import android.view.Display; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; import android.view.ViewStub; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.accessibility.AccessibilityEvent; -import android.widget.Button; +import android.view.animation.Animation; import android.widget.ImageView; import android.widget.TextView; +import com.android.contacts.common.animation.AnimationListenerAdapter; import com.android.contacts.common.util.ViewUtil; +import com.android.incallui.animation.ResizeAnimation; import java.util.List; @@ -42,6 +53,9 @@ import java.util.List; public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPresenter.CallCardUi> implements CallCardPresenter.CallCardUi { + private static final int REVEAL_ANIMATION_DURATION = 800; + private static final int SLIDE_ANIMATION_DURATION = 400; + // Primary caller info private TextView mPhoneNumber; private TextView mNumberLabel; @@ -51,17 +65,27 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr private ImageView mPhoto; private TextView mElapsedTime; + // Container view that houses the entire primary call card, including the call buttons + private View mPrimaryCallCardContainer; + // Container view that houses the primary call information + private View mPrimaryCallInfo; + private View mCallButtonsContainer; + // Secondary caller info private ViewStub mSecondaryCallInfo; private TextView mSecondaryCallName; private ImageView mSecondaryPhoto; private View mSecondaryPhotoOverlay; + private View mAnimatedScrim; + private View mEndCallButton; // Cached DisplayMetrics density. private float mDensity; + private final AnimatorListener mAnimatedScrimListener = new AnimatedScrimListener(); + @Override CallCardPresenter.CallCardUi getUi() { return this; @@ -109,6 +133,10 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr mCallStateLabel = (TextView) view.findViewById(R.id.callStateLabel); mCallTypeLabel = (TextView) view.findViewById(R.id.callTypeLabel); mElapsedTime = (TextView) view.findViewById(R.id.elapsedTime); + mPrimaryCallCardContainer = view.findViewById(R.id.primary_call_info_container); + mPrimaryCallInfo = view.findViewById(R.id.primary_call_banner); + mAnimatedScrim = view.findViewById(R.id.animated_scrim); + mCallButtonsContainer = view.findViewById(R.id.callButtonFragment); mEndCallButton = view.findViewById(R.id.endButton); mEndCallButton.setOnClickListener(new View.OnClickListener() { @@ -507,4 +535,78 @@ public class CallCardFragment extends BaseFragment<CallCardPresenter, CallCardPr eventText.add(null); } } + + public void animateForNewOutgoingCall() { + final View animatedSpacer = getView().findViewById(R.id.animated_scrim_spacer); + + mAnimatedScrim.setVisibility(View.VISIBLE); + mAnimatedScrim.getLayoutParams().height = LayoutParams.MATCH_PARENT; + mAnimatedScrim.requestLayout(); + + final ViewTreeObserver observer = getView().getViewTreeObserver(); + observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + final ViewTreeObserver observer = getView().getViewTreeObserver(); + if (!observer.isAlive()) { + return; + } + observer.removeOnGlobalLayoutListener(this); + + // Prepare the state of views before the circular reveal animation + final int targetHeight = mPrimaryCallCardContainer.getHeight(); + animatedSpacer.getLayoutParams().height = targetHeight; + animatedSpacer.requestLayout(); + + mPrimaryCallInfo.setAlpha(0); + mCallButtonsContainer.setAlpha(0); + + performAnimatedReveal(mAnimatedScrimListener); + } + }); + } + + private void performAnimatedReveal(AnimatorListener listener) { + final Activity activity = getActivity(); + final View view = activity.getWindow().getDecorView(); + final Display display = activity.getWindowManager().getDefaultDisplay(); + final Point size = new Point(); + display.getSize(size); + + final ValueAnimator valueAnimator = view.createRevealAnimator(size.x / 2, size.y / 2, + 0, Math.max(size.x, size.y)); + valueAnimator.setDuration(REVEAL_ANIMATION_DURATION); + valueAnimator.addListener(listener); + valueAnimator.start(); + } + + private final class AnimatedScrimListener extends AnimatorListenerAdapter { + @Override + public void onAnimationEnd(Animator animation) { + final int width = mAnimatedScrim.getWidth(); + ResizeAnimation resizeAnimation = + new ResizeAnimation(mAnimatedScrim, width, width, mAnimatedScrim.getHeight(), + 0); + resizeAnimation.setDuration(SLIDE_ANIMATION_DURATION); + resizeAnimation.setAnimationListener(new AnimationListenerAdapter() { + @Override + public void onAnimationStart(Animation animation) { + // Prepare the state of views before the scrim's sliding up animation + mEndCallButton.setTranslationY(200); + mEndCallButton.animate().translationY(0) + .setDuration(SLIDE_ANIMATION_DURATION); + mPrimaryCallInfo.animate().alpha(1).withLayer() + .setDuration(SLIDE_ANIMATION_DURATION); + mCallButtonsContainer.animate().alpha(1).withLayer() + .setDuration(SLIDE_ANIMATION_DURATION); + } + + @Override + public void onAnimationEnd(Animation animation) { + mAnimatedScrim.setVisibility(View.GONE); + } + }); + mAnimatedScrim.startAnimation(resizeAnimation); + } + }; } diff --git a/InCallUI/src/com/android/incallui/InCallActivity.java b/InCallUI/src/com/android/incallui/InCallActivity.java index 5262045f2..7769a0b7b 100644 --- a/InCallUI/src/com/android/incallui/InCallActivity.java +++ b/InCallUI/src/com/android/incallui/InCallActivity.java @@ -41,6 +41,7 @@ import com.android.incallui.Call.State; public class InCallActivity extends Activity { public static final String SHOW_DIALPAD_EXTRA = "InCallActivity.show_dialpad"; + public static final String NEW_OUTGOING_CALL = "InCallActivity.new_outgoing_call"; private static final int INVALID_RES_ID = -1; @@ -83,6 +84,8 @@ public class InCallActivity extends Activity { setContentView(R.layout.incall_screen); initializeInCall(); + + internalResolveIntent(getIntent()); Log.d(this, "onCreate(): exit"); } @@ -342,6 +345,10 @@ public class InCallActivity extends Activity { relaunchedFromDialer(showDialpad); } + if (intent.getBooleanExtra(NEW_OUTGOING_CALL, false)) { + mCallCardFragment.animateForNewOutgoingCall(); + } + return; } } diff --git a/InCallUI/src/com/android/incallui/InCallPresenter.java b/InCallUI/src/com/android/incallui/InCallPresenter.java index ac6835367..14c2a8020 100644 --- a/InCallUI/src/com/android/incallui/InCallPresenter.java +++ b/InCallUI/src/com/android/incallui/InCallPresenter.java @@ -375,7 +375,7 @@ public class InCallPresenter implements CallList.Listener { Call call = mCallList.getIncomingCall(); if (call != null) { TelecommAdapter.getInstance().answerCall(call.getCallId()); - showInCall(false); + showInCall(false, false/* newOutgoingCall */); } } @@ -450,7 +450,7 @@ public class InCallPresenter implements CallList.Listener { // 3. We are in a state where we want to show the incall ui if (mIsActivityPreviouslyStarted && !isShowingInCallUi() && mInCallState != InCallState.NO_CALLS) { - showInCall(showDialpad); + showInCall(showDialpad, false /* newOutgoingCall */); } } @@ -635,7 +635,7 @@ public class InCallPresenter implements CallList.Listener { if (showCallUi) { Log.i(this, "Start in call UI"); - showInCall(false); + showInCall(false /* showDialpad */, true /* newOutgoingCall */); } else if (startStartupSequence) { Log.i(this, "Start Full Screen in call UI"); @@ -722,11 +722,11 @@ public class InCallPresenter implements CallList.Listener { } } - private void showInCall(boolean showDialpad) { - mContext.startActivity(getInCallIntent(showDialpad)); + private void showInCall(boolean showDialpad, boolean newOutgoingCall) { + mContext.startActivity(getInCallIntent(showDialpad, newOutgoingCall)); } - public Intent getInCallIntent(boolean showDialpad) { + public Intent getInCallIntent(boolean showDialpad, boolean newOutgoingCall) { final Intent intent = new Intent(Intent.ACTION_MAIN, null); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS @@ -736,6 +736,7 @@ public class InCallPresenter implements CallList.Listener { intent.putExtra(InCallActivity.SHOW_DIALPAD_EXTRA, true); } + intent.putExtra(InCallActivity.NEW_OUTGOING_CALL, newOutgoingCall); return intent; } diff --git a/InCallUI/src/com/android/incallui/StatusBarNotifier.java b/InCallUI/src/com/android/incallui/StatusBarNotifier.java index c28b98de2..b7b36d87d 100644 --- a/InCallUI/src/com/android/incallui/StatusBarNotifier.java +++ b/InCallUI/src/com/android/incallui/StatusBarNotifier.java @@ -546,7 +546,8 @@ public class StatusBarNotifier implements InCallPresenter.InCallStateListener { } private PendingIntent createLaunchPendingIntent() { - final Intent intent = InCallPresenter.getInstance().getInCallIntent(/*showdialpad=*/false); + final Intent intent = InCallPresenter.getInstance().getInCallIntent( + 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 diff --git a/InCallUI/src/com/android/incallui/animation/ResizeAnimation.java b/InCallUI/src/com/android/incallui/animation/ResizeAnimation.java new file mode 100644 index 000000000..3151ffbf7 --- /dev/null +++ b/InCallUI/src/com/android/incallui/animation/ResizeAnimation.java @@ -0,0 +1,52 @@ +/* + * 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.animation; + +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +public class ResizeAnimation extends Animation { + private final int mStartWidth; + private final int mStartHeight; + private final int mEndWidth; + private final int mEndHeight; + private final View mView; + + public ResizeAnimation(View view, int startWidth, int endWidth, int startHeight, + int endHeight) { + this.mView = view; + this.mStartWidth = startWidth; + this.mStartHeight = startHeight; + this.mEndWidth = endWidth; + this.mEndHeight = endHeight; + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + int width = (int) (mStartWidth + (mEndWidth - mStartWidth) * interpolatedTime); + int height = (int) (mStartHeight + (mEndHeight - mStartHeight) * interpolatedTime); + mView.getLayoutParams().width = width; + mView.getLayoutParams().height = height; + mView.requestLayout(); + } + + @Override + public boolean willChangeBounds() { + return true; + } +}
\ No newline at end of file |