diff options
9 files changed, 550 insertions, 10 deletions
diff --git a/core/java/android/view/IDisplayWindowInsetsController.aidl b/core/java/android/view/IDisplayWindowInsetsController.aidl new file mode 100644 index 000000000000..429c3aeba9b3 --- /dev/null +++ b/core/java/android/view/IDisplayWindowInsetsController.aidl @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2019 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 android.view; + +import android.view.InsetsSourceControl; +import android.view.InsetsState; + +/** + * Singular controller of insets to use when there isn't another obvious controller available. + * Specifically, this will take over insets control in multi-window. + * @hide + */ +oneway interface IDisplayWindowInsetsController { + + /** + * @see IWindow#insetsChanged + */ + void insetsChanged(in InsetsState insetsState); + + /** + * @see IWindow#insetsControlChanged + */ + void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls); + + /** + * @see IWindow#showInsets + */ + void showInsets(int types, boolean fromIme); + + /** + * @see IWindow#hideInsets + */ + void hideInsets(int types, boolean fromIme); +} diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 9496827b1a84..993bdc4d6543 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -35,6 +35,7 @@ import android.os.ParcelFileDescriptor; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDockedStackListener; +import android.view.IDisplayWindowInsetsController; import android.view.IDisplayWindowListener; import android.view.IDisplayFoldListener; import android.view.IDisplayWindowRotationController; @@ -49,6 +50,7 @@ import android.view.IWindowSession; import android.view.IWindowSessionCallback; import android.view.KeyEvent; import android.view.InputEvent; +import android.view.InsetsState; import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.InputChannel; @@ -711,4 +713,16 @@ interface IWindowManager * @return true if the display was successfully mirrored. */ boolean mirrorDisplay(int displayId, out SurfaceControl outSurfaceControl); + + /** + * When in multi-window mode, the provided displayWindowInsetsController will control insets + * animations. + */ + void setDisplayWindowInsetsController( + int displayId, in IDisplayWindowInsetsController displayWindowInsetsController); + + /** + * Called when a remote process modifies insets on a display window container. + */ + void modifyDisplayWindowInsets(int displayId, in InsetsState state); } diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index eecc54c678c0..bbe972dea11f 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -121,6 +121,7 @@ import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.util.leak.LeakReporter; import com.android.systemui.util.sensors.AsyncSensorManager; +import com.android.systemui.wm.DisplayImeController; import com.android.systemui.wm.DisplayWindowController; import com.android.systemui.wm.SystemWindows; @@ -321,6 +322,7 @@ public class Dependency { @Inject Lazy<StatusBar> mStatusBar; @Inject Lazy<DisplayWindowController> mDisplayWindowController; @Inject Lazy<SystemWindows> mSystemWindows; + @Inject Lazy<DisplayImeController> mDisplayImeController; @Inject public Dependency() { @@ -509,6 +511,7 @@ public class Dependency { mProviders.put(StatusBar.class, mStatusBar::get); mProviders.put(DisplayWindowController.class, mDisplayWindowController::get); mProviders.put(SystemWindows.class, mSystemWindows::get); + mProviders.put(DisplayImeController.class, mDisplayImeController::get); // TODO(b/118592525): to support multi-display , we start to add something which is // per-display, while others may be global. I think it's time to add diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java new file mode 100644 index 000000000000..d413308d4573 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2019 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.wm; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.res.Configuration; +import android.os.Handler; +import android.os.RemoteException; +import android.util.Slog; +import android.util.SparseArray; +import android.view.IDisplayWindowInsetsController; +import android.view.InsetsSource; +import android.view.InsetsSourceControl; +import android.view.InsetsState; +import android.view.Surface; +import android.view.SurfaceControl; +import android.view.WindowInsets; +import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; + +import com.android.systemui.dagger.qualifiers.Main; + +import java.util.ArrayList; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Manages IME control at the display-level. This occurs when IME comes up in multi-window mode. + */ +@Singleton +public class DisplayImeController implements DisplayWindowController.DisplayWindowListener { + private static final String TAG = "DisplayImeController"; + + static final int ANIMATION_DURATION_SHOW_MS = 275; + static final int ANIMATION_DURATION_HIDE_MS = 340; + static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + private static final int DIRECTION_NONE = 0; + private static final int DIRECTION_SHOW = 1; + private static final int DIRECTION_HIDE = 2; + + SystemWindows mSystemWindows; + final Handler mHandler; + + final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>(); + + final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>(); + + @Inject + DisplayImeController(SystemWindows syswin, DisplayWindowController displayController, + @Main Handler mainHandler) { + mHandler = mainHandler; + mSystemWindows = syswin; + displayController.addDisplayWindowListener(this); + } + + @Override + public void onDisplayAdded(int displayId) { + // Add's a system-ui window-manager specifically for ime. This type is special because + // WM will defer IME inset handling to it in multi-window scenarious. + PerDisplay pd = new PerDisplay(displayId, + mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()); + try { + mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, pd); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to set insets controller on display " + displayId); + } + mImePerDisplay.put(displayId, pd); + } + + @Override + public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { + PerDisplay pd = mImePerDisplay.get(displayId); + if (pd == null) { + return; + } + if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation() + != pd.mRotation && isImeShowing(displayId)) { + pd.startAnimation(true); + } + } + + @Override + public void onDisplayRemoved(int displayId) { + try { + mSystemWindows.mWmService.setDisplayWindowInsetsController(displayId, null); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to remove insets controller on display " + displayId); + } + mImePerDisplay.remove(displayId); + } + + private boolean isImeShowing(int displayId) { + PerDisplay pd = mImePerDisplay.get(displayId); + if (pd == null) { + return false; + } + final InsetsSource imeSource = pd.mInsetsState.getSource(InsetsState.ITYPE_IME); + return imeSource != null && pd.mImeSourceControl != null && imeSource.isVisible(); + } + + private void dispatchPositionChanged(int displayId, int imeTop, + SurfaceControl.Transaction t) { + synchronized (mPositionProcessors) { + for (ImePositionProcessor pp : mPositionProcessors) { + pp.onImePositionChanged(displayId, imeTop, t); + } + } + } + + private void dispatchStartPositioning(int displayId, int imeTop, int finalImeTop, + boolean show, SurfaceControl.Transaction t) { + synchronized (mPositionProcessors) { + for (ImePositionProcessor pp : mPositionProcessors) { + pp.onImeStartPositioning(displayId, imeTop, finalImeTop, show, t); + } + } + } + + private void dispatchEndPositioning(int displayId, int imeTop, boolean show, + SurfaceControl.Transaction t) { + synchronized (mPositionProcessors) { + for (ImePositionProcessor pp : mPositionProcessors) { + pp.onImeEndPositioning(displayId, imeTop, show, t); + } + } + } + + /** + * Adds an {@link ImePositionProcessor} to be called during ime position updates. + */ + public void addPositionProcessor(ImePositionProcessor processor) { + synchronized (mPositionProcessors) { + if (mPositionProcessors.contains(processor)) { + return; + } + mPositionProcessors.add(processor); + } + } + + /** + * Removes an {@link ImePositionProcessor} to be called during ime position updates. + */ + public void removePositionProcessor(ImePositionProcessor processor) { + synchronized (mPositionProcessors) { + mPositionProcessors.remove(processor); + } + } + + class PerDisplay extends IDisplayWindowInsetsController.Stub { + final int mDisplayId; + final InsetsState mInsetsState = new InsetsState(); + InsetsSourceControl mImeSourceControl = null; + int mAnimationDirection = DIRECTION_NONE; + ValueAnimator mAnimation = null; + int mRotation = Surface.ROTATION_0; + + PerDisplay(int displayId, int initialRotation) { + mDisplayId = displayId; + mRotation = initialRotation; + } + + @Override + public void insetsChanged(InsetsState insetsState) { + if (mInsetsState.equals(insetsState)) { + return; + } + mInsetsState.set(insetsState, true /* copySources */); + } + + @Override + public void insetsControlChanged(InsetsState insetsState, + InsetsSourceControl[] activeControls) { + insetsChanged(insetsState); + if (activeControls != null) { + for (InsetsSourceControl activeControl : activeControls) { + if (activeControl == null) { + continue; + } + if (activeControl.getType() == InsetsState.ITYPE_IME) { + mImeSourceControl = activeControl; + } + } + } + } + + @Override + public void showInsets(int types, boolean fromIme) { + if ((types & WindowInsets.Type.ime()) == 0) { + return; + } + startAnimation(true /* show */); + } + + @Override + public void hideInsets(int types, boolean fromIme) { + if ((types & WindowInsets.Type.ime()) == 0) { + return; + } + startAnimation(false /* show */); + } + + /** + * Sends the local visibility state back to window manager. Needed for legacy adjustForIme. + */ + private void setVisibleDirectly(boolean visible) { + mInsetsState.getSource(InsetsState.ITYPE_IME).setVisible(visible); + try { + mSystemWindows.mWmService.modifyDisplayWindowInsets(mDisplayId, mInsetsState); + } catch (RemoteException e) { + } + } + + private int imeTop(InsetsSource imeSource, float surfaceOffset) { + return imeSource.getFrame().top + (int) surfaceOffset; + } + + private void startAnimation(final boolean show) { + final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME); + if (imeSource == null || mImeSourceControl == null) { + return; + } + if ((mAnimationDirection == DIRECTION_SHOW && show) + || (mAnimationDirection == DIRECTION_HIDE && !show)) { + return; + } + if (mAnimationDirection != DIRECTION_NONE) { + mAnimation.end(); + mAnimationDirection = DIRECTION_NONE; + } + mAnimationDirection = show ? DIRECTION_SHOW : DIRECTION_HIDE; + mHandler.post(() -> { + final float defaultY = mImeSourceControl.getSurfacePosition().y; + final float x = mImeSourceControl.getSurfacePosition().x; + final float startY = show ? defaultY + imeSource.getFrame().height() : defaultY; + final float endY = show ? defaultY : defaultY + imeSource.getFrame().height(); + mAnimation = ValueAnimator.ofFloat(startY, endY); + mAnimation.setDuration( + show ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS); + + mAnimation.addUpdateListener(animation -> { + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + float value = (float) animation.getAnimatedValue(); + t.setPosition(mImeSourceControl.getLeash(), x, value); + dispatchPositionChanged(mDisplayId, imeTop(imeSource, value), t); + t.apply(); + t.close(); + }); + mAnimation.setInterpolator(INTERPOLATOR); + mAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + t.setPosition(mImeSourceControl.getLeash(), x, startY); + dispatchStartPositioning(mDisplayId, imeTop(imeSource, startY), + imeTop(imeSource, endY), mAnimationDirection == DIRECTION_SHOW, + t); + if (mAnimationDirection == DIRECTION_SHOW) { + t.show(mImeSourceControl.getLeash()); + } + t.apply(); + t.close(); + } + @Override + public void onAnimationEnd(Animator animation) { + SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + t.setPosition(mImeSourceControl.getLeash(), x, endY); + dispatchEndPositioning(mDisplayId, imeTop(imeSource, endY), + mAnimationDirection == DIRECTION_SHOW, t); + if (mAnimationDirection == DIRECTION_HIDE) { + t.hide(mImeSourceControl.getLeash()); + } + t.apply(); + t.close(); + + mAnimationDirection = DIRECTION_NONE; + mAnimation = null; + } + }); + if (!show) { + // When going away, queue up insets change first, otherwise any bounds changes + // can have a "flicker" of ime-provided insets. + setVisibleDirectly(false /* visible */); + } + mAnimation.start(); + if (show) { + // When showing away, queue up insets change last, otherwise any bounds changes + // can have a "flicker" of ime-provided insets. + setVisibleDirectly(true /* visible */); + } + }); + } + } + + /** + * Allows other things to synchronize with the ime position + */ + public interface ImePositionProcessor { + /** + * Called when the IME position is starting to animate. + */ + void onImeStartPositioning(int displayId, int imeTop, int finalImeTop, boolean showing, + SurfaceControl.Transaction t); + + /** + * Called when the ime position changed. This is expected to be a synchronous call on the + * animation thread. Operations can be added to the transaction to be applied in sync. + */ + void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t); + + /** + * Called when the IME position is done animating. + */ + void onImeEndPositioning(int displayId, int imeTop, boolean showing, + SurfaceControl.Transaction t); + } +} diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 472baf6700c6..ba9d757d979f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -205,6 +205,7 @@ import android.view.Display; import android.view.DisplayCutout; import android.view.DisplayInfo; import android.view.Gravity; +import android.view.IDisplayWindowInsetsController; import android.view.ISystemGestureExclusionListener; import android.view.IWindow; import android.view.InputChannel; @@ -218,6 +219,7 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.SurfaceSession; import android.view.View; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowManagerPolicyConstants.PointerEventListener; @@ -570,6 +572,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ WindowState mInputMethodTarget; + InsetsControlTarget mInputMethodControlTarget; + /** If true hold off on modifying the animation layer of mInputMethodTarget */ boolean mInputMethodTargetWaitingAnim; @@ -598,6 +602,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private final float mWindowCornerRadius; private final SparseArray<ShellRoot> mShellRoots = new SparseArray<>(); + RemoteInsetsControlTarget mRemoteInsetsControlTarget = null; + private final IBinder.DeathRecipient mRemoteInsetsDeath = + () -> { + synchronized (mWmService.mGlobalLock) { + mRemoteInsetsControlTarget = null; + } + }; private RootWindowContainer mRootWindowContainer; @@ -1156,6 +1167,22 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mShellRoots.remove(windowType); } + void setRemoteInsetsController(IDisplayWindowInsetsController controller) { + if (mRemoteInsetsControlTarget != null) { + mRemoteInsetsControlTarget.mRemoteInsetsController.asBinder().unlinkToDeath( + mRemoteInsetsDeath, 0); + mRemoteInsetsControlTarget = null; + } + if (controller != null) { + try { + controller.asBinder().linkToDeath(mRemoteInsetsDeath, 0); + mRemoteInsetsControlTarget = new RemoteInsetsControlTarget(controller); + } catch (RemoteException e) { + return; + } + } + } + /** Changes the display the input window token is housed on to this one. */ void reParentWindowToken(WindowToken token) { final DisplayContent prevDc = token.getDisplayContent(); @@ -3383,6 +3410,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + boolean isImeAttachedToApp() { + return (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null + && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN + // An activity with override bounds should be letterboxed inside its parent bounds, + // so it doesn't fill the screen. + && mInputMethodTarget.mActivityRecord.matchParentBounds()); + } + private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) { if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) { return; @@ -3391,7 +3426,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mInputMethodTarget = target; mInputMethodTargetWaitingAnim = targetWaitingAnim; assignWindowLayers(false /* setLayoutNeeded */); - mInsetsStateController.onImeTargetChanged(target); + mInputMethodControlTarget = computeImeControlTarget(); + mInsetsStateController.onImeTargetChanged(mInputMethodControlTarget); updateImeParent(); } @@ -3416,11 +3452,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo // Attach it to app if the target is part of an app and such app is covering the entire // screen. If it's not covering the entire screen the IME might extend beyond the apps // bounds. - if (mInputMethodTarget != null && mInputMethodTarget.mActivityRecord != null - && mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN - // An activity with override bounds should be letterboxed inside its parent bounds, - // so it doesn't fill the screen. - && mInputMethodTarget.mActivityRecord.matchParentBounds()) { + if (isImeAttachedToApp()) { return mInputMethodTarget.mActivityRecord.getSurfaceControl(); } @@ -3428,6 +3460,19 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mWindowContainers.getSurfaceControl(); } + /** + * Computes which control-target the IME should be attached to. + */ + @VisibleForTesting + InsetsControlTarget computeImeControlTarget() { + if (!isImeAttachedToApp() && mRemoteInsetsControlTarget != null) { + return mRemoteInsetsControlTarget; + } + + // Otherwise, we just use the ime target + return mInputMethodTarget; + } + void setLayoutNeeded() { if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3)); mLayoutNeeded = true; @@ -6688,4 +6733,50 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo Context getDisplayUiContext() { return mDisplayPolicy.getSystemUiContext(); } + + class RemoteInsetsControlTarget implements InsetsControlTarget { + private final IDisplayWindowInsetsController mRemoteInsetsController; + + RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) { + mRemoteInsetsController = controller; + } + + void notifyInsetsChanged() { + try { + mRemoteInsetsController.insetsChanged( + getInsetsStateController().getRawInsetsState()); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to deliver inset state change", e); + } + } + + @Override + public void notifyInsetsControlChanged() { + final InsetsStateController stateController = getInsetsStateController(); + try { + mRemoteInsetsController.insetsControlChanged(stateController.getRawInsetsState(), + stateController.getControlsForDispatch(this)); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to deliver inset state change", e); + } + } + + @Override + public void showInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) { + try { + mRemoteInsetsController.showInsets(types, fromIme); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to deliver showInsets", e); + } + } + + @Override + public void hideInsets(@WindowInsets.Type.InsetsType int types, boolean fromIme) { + try { + mRemoteInsetsController.hideInsets(types, fromIme); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to deliver showInsets", e); + } + } + } } diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 05ede21472f2..fb97ecf8bbc4 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -69,7 +69,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { mShowImeRunner = () -> { // Target should still be the same. if (isImeTargetFromDisplayContentAndImeSame()) { - mDisplayContent.mInputMethodTarget.showInsets( + mDisplayContent.mInputMethodControlTarget.showInsets( WindowInsets.Type.ime(), true /* fromIme */); } abortShowImePostLayout(); diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 184e7d61c355..7b40f609aaf1 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -210,7 +210,7 @@ class InsetsSourceProvider { new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top)); } - boolean onInsetsModified(WindowState caller, InsetsSource modifiedSource) { + boolean onInsetsModified(InsetsControlTarget caller, InsetsSource modifiedSource) { if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) { return false; } diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 152607470ed1..720493f4a466 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -91,6 +91,10 @@ class InsetsStateController { return state; } + InsetsState getRawInsetsState() { + return mState; + } + @Nullable InsetsSourceControl[] getControlsForDispatch(InsetsControlTarget target) { ArrayList<Integer> controlled = mControlTargetTypeMap.get(target); if (controlled == null) { @@ -144,7 +148,7 @@ class InsetsStateController { getImeSourceProvider().onPostInsetsDispatched(); } - void onInsetsModified(WindowState windowState, InsetsState state) { + void onInsetsModified(InsetsControlTarget windowState, InsetsState state) { boolean changed = false; for (int i = state.getSourcesCount() - 1; i >= 0; i--) { final InsetsSource source = state.sourceAt(i); @@ -296,6 +300,9 @@ class InsetsStateController { void notifyInsetsChanged() { mDisplayContent.forAllWindows(mDispatchInsetsChanged, true /* traverseTopToBottom */); + if (mDisplayContent.mRemoteInsetsControlTarget != null) { + mDisplayContent.mRemoteInsetsControlTarget.notifyInsetsChanged(); + } } void dump(String prefix, PrintWriter pw) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 223e9b9e3df2..fb1ec3300749 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -205,6 +205,7 @@ import android.view.DisplayInfo; import android.view.Gravity; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IDisplayFoldListener; +import android.view.IDisplayWindowInsetsController; import android.view.IDisplayWindowListener; import android.view.IDisplayWindowRotationController; import android.view.IDockedStackListener; @@ -3727,6 +3728,48 @@ public class WindowManagerService extends IWindowManager.Stub } @Override + public void setDisplayWindowInsetsController( + int displayId, IDisplayWindowInsetsController insetsController) { + if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS); + } + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + return; + } + dc.setRemoteInsetsController(insetsController); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + @Override + public void modifyDisplayWindowInsets(int displayId, InsetsState state) { + if (mContext.checkCallingOrSelfPermission(MANAGE_APP_TOKENS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Must hold permission " + MANAGE_APP_TOKENS); + } + final long origId = Binder.clearCallingIdentity(); + try { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null || dc.mRemoteInsetsControlTarget == null) { + return; + } + dc.getInsetsStateController().onInsetsModified( + dc.mRemoteInsetsControlTarget, state); + } + } finally { + Binder.restoreCallingIdentity(origId); + } + } + + @Override public int watchRotation(IRotationWatcher watcher, int displayId) { final DisplayContent displayContent; synchronized (mGlobalLock) { @@ -7314,7 +7357,8 @@ public class WindowManagerService extends IWindowManager.Stub // If there was a pending IME show(), reset it as IME has been // requested to be hidden. dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout(); - dc.mInputMethodTarget.hideInsets(WindowInsets.Type.ime(), true /* fromIme */); + dc.mInputMethodControlTarget.hideInsets(WindowInsets.Type.ime(), + true /* fromIme */); } } } |