Merge "IME animation: hide IME-related navbar icons until perceptible" into rvc-dev am: e658c76b5c am: ba68b71a5c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11837615

Change-Id: I897a1afc63f971cb8061d02c44dad41ce5b84031
This commit is contained in:
Adrian Roos
2020-06-23 07:21:31 +00:00
committed by Automerger Merge Worker
15 changed files with 203 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ import static android.view.InsetsState.ITYPE_IME;
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.os.Parcel;
import android.text.TextUtils;
import android.view.SurfaceControl.Transaction;
@@ -153,6 +154,15 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer {
return mIsRequestedVisibleAwaitingControl || isRequestedVisible();
}
@Override
public void onPerceptible(boolean perceptible) {
super.onPerceptible(perceptible);
final IBinder window = mController.getHost().getWindowToken();
if (window != null) {
getImm().reportPerceptible(window, perceptible);
}
}
private boolean isDummyOrEmptyEditor(EditorInfo info) {
// TODO(b/123044812): Handle dummy input gracefully in IME Insets API
return info == null || (info.fieldId <= 0 && info.inputType <= 0);

View File

@@ -16,6 +16,7 @@
package android.view;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
/**
@@ -64,4 +65,15 @@ public interface InsetsAnimationControlCallbacks {
* previous calls to applySurfaceParams.
*/
void releaseSurfaceControlFromRt(SurfaceControl sc);
/**
* Reports that the perceptibility of the given types has changed to the given value.
*
* A type is perceptible if it is not (almost) entirely off-screen and not (almost) entirely
* transparent.
*
* @param types the (public) types whose perceptibility has changed
* @param perceptible true, if the types are now perceptible, false if they are not perceptible
*/
void reportPerceptible(@InsetsType int types, boolean perceptible);
}

View File

@@ -87,6 +87,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
private float mPendingAlpha = 1.0f;
@VisibleForTesting(visibility = PACKAGE)
public boolean mReadyDispatched;
private Boolean mPerceptible;
@VisibleForTesting
public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls, Rect frame,
@@ -121,6 +122,14 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
new Bounds(mHiddenInsets, mShownInsets));
}
private boolean calculatePerceptible(Insets currentInsets, float currentAlpha) {
return 100 * currentInsets.left >= 5 * (mShownInsets.left - mHiddenInsets.left)
&& 100 * currentInsets.top >= 5 * (mShownInsets.top - mHiddenInsets.top)
&& 100 * currentInsets.right >= 5 * (mShownInsets.right - mHiddenInsets.right)
&& 100 * currentInsets.bottom >= 5 * (mShownInsets.bottom - mHiddenInsets.bottom)
&& currentAlpha >= 0.5f;
}
@Override
public boolean hasZeroInsetsIme() {
return mHasZeroInsetsIme;
@@ -175,6 +184,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
mPendingInsets = sanitize(insets);
mPendingAlpha = sanitize(alpha);
mController.scheduleApplyChangeInsets(this);
boolean perceptible = calculatePerceptible(mPendingInsets, mPendingAlpha);
if (mPerceptible == null || perceptible != mPerceptible) {
mController.reportPerceptible(mTypes, perceptible);
mPerceptible = perceptible;
}
}
@VisibleForTesting

View File

@@ -90,6 +90,11 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro
// Since we don't push the SurfaceParams to the RT we can release directly
sc.release();
}
@Override
public void reportPerceptible(int types, boolean perceptible) {
mMainThreadHandler.post(() -> mOuterCallbacks.reportPerceptible(types, perceptible));
}
};
@UiThread

View File

@@ -35,6 +35,7 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Trace;
import android.util.ArraySet;
import android.util.Log;
@@ -165,6 +166,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
/** @see ViewRootImpl#dipToPx */
int dipToPx(int dips);
/**
* @return token associated with the host, if it has one.
*/
@Nullable
IBinder getWindowToken();
}
private static final String TAG = "InsetsController";
@@ -1353,6 +1360,18 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
mHost.releaseSurfaceControlFromRt(sc);
}
@Override
public void reportPerceptible(int types, boolean perceptible) {
final ArraySet<Integer> internalTypes = toInternalType(types);
final int size = mSourceConsumers.size();
for (int i = 0; i < size; i++) {
final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
if (internalTypes.contains(consumer.getType())) {
consumer.onPerceptible(perceptible);
}
}
}
Host getHost() {
return mHost;
}

