Files
Lawnchair/systemUI/anim/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
T

275 lines
14 KiB
Java

/*
* Copyright (C) 2024 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.animation;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.RemoteTransitionStub;
import android.window.TransitionInfo;
import android.window.WindowAnimationState;
import com.android.wm.shell.shared.CounterRotator;
public abstract class RemoteAnimationRunnerCompat extends IRemoteAnimationRunner.Stub {
private static final String TAG = "RemoteAnimRunnerCompat";
public abstract void onAnimationStart(@WindowManager.TransitionOldType int transit,
RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps, Runnable finishedCallback);
@Override
public final void onAnimationStart(@TransitionOldType int transit,
RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
onAnimationStart(transit, apps, wallpapers,
nonApps, () -> {
try {
finishedCallback.onAnimationFinished();
} catch (RemoteException e) {
Log.e(TAG, "Failed to call app controlled animation finished callback", e);
}
});
}
// Called only in R
public void onAnimationStart(RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets, IRemoteAnimationFinishedCallback finishedCallback) {
onAnimationStart(0 /* transit */, appTargets, wallpaperTargets,
new RemoteAnimationTarget[0], finishedCallback);
}
// Called only in Q
public void onAnimationStart(RemoteAnimationTarget[] appTargets,
IRemoteAnimationFinishedCallback finishedCallback) {
onAnimationStart(appTargets, new RemoteAnimationTarget[0], finishedCallback);
}
public void onAnimationCancelled(boolean isKeyguardOccluded) {
onAnimationCancelled();
}
// Called only in S+
public void onAnimationCancelled() {}
/** Wraps a remote animation runner in a remote-transition. */
public static RemoteTransitionStub wrap(IRemoteAnimationRunner runner) {
return new RemoteTransitionStub() {
@Override
public void startAnimation(IBinder token , TransitionInfo info , SurfaceControl.Transaction t , IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
}
};
}
public IRemoteTransition toRemoteTransition() {
return new IRemoteTransition.Stub() {
final ArrayMap<IBinder, Runnable> mFinishRunnables = new ArrayMap<>();
public void onTransitionConsumed(IBinder transition, boolean aborted) {}
@Override
public void startAnimation(IBinder token, TransitionInfo info,
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishCallback) {
final ArrayMap<SurfaceControl, SurfaceControl> leashMap = new ArrayMap<>();
final RemoteAnimationTarget[] apps =
RemoteAnimationTargetCompat.wrapApps(info, t, leashMap);
final RemoteAnimationTarget[] wallpapers =
RemoteAnimationTargetCompat.wrapNonApps(
info, true /* wallpapers */, t, leashMap);
final RemoteAnimationTarget[] nonApps =
RemoteAnimationTargetCompat.wrapNonApps(
info, false /* wallpapers */, t, leashMap);
// TODO(b/177438007): Move this set-up logic into launcher's animation impl.
boolean isReturnToHome = false;
TransitionInfo.Change launcherTask = null;
TransitionInfo.Change wallpaper = null;
int launcherLayer = 0;
int rotateDelta = 0;
float displayW = 0;
float displayH = 0;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
// skip changes that we didn't wrap
if (!leashMap.containsKey(change.getLeash())) continue;
if (change.getTaskInfo() != null
&& change.getTaskInfo().getActivityType() == ACTIVITY_TYPE_HOME) {
isReturnToHome = change.getMode() == TRANSIT_OPEN
|| change.getMode() == TRANSIT_TO_FRONT;
launcherTask = change;
launcherLayer = info.getChanges().size() - i;
} else if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
wallpaper = change;
}
if (change.getParent() == null && change.getEndRotation() >= 0
&& change.getEndRotation() != change.getStartRotation()) {
rotateDelta = change.getEndRotation() - change.getStartRotation();
displayW = change.getEndAbsBounds().width();
displayH = change.getEndAbsBounds().height();
}
}
// Prepare for rotation if there is one
final CounterRotator counterLauncher = new CounterRotator();
final CounterRotator counterWallpaper = new CounterRotator();
if (launcherTask != null && rotateDelta != 0 && launcherTask.getParent() != null) {
final TransitionInfo.Change parent = info.getChange(launcherTask.getParent());
if (parent != null) {
counterLauncher.setup(t, parent.getLeash(), rotateDelta, displayW,
displayH);
} else {
Log.e(TAG, "Malformed: " + launcherTask + " has parent="
+ launcherTask.getParent() + " but it's not in info.");
}
if (counterLauncher.getSurface() != null) {
t.setLayer(counterLauncher.getSurface(), launcherLayer);
}
}
if (isReturnToHome) {
if (counterLauncher.getSurface() != null) {
t.setLayer(counterLauncher.getSurface(), info.getChanges().size() * 3);
}
// Need to "boost" the closing things since that's what launcher expects.
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = leashMap.get(change.getLeash());
// skip changes that we didn't wrap
if (leash == null) continue;
final int mode = info.getChanges().get(i).getMode();
// Only deal with independent layers
if (!TransitionInfo.isIndependent(change, info)) continue;
if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
t.setLayer(leash, info.getChanges().size() * 3 - i);
counterLauncher.addChild(t, leash);
}
}
// Make wallpaper visible immediately since launcher apparently won't do this.
for (int i = wallpapers.length - 1; i >= 0; --i) {
t.show(wallpapers[i].leash);
t.setAlpha(wallpapers[i].leash, 1.f);
}
} else {
if (launcherTask != null) {
counterLauncher.addChild(t, leashMap.get(launcherTask.getLeash()));
}
if (wallpaper != null && rotateDelta != 0 && wallpaper.getParent() != null) {
counterWallpaper.setup(t, info.getChange(wallpaper.getParent()).getLeash(),
rotateDelta, displayW, displayH);
final TransitionInfo.Change parent = info.getChange(wallpaper.getParent());
if (parent != null) {
counterWallpaper.setup(t, parent.getLeash(), rotateDelta, displayW,
displayH);
} else {
Log.e(TAG, "Malformed: " + wallpaper + " has parent="
+ wallpaper.getParent() + " but it's not in info.");
}
if (counterWallpaper.getSurface() != null) {
t.setLayer(counterWallpaper.getSurface(), -1);
counterWallpaper.addChild(t, leashMap.get(wallpaper.getLeash()));
}
}
}
t.apply();
final Runnable animationFinishedCallback = () -> {
final SurfaceControl.Transaction finishTransaction =
new SurfaceControl.Transaction();
counterLauncher.cleanUp(finishTransaction);
counterWallpaper.cleanUp(finishTransaction);
// Release surface references now. This is apparently to free GPU memory
// before GC would.
info.releaseAllSurfaces();
// Don't release here since launcher might still be using them. Instead
// let launcher release them (eg. via RemoteAnimationTargets)
leashMap.clear();
try {
finishCallback.onTransitionFinished(null /* wct */, finishTransaction);
finishTransaction.close();
} catch (RemoteException e) {
Log.e(TAG, "Failed to call app controlled animation finished callback", e);
}
};
synchronized (mFinishRunnables) {
mFinishRunnables.put(token, animationFinishedCallback);
}
// TODO(bc-unlcok): Pass correct transit type.
onAnimationStart(TRANSIT_OLD_NONE,
apps, wallpapers, nonApps, new IRemoteAnimationFinishedCallback() {
@Override
public void onAnimationFinished() {
synchronized (mFinishRunnables) {
if (mFinishRunnables.remove(token) == null) return;
}
animationFinishedCallback.run();
}
@Override
public IBinder asBinder() {
return null;
}
});
}
@Override
public void mergeAnimation(IBinder token, TransitionInfo info,
SurfaceControl.Transaction t, IBinder mergeTarget,
IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
// TODO: hook up merge to recents onTaskAppeared if applicable. Until then, adapt
// to legacy cancel.
final Runnable finishRunnable;
synchronized (mFinishRunnables) {
finishRunnable = mFinishRunnables.remove(mergeTarget);
}
// Since we're not actually animating, release native memory now
t.close();
info.releaseAllSurfaces();
if (finishRunnable == null) return;
onAnimationCancelled(false /* isKeyguardOccluded */);
finishRunnable.run();
}
@Override
public void takeOverAnimation(IBinder transition , TransitionInfo info , SurfaceControl.Transaction t , IRemoteTransitionFinishedCallback finishCallback , WindowAnimationState[] states) throws RemoteException {
}
};
}
}