Merge "Fix IME flicker: move hiding the surface into the control target" into rvc-dev
This commit is contained in:
@@ -605,9 +605,6 @@ public class InputMethodService extends AbstractInputMethodService {
|
|||||||
if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
|
if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
|
||||||
+ " ic=" + mInputConnection);
|
+ " ic=" + mInputConnection);
|
||||||
// Unbind input is per process per display.
|
// Unbind input is per process per display.
|
||||||
// TODO(b/150902448): free-up IME surface when target is changing.
|
|
||||||
// e.g. DisplayContent#setInputMethodTarget()
|
|
||||||
removeImeSurface();
|
|
||||||
onUnbindInput();
|
onUnbindInput();
|
||||||
mInputBinding = null;
|
mInputBinding = null;
|
||||||
mInputConnection = null;
|
mInputConnection = null;
|
||||||
|
|||||||
@@ -119,11 +119,11 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
|
|||||||
// If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
|
// If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
|
||||||
// this code here means that we now got control, so we can start the animation immediately.
|
// this code here means that we now got control, so we can start the animation immediately.
|
||||||
// If client window is trying to control IME and IME is already visible, it is immediate.
|
// If client window is trying to control IME and IME is already visible, it is immediate.
|
||||||
if (fromIme || mState.getSource(getType()).isVisible()) {
|
if (fromIme || mState.getSource(getType()).isVisible() && getControl() != null) {
|
||||||
return ShowResult.SHOW_IMMEDIATELY;
|
return ShowResult.SHOW_IMMEDIATELY;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getImm().requestImeShow(null /* resultReceiver */)
|
return getImm().requestImeShow(mController.getHost().getWindowToken())
|
||||||
? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
|
? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,12 +132,15 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
void notifyHidden() {
|
void notifyHidden() {
|
||||||
getImm().notifyImeHidden();
|
getImm().notifyImeHidden(mController.getHost().getWindowToken());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeSurface() {
|
public void removeSurface() {
|
||||||
getImm().removeImeSurface();
|
final IBinder window = mController.getHost().getWindowToken();
|
||||||
|
if (window != null) {
|
||||||
|
getImm().removeImeSurface(window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -146,6 +149,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
|
|||||||
super.setControl(control, showTypes, hideTypes);
|
super.setControl(control, showTypes, hideTypes);
|
||||||
if (control == null && !mIsRequestedVisibleAwaitingControl) {
|
if (control == null && !mIsRequestedVisibleAwaitingControl) {
|
||||||
hide();
|
hide();
|
||||||
|
removeSurface();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,9 @@ public class InsetsSourceConsumer {
|
|||||||
if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
|
if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
|
||||||
applyHiddenToControl();
|
applyHiddenToControl();
|
||||||
}
|
}
|
||||||
|
if (!requestedVisible && !mIsAnimationPending) {
|
||||||
|
removeSurface();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastControl != null) {
|
if (lastControl != null) {
|
||||||
|
|||||||
@@ -9380,6 +9380,11 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
return mInputEventReceiver.getToken();
|
return mInputEventReceiver.getToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public IBinder getWindowToken() {
|
||||||
|
return mAttachInfo.mWindowToken;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for managing the accessibility interaction connection
|
* Class for managing the accessibility interaction connection
|
||||||
* based on the global accessibility state.
|
* based on the global accessibility state.
|
||||||
|
|||||||
@@ -2109,28 +2109,36 @@ public final class InputMethodManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Call showSoftInput with currently focused view.
|
* Call showSoftInput with currently focused view.
|
||||||
* @return {@code true} if IME can be shown.
|
*
|
||||||
|
* @param windowToken the window from which this request originates. If this doesn't match the
|
||||||
|
* currently served view, the request is ignored and returns {@code false}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public boolean requestImeShow(ResultReceiver resultReceiver) {
|
public boolean requestImeShow(IBinder windowToken) {
|
||||||
synchronized (mH) {
|
synchronized (mH) {
|
||||||
final View servedView = getServedViewLocked();
|
final View servedView = getServedViewLocked();
|
||||||
if (servedView == null) {
|
if (servedView == null || servedView.getWindowToken() != windowToken) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
showSoftInput(servedView, 0 /* flags */, resultReceiver);
|
showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify IME directly that it is no longer visible.
|
* Notify IME directly that it is no longer visible.
|
||||||
|
*
|
||||||
|
* @param windowToken the window from which this request originates. If this doesn't match the
|
||||||
|
* currently served view, the request is ignored.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void notifyImeHidden() {
|
public void notifyImeHidden(IBinder windowToken) {
|
||||||
synchronized (mH) {
|
synchronized (mH) {
|
||||||
try {
|
try {
|
||||||
if (mCurMethod != null) {
|
if (mCurMethod != null && mCurRootView != null
|
||||||
|
&& mCurRootView.getWindowToken() == windowToken) {
|
||||||
mCurMethod.notifyImeHidden();
|
mCurMethod.notifyImeHidden();
|
||||||
}
|
}
|
||||||
} catch (RemoteException re) {
|
} catch (RemoteException re) {
|
||||||
@@ -2140,15 +2148,15 @@ public final class InputMethodManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify IME directly to remove surface as it is no longer visible.
|
* Notify IME directly to remove surface as it is no longer visible.
|
||||||
|
* @param windowToken The client window token that requests the IME to remove its surface.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void removeImeSurface() {
|
public void removeImeSurface(IBinder windowToken) {
|
||||||
synchronized (mH) {
|
synchronized (mH) {
|
||||||
try {
|
try {
|
||||||
if (mCurMethod != null) {
|
mService.removeImeSurfaceFromWindow(windowToken);
|
||||||
mCurMethod.removeImeSurface();
|
} catch (RemoteException e) {
|
||||||
}
|
throw e.rethrowFromSystemServer();
|
||||||
} catch (RemoteException re) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,5 +73,8 @@ interface IInputMethodManager {
|
|||||||
in float[] matrixValues);
|
in float[] matrixValues);
|
||||||
|
|
||||||
oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
|
oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
|
||||||
|
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
|
||||||
void removeImeSurface();
|
void removeImeSurface();
|
||||||
|
/** Remove the IME surface. Requires passing the currently focused window. */
|
||||||
|
void removeImeSurfaceFromWindow(in IBinder windowToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ public class InsetsSourceConsumerTest {
|
|||||||
private SurfaceControl mLeash;
|
private SurfaceControl mLeash;
|
||||||
@Mock Transaction mMockTransaction;
|
@Mock Transaction mMockTransaction;
|
||||||
private InsetsSource mSpyInsetsSource;
|
private InsetsSource mSpyInsetsSource;
|
||||||
|
private boolean mRemoveSurfaceCalled = false;
|
||||||
|
private InsetsController mController;
|
||||||
|
private InsetsState mState;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
@@ -89,13 +92,19 @@ public class InsetsSourceConsumerTest {
|
|||||||
} catch (BadTokenException e) {
|
} catch (BadTokenException e) {
|
||||||
// activity isn't running, lets ignore BadTokenException.
|
// activity isn't running, lets ignore BadTokenException.
|
||||||
}
|
}
|
||||||
InsetsState state = new InsetsState();
|
mState = new InsetsState();
|
||||||
mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
|
mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
|
||||||
state.addSource(mSpyInsetsSource);
|
mState.addSource(mSpyInsetsSource);
|
||||||
|
|
||||||
mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, state,
|
mController = new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl));
|
||||||
() -> mMockTransaction,
|
mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mState,
|
||||||
new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl)));
|
() -> mMockTransaction, mController) {
|
||||||
|
@Override
|
||||||
|
public void removeSurface() {
|
||||||
|
super.removeSurface();
|
||||||
|
mRemoveSurfaceCalled = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
instrumentation.waitForIdleSync();
|
instrumentation.waitForIdleSync();
|
||||||
|
|
||||||
@@ -171,6 +180,25 @@ public class InsetsSourceConsumerTest {
|
|||||||
mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
|
mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
|
||||||
new int[1], hideTypes);
|
new int[1], hideTypes);
|
||||||
assertEquals(statusBars(), hideTypes[0]);
|
assertEquals(statusBars(), hideTypes[0]);
|
||||||
|
assertFalse(mRemoveSurfaceCalled);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRestore_noAnimation() {
|
||||||
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
|
mConsumer.hide();
|
||||||
|
mController.onStateChanged(mState);
|
||||||
|
mConsumer.setControl(null, new int[1], new int[1]);
|
||||||
|
reset(mMockTransaction);
|
||||||
|
verifyZeroInteractions(mMockTransaction);
|
||||||
|
mRemoveSurfaceCalled = false;
|
||||||
|
int[] hideTypes = new int[1];
|
||||||
|
mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
|
||||||
|
new int[1], hideTypes);
|
||||||
|
assertTrue(mRemoveSurfaceCalled);
|
||||||
|
assertEquals(0, hideTypes[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,6 +226,8 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
|
if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
|
||||||
&& mAnimation != null) {
|
&& mAnimation != null) {
|
||||||
startAnimation(mImeShowing, true /* forceRestart */);
|
startAnimation(mImeShowing, true /* forceRestart */);
|
||||||
|
} else if (!mImeShowing) {
|
||||||
|
removeImeSurface();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -370,16 +372,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
dispatchEndPositioning(mDisplayId, mCancelled, t);
|
dispatchEndPositioning(mDisplayId, mCancelled, t);
|
||||||
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
|
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
|
||||||
t.hide(mImeSourceControl.getLeash());
|
t.hide(mImeSourceControl.getLeash());
|
||||||
final IInputMethodManager imms = getImms();
|
removeImeSurface();
|
||||||
if (imms != null) {
|
|
||||||
try {
|
|
||||||
// Remove the IME surface to make the insets invisible for
|
|
||||||
// non-client controlled insets.
|
|
||||||
imms.removeImeSurface();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Slog.e(TAG, "Failed to remove IME surface.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
t.apply();
|
t.apply();
|
||||||
mTransactionPool.release(t);
|
mTransactionPool.release(t);
|
||||||
@@ -402,6 +395,19 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void removeImeSurface() {
|
||||||
|
final IInputMethodManager imms = getImms();
|
||||||
|
if (imms != null) {
|
||||||
|
try {
|
||||||
|
// Remove the IME surface to make the insets invisible for
|
||||||
|
// non-client controlled insets.
|
||||||
|
imms.removeImeSurface();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Failed to remove IME surface.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows other things to synchronize with the ime position
|
* Allows other things to synchronize with the ime position
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -119,6 +119,11 @@ public abstract class InputMethodManagerInternal {
|
|||||||
*/
|
*/
|
||||||
public abstract void reportImeControl(@Nullable IBinder windowToken);
|
public abstract void reportImeControl(@Nullable IBinder windowToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the IME surface.
|
||||||
|
*/
|
||||||
|
public abstract void removeImeSurface();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing.
|
* Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing.
|
||||||
*/
|
*/
|
||||||
@@ -166,6 +171,10 @@ public abstract class InputMethodManagerInternal {
|
|||||||
@Override
|
@Override
|
||||||
public void reportImeControl(@Nullable IBinder windowToken) {
|
public void reportImeControl(@Nullable IBinder windowToken) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeImeSurface() {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
static final int MSG_INITIALIZE_IME = 1040;
|
static final int MSG_INITIALIZE_IME = 1040;
|
||||||
static final int MSG_CREATE_SESSION = 1050;
|
static final int MSG_CREATE_SESSION = 1050;
|
||||||
static final int MSG_REMOVE_IME_SURFACE = 1060;
|
static final int MSG_REMOVE_IME_SURFACE = 1060;
|
||||||
|
static final int MSG_REMOVE_IME_SURFACE_FROM_WINDOW = 1061;
|
||||||
|
|
||||||
static final int MSG_START_INPUT = 2000;
|
static final int MSG_START_INPUT = 2000;
|
||||||
|
|
||||||
@@ -4005,6 +4006,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
|
mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeImeSurfaceFromWindow(IBinder windowToken) {
|
||||||
|
// No permission check, because we'll only execute the request if the calling window is
|
||||||
|
// also the current IME client.
|
||||||
|
mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
@BinderThread
|
@BinderThread
|
||||||
private void notifyUserAction(@NonNull IBinder token) {
|
private void notifyUserAction(@NonNull IBinder token) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@@ -4278,11 +4286,27 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case MSG_REMOVE_IME_SURFACE: {
|
case MSG_REMOVE_IME_SURFACE: {
|
||||||
try {
|
synchronized (mMethodMap) {
|
||||||
if (mEnabledSession != null && mEnabledSession.session != null) {
|
try {
|
||||||
mEnabledSession.session.removeImeSurface();
|
if (mEnabledSession != null && mEnabledSession.session != null
|
||||||
|
&& !mShowRequested) {
|
||||||
|
mEnabledSession.session.removeImeSurface();
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case MSG_REMOVE_IME_SURFACE_FROM_WINDOW: {
|
||||||
|
IBinder windowToken = (IBinder) msg.obj;
|
||||||
|
synchronized (mMethodMap) {
|
||||||
|
try {
|
||||||
|
if (windowToken == mCurFocusedWindow
|
||||||
|
&& mEnabledSession != null && mEnabledSession.session != null) {
|
||||||
|
mEnabledSession.session.removeImeSurface();
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -5116,6 +5140,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
public void reportImeControl(@Nullable IBinder windowToken) {
|
public void reportImeControl(@Nullable IBinder windowToken) {
|
||||||
mService.reportImeControl(windowToken);
|
mService.reportImeControl(windowToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeImeSurface() {
|
||||||
|
mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@BinderThread
|
@BinderThread
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ public final class MultiClientInputMethodManagerService {
|
|||||||
@Override
|
@Override
|
||||||
public void reportImeControl(@Nullable IBinder windowToken) {
|
public void reportImeControl(@Nullable IBinder windowToken) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeImeSurface() {
|
||||||
|
reportNotSupported();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1471,6 +1476,12 @@ public final class MultiClientInputMethodManagerService {
|
|||||||
reportNotSupported();
|
reportNotSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BinderThread
|
||||||
|
@Override
|
||||||
|
public void removeImeSurfaceFromWindow(IBinder windowToken) {
|
||||||
|
reportNotSupported();
|
||||||
|
}
|
||||||
|
|
||||||
@BinderThread
|
@BinderThread
|
||||||
@Override
|
@Override
|
||||||
public boolean showSoftInput(
|
public boolean showSoftInput(
|
||||||
|
|||||||
@@ -3574,12 +3574,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateImeControlTarget() {
|
void updateImeControlTarget() {
|
||||||
mInputMethodControlTarget = computeImeControlTarget();
|
mInputMethodControlTarget = computeImeControlTarget();
|
||||||
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
|
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
|
||||||
|
|
||||||
final WindowState win = mInputMethodControlTarget != null
|
final WindowState win = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
|
||||||
? mInputMethodControlTarget.getWindow() : null;
|
|
||||||
final IBinder token = win != null ? win.mClient.asBinder() : null;
|
final IBinder token = win != null ? win.mClient.asBinder() : null;
|
||||||
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
|
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
|
||||||
mWmService.mH.post(() ->
|
mWmService.mH.post(() ->
|
||||||
@@ -3603,6 +3602,17 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
|||||||
if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
|
if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
|
||||||
return mRemoteInsetsControlTarget;
|
return mRemoteInsetsControlTarget;
|
||||||
} else {
|
} else {
|
||||||
|
// Now, a special case -- if the last target's window is in the process of exiting, but
|
||||||
|
// not removed, keep on the last target to avoid IME flicker.
|
||||||
|
final WindowState cur = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
|
||||||
|
if (cur != null && !cur.mRemoved && cur.isDisplayedLw() && cur.isClosing()
|
||||||
|
&& !cur.isActivityTypeHome()) {
|
||||||
|
if (DEBUG_INPUT_METHOD) {
|
||||||
|
Slog.v(TAG_WM, "Not changing control while current window"
|
||||||
|
+ " is closing and not removed");
|
||||||
|
}
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
// Otherwise, we just use the ime target as received from IME.
|
// Otherwise, we just use the ime target as received from IME.
|
||||||
return mInputMethodInputTarget;
|
return mInputMethodInputTarget;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,14 @@ package com.android.server.wm;
|
|||||||
|
|
||||||
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
|
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
|
||||||
|
|
||||||
import android.graphics.PixelFormat;
|
|
||||||
import android.view.InsetsSource;
|
import android.view.InsetsSource;
|
||||||
import android.view.WindowInsets;
|
import android.view.WindowInsets;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.server.protolog.common.ProtoLog;
|
import com.android.server.protolog.common.ProtoLog;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for IME inset source on the server. It's called provider as it provides the
|
* Controller for IME inset source on the server. It's called provider as it provides the
|
||||||
* {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
|
* {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
|
||||||
@@ -132,8 +133,17 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
|
|||||||
|| (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
|
|| (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
|
||||||
&& dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
|
&& dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
|
||||||
|| mImeTargetFromIme == mDisplayContent.getImeFallback()
|
|| mImeTargetFromIme == mDisplayContent.getImeFallback()
|
||||||
// If IME target is transparent but control target matches requesting window.
|
|| (!mImeTargetFromIme.isClosing() && controlTarget == mImeTargetFromIme);
|
||||||
|| (controlTarget == mImeTargetFromIme
|
}
|
||||||
&& PixelFormat.formatHasAlpha(dcTarget.mAttrs.format));
|
|
||||||
|
@Override
|
||||||
|
public void dump(PrintWriter pw, String prefix) {
|
||||||
|
super.dump(pw, prefix);
|
||||||
|
if (mImeTargetFromIme != null) {
|
||||||
|
pw.print(prefix);
|
||||||
|
pw.print("showImePostLayout pending for mImeTargetFromIme=");
|
||||||
|
pw.print(mImeTargetFromIme);
|
||||||
|
pw.println();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,4 +62,8 @@ interface InsetsControlTarget {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns {@code target.getWindow()}, or null if {@code target} is {@code null}. */
|
||||||
|
static WindowState asWindowOrNull(InsetsControlTarget target) {
|
||||||
|
return target != null ? target.getWindow() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import android.view.InsetsState;
|
|||||||
import android.view.InsetsState.InternalInsetsType;
|
import android.view.InsetsState.InternalInsetsType;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import com.android.server.inputmethod.InputMethodManagerInternal;
|
||||||
import com.android.server.protolog.common.ProtoLog;
|
import com.android.server.protolog.common.ProtoLog;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
@@ -74,7 +75,21 @@ class InsetsStateController {
|
|||||||
w.notifyInsetsChanged();
|
w.notifyInsetsChanged();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() { };
|
private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() {
|
||||||
|
@Override
|
||||||
|
public void notifyInsetsControlChanged() {
|
||||||
|
InsetsSourceControl[] controls = getControlsForDispatch(this);
|
||||||
|
if (controls == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (InsetsSourceControl control : controls) {
|
||||||
|
if (control.getType() == ITYPE_IME) {
|
||||||
|
mDisplayContent.mWmService.mH.post(() ->
|
||||||
|
InputMethodManagerInternal.get().removeImeSurface());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
InsetsStateController(DisplayContent displayContent) {
|
InsetsStateController(DisplayContent displayContent) {
|
||||||
mDisplayContent = displayContent;
|
mDisplayContent = displayContent;
|
||||||
|
|||||||
@@ -2170,6 +2170,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
|
|||||||
if (isInputMethodTarget()) {
|
if (isInputMethodTarget()) {
|
||||||
dc.computeImeTarget(true /* updateImeTarget */);
|
dc.computeImeTarget(true /* updateImeTarget */);
|
||||||
}
|
}
|
||||||
|
if (dc.mInputMethodControlTarget == this) {
|
||||||
|
dc.updateImeControlTarget();
|
||||||
|
}
|
||||||
|
|
||||||
final int type = mAttrs.type;
|
final int type = mAttrs.type;
|
||||||
if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) {
|
if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) {
|
||||||
|
|||||||
@@ -897,6 +897,26 @@ public class DisplayContentTests extends WindowTestsBase {
|
|||||||
assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
|
assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComputeImeControlTarget_exitingApp() throws Exception {
|
||||||
|
final DisplayContent dc = createNewDisplay();
|
||||||
|
|
||||||
|
WindowState exitingWin = createWindow(null, TYPE_BASE_APPLICATION, "exiting app");
|
||||||
|
makeWindowVisible(exitingWin);
|
||||||
|
exitingWin.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
|
||||||
|
exitingWin.mAnimatingExit = true;
|
||||||
|
|
||||||
|
dc.mInputMethodControlTarget = exitingWin;
|
||||||
|
dc.mInputMethodTarget = dc.mInputMethodInputTarget =
|
||||||
|
createWindow(null, TYPE_BASE_APPLICATION, "starting app");
|
||||||
|
|
||||||
|
assertEquals(exitingWin, dc.computeImeControlTarget());
|
||||||
|
|
||||||
|
exitingWin.removeImmediately();
|
||||||
|
|
||||||
|
assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testComputeImeControlTarget_splitscreen() throws Exception {
|
public void testComputeImeControlTarget_splitscreen() throws Exception {
|
||||||
final DisplayContent dc = createNewDisplay();
|
final DisplayContent dc = createNewDisplay();
|
||||||
|
|||||||
Reference in New Issue
Block a user