Merge "Add one-shot remote handler and remote runner interface" into sc-dev
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user