1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.systemui.shared.recents.view; 17 18 import android.app.ActivityOptions; 19 import android.app.ActivityOptions.OnAnimationStartedListener; 20 import android.content.Context; 21 import android.graphics.Bitmap; 22 import android.graphics.Canvas; 23 import android.graphics.GraphicBuffer; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.os.IRemoteCallback; 27 import android.os.RemoteException; 28 import android.view.DisplayListCanvas; 29 import android.view.RenderNode; 30 import android.view.ThreadedRenderer; 31 import android.view.View; 32 33 import java.util.function.Consumer; 34 35 /** 36 * A helper class to create transitions to/from an App to Recents. 37 */ 38 public class RecentsTransition { 39 40 /** 41 * Creates a new transition aspect scaled transition activity options. 42 */ createAspectScaleAnimation(Context context, Handler handler, boolean scaleUp, AppTransitionAnimationSpecsFuture animationSpecsFuture, final Runnable animationStartCallback)43 public static ActivityOptions createAspectScaleAnimation(Context context, Handler handler, 44 boolean scaleUp, AppTransitionAnimationSpecsFuture animationSpecsFuture, 45 final Runnable animationStartCallback) { 46 final OnAnimationStartedListener animStartedListener = new OnAnimationStartedListener() { 47 private boolean mHandled; 48 49 @Override 50 public void onAnimationStarted() { 51 // OnAnimationStartedListener can be called numerous times, so debounce here to 52 // prevent multiple callbacks 53 if (mHandled) { 54 return; 55 } 56 mHandled = true; 57 58 if (animationStartCallback != null) { 59 animationStartCallback.run(); 60 } 61 } 62 }; 63 final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation( 64 context, handler, 65 animationSpecsFuture != null ? animationSpecsFuture.getFuture() : null, 66 animStartedListener, scaleUp); 67 return opts; 68 } 69 70 /** 71 * Wraps a animation-start callback in a binder that can be called from window manager. 72 */ wrapStartedListener(final Handler handler, final Runnable animationStartCallback)73 public static IRemoteCallback wrapStartedListener(final Handler handler, 74 final Runnable animationStartCallback) { 75 if (animationStartCallback == null) { 76 return null; 77 } 78 return new IRemoteCallback.Stub() { 79 @Override 80 public void sendResult(Bundle data) throws RemoteException { 81 handler.post(animationStartCallback); 82 } 83 }; 84 } 85 86 /** 87 * @return a {@link GraphicBuffer} with the {@param view} drawn into it. Result can be null if 88 * we were unable to allocate a hardware bitmap. 89 */ 90 public static Bitmap drawViewIntoHardwareBitmap(int width, int height, final View view, 91 final float scale, final int eraseColor) { 92 return createHardwareBitmap(width, height, new Consumer<Canvas>() { 93 @Override 94 public void accept(Canvas c) { 95 c.scale(scale, scale); 96 if (eraseColor != 0) { 97 c.drawColor(eraseColor); 98 } 99 if (view != null) { 100 view.draw(c); 101 } 102 } 103 }); 104 } 105 106 /** 107 * @return a hardware {@link Bitmap} after being drawn with the {@param consumer}. Result can be 108 * null if we were unable to allocate a hardware bitmap. 109 */ 110 public static Bitmap createHardwareBitmap(int width, int height, Consumer<Canvas> consumer) { 111 RenderNode node = RenderNode.create("RecentsTransition", null); 112 node.setLeftTopRightBottom(0, 0, width, height); 113 node.setClipToBounds(false); 114 DisplayListCanvas c = node.start(width, height); 115 consumer.accept(c); 116 node.end(c); 117 return ThreadedRenderer.createHardwareBitmap(node, width, height); 118 } 119 } 120