Merge "Add one-shot remote handler and remote runner interface" into sc-dev

This commit is contained in:
Evan Rosky
2021-03-30 23:01:43 +00:00
committed by Android (Google) Code Review
4 changed files with 197 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2021 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.wm.shell.transition;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
/**
* Handler that forwards to a RemoteTransition. It is designed for one-shot use to attach a
* specific remote animation to a specific transition.
*/
public class OneShotRemoteHandler implements Transitions.TransitionHandler {
private final ShellExecutor mMainExecutor;
/** The specific transition that this handler is associated with. Just for validation. */
private IBinder mTransition = null;
/** The remote to delegate animation to */
private final IRemoteTransition mRemote;
public OneShotRemoteHandler(@NonNull ShellExecutor mainExecutor,
@NonNull IRemoteTransition remote) {
mMainExecutor = mainExecutor;
mRemote = remote;
}
public void setTransition(@NonNull IBinder transition) {
mTransition = transition;
}
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (mTransition != transition) return false;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Using registered One-shot remote"
+ " transition %s for %s.", mRemote, transition);
final IBinder.DeathRecipient remoteDied = () -> {
Log.e(Transitions.TAG, "Remote transition died, finishing");
mMainExecutor.execute(
() -> finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
};
IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
@Override
public void onTransitionFinished(WindowContainerTransaction wct) {
if (mRemote.asBinder() != null) {
mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
}
mMainExecutor.execute(
() -> finishCallback.onTransitionFinished(wct, null /* wctCB */));
}
};
try {
if (mRemote.asBinder() != null) {
mRemote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
}
mRemote.startAnimation(info, t, cb);
} catch (RemoteException e) {
if (mRemote.asBinder() != null) {
mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
}
Log.e(Transitions.TAG, "Error running remote transition.", e);
finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
}
return true;
}
@Override
@Nullable
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@Nullable TransitionRequestInfo request) {
IRemoteTransition remote = request.getRemoteTransition();
if (remote != mRemote) return null;
mTransition = transition;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "RemoteTransition directly requested"
+ " for %s: %s", transition, remote);
return new WindowContainerTransaction();
}
}

View File

@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_FIRST_CUSTOM;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -30,6 +31,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -295,6 +298,44 @@ public class ShellTransitionTests {
verify(mOrganizer, times(1)).finishTransition(eq(transitToken), any(), any());
}
@Test
public void testOneShotRemoteHandler() {
Transitions transitions = new Transitions(mOrganizer, mTransactionPool, mContext,
mMainExecutor, mAnimExecutor);
transitions.replaceDefaultHandlerForTest(mDefaultHandler);
final boolean[] remoteCalled = new boolean[]{false};
final WindowContainerTransaction remoteFinishWCT = new WindowContainerTransaction();
IRemoteTransition testRemote = new IRemoteTransition.Stub() {
@Override
public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishCallback) throws RemoteException {
remoteCalled[0] = true;
finishCallback.onTransitionFinished(remoteFinishWCT);
}
};
final int transitType = TRANSIT_FIRST_CUSTOM + 1;
OneShotRemoteHandler oneShot = new OneShotRemoteHandler(mMainExecutor, testRemote);
// Verify that it responds to the remote but not other things.
IBinder transitToken = new Binder();
assertNotNull(oneShot.handleRequest(transitToken,
new TransitionRequestInfo(transitType, null, testRemote)));
assertNull(oneShot.handleRequest(transitToken,
new TransitionRequestInfo(transitType, null, null)));
Transitions.TransitionFinishCallback testFinish =
mock(Transitions.TransitionFinishCallback.class);
// Verify that it responds to animation properly
oneShot.setTransition(transitToken);
IBinder anotherToken = new Binder();
assertFalse(oneShot.startAnimation(anotherToken, new TransitionInfo(transitType, 0),
mock(SurfaceControl.Transaction.class), testFinish));
assertTrue(oneShot.startAnimation(transitToken, new TransitionInfo(transitType, 0),
mock(SurfaceControl.Transaction.class), testFinish));
}
class TransitionInfoBuilder {
final TransitionInfo mInfo;

View File

@@ -50,6 +50,8 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
*/
@DataClass
public class RemoteTransitionCompat implements Parcelable {
private static final String TAG = "RemoteTransitionCompat";
@NonNull final IRemoteTransition mTransition;
@Nullable TransitionFilter mFilter = null;
@@ -57,6 +59,23 @@ public class RemoteTransitionCompat implements Parcelable {
mTransition = transition;
}
public RemoteTransitionCompat(RemoteTransitionRunner runner) {
mTransition = new IRemoteTransition.Stub() {
@Override
public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishedCallback) {
final Runnable finishAdapter = () -> {
try {
finishedCallback.onTransitionFinished(null /* wct */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to call transition finished callback", e);
}
};
runner.startAnimation(info, t, finishAdapter);
}
};
}
/** Constructor specifically for recents animation */
public RemoteTransitionCompat(RecentsAnimationListener recents,
RecentsAnimationControllerCompat controller) {

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2021 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.system;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
/** Interface for something that runs a remote transition animation. */
public interface RemoteTransitionRunner {
/**
* Starts a transition animation. Once complete, the implementation should call
* `finishCallback`.
*/
void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
Runnable finishCallback);
}