Merge "IME to systemui"
This commit is contained in:
48
core/java/android/view/IDisplayWindowInsetsController.aidl
Normal file
48
core/java/android/view/IDisplayWindowInsetsController.aidl
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -3726,6 +3727,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;
|
||||
@@ -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 */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user