Loading core/java/android/view/ImeInsetsSourceConsumer.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -87,7 +87,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}. * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}. */ */ @Override @Override @ShowResult int requestShow(boolean fromIme) { public @ShowResult int requestShow(boolean fromIme) { // TODO: ResultReceiver for IME. // TODO: ResultReceiver for IME. // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag. // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag. if (fromIme) { if (fromIme) { Loading @@ -95,7 +95,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } } return getImm().requestImeShow(null /* resultReceiver */) return getImm().requestImeShow(null /* resultReceiver */) ? ShowResult.SHOW_DELAYED : ShowResult.SHOW_FAILED; ? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED; } } /** /** Loading core/java/android/view/InsetsController.java +97 −39 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.view; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.toPublicType; import static android.view.InsetsState.toPublicType; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.ime; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; Loading @@ -31,6 +32,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.graphics.Insets; import android.graphics.Insets; import android.graphics.Rect; import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.os.RemoteException; import android.util.ArraySet; import android.util.ArraySet; import android.util.Log; import android.util.Log; Loading @@ -55,6 +57,7 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.function.BiFunction; /** /** * Implements {@link WindowInsetsController} on the client. * Implements {@link WindowInsetsController} on the client. Loading @@ -64,6 +67,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_HIDE_MS = 340; private static final int ANIMATION_DURATION_HIDE_MS = 340; private static final int PENDING_CONTROL_TIMEOUT_MS = 2000; static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f); static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f); Loading Loading @@ -241,6 +245,30 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mStartingAnimation = startingAnimation; mStartingAnimation = startingAnimation; } } } } /** * Represents a control request that we had to defer because we are waiting for the IME to * process our show request. */ private static class PendingControlRequest { PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener, long durationMs, Interpolator interpolator, @AnimationType int animationType, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { this.types = types; this.listener = listener; this.durationMs = durationMs; this.interpolator = interpolator; this.animationType = animationType; this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation; } final @InsetsType int types; final WindowInsetsAnimationControlListener listener; final long durationMs; final Interpolator interpolator; final @AnimationType int animationType; final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation; } private final String TAG = "InsetsControllerImpl"; private final String TAG = "InsetsControllerImpl"; Loading @@ -248,8 +276,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final InsetsState mTmpState = new InsetsState(); private final InsetsState mTmpState = new InsetsState(); private final Rect mFrame = new Rect(); private final Rect mFrame = new Rect(); private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator; private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final ViewRootImpl mViewRoot; private final ViewRootImpl mViewRoot; private final Handler mHandler; private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>(); private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>(); Loading @@ -263,7 +293,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final Rect mLastLegacyContentInsets = new Rect(); private final Rect mLastLegacyContentInsets = new Rect(); private final Rect mLastLegacyStableInsets = new Rect(); private final Rect mLastLegacyStableInsets = new Rect(); private int mPendingTypesToShow; /** Pending control request that is waiting on IME to be ready to be shown */ private PendingControlRequest mPendingImeControlRequest; private int mLastLegacySoftInputMode; private int mLastLegacySoftInputMode; private int mLastLegacySystemUiFlags; private int mLastLegacySystemUiFlags; Loading @@ -271,8 +302,26 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private SyncRtSurfaceTransactionApplier mApplier; private SyncRtSurfaceTransactionApplier mApplier; private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; public InsetsController(ViewRootImpl viewRoot) { public InsetsController(ViewRootImpl viewRoot) { this(viewRoot, (controller, type) -> { if (type == ITYPE_IME) { return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller); } else { return new InsetsSourceConsumer(type, controller.mState, Transaction::new, controller); } }, viewRoot.mHandler); } @VisibleForTesting public InsetsController(ViewRootImpl viewRoot, BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator, Handler handler) { mViewRoot = viewRoot; mViewRoot = viewRoot; mConsumerCreator = consumerCreator; mHandler = handler; mAnimCallback = () -> { mAnimCallback = () -> { mAnimCallbackScheduled = false; mAnimCallbackScheduled = false; if (mRunningAnimations.isEmpty()) { if (mRunningAnimations.isEmpty()) { Loading Loading @@ -393,7 +442,21 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation show(types, false /* fromIme */); show(types, false /* fromIme */); } } void show(@InsetsType int types, boolean fromIme) { @VisibleForTesting public void show(@InsetsType int types, boolean fromIme) { // Handle pending request ready in case there was one set. if (fromIme && mPendingImeControlRequest != null) { PendingControlRequest pendingRequest = mPendingImeControlRequest; mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); controlAnimationUnchecked(pendingRequest.types, pendingRequest.listener, mFrame, true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator, false /* fade */, pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation); return; } // TODO: Support a ResultReceiver for IME. // TODO: Support a ResultReceiver for IME. // TODO(b/123718661): Make show() work for multi-session IME. // TODO(b/123718661): Make show() work for multi-session IME. int typesReady = 0; int typesReady = 0; Loading Loading @@ -463,6 +526,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { if (types == 0) { if (types == 0) { // nothing to animate. // nothing to animate. listener.onCancelled(); return; return; } } cancelExistingControllers(types); cancelExistingControllers(types); Loading @@ -471,19 +535,18 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); Pair<Integer, Boolean> typesReadyPair = collectSourceControls( Pair<Integer, Boolean> typesReadyPair = collectSourceControls( fromIme, internalTypes, controls, listener); fromIme, internalTypes, controls); int typesReady = typesReadyPair.first; int typesReady = typesReadyPair.first; boolean isReady = typesReadyPair.second; boolean imeReady = typesReadyPair.second; if (!isReady) { if (!imeReady) { // IME isn't ready, all requested types would be shown once IME is ready. // IME isn't ready, all requested types will be animated once IME is ready mPendingTypesToShow = typesReady; abortPendingImeControlRequest(); // TODO: listener for pending types. mPendingImeControlRequest = new PendingControlRequest(types, listener, durationMs, interpolator, animationType, layoutInsetsDuringAnimation); mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS); return; return; } } // pending types from previous request. typesReady = collectPendingTypes(typesReady); if (typesReady == 0) { if (typesReady == 0) { listener.onCancelled(); listener.onCancelled(); return; return; Loading @@ -496,13 +559,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } /** /** * @return Pair of (types ready to animate, is ready to animate). * @return Pair of (types ready to animate, IME ready to animate). */ */ private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls, ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls) { WindowInsetsAnimationControlListener listener) { int typesReady = 0; int typesReady = 0; boolean isReady = true; boolean imeReady = true; for (int i = internalTypes.size() - 1; i >= 0; i--) { for (int i = internalTypes.size() - 1; i >= 0; i--) { InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); boolean setVisible = !consumer.isRequestedVisible(); boolean setVisible = !consumer.isRequestedVisible(); Loading @@ -512,16 +574,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation case ShowResult.SHOW_IMMEDIATELY: case ShowResult.SHOW_IMMEDIATELY: typesReady |= InsetsState.toPublicType(consumer.getType()); typesReady |= InsetsState.toPublicType(consumer.getType()); break; break; case ShowResult.SHOW_DELAYED: case ShowResult.IME_SHOW_DELAYED: isReady = false; imeReady = false; break; break; case ShowResult.SHOW_FAILED: case ShowResult.IME_SHOW_FAILED: // IME cannot be shown (since it didn't have focus), proceed // IME cannot be shown (since it didn't have focus), proceed // with animation of other types. // with animation of other types. if (mPendingTypesToShow != 0) { // remove IME from pending because view no longer has focus. mPendingTypesToShow &= ~InsetsState.toPublicType(ITYPE_IME); } break; break; } } } else { } else { Loading @@ -538,13 +596,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation controls.put(consumer.getType(), control); controls.put(consumer.getType(), control); } } } } return new Pair<>(typesReady, isReady); return new Pair<>(typesReady, imeReady); } private int collectPendingTypes(@InsetsType int typesReady) { typesReady |= mPendingTypesToShow; mPendingTypesToShow = 0; return typesReady; } } private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode( private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode( Loading Loading @@ -577,6 +629,17 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation cancelAnimation(control, true /* invokeCallback */); cancelAnimation(control, true /* invokeCallback */); } } } } if ((types & ime()) != 0) { abortPendingImeControlRequest(); } } private void abortPendingImeControlRequest() { if (mPendingImeControlRequest != null) { mPendingImeControlRequest.listener.onCancelled(); mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); } } } @VisibleForTesting @VisibleForTesting Loading Loading @@ -608,6 +671,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation cancelAnimation(control, true /* invokeCallback */); cancelAnimation(control, true /* invokeCallback */); } } } } if (consumer.getType() == ITYPE_IME) { abortPendingImeControlRequest(); } } } private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) { private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) { Loading Loading @@ -635,7 +701,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (controller != null) { if (controller != null) { return controller; return controller; } } controller = createConsumerOfType(type); controller = mConsumerCreator.apply(this, type); mSourceConsumers.put(type, controller); mSourceConsumers.put(type, controller); return controller; return controller; } } Loading Loading @@ -696,14 +762,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return ANIMATION_TYPE_NONE; return ANIMATION_TYPE_NONE; } } private InsetsSourceConsumer createConsumerOfType(int type) { if (type == ITYPE_IME) { return new ImeInsetsSourceConsumer(mState, Transaction::new, this); } else { return new InsetsSourceConsumer(type, mState, Transaction::new, this); } } /** /** * Sends the local visibility state back to window manager. * Sends the local visibility state back to window manager. */ */ Loading core/java/android/view/InsetsSourceConsumer.java +5 −4 Original line number Original line Diff line number Diff line Loading @@ -36,7 +36,7 @@ import java.util.function.Supplier; public class InsetsSourceConsumer { public class InsetsSourceConsumer { @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.SHOW_DELAYED, ShowResult.SHOW_FAILED}) @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED}) @interface ShowResult { @interface ShowResult { /** /** * Window type is ready to be shown, will be shown immidiately. * Window type is ready to be shown, will be shown immidiately. Loading @@ -46,12 +46,12 @@ public class InsetsSourceConsumer { * Result will be delayed. Window needs to be prepared or request is not from controller. * Result will be delayed. Window needs to be prepared or request is not from controller. * Request will be delegated to controller and may or may not be shown. * Request will be delegated to controller and may or may not be shown. */ */ int SHOW_DELAYED = 1; int IME_SHOW_DELAYED = 1; /** /** * Window will not be shown because one of the conditions couldn't be met. * Window will not be shown because one of the conditions couldn't be met. * (e.g. in IME's case, when no editor is focused.) * (e.g. in IME's case, when no editor is focused.) */ */ int SHOW_FAILED = 2; int IME_SHOW_FAILED = 2; } } protected final InsetsController mController; protected final InsetsController mController; Loading Loading @@ -155,7 +155,8 @@ public class InsetsSourceConsumer { * {@link android.inputmethodservice.InputMethodService}). * {@link android.inputmethodservice.InputMethodService}). * @return @see {@link ShowResult}. * @return @see {@link ShowResult}. */ */ @ShowResult int requestShow(boolean fromController) { @VisibleForTesting public @ShowResult int requestShow(boolean fromController) { return ShowResult.SHOW_IMMEDIATELY; return ShowResult.SHOW_IMMEDIATELY; } } Loading core/java/android/view/ViewRootImpl.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -636,6 +636,7 @@ public final class ViewRootImpl implements ViewParent, InputEventConsistencyVerifier.isInstrumentationEnabled() ? InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, 0) : null; new InputEventConsistencyVerifier(this, 0) : null; private final InsetsController mInsetsController; private final ImeFocusController mImeFocusController; private final ImeFocusController mImeFocusController; /** /** Loading @@ -646,7 +647,6 @@ public final class ViewRootImpl implements ViewParent, return mImeFocusController; return mImeFocusController; } } private final InsetsController mInsetsController = new InsetsController(this); private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker(); private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker(); Loading Loading @@ -705,6 +705,7 @@ public final class ViewRootImpl implements ViewParent, mFallbackEventHandler = new PhoneFallbackEventHandler(context); mFallbackEventHandler = new PhoneFallbackEventHandler(context); mChoreographer = Choreographer.getInstance(); mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mInsetsController = new InsetsController(this); String processorOverrideName = context.getResources().getString( String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); R.string.config_inputEventCompatProcessorOverrideClassName); Loading core/tests/coretests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ android_test { "truth-prebuilt", "truth-prebuilt", "print-test-util-lib", "print-test-util-lib", "testng", "testng", "servicestests-utils" ], ], libs: [ libs: [ Loading Loading
core/java/android/view/ImeInsetsSourceConsumer.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -87,7 +87,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}. * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}. */ */ @Override @Override @ShowResult int requestShow(boolean fromIme) { public @ShowResult int requestShow(boolean fromIme) { // TODO: ResultReceiver for IME. // TODO: ResultReceiver for IME. // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag. // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag. if (fromIme) { if (fromIme) { Loading @@ -95,7 +95,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { } } return getImm().requestImeShow(null /* resultReceiver */) return getImm().requestImeShow(null /* resultReceiver */) ? ShowResult.SHOW_DELAYED : ShowResult.SHOW_FAILED; ? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED; } } /** /** Loading
core/java/android/view/InsetsController.java +97 −39 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.view; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.toPublicType; import static android.view.InsetsState.toPublicType; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.all; import static android.view.WindowInsets.Type.ime; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; Loading @@ -31,6 +32,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.graphics.Insets; import android.graphics.Insets; import android.graphics.Rect; import android.graphics.Rect; import android.os.Handler; import android.os.RemoteException; import android.os.RemoteException; import android.util.ArraySet; import android.util.ArraySet; import android.util.Log; import android.util.Log; Loading @@ -55,6 +57,7 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.ArrayList; import java.util.function.BiFunction; /** /** * Implements {@link WindowInsetsController} on the client. * Implements {@link WindowInsetsController} on the client. Loading @@ -64,6 +67,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_HIDE_MS = 340; private static final int ANIMATION_DURATION_HIDE_MS = 340; private static final int PENDING_CONTROL_TIMEOUT_MS = 2000; static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f); static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f); Loading Loading @@ -241,6 +245,30 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mStartingAnimation = startingAnimation; mStartingAnimation = startingAnimation; } } } } /** * Represents a control request that we had to defer because we are waiting for the IME to * process our show request. */ private static class PendingControlRequest { PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener, long durationMs, Interpolator interpolator, @AnimationType int animationType, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { this.types = types; this.listener = listener; this.durationMs = durationMs; this.interpolator = interpolator; this.animationType = animationType; this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation; } final @InsetsType int types; final WindowInsetsAnimationControlListener listener; final long durationMs; final Interpolator interpolator; final @AnimationType int animationType; final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation; } private final String TAG = "InsetsControllerImpl"; private final String TAG = "InsetsControllerImpl"; Loading @@ -248,8 +276,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final InsetsState mTmpState = new InsetsState(); private final InsetsState mTmpState = new InsetsState(); private final Rect mFrame = new Rect(); private final Rect mFrame = new Rect(); private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator; private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final ViewRootImpl mViewRoot; private final ViewRootImpl mViewRoot; private final Handler mHandler; private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>(); private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>(); private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>(); Loading @@ -263,7 +293,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final Rect mLastLegacyContentInsets = new Rect(); private final Rect mLastLegacyContentInsets = new Rect(); private final Rect mLastLegacyStableInsets = new Rect(); private final Rect mLastLegacyStableInsets = new Rect(); private int mPendingTypesToShow; /** Pending control request that is waiting on IME to be ready to be shown */ private PendingControlRequest mPendingImeControlRequest; private int mLastLegacySoftInputMode; private int mLastLegacySoftInputMode; private int mLastLegacySystemUiFlags; private int mLastLegacySystemUiFlags; Loading @@ -271,8 +302,26 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private SyncRtSurfaceTransactionApplier mApplier; private SyncRtSurfaceTransactionApplier mApplier; private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest; public InsetsController(ViewRootImpl viewRoot) { public InsetsController(ViewRootImpl viewRoot) { this(viewRoot, (controller, type) -> { if (type == ITYPE_IME) { return new ImeInsetsSourceConsumer(controller.mState, Transaction::new, controller); } else { return new InsetsSourceConsumer(type, controller.mState, Transaction::new, controller); } }, viewRoot.mHandler); } @VisibleForTesting public InsetsController(ViewRootImpl viewRoot, BiFunction<InsetsController, Integer, InsetsSourceConsumer> consumerCreator, Handler handler) { mViewRoot = viewRoot; mViewRoot = viewRoot; mConsumerCreator = consumerCreator; mHandler = handler; mAnimCallback = () -> { mAnimCallback = () -> { mAnimCallbackScheduled = false; mAnimCallbackScheduled = false; if (mRunningAnimations.isEmpty()) { if (mRunningAnimations.isEmpty()) { Loading Loading @@ -393,7 +442,21 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation show(types, false /* fromIme */); show(types, false /* fromIme */); } } void show(@InsetsType int types, boolean fromIme) { @VisibleForTesting public void show(@InsetsType int types, boolean fromIme) { // Handle pending request ready in case there was one set. if (fromIme && mPendingImeControlRequest != null) { PendingControlRequest pendingRequest = mPendingImeControlRequest; mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); controlAnimationUnchecked(pendingRequest.types, pendingRequest.listener, mFrame, true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator, false /* fade */, pendingRequest.animationType, pendingRequest.layoutInsetsDuringAnimation); return; } // TODO: Support a ResultReceiver for IME. // TODO: Support a ResultReceiver for IME. // TODO(b/123718661): Make show() work for multi-session IME. // TODO(b/123718661): Make show() work for multi-session IME. int typesReady = 0; int typesReady = 0; Loading Loading @@ -463,6 +526,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) { if (types == 0) { if (types == 0) { // nothing to animate. // nothing to animate. listener.onCancelled(); return; return; } } cancelExistingControllers(types); cancelExistingControllers(types); Loading @@ -471,19 +535,18 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); Pair<Integer, Boolean> typesReadyPair = collectSourceControls( Pair<Integer, Boolean> typesReadyPair = collectSourceControls( fromIme, internalTypes, controls, listener); fromIme, internalTypes, controls); int typesReady = typesReadyPair.first; int typesReady = typesReadyPair.first; boolean isReady = typesReadyPair.second; boolean imeReady = typesReadyPair.second; if (!isReady) { if (!imeReady) { // IME isn't ready, all requested types would be shown once IME is ready. // IME isn't ready, all requested types will be animated once IME is ready mPendingTypesToShow = typesReady; abortPendingImeControlRequest(); // TODO: listener for pending types. mPendingImeControlRequest = new PendingControlRequest(types, listener, durationMs, interpolator, animationType, layoutInsetsDuringAnimation); mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS); return; return; } } // pending types from previous request. typesReady = collectPendingTypes(typesReady); if (typesReady == 0) { if (typesReady == 0) { listener.onCancelled(); listener.onCancelled(); return; return; Loading @@ -496,13 +559,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } /** /** * @return Pair of (types ready to animate, is ready to animate). * @return Pair of (types ready to animate, IME ready to animate). */ */ private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls, ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls) { WindowInsetsAnimationControlListener listener) { int typesReady = 0; int typesReady = 0; boolean isReady = true; boolean imeReady = true; for (int i = internalTypes.size() - 1; i >= 0; i--) { for (int i = internalTypes.size() - 1; i >= 0; i--) { InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i)); boolean setVisible = !consumer.isRequestedVisible(); boolean setVisible = !consumer.isRequestedVisible(); Loading @@ -512,16 +574,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation case ShowResult.SHOW_IMMEDIATELY: case ShowResult.SHOW_IMMEDIATELY: typesReady |= InsetsState.toPublicType(consumer.getType()); typesReady |= InsetsState.toPublicType(consumer.getType()); break; break; case ShowResult.SHOW_DELAYED: case ShowResult.IME_SHOW_DELAYED: isReady = false; imeReady = false; break; break; case ShowResult.SHOW_FAILED: case ShowResult.IME_SHOW_FAILED: // IME cannot be shown (since it didn't have focus), proceed // IME cannot be shown (since it didn't have focus), proceed // with animation of other types. // with animation of other types. if (mPendingTypesToShow != 0) { // remove IME from pending because view no longer has focus. mPendingTypesToShow &= ~InsetsState.toPublicType(ITYPE_IME); } break; break; } } } else { } else { Loading @@ -538,13 +596,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation controls.put(consumer.getType(), control); controls.put(consumer.getType(), control); } } } } return new Pair<>(typesReady, isReady); return new Pair<>(typesReady, imeReady); } private int collectPendingTypes(@InsetsType int typesReady) { typesReady |= mPendingTypesToShow; mPendingTypesToShow = 0; return typesReady; } } private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode( private @LayoutInsetsDuringAnimation int getLayoutInsetsDuringAnimationMode( Loading Loading @@ -577,6 +629,17 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation cancelAnimation(control, true /* invokeCallback */); cancelAnimation(control, true /* invokeCallback */); } } } } if ((types & ime()) != 0) { abortPendingImeControlRequest(); } } private void abortPendingImeControlRequest() { if (mPendingImeControlRequest != null) { mPendingImeControlRequest.listener.onCancelled(); mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); } } } @VisibleForTesting @VisibleForTesting Loading Loading @@ -608,6 +671,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation cancelAnimation(control, true /* invokeCallback */); cancelAnimation(control, true /* invokeCallback */); } } } } if (consumer.getType() == ITYPE_IME) { abortPendingImeControlRequest(); } } } private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) { private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) { Loading Loading @@ -635,7 +701,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (controller != null) { if (controller != null) { return controller; return controller; } } controller = createConsumerOfType(type); controller = mConsumerCreator.apply(this, type); mSourceConsumers.put(type, controller); mSourceConsumers.put(type, controller); return controller; return controller; } } Loading Loading @@ -696,14 +762,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return ANIMATION_TYPE_NONE; return ANIMATION_TYPE_NONE; } } private InsetsSourceConsumer createConsumerOfType(int type) { if (type == ITYPE_IME) { return new ImeInsetsSourceConsumer(mState, Transaction::new, this); } else { return new InsetsSourceConsumer(type, mState, Transaction::new, this); } } /** /** * Sends the local visibility state back to window manager. * Sends the local visibility state back to window manager. */ */ Loading
core/java/android/view/InsetsSourceConsumer.java +5 −4 Original line number Original line Diff line number Diff line Loading @@ -36,7 +36,7 @@ import java.util.function.Supplier; public class InsetsSourceConsumer { public class InsetsSourceConsumer { @Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE) @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.SHOW_DELAYED, ShowResult.SHOW_FAILED}) @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED}) @interface ShowResult { @interface ShowResult { /** /** * Window type is ready to be shown, will be shown immidiately. * Window type is ready to be shown, will be shown immidiately. Loading @@ -46,12 +46,12 @@ public class InsetsSourceConsumer { * Result will be delayed. Window needs to be prepared or request is not from controller. * Result will be delayed. Window needs to be prepared or request is not from controller. * Request will be delegated to controller and may or may not be shown. * Request will be delegated to controller and may or may not be shown. */ */ int SHOW_DELAYED = 1; int IME_SHOW_DELAYED = 1; /** /** * Window will not be shown because one of the conditions couldn't be met. * Window will not be shown because one of the conditions couldn't be met. * (e.g. in IME's case, when no editor is focused.) * (e.g. in IME's case, when no editor is focused.) */ */ int SHOW_FAILED = 2; int IME_SHOW_FAILED = 2; } } protected final InsetsController mController; protected final InsetsController mController; Loading Loading @@ -155,7 +155,8 @@ public class InsetsSourceConsumer { * {@link android.inputmethodservice.InputMethodService}). * {@link android.inputmethodservice.InputMethodService}). * @return @see {@link ShowResult}. * @return @see {@link ShowResult}. */ */ @ShowResult int requestShow(boolean fromController) { @VisibleForTesting public @ShowResult int requestShow(boolean fromController) { return ShowResult.SHOW_IMMEDIATELY; return ShowResult.SHOW_IMMEDIATELY; } } Loading
core/java/android/view/ViewRootImpl.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -636,6 +636,7 @@ public final class ViewRootImpl implements ViewParent, InputEventConsistencyVerifier.isInstrumentationEnabled() ? InputEventConsistencyVerifier.isInstrumentationEnabled() ? new InputEventConsistencyVerifier(this, 0) : null; new InputEventConsistencyVerifier(this, 0) : null; private final InsetsController mInsetsController; private final ImeFocusController mImeFocusController; private final ImeFocusController mImeFocusController; /** /** Loading @@ -646,7 +647,6 @@ public final class ViewRootImpl implements ViewParent, return mImeFocusController; return mImeFocusController; } } private final InsetsController mInsetsController = new InsetsController(this); private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker(); private final GestureExclusionTracker mGestureExclusionTracker = new GestureExclusionTracker(); Loading Loading @@ -705,6 +705,7 @@ public final class ViewRootImpl implements ViewParent, mFallbackEventHandler = new PhoneFallbackEventHandler(context); mFallbackEventHandler = new PhoneFallbackEventHandler(context); mChoreographer = Choreographer.getInstance(); mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); mInsetsController = new InsetsController(this); String processorOverrideName = context.getResources().getString( String processorOverrideName = context.getResources().getString( R.string.config_inputEventCompatProcessorOverrideClassName); R.string.config_inputEventCompatProcessorOverrideClassName); Loading
core/tests/coretests/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -41,6 +41,7 @@ android_test { "truth-prebuilt", "truth-prebuilt", "print-test-util-lib", "print-test-util-lib", "testng", "testng", "servicestests-utils" ], ], libs: [ libs: [ Loading