Loading src/com/android/contacts/activities/PeopleActivity.java +6 −1 Original line number Diff line number Diff line Loading @@ -560,6 +560,11 @@ public class PeopleActivity extends ContactsActivity case ContactsRequest.ACTION_VIEW_CONTACT: // We redirect this intent to the detail activity on 1-pane, so we don't get // here. It's only for 2-pane. Uri currentlyLoadedContactUri = mContactDetailFragment.getUri(); if (currentlyLoadedContactUri != null && !mRequest.getContactUri().equals(currentlyLoadedContactUri)) { mContactDetailsView.setMaskVisibility(true); } tabToOpen = TabState.ALL; break; case ContactsRequest.ACTION_GROUP: Loading Loading @@ -612,7 +617,7 @@ public class PeopleActivity extends ContactsActivity // If we are switching from one group to another, do a cross-fade if (mGroupDetailFragment != null && mGroupDetailFragment.getGroupUri() != null && !UriUtils.areEqual(mGroupDetailFragment.getGroupUri(), groupUri)) { mGroupDetailsView.startTransition(mGroupDetailFragment.getView(), false); mGroupDetailsView.startMaskTransition(false); } mGroupDetailFragment.loadGroup(groupUri); invalidateOptionsMenuIfNeeded(); Loading src/com/android/contacts/detail/ContactDetailFragment.java +6 −0 Original line number Diff line number Diff line Loading @@ -356,6 +356,9 @@ public class ContactDetailFragment extends Fragment implements FragmentKeyListen mShowStaticPhoto = showPhoto; } /** * Shows the contact detail with a message indicating there are no contact details. */ public void showEmptyState() { setData(null, null); } Loading Loading @@ -406,6 +409,9 @@ public class ContactDetailFragment extends Fragment implements FragmentKeyListen if (mContactData == null) { mView.setVisibility(View.INVISIBLE); if (mStaticPhotoContainer != null) { mStaticPhotoContainer.setVisibility(View.GONE); } mAllEntries.clear(); if (mAdapter != null) { mAdapter.notifyDataSetChanged(); Loading src/com/android/contacts/detail/ContactDetailLayoutController.java +2 −3 Original line number Diff line number Diff line Loading @@ -291,8 +291,7 @@ public class ContactDetailLayoutController { if (PhoneCapabilityTester.isUsingTwoPanes(mActivity)) { // Tablet: If we already showed data before, we want to cross-fade from screen to screen if (contactWasLoaded && mTransitionAnimationView != null && isDifferentContact) { mTransitionAnimationView.startTransition( mViewContainer, mContactData == null); mTransitionAnimationView.startMaskTransition(mContactData == null); } } else { // Small screen: We are on our own screen. Fade the data in, but only the first time Loading Loading @@ -367,7 +366,7 @@ public class ContactDetailLayoutController { // This is screen is very hard to animate properly, because there is such a hard // cut from the regular version. A proper animation would have to reflow text // and move things around. Doing a simple cross-fade instead. mTransitionAnimationView.startTransition(mViewContainer, false); mTransitionAnimationView.startMaskTransition(false); } // Set the contact data (hide the static photo because the photo will already be in Loading src/com/android/contacts/util/ImageViewDrawableSetter.java +7 −3 Original line number Diff line number Diff line Loading @@ -39,10 +39,10 @@ public class ImageViewDrawableSetter { private ImageView mTarget; private byte[] mCompressed; private Drawable mPreviousDrawable; private int mDurationInMillis = 0; private static final String TAG = "ImageViewDrawableSetter"; public ImageViewDrawableSetter() { } public ImageViewDrawableSetter(ImageView target) { Loading @@ -54,6 +54,10 @@ public class ImageViewDrawableSetter { setCompressedImage(contactData.getPhotoBinaryData()); } public void setTransitionDuration(int durationInMillis) { mDurationInMillis = durationInMillis; } public ImageView getTarget() { return mTarget; } Loading Loading @@ -97,7 +101,7 @@ public class ImageViewDrawableSetter { // If we don't have a new Drawable, something went wrong... bail out. if (newDrawable == null) return previousBitmap(); if (mPreviousDrawable == null) { if (mPreviousDrawable == null || mDurationInMillis == 0) { // Set the new one immediately. mTarget.setImageDrawable(newDrawable); } else { Loading @@ -107,7 +111,7 @@ public class ImageViewDrawableSetter { beforeAndAfter[1] = newDrawable; final TransitionDrawable transition = new TransitionDrawable(beforeAndAfter); mTarget.setImageDrawable(transition); transition.startTransition(200); transition.startTransition(mDurationInMillis); } // Remember this for next time, so that we can transition from it to the Loading src/com/android/contacts/widget/TransitionAnimationView.java +34 −76 Original line number Diff line number Diff line Loading @@ -15,30 +15,20 @@ */ package com.android.contacts.widget; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; /** * A container for a view that needs to have exit/enter animations when rebinding data. * After rebinding the contents, the following call should be made (where child is the only visible) * child * <pre> * TransitionAnimationView.startAnimation(child); * </pre> * A container that places a masking view on top of all other views. The masking view can be * faded in and out. Currently, the masking view is solid color white. */ public class TransitionAnimationView extends FrameLayout implements AnimatorListener { private View mPreviousStateView; private Bitmap mPreviousStateBitmap; private ObjectAnimator mPreviousAnimator; public class TransitionAnimationView extends FrameLayout { private View mMaskingView; private ObjectAnimator mAnimator; public TransitionAnimationView(Context context) { this(context, null, 0); Loading @@ -55,75 +45,43 @@ public class TransitionAnimationView extends FrameLayout implements AnimatorList @Override protected void onFinishInflate() { super.onFinishInflate(); mPreviousStateView = new View(getContext()); mPreviousStateView.setVisibility(View.INVISIBLE); mPreviousStateView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, mMaskingView = new View(getContext()); mMaskingView.setVisibility(View.INVISIBLE); mMaskingView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); addView(mPreviousStateView); mMaskingView.setBackgroundColor(Color.WHITE); addView(mMaskingView); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mPreviousStateView.setBackgroundDrawable(null); if (mPreviousStateBitmap != null) { mPreviousStateBitmap.recycle(); mPreviousStateBitmap = null; } } public void startTransition(View view, boolean closing) { if (mPreviousAnimator != null && mPreviousAnimator.isRunning()) { mPreviousAnimator.end(); } if (view.getVisibility() != View.VISIBLE) { if (!closing) { mPreviousAnimator = ObjectAnimator.ofFloat(view, View.ALPHA, 0.0f, 1.0f); mPreviousAnimator.start(); } } else if (closing) { mPreviousAnimator = ObjectAnimator.ofFloat(view, View.ALPHA, 1.0f, 0.0f); mPreviousAnimator.start(); public void setMaskVisibility(boolean flag) { if (flag) { mMaskingView.setAlpha(1.0f); mMaskingView.setVisibility(View.VISIBLE); } else { if (view.getWidth() > 0 && view.getHeight() > 0) { // Take a "screenshot" of the current state of the screen and show that on top // of the real content. Then, fade that out. mPreviousStateBitmap = Bitmap.createBitmap( view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); mPreviousStateView.setBackgroundDrawable( new BitmapDrawable(getContext().getResources(), mPreviousStateBitmap)); mPreviousStateView.setLayoutParams(view.getLayoutParams()); mPreviousStateBitmap.eraseColor(Color.WHITE); Canvas canvas = new Canvas(mPreviousStateBitmap); view.draw(canvas); canvas.setBitmap(null); mPreviousStateView.setVisibility(View.VISIBLE); mPreviousAnimator = ObjectAnimator.ofFloat(mPreviousStateView, View.ALPHA, 1.0f, 0.0f); mPreviousAnimator.start(); } } mMaskingView.setVisibility(View.INVISIBLE); } @Override public void onAnimationEnd(Animator animation) { mPreviousStateView.setVisibility(View.INVISIBLE); mPreviousStateView.setBackgroundDrawable(null); mPreviousStateBitmap.recycle(); mPreviousStateBitmap = null; mPreviousAnimator = null; } @Override public void onAnimationCancel(Animator animation) { /** * Starts the transition of showing or hiding the mask. * If showMask is true, the mask will be set to be invisible then fade into hide the other * views in this container. If showMask is false, the mask will be set to be hide other views * initially. Then, the other views in this container will be revealed. */ public void startMaskTransition(boolean showMask) { // Stop any animation that may still be running. if (mAnimator != null && mAnimator.isRunning()) { mAnimator.end(); } @Override public void onAnimationStart(Animator animation) { mMaskingView.setVisibility(View.VISIBLE); if (showMask) { mAnimator = ObjectAnimator.ofFloat(mMaskingView, View.ALPHA, 0.0f, 1.0f); mAnimator.start(); } else { // asked to hide the view mAnimator = ObjectAnimator.ofFloat(mMaskingView, View.ALPHA, 1.0f, 0.0f); mAnimator.start(); } @Override public void onAnimationRepeat(Animator animation) { } } Loading
src/com/android/contacts/activities/PeopleActivity.java +6 −1 Original line number Diff line number Diff line Loading @@ -560,6 +560,11 @@ public class PeopleActivity extends ContactsActivity case ContactsRequest.ACTION_VIEW_CONTACT: // We redirect this intent to the detail activity on 1-pane, so we don't get // here. It's only for 2-pane. Uri currentlyLoadedContactUri = mContactDetailFragment.getUri(); if (currentlyLoadedContactUri != null && !mRequest.getContactUri().equals(currentlyLoadedContactUri)) { mContactDetailsView.setMaskVisibility(true); } tabToOpen = TabState.ALL; break; case ContactsRequest.ACTION_GROUP: Loading Loading @@ -612,7 +617,7 @@ public class PeopleActivity extends ContactsActivity // If we are switching from one group to another, do a cross-fade if (mGroupDetailFragment != null && mGroupDetailFragment.getGroupUri() != null && !UriUtils.areEqual(mGroupDetailFragment.getGroupUri(), groupUri)) { mGroupDetailsView.startTransition(mGroupDetailFragment.getView(), false); mGroupDetailsView.startMaskTransition(false); } mGroupDetailFragment.loadGroup(groupUri); invalidateOptionsMenuIfNeeded(); Loading
src/com/android/contacts/detail/ContactDetailFragment.java +6 −0 Original line number Diff line number Diff line Loading @@ -356,6 +356,9 @@ public class ContactDetailFragment extends Fragment implements FragmentKeyListen mShowStaticPhoto = showPhoto; } /** * Shows the contact detail with a message indicating there are no contact details. */ public void showEmptyState() { setData(null, null); } Loading Loading @@ -406,6 +409,9 @@ public class ContactDetailFragment extends Fragment implements FragmentKeyListen if (mContactData == null) { mView.setVisibility(View.INVISIBLE); if (mStaticPhotoContainer != null) { mStaticPhotoContainer.setVisibility(View.GONE); } mAllEntries.clear(); if (mAdapter != null) { mAdapter.notifyDataSetChanged(); Loading
src/com/android/contacts/detail/ContactDetailLayoutController.java +2 −3 Original line number Diff line number Diff line Loading @@ -291,8 +291,7 @@ public class ContactDetailLayoutController { if (PhoneCapabilityTester.isUsingTwoPanes(mActivity)) { // Tablet: If we already showed data before, we want to cross-fade from screen to screen if (contactWasLoaded && mTransitionAnimationView != null && isDifferentContact) { mTransitionAnimationView.startTransition( mViewContainer, mContactData == null); mTransitionAnimationView.startMaskTransition(mContactData == null); } } else { // Small screen: We are on our own screen. Fade the data in, but only the first time Loading Loading @@ -367,7 +366,7 @@ public class ContactDetailLayoutController { // This is screen is very hard to animate properly, because there is such a hard // cut from the regular version. A proper animation would have to reflow text // and move things around. Doing a simple cross-fade instead. mTransitionAnimationView.startTransition(mViewContainer, false); mTransitionAnimationView.startMaskTransition(false); } // Set the contact data (hide the static photo because the photo will already be in Loading
src/com/android/contacts/util/ImageViewDrawableSetter.java +7 −3 Original line number Diff line number Diff line Loading @@ -39,10 +39,10 @@ public class ImageViewDrawableSetter { private ImageView mTarget; private byte[] mCompressed; private Drawable mPreviousDrawable; private int mDurationInMillis = 0; private static final String TAG = "ImageViewDrawableSetter"; public ImageViewDrawableSetter() { } public ImageViewDrawableSetter(ImageView target) { Loading @@ -54,6 +54,10 @@ public class ImageViewDrawableSetter { setCompressedImage(contactData.getPhotoBinaryData()); } public void setTransitionDuration(int durationInMillis) { mDurationInMillis = durationInMillis; } public ImageView getTarget() { return mTarget; } Loading Loading @@ -97,7 +101,7 @@ public class ImageViewDrawableSetter { // If we don't have a new Drawable, something went wrong... bail out. if (newDrawable == null) return previousBitmap(); if (mPreviousDrawable == null) { if (mPreviousDrawable == null || mDurationInMillis == 0) { // Set the new one immediately. mTarget.setImageDrawable(newDrawable); } else { Loading @@ -107,7 +111,7 @@ public class ImageViewDrawableSetter { beforeAndAfter[1] = newDrawable; final TransitionDrawable transition = new TransitionDrawable(beforeAndAfter); mTarget.setImageDrawable(transition); transition.startTransition(200); transition.startTransition(mDurationInMillis); } // Remember this for next time, so that we can transition from it to the Loading
src/com/android/contacts/widget/TransitionAnimationView.java +34 −76 Original line number Diff line number Diff line Loading @@ -15,30 +15,20 @@ */ package com.android.contacts.widget; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; /** * A container for a view that needs to have exit/enter animations when rebinding data. * After rebinding the contents, the following call should be made (where child is the only visible) * child * <pre> * TransitionAnimationView.startAnimation(child); * </pre> * A container that places a masking view on top of all other views. The masking view can be * faded in and out. Currently, the masking view is solid color white. */ public class TransitionAnimationView extends FrameLayout implements AnimatorListener { private View mPreviousStateView; private Bitmap mPreviousStateBitmap; private ObjectAnimator mPreviousAnimator; public class TransitionAnimationView extends FrameLayout { private View mMaskingView; private ObjectAnimator mAnimator; public TransitionAnimationView(Context context) { this(context, null, 0); Loading @@ -55,75 +45,43 @@ public class TransitionAnimationView extends FrameLayout implements AnimatorList @Override protected void onFinishInflate() { super.onFinishInflate(); mPreviousStateView = new View(getContext()); mPreviousStateView.setVisibility(View.INVISIBLE); mPreviousStateView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, mMaskingView = new View(getContext()); mMaskingView.setVisibility(View.INVISIBLE); mMaskingView.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); addView(mPreviousStateView); mMaskingView.setBackgroundColor(Color.WHITE); addView(mMaskingView); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mPreviousStateView.setBackgroundDrawable(null); if (mPreviousStateBitmap != null) { mPreviousStateBitmap.recycle(); mPreviousStateBitmap = null; } } public void startTransition(View view, boolean closing) { if (mPreviousAnimator != null && mPreviousAnimator.isRunning()) { mPreviousAnimator.end(); } if (view.getVisibility() != View.VISIBLE) { if (!closing) { mPreviousAnimator = ObjectAnimator.ofFloat(view, View.ALPHA, 0.0f, 1.0f); mPreviousAnimator.start(); } } else if (closing) { mPreviousAnimator = ObjectAnimator.ofFloat(view, View.ALPHA, 1.0f, 0.0f); mPreviousAnimator.start(); public void setMaskVisibility(boolean flag) { if (flag) { mMaskingView.setAlpha(1.0f); mMaskingView.setVisibility(View.VISIBLE); } else { if (view.getWidth() > 0 && view.getHeight() > 0) { // Take a "screenshot" of the current state of the screen and show that on top // of the real content. Then, fade that out. mPreviousStateBitmap = Bitmap.createBitmap( view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); mPreviousStateView.setBackgroundDrawable( new BitmapDrawable(getContext().getResources(), mPreviousStateBitmap)); mPreviousStateView.setLayoutParams(view.getLayoutParams()); mPreviousStateBitmap.eraseColor(Color.WHITE); Canvas canvas = new Canvas(mPreviousStateBitmap); view.draw(canvas); canvas.setBitmap(null); mPreviousStateView.setVisibility(View.VISIBLE); mPreviousAnimator = ObjectAnimator.ofFloat(mPreviousStateView, View.ALPHA, 1.0f, 0.0f); mPreviousAnimator.start(); } } mMaskingView.setVisibility(View.INVISIBLE); } @Override public void onAnimationEnd(Animator animation) { mPreviousStateView.setVisibility(View.INVISIBLE); mPreviousStateView.setBackgroundDrawable(null); mPreviousStateBitmap.recycle(); mPreviousStateBitmap = null; mPreviousAnimator = null; } @Override public void onAnimationCancel(Animator animation) { /** * Starts the transition of showing or hiding the mask. * If showMask is true, the mask will be set to be invisible then fade into hide the other * views in this container. If showMask is false, the mask will be set to be hide other views * initially. Then, the other views in this container will be revealed. */ public void startMaskTransition(boolean showMask) { // Stop any animation that may still be running. if (mAnimator != null && mAnimator.isRunning()) { mAnimator.end(); } @Override public void onAnimationStart(Animator animation) { mMaskingView.setVisibility(View.VISIBLE); if (showMask) { mAnimator = ObjectAnimator.ofFloat(mMaskingView, View.ALPHA, 0.0f, 1.0f); mAnimator.start(); } else { // asked to hide the view mAnimator = ObjectAnimator.ofFloat(mMaskingView, View.ALPHA, 1.0f, 0.0f); mAnimator.start(); } @Override public void onAnimationRepeat(Animator animation) { } }