Loading core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3256,6 +3256,7 @@ package android.view.inputmethod { method public int getDisplayId(); method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int); method public boolean hasActiveInputConnection(@Nullable android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long); field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L Loading core/java/android/view/ImeInsetsSourceConsumer.java +32 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import static android.os.Trace.TRACE_TAG_VIEW; import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER; import static android.view.ImeInsetsSourceConsumerProto.IS_HIDE_ANIMATION_RUNNING; import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL; Loading @@ -23,11 +24,15 @@ import static android.view.ImeInsetsSourceConsumerProto.IS_SHOW_REQUESTED_DURING import android.annotation.Nullable; import android.os.IBinder; import android.os.Process; import android.os.Trace; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl.Transaction; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputMethodManager; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; import java.util.function.Supplier; Loading @@ -48,8 +53,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { /** * Tracks whether {@link WindowInsetsController#show(int)} or * {@link InputMethodManager#showSoftInput(View, int)} is called during IME hide animation. * If it was called, we should not call {@link InputMethodManager#notifyImeHidden(IBinder)}, * because the IME is being shown. * If it was called, we should not call {@link InputMethodManager#notifyImeHidden(IBinder, * ImeTracker.Token)}, because the IME is being shown. */ private boolean mIsShowRequestedDuringHideAnimation; Loading @@ -76,7 +81,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { // Remove IME surface as IME has finished hide animation, if there is no pending // show request. if (!mIsShowRequestedDuringHideAnimation) { notifyHidden(); notifyHidden(null /* statsToken */); removeSurface(); } } Loading Loading @@ -120,7 +125,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}. */ @Override public @ShowResult int requestShow(boolean fromIme) { @ShowResult public int requestShow(boolean fromIme, @Nullable ImeTracker.Token statsToken) { if (fromIme) { ImeTracing.getInstance().triggerClientDump( "ImeInsetsSourceConsumer#requestShow", Loading @@ -129,6 +135,9 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { // TODO: ResultReceiver for IME. // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag. ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW); if (getControl() == null) { // If control is null, schedule to show IME when control is available. mIsRequestedVisibleAwaitingControl = true; Loading @@ -140,16 +149,32 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { return ShowResult.SHOW_IMMEDIATELY; } return getImm().requestImeShow(mController.getHost().getWindowToken()) return getImm().requestImeShow(mController.getHost().getWindowToken(), statsToken) ? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED; } /** * Notify {@link com.android.server.inputmethod.InputMethodManagerService} that * IME insets are hidden. * * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. */ private void notifyHidden() { getImm().notifyImeHidden(mController.getHost().getWindowToken()); private void notifyHidden(@Nullable ImeTracker.Token statsToken) { // Create a new stats token to track the hide request when: // - we do not already have one, or // - we do already have one, but we have control and use the passed in token // for the insets animation already. if (statsToken == null || getControl() != null) { statsToken = ImeTracker.get().onRequestHide(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API); } ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN); getImm().notifyImeHidden(mController.getHost().getWindowToken(), statsToken); Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0); } @Override Loading core/java/android/view/InsetsController.java +37 −12 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.graphics.Rect; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.Process; import android.os.Trace; import android.text.TextUtils; import android.util.ArraySet; Loading @@ -64,6 +65,7 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; import java.io.PrintWriter; import java.lang.annotation.Retention; Loading Loading @@ -977,7 +979,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void show(@InsetsType int types) { show(types, false /* fromIme */, null /* statsToken */); ImeTracker.Token statsToken = null; if ((types & ime()) != 0) { statsToken = ImeTracker.get().onRequestShow(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API); } show(types, false /* fromIme */, statsToken); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) Loading Loading @@ -1054,7 +1063,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void hide(@InsetsType int types) { hide(types, false /* fromIme */, null /* statsToken */); ImeTracker.Token statsToken = null; if ((types & ime()) != 0) { statsToken = ImeTracker.get().onRequestHide(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API); } hide(types, false /* fromIme */, statsToken); } @VisibleForTesting Loading Loading @@ -1164,8 +1180,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (DEBUG) Log.d(TAG, "user animation disabled types: " + disabledTypes); types &= ~mDisabledUserAnimationInsetsTypes; if (fromIme && (disabledTypes & ime()) != 0 && !mState.getSource(mImeSourceConsumer.getId()).isVisible()) { if ((disabledTypes & ime()) != 0) { ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION); if (fromIme && !mState.getSource(mImeSourceConsumer.getId()).isVisible()) { // We've requested IMM to show IME, but the IME is not controllable. We need to // cancel the request. setRequestedVisibleTypes(0 /* visibleTypes */, ime()); Loading @@ -1174,6 +1193,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } } } if (types == 0) { // nothing to animate. listener.onCancelled(null); Loading @@ -1182,6 +1202,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0); return; } ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION); cancelExistingControllers(types); if (DEBUG) Log.d(TAG, "controlAnimation types: " + types); mLastStartedAnimTypes |= types; Loading @@ -1189,7 +1211,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); Pair<Integer, Boolean> typesReadyPair = collectSourceControls( fromIme, types, controls, animationType); fromIme, types, controls, animationType, statsToken); int typesReady = typesReadyPair.first; boolean imeReady = typesReadyPair.second; if (DEBUG) Log.d(TAG, String.format( Loading Loading @@ -1288,7 +1310,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation * @return Pair of (types ready to animate, IME ready to animate). */ private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, @InsetsType int types, SparseArray<InsetsSourceControl> controls, @AnimationType int animationType) { SparseArray<InsetsSourceControl> controls, @AnimationType int animationType, @Nullable ImeTracker.Token statsToken) { ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS); int typesReady = 0; boolean imeReady = true; for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { Loading @@ -1301,7 +1326,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation boolean canRun = true; if (show) { // Show request switch(consumer.requestShow(fromIme)) { switch(consumer.requestShow(fromIme, statsToken)) { case ShowResult.SHOW_IMMEDIATELY: break; case ShowResult.IME_SHOW_DELAYED: Loading core/java/android/view/InsetsSourceConsumer.java +20 −7 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; import android.view.inputmethod.ImeTracker; import com.android.internal.annotations.VisibleForTesting; Loading @@ -50,10 +51,14 @@ import java.util.function.Supplier; public class InsetsSourceConsumer { @Retention(RetentionPolicy.SOURCE) @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED}) @IntDef(value = { ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED }) @interface ShowResult { /** * Window type is ready to be shown, will be shown immidiately. * Window type is ready to be shown, will be shown immediately. */ int SHOW_IMMEDIATELY = 0; /** Loading @@ -71,11 +76,13 @@ public class InsetsSourceConsumer { protected final InsetsController mController; protected final InsetsState mState; private int mId; private final @InsetsType int mType; @InsetsType private final int mType; private static final String TAG = "InsetsSourceConsumer"; private final Supplier<Transaction> mTransactionSupplier; private @Nullable InsetsSourceControl mSourceControl; @Nullable private InsetsSourceControl mSourceControl; private boolean mHasWindowFocus; /** Loading Loading @@ -180,7 +187,7 @@ public class InsetsSourceConsumer { return true; } @VisibleForTesting @VisibleForTesting(visibility = PACKAGE) public InsetsSourceControl getControl() { return mSourceControl; } Loading Loading @@ -280,10 +287,16 @@ public class InsetsSourceConsumer { * @param fromController {@code true} if request is coming from controller. * (e.g. in IME case, controller is * {@link android.inputmethodservice.InputMethodService}). * @param statsToken the token tracking the current IME show request or {@code null} otherwise. * * @implNote The {@code statsToken} is ignored here, and only handled in * {@link ImeInsetsSourceConsumer} for IME animations only. * * @return @see {@link ShowResult}. */ @VisibleForTesting public @ShowResult int requestShow(boolean fromController) { @VisibleForTesting(visibility = PACKAGE) @ShowResult public int requestShow(boolean fromController, @Nullable ImeTracker.Token statsToken) { return ShowResult.SHOW_IMMEDIATELY; } Loading core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java +137 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; import com.android.internal.view.IImeTracker; import com.android.internal.view.IInputMethodManager; import java.util.ArrayList; Loading @@ -61,6 +62,9 @@ final class IInputMethodManagerGlobalInvoker { @Nullable private static volatile IInputMethodManager sServiceCache = null; @Nullable private static volatile IImeTracker sTrackerServiceCache = null; /** * @return {@code true} if {@link IInputMethodManager} is available. */ Loading Loading @@ -527,4 +531,137 @@ final class IInputMethodManagerGlobalInvoker { throw e.rethrowFromSystemServer(); } } @AnyThread @Nullable static IBinder onRequestShow(int uid, @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) { final IImeTracker service = getImeTrackerService(); if (service == null) { return null; } try { return service.onRequestShow(uid, origin, reason); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @Nullable static IBinder onRequestHide(int uid, @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) { final IImeTracker service = getImeTrackerService(); if (service == null) { return null; } try { return service.onRequestHide(uid, origin, reason); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onProgress(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onProgress(statsToken, phase); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onFailed(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onFailed(statsToken, phase); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onCancelled(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onCancelled(statsToken, phase); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onShown(@NonNull IBinder statsToken) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onShown(statsToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onHidden(@NonNull IBinder statsToken) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onHidden(statsToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) static boolean hasPendingImeVisibilityRequests() { final var service = getImeTrackerService(); if (service == null) { return true; } try { return service.hasPendingImeVisibilityRequests(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @Nullable private static IImeTracker getImeTrackerService() { var trackerService = sTrackerServiceCache; if (trackerService == null) { final var service = getService(); if (service == null) { return null; } try { trackerService = service.getImeTrackerService(); if (trackerService == null) { return null; } sTrackerServiceCache = trackerService; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return trackerService; } } Loading
core/api/test-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -3256,6 +3256,7 @@ package android.view.inputmethod { method public int getDisplayId(); method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int); method public boolean hasActiveInputConnection(@Nullable android.view.View); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean hasPendingImeVisibilityRequests(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown(); method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long); field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L Loading
core/java/android/view/ImeInsetsSourceConsumer.java +32 −7 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import static android.os.Trace.TRACE_TAG_VIEW; import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER; import static android.view.ImeInsetsSourceConsumerProto.IS_HIDE_ANIMATION_RUNNING; import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL; Loading @@ -23,11 +24,15 @@ import static android.view.ImeInsetsSourceConsumerProto.IS_SHOW_REQUESTED_DURING import android.annotation.Nullable; import android.os.IBinder; import android.os.Process; import android.os.Trace; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl.Transaction; import android.view.inputmethod.ImeTracker; import android.view.inputmethod.InputMethodManager; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; import java.util.function.Supplier; Loading @@ -48,8 +53,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { /** * Tracks whether {@link WindowInsetsController#show(int)} or * {@link InputMethodManager#showSoftInput(View, int)} is called during IME hide animation. * If it was called, we should not call {@link InputMethodManager#notifyImeHidden(IBinder)}, * because the IME is being shown. * If it was called, we should not call {@link InputMethodManager#notifyImeHidden(IBinder, * ImeTracker.Token)}, because the IME is being shown. */ private boolean mIsShowRequestedDuringHideAnimation; Loading @@ -76,7 +81,7 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { // Remove IME surface as IME has finished hide animation, if there is no pending // show request. if (!mIsShowRequestedDuringHideAnimation) { notifyHidden(); notifyHidden(null /* statsToken */); removeSurface(); } } Loading Loading @@ -120,7 +125,8 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { * @return @see {@link android.view.InsetsSourceConsumer.ShowResult}. */ @Override public @ShowResult int requestShow(boolean fromIme) { @ShowResult public int requestShow(boolean fromIme, @Nullable ImeTracker.Token statsToken) { if (fromIme) { ImeTracing.getInstance().triggerClientDump( "ImeInsetsSourceConsumer#requestShow", Loading @@ -129,6 +135,9 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { // TODO: ResultReceiver for IME. // TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag. ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_REQUEST_SHOW); if (getControl() == null) { // If control is null, schedule to show IME when control is available. mIsRequestedVisibleAwaitingControl = true; Loading @@ -140,16 +149,32 @@ public final class ImeInsetsSourceConsumer extends InsetsSourceConsumer { return ShowResult.SHOW_IMMEDIATELY; } return getImm().requestImeShow(mController.getHost().getWindowToken()) return getImm().requestImeShow(mController.getHost().getWindowToken(), statsToken) ? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED; } /** * Notify {@link com.android.server.inputmethod.InputMethodManagerService} that * IME insets are hidden. * * @param statsToken the token tracking the current IME hide request or {@code null} otherwise. */ private void notifyHidden() { getImm().notifyImeHidden(mController.getHost().getWindowToken()); private void notifyHidden(@Nullable ImeTracker.Token statsToken) { // Create a new stats token to track the hide request when: // - we do not already have one, or // - we do already have one, but we have control and use the passed in token // for the insets animation already. if (statsToken == null || getControl() != null) { statsToken = ImeTracker.get().onRequestHide(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API); } ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN); getImm().notifyImeHidden(mController.getHost().getWindowToken(), statsToken); Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.hideRequestFromApi", 0); } @Override Loading
core/java/android/view/InsetsController.java +37 −12 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.graphics.Rect; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.os.Process; import android.os.Trace; import android.text.TextUtils; import android.util.ArraySet; Loading @@ -64,6 +65,7 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.SoftInputShowHideReason; import java.io.PrintWriter; import java.lang.annotation.Retention; Loading Loading @@ -977,7 +979,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void show(@InsetsType int types) { show(types, false /* fromIme */, null /* statsToken */); ImeTracker.Token statsToken = null; if ((types & ime()) != 0) { statsToken = ImeTracker.get().onRequestShow(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API); } show(types, false /* fromIme */, statsToken); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) Loading Loading @@ -1054,7 +1063,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void hide(@InsetsType int types) { hide(types, false /* fromIme */, null /* statsToken */); ImeTracker.Token statsToken = null; if ((types & ime()) != 0) { statsToken = ImeTracker.get().onRequestHide(null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API); } hide(types, false /* fromIme */, statsToken); } @VisibleForTesting Loading Loading @@ -1164,8 +1180,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (DEBUG) Log.d(TAG, "user animation disabled types: " + disabledTypes); types &= ~mDisabledUserAnimationInsetsTypes; if (fromIme && (disabledTypes & ime()) != 0 && !mState.getSource(mImeSourceConsumer.getId()).isVisible()) { if ((disabledTypes & ime()) != 0) { ImeTracker.get().onFailed(statsToken, ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION); if (fromIme && !mState.getSource(mImeSourceConsumer.getId()).isVisible()) { // We've requested IMM to show IME, but the IME is not controllable. We need to // cancel the request. setRequestedVisibleTypes(0 /* visibleTypes */, ime()); Loading @@ -1174,6 +1193,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } } } } if (types == 0) { // nothing to animate. listener.onCancelled(null); Loading @@ -1182,6 +1202,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.showRequestFromApiToImeReady", 0); return; } ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_DISABLED_USER_ANIMATION); cancelExistingControllers(types); if (DEBUG) Log.d(TAG, "controlAnimation types: " + types); mLastStartedAnimTypes |= types; Loading @@ -1189,7 +1211,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); Pair<Integer, Boolean> typesReadyPair = collectSourceControls( fromIme, types, controls, animationType); fromIme, types, controls, animationType, statsToken); int typesReady = typesReadyPair.first; boolean imeReady = typesReadyPair.second; if (DEBUG) Log.d(TAG, String.format( Loading Loading @@ -1288,7 +1310,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation * @return Pair of (types ready to animate, IME ready to animate). */ private Pair<Integer, Boolean> collectSourceControls(boolean fromIme, @InsetsType int types, SparseArray<InsetsSourceControl> controls, @AnimationType int animationType) { SparseArray<InsetsSourceControl> controls, @AnimationType int animationType, @Nullable ImeTracker.Token statsToken) { ImeTracker.get().onProgress(statsToken, ImeTracker.PHASE_CLIENT_COLLECT_SOURCE_CONTROLS); int typesReady = 0; boolean imeReady = true; for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { Loading @@ -1301,7 +1326,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation boolean canRun = true; if (show) { // Show request switch(consumer.requestShow(fromIme)) { switch(consumer.requestShow(fromIme, statsToken)) { case ShowResult.SHOW_IMMEDIATELY: break; case ShowResult.IME_SHOW_DELAYED: Loading
core/java/android/view/InsetsSourceConsumer.java +20 −7 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.util.Log; import android.util.proto.ProtoOutputStream; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; import android.view.inputmethod.ImeTracker; import com.android.internal.annotations.VisibleForTesting; Loading @@ -50,10 +51,14 @@ import java.util.function.Supplier; public class InsetsSourceConsumer { @Retention(RetentionPolicy.SOURCE) @IntDef(value = {ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED}) @IntDef(value = { ShowResult.SHOW_IMMEDIATELY, ShowResult.IME_SHOW_DELAYED, ShowResult.IME_SHOW_FAILED }) @interface ShowResult { /** * Window type is ready to be shown, will be shown immidiately. * Window type is ready to be shown, will be shown immediately. */ int SHOW_IMMEDIATELY = 0; /** Loading @@ -71,11 +76,13 @@ public class InsetsSourceConsumer { protected final InsetsController mController; protected final InsetsState mState; private int mId; private final @InsetsType int mType; @InsetsType private final int mType; private static final String TAG = "InsetsSourceConsumer"; private final Supplier<Transaction> mTransactionSupplier; private @Nullable InsetsSourceControl mSourceControl; @Nullable private InsetsSourceControl mSourceControl; private boolean mHasWindowFocus; /** Loading Loading @@ -180,7 +187,7 @@ public class InsetsSourceConsumer { return true; } @VisibleForTesting @VisibleForTesting(visibility = PACKAGE) public InsetsSourceControl getControl() { return mSourceControl; } Loading Loading @@ -280,10 +287,16 @@ public class InsetsSourceConsumer { * @param fromController {@code true} if request is coming from controller. * (e.g. in IME case, controller is * {@link android.inputmethodservice.InputMethodService}). * @param statsToken the token tracking the current IME show request or {@code null} otherwise. * * @implNote The {@code statsToken} is ignored here, and only handled in * {@link ImeInsetsSourceConsumer} for IME animations only. * * @return @see {@link ShowResult}. */ @VisibleForTesting public @ShowResult int requestShow(boolean fromController) { @VisibleForTesting(visibility = PACKAGE) @ShowResult public int requestShow(boolean fromController, @Nullable ImeTracker.Token statsToken) { return ShowResult.SHOW_IMMEDIATELY; } Loading
core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java +137 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import com.android.internal.inputmethod.InputBindResult; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.inputmethod.StartInputFlags; import com.android.internal.inputmethod.StartInputReason; import com.android.internal.view.IImeTracker; import com.android.internal.view.IInputMethodManager; import java.util.ArrayList; Loading @@ -61,6 +62,9 @@ final class IInputMethodManagerGlobalInvoker { @Nullable private static volatile IInputMethodManager sServiceCache = null; @Nullable private static volatile IImeTracker sTrackerServiceCache = null; /** * @return {@code true} if {@link IInputMethodManager} is available. */ Loading Loading @@ -527,4 +531,137 @@ final class IInputMethodManagerGlobalInvoker { throw e.rethrowFromSystemServer(); } } @AnyThread @Nullable static IBinder onRequestShow(int uid, @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) { final IImeTracker service = getImeTrackerService(); if (service == null) { return null; } try { return service.onRequestShow(uid, origin, reason); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @Nullable static IBinder onRequestHide(int uid, @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) { final IImeTracker service = getImeTrackerService(); if (service == null) { return null; } try { return service.onRequestHide(uid, origin, reason); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onProgress(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onProgress(statsToken, phase); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onFailed(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onFailed(statsToken, phase); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onCancelled(@NonNull IBinder statsToken, @ImeTracker.Phase int phase) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onCancelled(statsToken, phase); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onShown(@NonNull IBinder statsToken) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onShown(statsToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread static void onHidden(@NonNull IBinder statsToken) { final IImeTracker service = getImeTrackerService(); if (service == null) { return; } try { service.onHidden(statsToken); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD) static boolean hasPendingImeVisibilityRequests() { final var service = getImeTrackerService(); if (service == null) { return true; } try { return service.hasPendingImeVisibilityRequests(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @AnyThread @Nullable private static IImeTracker getImeTrackerService() { var trackerService = sTrackerServiceCache; if (trackerService == null) { final var service = getService(); if (service == null) { return null; } try { trackerService = service.getImeTrackerService(); if (trackerService == null) { return null; } sTrackerServiceCache = trackerService; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } return trackerService; } }