diff options
Diffstat (limited to 'src/com/android/incallui/CircularRevealActivity.java')
-rw-r--r-- | src/com/android/incallui/CircularRevealActivity.java | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/com/android/incallui/CircularRevealActivity.java b/src/com/android/incallui/CircularRevealActivity.java new file mode 100644 index 00000000..7a9b7ccb --- /dev/null +++ b/src/com/android/incallui/CircularRevealActivity.java @@ -0,0 +1,169 @@ +/* + * 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); + final Point touchPoint = getIntent().getParcelableExtra(TouchPointManager.TOUCH_POINT); + final MaterialPalette palette = getIntent().getParcelableExtra(EXTRA_THEME_COLORS); + setupDecorView(touchPoint, palette); + } + + @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(); + } + + 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; + } +} |