diff options
11 files changed, 212 insertions, 35 deletions
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index cc4bc58fbf9d..da50776708b3 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -29,4 +29,9 @@ interface ISystemUiProxy { */ GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer, int maxLayer, boolean useIdentityTransform, int rotation); + + /** + * Called when the overview service has started the recents animation. + */ + void onRecentsAnimationStarted(); } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index c9a6ea9939f5..f9e1069cfe95 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -32,6 +32,7 @@ import android.app.AppGlobals; import android.app.IAssistDataReceiver; import android.app.WindowConfiguration.ActivityType; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -48,7 +49,10 @@ import android.os.RemoteException; import android.os.UserHandle; import android.util.IconDrawableFactory; import android.util.Log; +import android.view.IRecentsAnimationController; +import android.view.IRecentsAnimationRunner; +import android.view.RemoteAnimationTarget; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.Task.TaskKey; import com.android.systemui.shared.recents.model.ThumbnailData; @@ -243,10 +247,9 @@ public class ActivityManagerWrapper { /** * Starts the recents activity. The caller should manage the thread on which this is called. */ - public void startRecentsActivity(AssistDataReceiverCompat assistDataReceiver, Bundle options, - ActivityOptions opts, int userId, Consumer<Boolean> resultCallback, + public void startRecentsActivity(Intent intent, AssistDataReceiver assistDataReceiver, + RecentsAnimationListener animationHandler, Consumer<Boolean> resultCallback, Handler resultCallbackHandler) { - Bundle activityOptions = opts != null ? opts.toBundle() : null; try { IAssistDataReceiver receiver = null; if (assistDataReceiver != null) { @@ -259,8 +262,24 @@ public class ActivityManagerWrapper { } }; } - ActivityManager.getService().startRecentsActivity(receiver, options, activityOptions, - userId); + IRecentsAnimationRunner runner = null; + if (animationHandler != null) { + runner = new IRecentsAnimationRunner.Stub() { + public void onAnimationStart(IRecentsAnimationController controller, + RemoteAnimationTarget[] apps) { + final RecentsAnimationControllerCompat controllerCompat = + new RecentsAnimationControllerCompat(controller); + final RemoteAnimationTargetCompat[] appsCompat = + RemoteAnimationTargetCompat.wrap(apps); + animationHandler.onAnimationStart(controllerCompat, appsCompat); + } + + public void onAnimationCanceled() { + animationHandler.onAnimationCanceled(); + } + }; + } + ActivityManager.getService().startRecentsActivity(intent, receiver, runner); if (resultCallback != null) { resultCallbackHandler.post(new Runnable() { @Override diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiver.java index cd943f62ea9b..7cd6c512b660 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiverCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/AssistDataReceiver.java @@ -22,7 +22,7 @@ import android.os.Bundle; /** * Abstract class for assist data receivers. */ -public abstract class AssistDataReceiverCompat { - public abstract void onHandleAssistData(Bundle resultData); - public abstract void onHandleAssistScreenshot(Bitmap screenshot); +public abstract class AssistDataReceiver { + public void onHandleAssistData(Bundle resultData) {} + public void onHandleAssistScreenshot(Bitmap screenshot) {} } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java index db4f988a9122..38b8ae8418af 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package com.android.systemui.pip.phone; +package com.android.systemui.shared.system; import static android.view.WindowManager.INPUT_CONSUMER_PIP; +import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import android.os.Binder; import android.os.IBinder; @@ -29,11 +30,12 @@ import android.view.InputChannel; import android.view.InputEvent; import android.view.IWindowManager; import android.view.MotionEvent; +import android.view.WindowManagerGlobal; import java.io.PrintWriter; /** - * Manages the input consumer that allows the SystemUI to control the PiP. + * Manages the input consumer that allows the SystemUI to directly receive touch input. */ public class InputConsumerController { @@ -55,12 +57,12 @@ public class InputConsumerController { } /** - * Input handler used for the PiP input consumer. Input events are batched and consumed with the + * Input handler used for the input consumer. Input events are batched and consumed with the * SurfaceFlinger vsync. */ - private final class PipInputEventReceiver extends BatchedInputEventReceiver { + private final class InputEventReceiver extends BatchedInputEventReceiver { - public PipInputEventReceiver(InputChannel inputChannel, Looper looper) { + public InputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper, Choreographer.getSfInstance()); } @@ -68,7 +70,6 @@ public class InputConsumerController { public void onInputEvent(InputEvent event, int displayId) { boolean handled = true; try { - // To be implemented for input handling over Pip windows if (mListener != null && event instanceof MotionEvent) { MotionEvent ev = (MotionEvent) event; handled = mListener.onTouchEvent(ev); @@ -81,15 +82,35 @@ public class InputConsumerController { private final IWindowManager mWindowManager; private final IBinder mToken; + private final String mName; - private PipInputEventReceiver mInputEventReceiver; + private InputEventReceiver mInputEventReceiver; private TouchListener mListener; private RegistrationListener mRegistrationListener; - public InputConsumerController(IWindowManager windowManager) { + /** + * @param name the name corresponding to the input consumer that is defined in the system. + */ + public InputConsumerController(IWindowManager windowManager, String name) { mWindowManager = windowManager; mToken = new Binder(); - registerInputConsumer(); + mName = name; + } + + /** + * @return A controller for the pip input consumer. + */ + public static InputConsumerController getPipInputConsumer() { + return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(), + INPUT_CONSUMER_PIP); + } + + /** + * @return A controller for the recents animation input consumer. + */ + public static InputConsumerController getRecentsAnimationInputConsumer() { + return new InputConsumerController(WindowManagerGlobal.getWindowManagerService(), + INPUT_CONSUMER_RECENTS_ANIMATION); } /** @@ -125,12 +146,12 @@ public class InputConsumerController { if (mInputEventReceiver == null) { final InputChannel inputChannel = new InputChannel(); try { - mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); - mWindowManager.createInputConsumer(mToken, INPUT_CONSUMER_PIP, inputChannel); + mWindowManager.destroyInputConsumer(mName); + mWindowManager.createInputConsumer(mToken, mName, inputChannel); } catch (RemoteException e) { - Log.e(TAG, "Failed to create PIP input consumer", e); + Log.e(TAG, "Failed to create input consumer", e); } - mInputEventReceiver = new PipInputEventReceiver(inputChannel, Looper.myLooper()); + mInputEventReceiver = new InputEventReceiver(inputChannel, Looper.myLooper()); if (mRegistrationListener != null) { mRegistrationListener.onRegistrationChanged(true /* isRegistered */); } @@ -143,9 +164,9 @@ public class InputConsumerController { public void unregisterInputConsumer() { if (mInputEventReceiver != null) { try { - mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP); + mWindowManager.destroyInputConsumer(mName); } catch (RemoteException e) { - Log.e(TAG, "Failed to destroy PIP input consumer", e); + Log.e(TAG, "Failed to destroy input consumer", e); } mInputEventReceiver.dispose(); mInputEventReceiver = null; diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java new file mode 100644 index 000000000000..9a7abf82c56c --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018 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.app.ActivityManager.TaskSnapshot; +import android.os.RemoteException; +import android.util.Log; +import android.view.IRecentsAnimationController; + +import com.android.systemui.shared.recents.model.ThumbnailData; + +public class RecentsAnimationControllerCompat { + + private static final String TAG = RecentsAnimationControllerCompat.class.getSimpleName(); + + private IRecentsAnimationController mAnimationController; + + public RecentsAnimationControllerCompat(IRecentsAnimationController animationController) { + mAnimationController = animationController; + } + + public ThumbnailData screenshotTask(int taskId) { + try { + TaskSnapshot snapshot = mAnimationController.screenshotTask(taskId); + return snapshot != null ? new ThumbnailData(snapshot) : new ThumbnailData(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to screenshot task", e); + return new ThumbnailData(); + } + } + + public void setInputConsumerEnabled(boolean enabled) { + try { + mAnimationController.setInputConsumerEnabled(enabled); + } catch (RemoteException e) { + Log.e(TAG, "Failed to set input consumer enabled state", e); + } + } + + public void finish(boolean toHome) { + try { + mAnimationController.finish(toHome); + } catch (RemoteException e) { + Log.e(TAG, "Failed to finish recents animation", e); + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java new file mode 100644 index 000000000000..bf6179d70a5e --- /dev/null +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java @@ -0,0 +1,31 @@ +/* + * 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.system; + +public interface RecentsAnimationListener { + + /** + * Called when the animation into Recents can start. This call is made on the binder thread. + */ + void onAnimationStart(RecentsAnimationControllerCompat controller, + RemoteAnimationTargetCompat[] apps); + + /** + * Called when the animation into Recents was canceled. This call is made on the binder thread. + */ + void onAnimationCanceled(); +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 244c1b990448..b6e49ae6cc2c 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -77,6 +77,15 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis Binder.restoreCallingIdentity(token); } } + + public void onRecentsAnimationStarted() { + long token = Binder.clearCallingIdentity(); + try { + notifyRecentsAnimationStarted(); + } finally { + Binder.restoreCallingIdentity(token); + } + } }; private final BroadcastReceiver mLauncherAddedReceiver = new BroadcastReceiver() { @@ -214,6 +223,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } + private void notifyRecentsAnimationStarted() { + for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) { + mConnectionCallbacks.get(i).onRecentsAnimationStarted(); + } + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println(TAG_OPS + " state:"); @@ -224,6 +239,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } public interface OverviewProxyListener { - void onConnectionChanged(boolean isConnected); + default void onConnectionChanged(boolean isConnected) {} + default void onRecentsAnimationStarted() {} } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 36531bb727a4..24d0126a1494 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -16,12 +16,10 @@ package com.android.systemui.pip.phone; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.WindowManager.INPUT_CONSUMER_PIP; import android.app.ActivityManager; -import android.app.ActivityManager.StackInfo; import android.app.IActivityManager; import android.content.ComponentName; import android.content.Context; @@ -43,6 +41,7 @@ import com.android.systemui.recents.events.component.ExpandPipEvent; import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.InputConsumerController; import java.io.PrintWriter; @@ -174,7 +173,8 @@ public class PipManager implements BasePipManager { } ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener); - mInputConsumerController = new InputConsumerController(mWindowManager); + mInputConsumerController = InputConsumerController.getPipInputConsumer(); + mInputConsumerController.registerInputConsumer(); mMediaController = new PipMediaController(context, mActivityManager); mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController, mInputConsumerController); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index 9fb201b82d8c..26fced307bac 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -23,7 +23,6 @@ import android.app.ActivityManager.StackInfo; import android.app.ActivityOptions; import android.app.IActivityManager; import android.app.RemoteAction; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ParceledListSlice; @@ -43,6 +42,7 @@ import com.android.systemui.pip.phone.PipMediaController.ActionListener; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.component.HidePipMenuEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; +import com.android.systemui.shared.system.InputConsumerController; import java.io.PrintWriter; import java.util.ArrayList; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index c0fed342ef44..b25351731a35 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -46,6 +46,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.logging.MetricsLoggerWrapper; import com.android.internal.policy.PipSnapAlgorithm; import com.android.systemui.R; +import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.statusbar.FlingAnimationUtils; import java.io.PrintWriter; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 9bef0eecaa06..445fb243923f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -104,6 +104,7 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav private DeadZone mDeadZone; private final NavigationBarTransitions mBarTransitions; private final OverviewProxyService mOverviewProxyService; + private boolean mRecentsAnimationStarted; // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288) final static boolean WORKAROUND_INVALID_LAYOUT = true; @@ -205,10 +206,18 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav } } - private final OverviewProxyListener mOverviewProxyListener = isConnected -> { - setSlippery(!isConnected); - setDisabledFlags(mDisabledFlags, true); - setUpSwipeUpOnboarding(isConnected); + private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() { + @Override + public void onConnectionChanged(boolean isConnected) { + setSlippery(!isConnected); + setDisabledFlags(mDisabledFlags, true); + setUpSwipeUpOnboarding(isConnected); + } + + @Override + public void onRecentsAnimationStarted() { + mRecentsAnimationStarted = true; + } }; public NavigationBarView(Context context, AttributeSet attrs) { @@ -270,12 +279,26 @@ public class NavigationBarView extends FrameLayout implements PluginListener<Nav if (mGestureHelper.onTouchEvent(event)) { return true; } - return super.onTouchEvent(event); + return mRecentsAnimationStarted || super.onTouchEvent(event); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { - return mGestureHelper.onInterceptTouchEvent(event); + int action = event.getActionMasked(); + if (action == MotionEvent.ACTION_DOWN) { + mRecentsAnimationStarted = false; + } else if (action == MotionEvent.ACTION_UP) { + // If the overview proxy service has not started the recents animation then clean up + // after it to ensure that the nav bar buttons still work + if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) { + try { + ActivityManager.getService().cancelRecentsAnimation(); + } catch (RemoteException e) { + Log.e(TAG, "Could not cancel recents animation"); + } + } + } + return mRecentsAnimationStarted || mGestureHelper.onInterceptTouchEvent(event); } public void abortCurrentGesture() { |