View File

@@ -260,6 +260,15 @@ public class InsetsSourceConsumer {
return ShowResult.SHOW_IMMEDIATELY;
}
/**
* Reports that this source's perceptibility has changed
*
* @param perceptible true if the source is perceptible, false otherwise.
* @see InsetsAnimationControlCallbacks#reportPerceptible
*/
public void onPerceptible(boolean perceptible) {
}
/**
* Notify listeners that window is now hidden.
*/
@@ -339,5 +348,6 @@ public class InsetsSourceConsumer {
t.hide(mSourceControl.getLeash());
}
t.apply();
onPerceptible(mRequestedVisible);
}
}

View File

@@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONT
import android.annotation.NonNull;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
@@ -236,4 +237,16 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host {
}
return 0;
}
@Override
public IBinder getWindowToken() {
if (mViewRoot == null) {
return null;
}
final View view = mViewRoot.getView();
if (view == null) {
return null;
}
return view.getWindowToken();
}
}

View File

@@ -541,6 +541,19 @@ public final class InputMethodManager {
return servedView.hasWindowFocus() || isAutofillUIShowing(servedView);
}
/**
* Reports whether the IME is currently perceptible or not, according to the leash applied by
* {@link android.view.WindowInsetsController}.
* @hide
*/
public void reportPerceptible(IBinder windowToken, boolean perceptible) {
try {
mService.reportPerceptible(windowToken, perceptible);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private final class DelegateImpl implements
ImeFocusController.InputMethodManagerDelegate {
/**

View File

@@ -72,5 +72,6 @@ interface IInputMethodManager {
void reportActivityView(in IInputMethodClient parentClient, int childDisplayId,
in float[] matrixValues);
oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
void removeImeSurface();
}

View File

@@ -234,6 +234,24 @@ public class InsetsAnimationControlImplTest {
verify(mMockListener).onFinished(mController);
}
@Test
public void testPerceptible_insets() {
mController.setInsetsAndAlpha(mController.getHiddenStateInsets(), 1f, 1f);
verify(mMockController).reportPerceptible(systemBars(), false);
mController.setInsetsAndAlpha(mController.getShownStateInsets(), 1f, 1f);
verify(mMockController).reportPerceptible(systemBars(), true);
}
@Test
public void testPerceptible_alpha() {
mController.setInsetsAndAlpha(mController.getShownStateInsets(), 0f, 1f);
verify(mMockController).reportPerceptible(systemBars(), false);
mController.setInsetsAndAlpha(mController.getShownStateInsets(), 1f, 1f);
verify(mMockController).reportPerceptible(systemBars(), true);
}
private void assertPosition(Matrix m, Rect original, Rect transformed) {
RectF rect = new RectF(original);
rect.offsetTo(0, 0);

View File

@@ -17,6 +17,7 @@
package com.android.server.inputmethod;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.os.IBinder;
import android.view.inputmethod.InlineSuggestionsRequest;
@@ -108,6 +109,16 @@ public abstract class InputMethodManagerInternal {
public abstract boolean transferTouchFocusToImeWindow(@NonNull IBinder sourceInputToken,
int displayId);
/**
* Reports that IME control has transferred to the given window token, or if null that
* control has been taken away from client windows (and is instead controlled by the policy
* or SystemUI).
*
* @param windowToken the window token that is now in control, or {@code null} if no client
* window is in control of the IME.
*/
public abstract void reportImeControl(@Nullable IBinder windowToken);
/**
* Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing.
*/
@@ -151,6 +162,10 @@ public abstract class InputMethodManagerInternal {
int displayId) {
return false;
}
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
};
/**

View File

@@ -179,6 +179,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
@@ -592,6 +593,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// Was the keyguard locked when this client became current?
private boolean mCurClientInKeyguard;
/**
* {@code true} if the IME has not been mostly hidden via {@link android.view.InsetsController}
*/
private boolean mCurPerceptible;
/**
* Set to true if our ServiceConnection is currently actively bound to
* a service (whether or not we have gotten its IBinder back yet).
@@ -2936,6 +2942,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (vis != 0 && isKeyguardLocked() && !mCurClientInKeyguard) {
vis = 0;
}
if (!mCurPerceptible) {
vis = 0;
}
// mImeWindowVis should be updated before calling shouldShowImeSwitcherLocked().
final boolean needsToShowImeSwitcher = shouldShowImeSwitcherLocked(vis);
if (mStatusBar != null) {
@@ -3148,6 +3157,28 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
@BinderThread
@Override
public void reportPerceptible(IBinder windowToken, boolean perceptible) {
Objects.requireNonNull(windowToken, "windowToken must not be null");
int uid = Binder.getCallingUid();
synchronized (mMethodMap) {
if (!calledFromValidUserLocked()) {
return;
}
final long ident = Binder.clearCallingIdentity();
try {
if (mCurFocusedWindow == windowToken
&& mCurPerceptible != perceptible) {
mCurPerceptible = perceptible;
updateSystemUiLocked(mImeWindowVis, mBackDisposition);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
@GuardedBy("mMethodMap")
boolean showCurrentInputLocked(IBinder windowToken, int flags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
@@ -3451,6 +3482,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurFocusedWindow = windowToken;
mCurFocusedWindowSoftInputMode = softInputMode;
mCurFocusedWindowClient = cs;
mCurPerceptible = true;
// Should we auto-show the IME even if the caller has not
// specified what should be done with it?
@@ -5010,6 +5042,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mInputManagerInternal.transferTouchFocus(sourceInputToken, curHostInputToken);
}
private void reportImeControl(@Nullable IBinder windowToken) {
synchronized (mMethodMap) {
if (mCurFocusedWindow != windowToken) {
// mCurPerceptible was set by the focused window, but it is no longer in control,
// so we reset mCurPerceptible.
mCurPerceptible = true;
}
}
}
private static final class LocalServiceImpl extends InputMethodManagerInternal {
@NonNull
private final InputMethodManagerService mService;
@@ -5062,6 +5104,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
int displayId) {
return mService.transferTouchFocusToImeWindow(sourceInputToken, displayId);
}
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
mService.reportImeControl(windowToken);
}
}
@BinderThread
@@ -5164,6 +5211,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
p.println(" mCurMethodId=" + mCurMethodId);
client = mCurClient;
p.println(" mCurClient=" + client + " mCurSeq=" + mCurSeq);
p.println(" mCurPerceptible=" + mCurPerceptible);
p.println(" mCurFocusedWindow=" + mCurFocusedWindow
+ " softInputMode=" +
InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode)

View File

@@ -221,6 +221,10 @@ public final class MultiClientInputMethodManagerService {
reportNotSupported();
return false;
}
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
});
}
@@ -1751,6 +1755,12 @@ public final class MultiClientInputMethodManagerService {
reportNotSupported();
}
@BinderThread
@Override
public void reportPerceptible(IBinder windowClient, boolean perceptible) {
reportNotSupported();
}
@BinderThread
@Override
public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out,

View File

@@ -210,6 +210,7 @@ import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.utils.DisplayRotationUtil;
@@ -3566,6 +3567,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
private void updateImeControlTarget() {
mInputMethodControlTarget = computeImeControlTarget();
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
final WindowState win = mInputMethodControlTarget != null
? mInputMethodControlTarget.getWindow() : 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.
mWmService.mH.post(() ->
InputMethodManagerInternal.get().reportImeControl(token)
);
}
private void updateImeParent() {

View File

@@ -482,6 +482,12 @@ class InsetsPolicy {
WindowInsetsAnimation animation,
Bounds bounds) {
}
@Override
public void reportPerceptible(int types, boolean perceptible) {
// No-op for now - only client windows report perceptibility for now, with policy
// controllers assumed to always be perceptible.
}
}
}
}