blob: e253360a53641d17e82c8ddb2ae4b133435381d4 [file] [log] [blame]
/*
* Copyright (C) 2017 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.systemui.shared.recents.view;
import android.app.ActivityOptions;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.GraphicBuffer;
import android.graphics.Picture;
import android.os.Bundle;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.view.View;
import java.util.function.Consumer;
/**
* A helper class to create transitions to/from an App to Recents.
*/
public class RecentsTransition {
/**
* Creates a new transition aspect scaled transition activity options.
*/
public static ActivityOptions createAspectScaleAnimation(Context context, Handler handler,
boolean scaleUp, AppTransitionAnimationSpecsFuture animationSpecsFuture,
final Runnable animationStartCallback) {
final OnAnimationStartedListener animStartedListener = new OnAnimationStartedListener() {
private boolean mHandled;
@Override
public void onAnimationStarted() {
// OnAnimationStartedListener can be called numerous times, so debounce here to
// prevent multiple callbacks
if (mHandled) {
return;
}
mHandled = true;
if (animationStartCallback != null) {
animationStartCallback.run();
}
}
};
final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(
context, handler,
animationSpecsFuture != null ? animationSpecsFuture.getFuture() : null,
animStartedListener, scaleUp);
return opts;
}
/**
* Wraps a animation-start callback in a binder that can be called from window manager.
*/
public static IRemoteCallback wrapStartedListener(final Handler handler,
final Runnable animationStartCallback) {
if (animationStartCallback == null) {
return null;
}
return new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
handler.post(animationStartCallback);
}
};
}
/**
* @return a {@link GraphicBuffer} with the {@param view} drawn into it. Result can be null if
* we were unable to allocate a hardware bitmap.
*/
public static Bitmap drawViewIntoHardwareBitmap(int width, int height, final View view,
final float scale, final int eraseColor) {
return createHardwareBitmap(width, height, new Consumer<Canvas>() {
@Override
public void accept(Canvas c) {
c.scale(scale, scale);
if (eraseColor != 0) {
c.drawColor(eraseColor);
}
if (view != null) {
view.draw(c);
}
}
});
}
/**
* @return a hardware {@link Bitmap} after being drawn with the {@param consumer}. Result can be
* null if we were unable to allocate a hardware bitmap.
*/
public static Bitmap createHardwareBitmap(int width, int height, Consumer<Canvas> consumer) {
final Picture picture = new Picture();
final Canvas canvas = picture.beginRecording(width, height);
consumer.accept(canvas);
picture.endRecording();
return Bitmap.createBitmap(picture);
}
}