16596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee/* 26596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * Copyright (C) 2014 The Android Open Source Project 36596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * 46596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * Licensed under the Apache License, Version 2.0 (the "License"); 56596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * you may not use this file except in compliance with the License. 66596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * You may obtain a copy of the License at 76596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * 86596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * http://www.apache.org/licenses/LICENSE-2.0 96596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * 106596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * Unless required by applicable law or agreed to in writing, software 116596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * distributed under the License is distributed on an "AS IS" BASIS, 126596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * See the License for the specific language governing permissions and 146596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * limitations under the License. 156596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee */ 166596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 176596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leepackage com.android.incallui; 186596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 196596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.animation.Animator; 206596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.animation.AnimatorListenerAdapter; 216596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.app.Activity; 226596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.app.Fragment; 236596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.app.FragmentManager; 246596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.graphics.Outline; 256596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.graphics.Point; 266596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.os.Bundle; 276596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.Display; 286596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.LayoutInflater; 296596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.View; 306596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.ViewAnimationUtils; 316596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.ViewGroup; 326596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.ViewOutlineProvider; 336596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.ViewTreeObserver; 346596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport android.view.ViewTreeObserver.OnPreDrawListener; 356596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 366596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leeimport com.android.contacts.common.util.MaterialColorMapUtils.MaterialPalette; 3768d86c656e5522dec1b04e85ebc0e0f78e436c3dSailesh Nepalimport com.android.dialer.R; 386596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 396596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Leepublic class CircularRevealFragment extends Fragment { 406596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee static final String TAG = "CircularRevealFragment"; 416596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 426596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee private Point mTouchPoint; 436596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee private OnCircularRevealCompleteListener mListener; 446596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee private boolean mAnimationStarted; 456596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 466596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee interface OnCircularRevealCompleteListener { 476596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public void onCircularRevealComplete(FragmentManager fm); 486596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 496596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 506596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public static void startCircularReveal(FragmentManager fm, Point touchPoint, 516596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee OnCircularRevealCompleteListener listener) { 52d06de8235438ac3b45af381dbf93b83f0fb8460eYorke Lee if (fm.findFragmentByTag(TAG) == null) { 53d06de8235438ac3b45af381dbf93b83f0fb8460eYorke Lee fm.beginTransaction().add(R.id.main, 54d06de8235438ac3b45af381dbf93b83f0fb8460eYorke Lee new CircularRevealFragment(touchPoint, listener), TAG) 55d06de8235438ac3b45af381dbf93b83f0fb8460eYorke Lee .commitAllowingStateLoss(); 56d06de8235438ac3b45af381dbf93b83f0fb8460eYorke Lee } else { 57d06de8235438ac3b45af381dbf93b83f0fb8460eYorke Lee Log.w(TAG, "An instance of CircularRevealFragment already exists"); 58d06de8235438ac3b45af381dbf93b83f0fb8460eYorke Lee } 596596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 606596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 616596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public static void endCircularReveal(FragmentManager fm) { 626596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final Fragment fragment = fm.findFragmentByTag(TAG); 636596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee if (fragment != null) { 646596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee fm.beginTransaction().remove(fragment).commitAllowingStateLoss(); 656596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 666596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 676596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 686596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee /** 696596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee * Empty constructor used only by the {@link FragmentManager}. 706596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee */ 716596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public CircularRevealFragment() {} 726596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 736596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public CircularRevealFragment(Point touchPoint, OnCircularRevealCompleteListener listener) { 746596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee mTouchPoint = touchPoint; 756596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee mListener = listener; 766596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 776596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 786596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee @Override 796596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public void onResume() { 806596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee super.onResume(); 816596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee if (!mAnimationStarted) { 826596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee // Only run the animation once for each instance of the fragment 836596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee startOutgoingAnimation(InCallPresenter.getInstance().getThemeColors()); 846596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 856596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee mAnimationStarted = true; 866596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 876596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 886596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee @Override 896596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public View onCreateView(LayoutInflater inflater, ViewGroup container, 906596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee Bundle savedInstanceState) { 916596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee return inflater.inflate(R.layout.outgoing_call_animation, container, false); 926596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 936596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 946596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public void startOutgoingAnimation(MaterialPalette palette) { 956596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final Activity activity = getActivity(); 966596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee if (activity == null) { 976596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee Log.w(this, "Asked to do outgoing call animation when not attached"); 986596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee return; 996596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1006596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 1016596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final View view = activity.getWindow().getDecorView(); 1026596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 1036596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee // The circle starts from an initial size of 0 so clip it such that it is invisible. 1046596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee // Otherwise the first frame is drawn with a fully opaque screen which causes jank. When 1056596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee // the animation later starts, this clip will be clobbered by the circular reveal clip. 1066596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee // See ViewAnimationUtils.createCircularReveal. 1076596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee view.setOutlineProvider(new ViewOutlineProvider() { 1086596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee @Override 1096596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public void getOutline(View view, Outline outline) { 1106596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee // Using (0, 0, 0, 0) will not work since the outline will simply be treated as 1116596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee // an empty outline. 1126596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee outline.setOval(-1, -1, 0, 0); 1136596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1146596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee }); 1156596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee view.setClipToOutline(true); 1166596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 1176596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee if (palette != null) { 1186596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee view.findViewById(R.id.outgoing_call_animation_circle).setBackgroundColor( 1196596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee palette.mPrimaryColor); 1206596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee activity.getWindow().setStatusBarColor(palette.mSecondaryColor); 1216596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1226596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 1236596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { 1246596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee @Override 1256596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee public boolean onPreDraw() { 1266596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final ViewTreeObserver vto = view.getViewTreeObserver(); 1276596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee if (vto.isAlive()) { 1286596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee vto.removeOnPreDrawListener(this); 1296596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1306596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final Animator animator = getRevealAnimator(mTouchPoint); 131471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner if (animator != null) { 132471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner animator.addListener(new AnimatorListenerAdapter() { 133471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner @Override 134471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner public void onAnimationEnd(Animator animation) { 135471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner view.setClipToOutline(false); 136471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner if (mListener != null) { 137471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner mListener.onCircularRevealComplete(getFragmentManager()); 138471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner } 1396596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 140471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner }); 141471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner animator.start(); 142471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner } 1436596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee return false; 1446596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1456596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee }); 1466596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1476596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 1486596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee private Animator getRevealAnimator(Point touchPoint) { 1496596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final Activity activity = getActivity(); 150471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner if (activity == null) { 151471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner return null; 152471f63aa71568456b368b80d38a5e43f7051d28dJay Shrauner } 1536596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final View view = activity.getWindow().getDecorView(); 1546596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final Display display = activity.getWindowManager().getDefaultDisplay(); 1556596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final Point size = new Point(); 1566596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee display.getSize(size); 1576596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 1586596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee int startX = size.x / 2; 1596596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee int startY = size.y / 2; 1606596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee if (touchPoint != null) { 1616596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee startX = touchPoint.x; 1626596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee startY = touchPoint.y; 1636596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1646596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee 1656596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee final Animator valueAnimator = ViewAnimationUtils.createCircularReveal(view, 1666596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee startX, startY, 0, Math.max(size.x, size.y)); 1676596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee valueAnimator.setDuration(getResources().getInteger(R.integer.reveal_animation_duration)); 1686596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee return valueAnimator; 1696596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee } 1706596e1be9d3e15e2cbe4a5e9c3824ee47a0e2744Yorke Lee} 171