Merge "Remove the fork of STL UserAction" into main
diff --git a/Android.bp b/Android.bp
index 5ada10d..8d7ab98 100644
--- a/Android.bp
+++ b/Android.bp
@@ -386,6 +386,7 @@
// TODO(b/120066492): remove gps_debug and protolog.conf.json when the build
// system propagates "required" properly.
"gps_debug.conf",
+ "protolog.conf.json.gz",
"core.protolog.pb",
"framework-res",
// any install dependencies should go into framework-minus-apex-install-dependencies
diff --git a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
index ba15796..fc3738c 100644
--- a/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
+++ b/apct-tests/perftests/rubidium/src/android/rubidium/js/JSScriptEnginePerfTests.java
@@ -53,6 +53,7 @@
import com.android.adservices.service.adselection.AdWithBidArgumentUtil;
import com.android.adservices.service.adselection.CustomAudienceBiddingSignalsArgumentUtil;
import com.android.adservices.service.adselection.CustomAudienceScoringSignalsArgumentUtil;
+import com.android.adservices.service.common.NoOpRetryStrategyImpl;
import com.android.adservices.service.js.IsolateSettings;
import com.android.adservices.service.js.JSScriptArgument;
import com.android.adservices.service.js.JSScriptArrayArgument;
@@ -411,7 +412,8 @@
jsScript,
args,
functionName,
- IsolateSettings.forMaxHeapSizeEnforcementDisabled());
+ IsolateSettings.forMaxHeapSizeEnforcementDisabled(),
+ new NoOpRetryStrategyImpl());
result.addListener(resultLatch::countDown, sExecutorService);
return result;
}
@@ -430,7 +432,8 @@
wasmScript,
args,
functionName,
- IsolateSettings.forMaxHeapSizeEnforcementDisabled());
+ IsolateSettings.forMaxHeapSizeEnforcementDisabled(),
+ new NoOpRetryStrategyImpl());
result.addListener(resultLatch::countDown, sExecutorService);
return result;
}
diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp
index 5586295..0104ee1 100644
--- a/apex/jobscheduler/service/Android.bp
+++ b/apex/jobscheduler/service/Android.bp
@@ -21,6 +21,7 @@
libs: [
"app-compat-annotations",
+ "error_prone_annotations",
"framework",
"services.core",
"unsupportedappusage",
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e3e588c..a28dc49 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3961,6 +3961,7 @@
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 void hideSoftInputFromServerForTest();
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isCurrentRootView(@NonNull android.view.View);
method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
method @FlaggedApi("android.view.inputmethod.imm_userhandle_hostsidetests") @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public boolean isStylusHandwritingAvailableAsUser(@NonNull android.os.UserHandle);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fd2af99..42dd87a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1064,7 +1064,11 @@
}
if (sender != null) {
- intent.putExtra(EXTRA_CHOOSER_RESULT_INTENT_SENDER, sender);
+ if (android.service.chooser.Flags.enableChooserResult()) {
+ intent.putExtra(EXTRA_CHOOSER_RESULT_INTENT_SENDER, sender);
+ } else {
+ intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender);
+ }
}
// Migrate any clip data and flags from target.
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index f5b58b9..9dc8c5d 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -453,7 +453,7 @@
@BinderThread
@Override
- public void showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+ public void showSoftInput(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_SHOW_SOFT_INPUT,
@@ -462,7 +462,7 @@
@BinderThread
@Override
- public void hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
+ public void hideSoftInput(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
int flags, ResultReceiver resultReceiver) {
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_WRAPPER);
mCaller.executeOrSendMessage(mCaller.obtainMessageIOOO(DO_HIDE_SOFT_INPUT,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 2c7ca27..4dbdd91 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -701,7 +701,13 @@
*/
private IBinder mCurHideInputToken;
- /** The token tracking the current IME request or {@code null} otherwise. */
+ /**
+ * The token tracking the current IME request.
+ *
+ * <p> This exists as a workaround to changing the signatures of public methods. It will get
+ * set to a {@code non-null} value before every call that uses it, stored locally inside the
+ * callee, and immediately after reset to {@code null} from the callee.
+ */
@Nullable
private ImeTracker.Token mCurStatsToken;
@@ -907,14 +913,13 @@
@MainThread
@Override
public void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver,
- IBinder hideInputToken, @Nullable ImeTracker.Token statsToken) {
+ IBinder hideInputToken, @NonNull ImeTracker.Token statsToken) {
mSystemCallingHideSoftInput = true;
mCurHideInputToken = hideInputToken;
mCurStatsToken = statsToken;
try {
hideSoftInput(flags, resultReceiver);
} finally {
- mCurStatsToken = null;
mCurHideInputToken = null;
mSystemCallingHideSoftInput = false;
}
@@ -926,23 +931,33 @@
@MainThread
@Override
public void hideSoftInput(int flags, ResultReceiver resultReceiver) {
- ImeTracker.forLogging().onProgress(
- mCurStatsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
if (DEBUG) Log.v(TAG, "hideSoftInput()");
+
+ final var statsToken = mCurStatsToken != null ? mCurStatsToken
+ : createStatsToken(false /* show */,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT,
+ ImeTracker.isFromUser(mRootView));
+ mCurStatsToken = null;
+
+ // TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods.
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
&& !mSystemCallingHideSoftInput) {
Log.e(TAG, "IME shouldn't call hideSoftInput on itself."
+ " Use requestHideSelf(int) itself");
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_SOFT_INPUT);
+
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService.InputMethodImpl#hideSoftInput", mDumper,
null /* icProto */);
final boolean wasVisible = isInputViewShown();
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.hideSoftInput");
mShowInputFlags = 0;
mShowInputRequested = false;
+ mCurStatsToken = statsToken;
hideWindow();
final boolean isVisible = isInputViewShown();
final boolean visibilityChanged = isVisible != wasVisible;
@@ -963,14 +978,13 @@
@Override
public void showSoftInputWithToken(@InputMethod.ShowFlags int flags,
ResultReceiver resultReceiver, IBinder showInputToken,
- @Nullable ImeTracker.Token statsToken) {
+ @NonNull ImeTracker.Token statsToken) {
mSystemCallingShowSoftInput = true;
mCurShowInputToken = showInputToken;
mCurStatsToken = statsToken;
try {
showSoftInput(flags, resultReceiver);
} finally {
- mCurStatsToken = null;
mCurShowInputToken = null;
mSystemCallingShowSoftInput = false;
}
@@ -982,16 +996,23 @@
@MainThread
@Override
public void showSoftInput(@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
- ImeTracker.forLogging().onProgress(
- mCurStatsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
if (DEBUG) Log.v(TAG, "showSoftInput()");
+
+ final var statsToken = mCurStatsToken != null ? mCurStatsToken
+ : createStatsToken(true /* show */,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT,
+ ImeTracker.isFromUser(mRootView));
+ mCurStatsToken = null;
+
// TODO(b/148086656): Disallow IME developers from calling InputMethodImpl methods.
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R
&& !mSystemCallingShowSoftInput) {
- Log.e(TAG," IME shouldn't call showSoftInput on itself."
+ Log.e(TAG, "IME shouldn't call showSoftInput on itself."
+ " Use requestShowSelf(int) itself");
+ ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_SOFT_INPUT);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showSoftInput");
ImeTracing.getInstance().triggerServiceDump(
@@ -999,11 +1020,12 @@
null /* icProto */);
final boolean wasVisible = isInputViewShown();
if (dispatchOnShowInputRequested(flags, false)) {
- ImeTracker.forLogging().onProgress(mCurStatsToken,
+ ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
- showWindow(true);
+ mCurStatsToken = statsToken;
+ showWindow(true /* showInput */);
} else {
- ImeTracker.forLogging().onFailed(mCurStatsToken,
+ ImeTracker.forLogging().onFailed(statsToken,
ImeTracker.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE);
}
setImeWindowStatus(mapToImeWindowStatus(), mBackDisposition);
@@ -1895,21 +1917,23 @@
if (showingInput) {
// If we were last showing the soft keyboard, try to do so again.
if (dispatchOnShowInputRequested(showFlags, true)) {
- showWindow(true);
+ showWindowWithToken(true /* showInput */,
+ SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
if (completions != null) {
mCurCompletions = completions;
onDisplayCompletions(completions);
}
} else {
- hideWindow();
+ hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
}
} else if (mCandidatesVisibility == View.VISIBLE) {
// If the candidates are currently visible, make sure the
// window is shown for them.
- showWindow(false);
+ showWindowWithToken(false /* showInput */,
+ SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
} else {
// Otherwise hide the window.
- hideWindow();
+ hideWindowWithToken(SoftInputShowHideReason.RESET_NEW_CONFIGURATION);
}
// If user uses hard keyboard, IME button should always be shown.
boolean showing = onEvaluateInputViewShown();
@@ -2368,13 +2392,15 @@
// has not asked for the input view to be shown, then we need
// to update whether the window is shown.
if (shown) {
- showWindow(false);
+ showWindowWithToken(false /* showInput */,
+ SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY);
} else {
- hideWindow();
+ hideWindowWithToken(
+ SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY);
}
}
}
-
+
void updateCandidatesVisibility(boolean shown) {
int vis = shown ? View.VISIBLE : getCandidatesHiddenVisibility();
if (mCandidatesVisibility != vis) {
@@ -3009,6 +3035,19 @@
return result;
}
+ /**
+ * Utility function that creates an IME request tracking token before
+ * calling {@link #showWindow}.
+ *
+ * @param showInput whether the input window should be shown.
+ * @param reason the reason why the IME request was created.
+ */
+ private void showWindowWithToken(boolean showInput, @SoftInputShowHideReason int reason) {
+ mCurStatsToken = createStatsToken(true /* show */, reason,
+ ImeTracker.isFromUser(mRootView));
+ showWindow(showInput);
+ }
+
public void showWindow(boolean showInput) {
if (DEBUG) Log.v(TAG, "Showing window: showInput=" + showInput
+ " mShowInputRequested=" + mShowInputRequested
@@ -3018,11 +3057,20 @@
+ " mInputStarted=" + mInputStarted
+ " mShowInputFlags=" + mShowInputFlags);
+ final var statsToken = mCurStatsToken != null ? mCurStatsToken
+ : createStatsToken(true /* show */,
+ SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT,
+ ImeTracker.isFromUser(mRootView));
+ mCurStatsToken = null;
+
if (mInShowWindow) {
Log.w(TAG, "Re-entrance in to showWindow");
+ ImeTracker.forLogging().onCancelled(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_SHOW_WINDOW);
+
ImeTracing.getInstance().triggerServiceDump("InputMethodService#showWindow", mDumper,
null /* icProto */);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.showWindow");
@@ -3046,7 +3094,7 @@
if (DEBUG) Log.v(TAG, "showWindow: draw decorView!");
mWindow.show();
mDecorViewWasVisible = true;
- applyVisibilityInInsetsConsumerIfNecessary(true);
+ applyVisibilityInInsetsConsumerIfNecessary(true /* setVisible */, statsToken);
cancelImeSurfaceRemoval();
mInShowWindow = false;
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -3137,13 +3185,15 @@
* Applies the IME visibility in {@link android.view.ImeInsetsSourceConsumer}.
*
* @param setVisible {@code true} to make it visible, false to hide it.
+ * @param statsToken the token tracking the current IME request.
*/
- private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible) {
+ private void applyVisibilityInInsetsConsumerIfNecessary(boolean setVisible,
+ @NonNull ImeTracker.Token statsToken) {
ImeTracing.getInstance().triggerServiceDump(
"InputMethodService#applyVisibilityInInsetsConsumerIfNecessary", mDumper,
null /* icProto */);
mPrivOps.applyImeVisibilityAsync(setVisible
- ? mCurShowInputToken : mCurHideInputToken, setVisible, mCurStatsToken);
+ ? mCurShowInputToken : mCurHideInputToken, setVisible, statsToken);
}
private void finishViews(boolean finishingInput) {
@@ -3159,12 +3209,35 @@
mCandidatesViewStarted = false;
}
+ /**
+ * Utility function that creates an IME request tracking token before
+ * calling {@link #hideWindow}.
+ *
+ * @param reason the reason why the IME request was created.
+ */
+ private void hideWindowWithToken(@SoftInputShowHideReason int reason) {
+ // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it
+ // to work with onClickListeners
+ final boolean isFromUser = ImeTracker.isFromUser(mRootView)
+ || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY;
+ mCurStatsToken = createStatsToken(false /* show */, reason, isFromUser);
+ hideWindow();
+ }
+
public void hideWindow() {
if (DEBUG) Log.v(TAG, "CALL: hideWindow");
+
+ final var statsToken = mCurStatsToken != null ? mCurStatsToken
+ : createStatsToken(false /* show */,
+ SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT,
+ ImeTracker.isFromUser(mRootView));
+ mCurStatsToken = null;
+
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_HIDE_WINDOW);
ImeTracing.getInstance().triggerServiceDump("InputMethodService#hideWindow", mDumper,
null /* icProto */);
setImeWindowStatus(0, mBackDisposition);
- applyVisibilityInInsetsConsumerIfNecessary(false);
+ applyVisibilityInInsetsConsumerIfNecessary(false /* setVisible */, statsToken);
mWindowVisible = false;
finishViews(false /* finishingInput */);
if (mDecorViewVisible) {
@@ -3440,9 +3513,14 @@
private void requestHideSelf(@InputMethodManager.HideFlags int flags,
@SoftInputShowHideReason int reason) {
+ // TODO(b/303041796): this should be handled by ImeTracker.isFromUser after fixing it
+ // to work with onClickListeners
+ final boolean isFromUser = ImeTracker.isFromUser(mRootView)
+ || reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY;
+ final var statsToken = createStatsToken(false /* show */, reason, isFromUser);
ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestHideSelf", mDumper,
null /* icProto */);
- mPrivOps.hideMySoftInput(flags, reason);
+ mPrivOps.hideMySoftInput(statsToken, flags, reason);
}
/**
@@ -3450,9 +3528,16 @@
* interact with it.
*/
public final void requestShowSelf(@InputMethodManager.ShowFlags int flags) {
+ requestShowSelf(flags, SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME);
+ }
+
+ private void requestShowSelf(@InputMethodManager.ShowFlags int flags,
+ @SoftInputShowHideReason int reason) {
+ final var statsToken = createStatsToken(true /* show */, reason,
+ ImeTracker.isFromUser(mRootView));
ImeTracing.getInstance().triggerServiceDump("InputMethodService#requestShowSelf", mDumper,
null /* icProto */);
- mPrivOps.showMySoftInput(flags);
+ mPrivOps.showMySoftInput(statsToken, flags, reason);
}
private boolean handleBack(boolean doIt) {
@@ -3472,7 +3557,7 @@
// If we have the window visible for some other reason --
// most likely to show candidates -- then just get rid
// of it. This really shouldn't happen, but just in case...
- if (doIt) hideWindow();
+ if (doIt) hideWindowWithToken(SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY);
}
return true;
}
@@ -3627,10 +3712,11 @@
@InputMethodManager.HideFlags int hideFlags) {
if (DEBUG) Log.v(TAG, "toggleSoftInput()");
if (isInputViewShown()) {
- requestHideSelf(
- hideFlags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
+ requestHideSelf(hideFlags,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
} else {
- requestShowSelf(showFlags);
+ requestShowSelf(showFlags,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT);
}
}
@@ -4272,6 +4358,20 @@
}
/**
+ * Creates an IME request tracking token.
+ *
+ * @param show whether this is a show or a hide request.
+ * @param reason the reason why the IME request was created.
+ * @param isFromUser whether this request was created directly from user interaction.
+ */
+ @NonNull
+ private ImeTracker.Token createStatsToken(boolean show, @SoftInputShowHideReason int reason,
+ boolean isFromUser) {
+ return ImeTracker.forLogging().onStart(show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_IME, reason, isFromUser);
+ }
+
+ /**
* Performs a dump of the InputMethodService's internal state. Override
* to add your own information to the dump.
*/
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 11180ae..5ee526e 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -73,7 +73,7 @@
*
* @param types internal insets types (WindowInsets.Type.InsetsType) to show
* @param fromIme true if this request originated from IME (InputMethodService).
- * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*/
void showInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken);
@@ -82,7 +82,7 @@
*
* @param types internal insets types (WindowInsets.Type.InsetsType) to hide
* @param fromIme true if this request originated from IME (InputMethodService).
- * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*/
void hideInsets(int types, boolean fromIme, in @nullable ImeTracker.Token statsToken);
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index de809c8..821e13d 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -21,9 +21,9 @@
import static android.view.ImeInsetsSourceConsumerProto.INSETS_SOURCE_CONSUMER;
import static android.view.ImeInsetsSourceConsumerProto.IS_REQUESTED_VISIBLE_AWAITING_CONTROL;
+import android.annotation.NonNull;
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;
@@ -70,7 +70,11 @@
if (!isShowRequested()) {
mIsRequestedVisibleAwaitingControl = false;
if (!running && !mHasPendingRequest) {
- notifyHidden(null /* statsToken */);
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED,
+ mController.getHost().isHandlingPointerEvent() /* fromUser */);
+ notifyHidden(statsToken);
removeSurface();
}
}
@@ -144,9 +148,17 @@
void requestHide(boolean fromIme, @Nullable ImeTracker.Token statsToken) {
if (!fromIme) {
+ // Create a new token to track the hide request when we have control,
+ // as we use the passed in token for the insets animation already.
+ final var notifyStatsToken = getControl() != null
+ ? ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL,
+ mController.getHost().isHandlingPointerEvent() /* fromUser */)
+ : statsToken;
// The insets might be controlled by a remote target. Let the server know we are
// requested to hide.
- notifyHidden(statsToken);
+ notifyHidden(notifyStatsToken);
}
if (mAnimationState == ANIMATION_STATE_SHOW) {
mHasPendingRequest = true;
@@ -157,21 +169,9 @@
* 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.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*/
- 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.forLogging().onRequestHide(null /* component */,
- Process.myUid(),
- ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
- mController.getHost().isHandlingPointerEvent() /* fromUser */);
- }
-
+ private void notifyHidden(@NonNull ImeTracker.Token statsToken) {
ImeTracker.forLogging().onProgress(statsToken,
ImeTracker.PHASE_CLIENT_INSETS_CONSUMER_NOTIFY_HIDDEN);
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 7f1e037..85c779b 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -43,7 +43,6 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
-import static android.view.inputmethod.ImeTracker.TOKEN_NONE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
@@ -165,9 +164,9 @@
mStatsToken = statsToken;
if (DEBUG_IME_VISIBILITY && (types & ime()) != 0) {
EventLog.writeEvent(IMF_IME_ANIM_START,
- mStatsToken != null ? mStatsToken.getTag() : TOKEN_NONE, mAnimationType,
- mCurrentAlpha, "Current:" + mCurrentInsets, "Shown:" + mShownInsets,
- "Hidden:" + mHiddenInsets);
+ mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+ mAnimationType, mCurrentAlpha, "Current:" + mCurrentInsets,
+ "Shown:" + mShownInsets, "Hidden:" + mHiddenInsets);
}
mController.startAnimation(this, listener, types, mAnimation,
new Bounds(mHiddenInsets, mShownInsets));
@@ -245,6 +244,7 @@
}
@Override
+ @Nullable
public ImeTracker.Token getStatsToken() {
return mStatsToken;
}
@@ -330,8 +330,8 @@
mListener.onFinished(this);
if (DEBUG_IME_VISIBILITY && (mTypes & ime()) != 0) {
EventLog.writeEvent(IMF_IME_ANIM_FINISH,
- mStatsToken != null ? mStatsToken.getTag() : TOKEN_NONE, mAnimationType,
- mCurrentAlpha, shown ? 1 : 0, Objects.toString(insets));
+ mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+ mAnimationType, mCurrentAlpha, shown ? 1 : 0, Objects.toString(insets));
}
}
@@ -355,8 +355,8 @@
if (DEBUG) Log.d(TAG, "notify Control request cancelled for types: " + mTypes);
if (DEBUG_IME_VISIBILITY && (mTypes & ime()) != 0) {
EventLog.writeEvent(IMF_IME_ANIM_CANCEL,
- mStatsToken != null ? mStatsToken.getTag() : TOKEN_NONE, mAnimationType,
- Objects.toString(mPendingInsets));
+ mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+ mAnimationType, Objects.toString(mPendingInsets));
}
releaseLeashes();
}
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 079991a..92e20e0 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -137,6 +137,7 @@
}
@Override
+ @Nullable
public ImeTracker.Token getStatsToken() {
return mControl.getStatsToken();
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 1803a6e..6cc4b20 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -28,7 +28,6 @@
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.ime;
-import static android.view.inputmethod.ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL;
import android.animation.AnimationHandler;
import android.animation.Animator;
@@ -47,7 +46,6 @@
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.IntArray;
@@ -659,6 +657,7 @@
private final Runnable mAnimCallback;
/** Pending control request that is waiting on IME to be ready to be shown */
+ @Nullable
private PendingControlRequest mPendingImeControlRequest;
private int mWindowType;
@@ -1043,12 +1042,18 @@
hideTypes[0] &= ~animatingTypes;
if (showTypes[0] != 0) {
- applyAnimation(showTypes[0], true /* show */, false /* fromIme */,
- null /* statsToken */);
+ final var statsToken = (showTypes[0] & ime()) == 0 ? null
+ : ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+ ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.CONTROLS_CHANGED,
+ mHost.isHandlingPointerEvent() /* fromUser */);
+ applyAnimation(showTypes[0], true /* show */, false /* fromIme */, statsToken);
}
if (hideTypes[0] != 0) {
- applyAnimation(hideTypes[0], false /* show */, false /* fromIme */,
- null /* statsToken */);
+ final var statsToken = (hideTypes[0] & ime()) == 0 ? null
+ : ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT, SoftInputShowHideReason.CONTROLS_CHANGED,
+ mHost.isHandlingPointerEvent() /* fromUser */);
+ applyAnimation(hideTypes[0], false /* show */, false /* fromIme */, statsToken);
}
if (mControllableTypes != controllableTypes) {
@@ -1064,15 +1069,7 @@
@Override
public void show(@InsetsType int types) {
- ImeTracker.Token statsToken = null;
- if ((types & ime()) != 0) {
- statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
- Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
- SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API,
- mHost.isHandlingPointerEvent() /* fromUser */);
- }
-
- show(types, false /* fromIme */, statsToken);
+ show(types, false /* fromIme */, null /* statsToken */);
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -1080,6 +1077,13 @@
@Nullable ImeTracker.Token statsToken) {
if ((types & ime()) != 0) {
Log.d(TAG, "show(ime(), fromIme=" + fromIme + ")");
+
+ if (statsToken == null) {
+ statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+ ImeTracker.ORIGIN_CLIENT,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_BY_INSETS_API,
+ mHost.isHandlingPointerEvent() /* fromUser */);
+ }
}
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#show",
@@ -1148,9 +1152,11 @@
}
/**
- * Handle the {@link #mPendingImeControlRequest} when
- * - The IME insets is ready to show.
- * - The IME insets has being requested invisible.
+ * Handle the {@link #mPendingImeControlRequest} when:
+ * <ul>
+ * <li> The IME insets is ready to show.
+ * <li> The IME insets has being requested invisible.
+ * </ul>
*/
private void handlePendingControlRequest(@Nullable ImeTracker.Token statsToken) {
PendingControlRequest pendingRequest = mPendingImeControlRequest;
@@ -1170,20 +1176,22 @@
@Override
public void hide(@InsetsType int types) {
- ImeTracker.Token statsToken = null;
- if ((types & ime()) != 0) {
- statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
- Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
- mHost.isHandlingPointerEvent() /* fromUser */);
- }
-
- hide(types, false /* fromIme */, statsToken);
+ hide(types, false /* fromIme */, null /* statsToken */);
}
@VisibleForTesting
public void hide(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {
+ if ((types & ime()) != 0) {
+ Log.d(TAG, "hide(ime(), fromIme=" + fromIme + ")");
+
+ if (statsToken == null) {
+ statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
+ mHost.isHandlingPointerEvent() /* fromUser */);
+ }
+ }
if (fromIme) {
ImeTracing.getInstance().triggerClientDump("InsetsController#hide",
mHost.getInputMethodManager(), null /* icProto */);
@@ -1307,10 +1315,12 @@
if (monitoredAnimation && (types & Type.ime()) != 0) {
if (animationType == ANIMATION_TYPE_SHOW) {
ImeTracker.forLatency().onShowCancelled(statsToken,
- PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+ ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL,
+ ActivityThread::currentApplication);
} else {
ImeTracker.forLatency().onHideCancelled(statsToken,
- PHASE_CLIENT_ANIMATION_CANCEL, ActivityThread::currentApplication);
+ ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL,
+ ActivityThread::currentApplication);
}
ImeTracker.forLogging().onCancelled(statsToken,
ImeTracker.PHASE_CLIENT_CONTROL_ANIMATION);
@@ -1602,12 +1612,12 @@
private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
if (invokeCallback) {
ImeTracker.forLogging().onCancelled(control.getStatsToken(),
- PHASE_CLIENT_ANIMATION_CANCEL);
+ ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
control.cancel();
} else {
// Succeeds if invokeCallback is false (i.e. when called from notifyFinished).
ImeTracker.forLogging().onProgress(control.getStatsToken(),
- PHASE_CLIENT_ANIMATION_CANCEL);
+ ImeTracker.PHASE_CLIENT_ANIMATION_CANCEL);
}
if (DEBUG) {
Log.d(TAG, TextUtils.formatSimple(
diff --git a/core/java/android/view/InsetsResizeAnimationRunner.java b/core/java/android/view/InsetsResizeAnimationRunner.java
index bffaeea..ebdddd5 100644
--- a/core/java/android/view/InsetsResizeAnimationRunner.java
+++ b/core/java/android/view/InsetsResizeAnimationRunner.java
@@ -29,6 +29,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.annotation.Nullable;
import android.graphics.Insets;
import android.graphics.Rect;
import android.util.SparseArray;
@@ -92,6 +93,7 @@
}
@Override
+ @Nullable
public ImeTracker.Token getStatsToken() {
// Return null as resizing the IME view is not explicitly tracked.
return null;
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 0ce61bb..fdb2a6e 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -314,7 +314,7 @@
* @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.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*
* @implNote The {@code statsToken} is ignored here, and only handled in
* {@link ImeInsetsSourceConsumer} for IME animations only.
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index 491b0e3..cedf8d0 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -25,7 +25,6 @@
import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.content.Context;
-import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -298,7 +297,7 @@
@AnyThread
static boolean showSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+ @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
int lastClickToolType, @Nullable ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
final IInputMethodManager service = getService();
@@ -315,7 +314,7 @@
@AnyThread
static boolean hideSoftInput(@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
+ @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
@Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -331,6 +330,20 @@
// TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled.
@AnyThread
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
+ static void hideSoftInputFromServerForTest() {
+ final IInputMethodManager service = getService();
+ if (service == null) {
+ return;
+ }
+ try {
+ service.hideSoftInputFromServerForTest();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @AnyThread
@NonNull
@RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static InputBindResult startInputOrWindowGainedFocus(@StartInputReason int startInputReason,
@@ -654,35 +667,18 @@
}
}
- /** @see com.android.server.inputmethod.ImeTrackerService#onRequestShow */
+ /** @see com.android.server.inputmethod.ImeTrackerService#onStart */
@AnyThread
@NonNull
- static ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
+ static ImeTracker.Token onStart(@NonNull String tag, int uid, @ImeTracker.Type int type,
@ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
- final IImeTracker service = getImeTrackerService();
+ final var service = getImeTrackerService();
if (service == null) {
- // Create token with "fake" binder if the service was not found.
- return new ImeTracker.Token(new Binder(), tag);
+ // Create token with "empty" binder if the service was not found.
+ return ImeTracker.Token.empty(tag);
}
try {
- return service.onRequestShow(tag, uid, origin, reason, fromUser);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /** @see com.android.server.inputmethod.ImeTrackerService#onRequestHide */
- @AnyThread
- @NonNull
- static ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
- @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
- final IImeTracker service = getImeTrackerService();
- if (service == null) {
- // Create token with "fake" binder if the service was not found.
- return new ImeTracker.Token(new Binder(), tag);
- }
- try {
- return service.onRequestHide(tag, uid, origin, reason, fromUser);
+ return service.onStart(tag, uid, type, origin, reason, fromUser);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/view/inputmethod/ImeTracker.java b/core/java/android/view/inputmethod/ImeTracker.java
index b1fdaa9..7f79661 100644
--- a/core/java/android/view/inputmethod/ImeTracker.java
+++ b/core/java/android/view/inputmethod/ImeTracker.java
@@ -28,17 +28,20 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.ActivityThread;
import android.content.Context;
+import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.os.SystemProperties;
import android.util.Log;
import android.view.InsetsController.AnimationType;
import android.view.SurfaceControl;
import android.view.View;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.jank.InteractionJankMonitor;
@@ -108,34 +111,32 @@
/**
* The origin of the IME request
*
- * The name follows the format {@code PHASE_x_...} where {@code x} denotes
- * where the origin is (i.e. {@code PHASE_SERVER_...} occurs in the server).
+ * <p> The name follows the format {@code ORIGIN_x_...} where {@code x} denotes
+ * where the origin is (i.e. {@code ORIGIN_SERVER} occurs in the server).
*/
@IntDef(prefix = { "ORIGIN_" }, value = {
- ORIGIN_CLIENT_SHOW_SOFT_INPUT,
- ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- ORIGIN_SERVER_START_INPUT,
- ORIGIN_SERVER_HIDE_INPUT
+ ORIGIN_CLIENT,
+ ORIGIN_SERVER,
+ ORIGIN_IME
})
@Retention(RetentionPolicy.SOURCE)
@interface Origin {}
- /** The IME show request originated in the client. */
- int ORIGIN_CLIENT_SHOW_SOFT_INPUT = ImeProtoEnums.ORIGIN_CLIENT_SHOW_SOFT_INPUT;
+ /** The IME request originated in the client. */
+ int ORIGIN_CLIENT = ImeProtoEnums.ORIGIN_CLIENT;
- /** The IME hide request originated in the client. */
- int ORIGIN_CLIENT_HIDE_SOFT_INPUT = ImeProtoEnums.ORIGIN_CLIENT_HIDE_SOFT_INPUT;
+ /** The IME request originated in the server. */
+ int ORIGIN_SERVER = ImeProtoEnums.ORIGIN_SERVER;
- /** The IME show request originated in the server. */
- int ORIGIN_SERVER_START_INPUT = ImeProtoEnums.ORIGIN_SERVER_START_INPUT;
-
- /** The IME hide request originated in the server. */
- int ORIGIN_SERVER_HIDE_INPUT = ImeProtoEnums.ORIGIN_SERVER_HIDE_INPUT;
+ /** The IME request originated in the IME. */
+ int ORIGIN_IME = ImeProtoEnums.ORIGIN_IME;
+ /** The IME request originated in the WindowManager Shell. */
+ int ORIGIN_WM_SHELL = ImeProtoEnums.ORIGIN_WM_SHELL;
/**
* The current phase of the IME request.
*
- * The name follows the format {@code PHASE_x_...} where {@code x} denotes
+ * <p> The name follows the format {@code PHASE_x_...} where {@code x} denotes
* where the phase is (i.e. {@code PHASE_SERVER_...} occurs in the server).
*/
@IntDef(prefix = { "PHASE_" }, value = {
@@ -155,7 +156,6 @@
PHASE_IME_SHOW_SOFT_INPUT,
PHASE_IME_HIDE_SOFT_INPUT,
PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE,
- PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER,
PHASE_SERVER_APPLY_IME_VISIBILITY,
PHASE_WM_SHOW_IME_RUNNER,
PHASE_WM_SHOW_IME_READY,
@@ -182,6 +182,11 @@
PHASE_CLIENT_ANIMATION_FINISHED_SHOW,
PHASE_CLIENT_ANIMATION_FINISHED_HIDE,
PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT,
+ PHASE_CLIENT_ANIMATION_FINISHED_HIDE,
+ PHASE_IME_SHOW_WINDOW,
+ PHASE_IME_HIDE_WINDOW,
+ PHASE_IME_PRIVILEGED_OPERATIONS,
+ PHASE_SERVER_CURRENT_ACTIVE_IME,
})
@Retention(RetentionPolicy.SOURCE)
@interface Phase {}
@@ -224,19 +229,15 @@
/** Dispatched from the IME wrapper to the IME. */
int PHASE_IME_WRAPPER_DISPATCH = ImeProtoEnums.PHASE_IME_WRAPPER_DISPATCH;
- /** Reached the IME' showSoftInput method. */
+ /** Reached the IME's showSoftInput method. */
int PHASE_IME_SHOW_SOFT_INPUT = ImeProtoEnums.PHASE_IME_SHOW_SOFT_INPUT;
- /** Reached the IME' hideSoftInput method. */
+ /** Reached the IME's hideSoftInput method. */
int PHASE_IME_HIDE_SOFT_INPUT = ImeProtoEnums.PHASE_IME_HIDE_SOFT_INPUT;
/** The server decided the IME should be shown. */
int PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE = ImeProtoEnums.PHASE_IME_ON_SHOW_SOFT_INPUT_TRUE;
- /** Requested applying the IME visibility in the insets source consumer. */
- int PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER =
- ImeProtoEnums.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER;
-
/** Applied the IME visibility. */
int PHASE_SERVER_APPLY_IME_VISIBILITY = ImeProtoEnums.PHASE_SERVER_APPLY_IME_VISIBILITY;
@@ -323,37 +324,49 @@
int PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT =
ImeProtoEnums.PHASE_WM_ABORT_SHOW_IME_POST_LAYOUT;
+ /** Reached the IME's showWindow method. */
+ int PHASE_IME_SHOW_WINDOW = ImeProtoEnums.PHASE_IME_SHOW_WINDOW;
+
+ /** Reached the IME's hideWindow method. */
+ int PHASE_IME_HIDE_WINDOW = ImeProtoEnums.PHASE_IME_HIDE_WINDOW;
+
+ /** Reached the InputMethodPrivilegedOperations handler. */
+ int PHASE_IME_PRIVILEGED_OPERATIONS = ImeProtoEnums.PHASE_IME_PRIVILEGED_OPERATIONS;
+
+ /** Checked that the calling IME is the currently active IME. */
+ int PHASE_SERVER_CURRENT_ACTIVE_IME = ImeProtoEnums.PHASE_SERVER_CURRENT_ACTIVE_IME;
+
/**
- * Creates an IME show request tracking token.
+ * Called when an IME request is started.
*
- * @param component the name of the component that created the IME request, or {@code null}
- * otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
- * @param uid the uid of the client that requested the IME.
- * @param origin the origin of the IME show request.
- * @param reason the reason why the IME show request was created.
+ * @param component the name of the component that started the request.
+ * @param uid the uid of the client that started the request.
+ * @param type the type of the request.
+ * @param origin the origin of the request.
+ * @param reason the reason for starting the request.
* @param fromUser whether this request was created directly from user interaction.
*
- * @return An IME tracking token.
+ * @return An IME request tracking token.
*/
@NonNull
- Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
+ Token onStart(@NonNull String component, int uid, @Type int type, @Origin int origin,
@SoftInputShowHideReason int reason, boolean fromUser);
/**
- * Creates an IME hide request tracking token.
+ * Called when an IME request is started for the current process.
*
- * @param component the name of the component that created the IME request, or {@code null}
- * otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
- * @param uid the uid of the client that requested the IME.
- * @param origin the origin of the IME hide request.
- * @param reason the reason why the IME hide request was created.
+ * @param type the type of the request.
+ * @param origin the origin of the request.
+ * @param reason the reason for starting the request.
* @param fromUser whether this request was created directly from user interaction.
*
- * @return An IME tracking token.
+ * @return An IME request tracking token.
*/
@NonNull
- Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
- @SoftInputShowHideReason int reason, boolean fromUser);
+ default Token onStart(@Type int type, @Origin int origin, @SoftInputShowHideReason int reason,
+ boolean fromUser) {
+ return onStart(Process.myProcessName(), Process.myUid(), type, origin, reason, fromUser);
+ }
/**
* Called when an IME request progresses to a further phase.
@@ -390,14 +403,14 @@
/**
* Called when the IME show request is successful.
*
- * @param token the token tracking the current IME show request or {@code null} otherwise.
+ * @param token the token tracking the current IME request or {@code null} otherwise.
*/
void onShown(@Nullable Token token);
/**
* Called when the IME hide request is successful.
*
- * @param token the token tracking the current IME hide request or {@code null} otherwise.
+ * @param token the token tracking the current IME request or {@code null} otherwise.
*/
void onHidden(@Nullable Token token);
@@ -479,33 +492,17 @@
@NonNull
@Override
- public Token onRequestShow(@Nullable String component, int uid, @Origin int origin,
+ public Token onStart(@NonNull String component, int uid, @Type int type, @Origin int origin,
@SoftInputShowHideReason int reason, boolean fromUser) {
- final var tag = getTag(component);
- final var token = IInputMethodManagerGlobalInvoker.onRequestShow(tag, uid, origin,
- reason, fromUser);
+ final var tag = Token.createTag(component);
+ final var token = IInputMethodManagerGlobalInvoker.onStart(tag, uid, type,
+ origin, reason, fromUser);
- Log.i(TAG, token.mTag + ": onRequestShow at " + Debug.originToString(origin)
+ Log.i(TAG, token.mTag + ": onRequest" + (type == TYPE_SHOW ? "Show" : "Hide")
+ + " at " + Debug.originToString(origin)
+ " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
+ " fromUser " + fromUser,
mLogStackTrace ? new Throwable() : null);
-
- return token;
- }
-
- @NonNull
- @Override
- public Token onRequestHide(@Nullable String component, int uid, @Origin int origin,
- @SoftInputShowHideReason int reason, boolean fromUser) {
- final var tag = getTag(component);
- final var token = IInputMethodManagerGlobalInvoker.onRequestHide(tag, uid, origin,
- reason, fromUser);
-
- Log.i(TAG, token.mTag + ": onRequestHide at " + Debug.originToString(origin)
- + " reason " + InputMethodDebug.softInputDisplayReasonToString(reason)
- + " fromUser " + fromUser,
- mLogStackTrace ? new Throwable() : null);
-
return token;
}
@@ -556,20 +553,6 @@
Log.i(TAG, token.mTag + ": onHidden");
}
-
- /**
- * Returns a logging tag using the given component name.
- *
- * @param component the name of the component that created the IME request, or {@code null}
- * otherwise (defaulting to {@link ActivityThread#currentProcessName()}).
- */
- @NonNull
- private String getTag(@Nullable String component) {
- if (component == null) {
- component = ActivityThread.currentProcessName();
- }
- return component + ":" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
- }
};
/** The singleton IME tracker instance for instrumenting jank metrics. */
@@ -581,6 +564,10 @@
/** A token that tracks the progress of an IME request. */
final class Token implements Parcelable {
+ /** Empty binder, lazily initialized, used for empty token instantiation. */
+ @Nullable
+ private static IBinder sEmptyBinder;
+
/** The binder used to identify this token. */
@NonNull
private final IBinder mBinder;
@@ -599,16 +586,56 @@
mTag = in.readString8();
}
+ /** Returns the binder used to identify this token. */
@NonNull
public IBinder getBinder() {
return mBinder;
}
+ /** Returns the logging tag of this token. */
@NonNull
public String getTag() {
return mTag;
}
+ /**
+ * Creates a logging tag.
+ *
+ * @param component the name of the component that created the IME request.
+ */
+ @NonNull
+ private static String createTag(@NonNull String component) {
+ return component + ":" + Integer.toHexString(ThreadLocalRandom.current().nextInt());
+ }
+
+ /** Returns a new token with an empty binder. */
+ @NonNull
+ @VisibleForTesting(visibility = Visibility.PACKAGE)
+ public static Token empty() {
+ final var tag = createTag(Process.myProcessName());
+ return empty(tag);
+ }
+
+ /** Returns a new token with an empty binder and the given logging tag. */
+ @NonNull
+ static Token empty(@NonNull String tag) {
+ return new Token(getEmptyBinder(), tag);
+ }
+
+ /** Returns the empty binder instance for empty token creation, lazily initializing it. */
+ @NonNull
+ private static IBinder getEmptyBinder() {
+ if (sEmptyBinder == null) {
+ sEmptyBinder = new Binder();
+ }
+ return sEmptyBinder;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "(tag: " + mTag + ")";
+ }
+
/** For Parcelable, no special marshalled objects. */
@Override
public int describeContents() {
diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java
index 33f34c5..88607fc 100644
--- a/core/java/android/view/inputmethod/InputMethod.java
+++ b/core/java/android/view/inputmethod/InputMethod.java
@@ -281,7 +281,7 @@
})
@Retention(RetentionPolicy.SOURCE)
@interface ShowFlags {}
-
+
/**
* Flag for {@link #showSoftInput}: this show has been explicitly
* requested by the user. If not set, the system has decided it may be
@@ -314,18 +314,18 @@
* @param showInputToken an opaque {@link android.os.Binder} token to identify which API call
* of {@link InputMethodManager#showSoftInput(View, int)} is associated with
* this callback.
- * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request.
* @hide
*/
@MainThread
public default void showSoftInputWithToken(@ShowFlags int flags, ResultReceiver resultReceiver,
- IBinder showInputToken, @Nullable ImeTracker.Token statsToken) {
+ IBinder showInputToken, @NonNull ImeTracker.Token statsToken) {
showSoftInput(flags, resultReceiver);
}
/**
* Request that any soft input part of the input method be shown to the user.
- *
+ *
* @param resultReceiver The client requesting the show may wish to
* be told the impact of their request, which should be supplied here.
* The result code should be
@@ -352,12 +352,12 @@
* @param hideInputToken an opaque {@link android.os.Binder} token to identify which API call
* of {@link InputMethodManager#hideSoftInputFromWindow(IBinder, int)}} is associated
* with this callback.
- * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request.
* @hide
*/
@MainThread
public default void hideSoftInputWithToken(int flags, ResultReceiver resultReceiver,
- IBinder hideInputToken, @Nullable ImeTracker.Token statsToken) {
+ IBinder hideInputToken, @NonNull ImeTracker.Token statsToken) {
hideSoftInput(flags, resultReceiver);
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 68940d6..3be76cc 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2263,21 +2263,22 @@
* {@link #RESULT_HIDDEN}.
*/
public boolean showSoftInput(View view, @ShowFlags int flags, ResultReceiver resultReceiver) {
- return showSoftInput(view, null /* statsToken */, flags, resultReceiver,
- SoftInputShowHideReason.SHOW_SOFT_INPUT);
+ return showSoftInput(view, flags, resultReceiver, SoftInputShowHideReason.SHOW_SOFT_INPUT);
}
- private boolean showSoftInput(View view, @Nullable ImeTracker.Token statsToken,
- @ShowFlags int flags, ResultReceiver resultReceiver,
+ private boolean showSoftInput(View view, @ShowFlags int flags,
+ @Nullable ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
+ // TODO(b/303041796): handle tracking physical keyboard and DPAD as user interactions
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+ ImeTracker.ORIGIN_CLIENT, reason, ImeTracker.isFromUser(view));
+ return showSoftInput(view, statsToken, flags, resultReceiver, reason);
+ }
+
+ private boolean showSoftInput(View view, @NonNull ImeTracker.Token statsToken,
+ @ShowFlags int flags, @Nullable ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
- if (statsToken == null) {
- // TODO(b/303041796): handle tracking physical keyboard and DPAD as user interactions
- statsToken = ImeTracker.forLogging().onRequestShow(null /* component */,
- Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT, reason,
- ImeTracker.isFromUser(view));
- }
- ImeTracker.forLatency().onRequestShow(statsToken, ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
- reason, ActivityThread::currentApplication);
+ ImeTracker.forLatency().onRequestShow(statsToken,
+ ImeTracker.ORIGIN_CLIENT, reason, ActivityThread::currentApplication);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#showSoftInput", this,
null /* icProto */);
// Re-dispatch if there is a context mismatch.
@@ -2290,9 +2291,8 @@
synchronized (mH) {
if (!hasServedByInputMethodLocked(view)) {
ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
- ImeTracker.forLatency().onShowFailed(
- statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
- ActivityThread::currentApplication);
+ ImeTracker.forLatency().onShowFailed(statsToken,
+ ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
Log.w(TAG, "Ignoring showSoftInput() as view=" + view + " is not served.");
return false;
}
@@ -2327,9 +2327,9 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768499)
public void showSoftInputUnchecked(@ShowFlags int flags, ResultReceiver resultReceiver) {
synchronized (mH) {
- final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestShow(
- null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_SHOW_SOFT_INPUT,
- SoftInputShowHideReason.SHOW_SOFT_INPUT, false /* fromUser */);
+ final int reason = SoftInputShowHideReason.SHOW_SOFT_INPUT;
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+ ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
Log.w(TAG, "showSoftInputUnchecked() is a hidden method, which will be"
+ " removed soon. If you are using androidx.appcompat.widget.SearchView,"
@@ -2353,7 +2353,7 @@
flags,
mCurRootView.getLastClickToolType(),
resultReceiver,
- SoftInputShowHideReason.SHOW_SOFT_INPUT);
+ reason);
}
}
@@ -2429,11 +2429,10 @@
initialServedView = getServedViewLocked();
}
- final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
- null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- reason, ImeTracker.isFromUser(initialServedView));
- ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- reason, ActivityThread::currentApplication);
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT, reason, ImeTracker.isFromUser(initialServedView));
+ ImeTracker.forLatency().onRequestHide(statsToken,
+ ImeTracker.ORIGIN_CLIENT, reason, ActivityThread::currentApplication);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromWindow",
this, null /* icProto */);
checkFocus();
@@ -2472,20 +2471,18 @@
}
}
- final var reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW;
- final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
- null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- reason, ImeTracker.isFromUser(view));
- ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- reason, ActivityThread::currentApplication);
+ final int reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW;
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT, reason, ImeTracker.isFromUser(view));
+ ImeTracker.forLatency().onRequestHide(statsToken,
+ ImeTracker.ORIGIN_CLIENT, reason, ActivityThread::currentApplication);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#hideSoftInputFromView",
this, null /* icProto */);
synchronized (mH) {
if (!hasServedByInputMethodLocked(view)) {
ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED);
- ImeTracker.forLatency().onShowFailed(
- statsToken, ImeTracker.PHASE_CLIENT_VIEW_SERVED,
- ActivityThread::currentApplication);
+ ImeTracker.forLatency().onShowFailed(statsToken,
+ ImeTracker.PHASE_CLIENT_VIEW_SERVED, ActivityThread::currentApplication);
Log.w(TAG, "Ignoring hideSoftInputFromView() as view=" + view + " is not served.");
return false;
}
@@ -2498,6 +2495,19 @@
}
/**
+ * A test API for CTS to request hiding the current soft input window, with the request origin
+ * on the server side.
+ *
+ * @hide
+ */
+ @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
+ @TestApi
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
+ public void hideSoftInputFromServerForTest() {
+ IInputMethodManagerGlobalInvoker.hideSoftInputFromServerForTest();
+ }
+
+ /**
* Start stylus handwriting session.
*
* If supported by the current input method, a stylus handwriting session is started on the
@@ -2973,10 +2983,11 @@
if (view != null) {
final WindowInsets rootInsets = view.getRootWindowInsets();
if (rootInsets != null && rootInsets.isVisible(WindowInsets.Type.ime())) {
- hideSoftInputFromWindow(view.getWindowToken(), hideFlags, null,
+ hideSoftInputFromWindow(view.getWindowToken(), hideFlags,
+ null /* resultReceiver */,
SoftInputShowHideReason.HIDE_TOGGLE_SOFT_INPUT);
} else {
- showSoftInput(view, null /* statsToken */, showFlags, null /* resultReceiver */,
+ showSoftInput(view, showFlags, null /* resultReceiver */,
SoftInputShowHideReason.SHOW_TOGGLE_SOFT_INPUT);
}
}
@@ -3537,11 +3548,11 @@
@UnsupportedAppUsage
void closeCurrentInput() {
- final ImeTracker.Token statsToken = ImeTracker.forLogging().onRequestHide(
- null /* component */, Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION, false /* fromUser */);
- ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION,
+ final int reason = SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION;
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
+ ImeTracker.forLatency().onRequestHide(statsToken,
+ ImeTracker.ORIGIN_CLIENT, reason,
ActivityThread::currentApplication);
synchronized (mH) {
@@ -3562,7 +3573,7 @@
statsToken,
HIDE_NOT_ALWAYS,
null,
- SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION);
+ reason);
}
}
@@ -3603,12 +3614,12 @@
*
* @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}.
- * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request.
*
* @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
* @hide
*/
- public boolean requestImeShow(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
+ public boolean requestImeShow(IBinder windowToken, @NonNull ImeTracker.Token statsToken) {
checkFocus();
synchronized (mH) {
final View servedView = getServedViewLocked();
@@ -3632,16 +3643,11 @@
*
* @param windowToken the window from which this request originates. If this doesn't match the
* currently served view, the request is ignored.
- * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request.
* @hide
*/
- public void notifyImeHidden(IBinder windowToken, @Nullable ImeTracker.Token statsToken) {
- if (statsToken == null) {
- statsToken = ImeTracker.forLogging().onRequestHide(null /* component */,
- Process.myUid(), ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
- SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API, false /* fromUser */);
- }
- ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT_HIDE_SOFT_INPUT,
+ public void notifyImeHidden(IBinder windowToken, @NonNull ImeTracker.Token statsToken) {
+ ImeTracker.forLatency().onRequestHide(statsToken, ImeTracker.ORIGIN_CLIENT,
SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_INSETS_API,
ActivityThread::currentApplication);
ImeTracing.getInstance().triggerClientDump("InputMethodManager#notifyImeHidden", this,
@@ -4025,8 +4031,11 @@
*/
@Deprecated
public void hideSoftInputFromInputMethod(IBinder token, @HideFlags int flags) {
- InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(
- flags, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION);
+ final int reason = SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION;
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
+ InputMethodPrivilegedOperationsRegistry.get(token).hideMySoftInput(statsToken, flags,
+ reason);
}
/**
@@ -4044,7 +4053,11 @@
*/
@Deprecated
public void showSoftInputFromInputMethod(IBinder token, @ShowFlags int flags) {
- InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(flags);
+ final int reason = SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION;
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_SHOW,
+ ImeTracker.ORIGIN_CLIENT, reason, false /* fromUser */);
+ InputMethodPrivilegedOperationsRegistry.get(token).showMySoftInput(statsToken, flags,
+ reason);
}
/**
diff --git a/core/java/com/android/internal/inputmethod/IImeTracker.aidl b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
index 2759043..b45bc1c 100644
--- a/core/java/com/android/internal/inputmethod/IImeTracker.aidl
+++ b/core/java/com/android/internal/inputmethod/IImeTracker.aidl
@@ -25,28 +25,19 @@
interface IImeTracker {
/**
- * Called when an IME show request is created.
+ * Called when an IME request is started.
*
* @param tag the logging tag.
- * @param uid the uid of the client that requested the IME.
- * @param origin the origin of the IME show request.
- * @param reason the reason why the IME show request was created.
+ * @param uid the uid of the client that started the request.
+ * @param type the type of the request.
+ * @param origin the origin of the request.
* @param fromUser whether this request was created directly from user interaction.
- * @return A new IME tracking token.
- */
- ImeTracker.Token onRequestShow(String tag, int uid, int origin, int reason, boolean fromUser);
-
- /**
- * Called when an IME hide request is created.
+ * @param reason the reason for starting the request.
*
- * @param tag the logging tag.
- * @param uid the uid of the client that requested the IME.
- * @param origin the origin of the IME hide request.
- * @param reason the reason why the IME hide request was created.
- * @param fromUser whether this request was created directly from user interaction.
- * @return A new IME tracking token.
+ * @return An IME request tracking token.
*/
- ImeTracker.Token onRequestHide(String tag, int uid, int origin, int reason, boolean fromUser);
+ ImeTracker.Token onStart(String tag, int uid, int type, int origin, int reason,
+ boolean fromUser);
/**
* Called when the IME request progresses to a further phase.
diff --git a/core/java/com/android/internal/inputmethod/IInputMethod.aidl b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
index 6abd9e8..2593b78 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethod.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
@@ -71,11 +71,11 @@
void setSessionEnabled(IInputMethodSession session, boolean enabled);
- void showSoftInput(in IBinder showInputToken, in @nullable ImeTracker.Token statsToken,
- int flags, in ResultReceiver resultReceiver);
+ void showSoftInput(in IBinder showInputToken, in ImeTracker.Token statsToken, int flags,
+ in ResultReceiver resultReceiver);
- void hideSoftInput(in IBinder hideInputToken, in @nullable ImeTracker.Token statsToken,
- int flags, in ResultReceiver resultReceiver);
+ void hideSoftInput(in IBinder hideInputToken, in ImeTracker.Token statsToken, int flags,
+ in ResultReceiver resultReceiver);
void updateEditorToolType(int toolType);
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 65a2f4b..457b9dd 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -35,15 +35,17 @@
void setInputMethod(String id, in AndroidFuture future /* T=Void */);
void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
in AndroidFuture future /* T=Void */);
- void hideMySoftInput(int flags, int reason, in AndroidFuture future /* T=Void */);
- void showMySoftInput(int flags, in AndroidFuture future /* T=Void */);
+ void hideMySoftInput(in ImeTracker.Token statsToken, int flags, int reason,
+ in AndroidFuture future /* T=Void */);
+ void showMySoftInput(in ImeTracker.Token statsToken, int flags, int reason,
+ in AndroidFuture future /* T=Void */);
void updateStatusIconAsync(String packageName, int iconId);
void switchToPreviousInputMethod(in AndroidFuture future /* T=Boolean */);
void switchToNextInputMethod(boolean onlyCurrentIme, in AndroidFuture future /* T=Boolean */);
void shouldOfferSwitchingToNextInputMethod(in AndroidFuture future /* T=Boolean */);
void notifyUserActionAsync();
void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible,
- in @nullable ImeTracker.Token statsToken);
+ in ImeTracker.Token statsToken);
void onStylusHandwritingReady(int requestId, int pid);
void resetStylusHandwriting(int requestId);
void switchKeyboardLayoutAsync(int direction);
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 9b7fa2f..a0aad31 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -189,6 +189,8 @@
*/
public static String softInputDisplayReasonToString(@SoftInputShowHideReason int reason) {
switch (reason) {
+ case SoftInputShowHideReason.NOT_SET:
+ return "NOT_SET";
case SoftInputShowHideReason.SHOW_SOFT_INPUT:
return "SHOW_SOFT_INPUT";
case SoftInputShowHideReason.ATTACH_NEW_INPUT:
@@ -265,6 +267,36 @@
return "HIDE_SOFT_INPUT_CLOSE_CURRENT_SESSION";
case SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW:
return "HIDE_SOFT_INPUT_FROM_VIEW";
+ case SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT:
+ return "SHOW_SOFT_INPUT_LEGACY_DIRECT";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT:
+ return "HIDE_SOFT_INPUT_LEGACY_DIRECT";
+ case SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT:
+ return "SHOW_WINDOW_LEGACY_DIRECT";
+ case SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT:
+ return "HIDE_WINDOW_LEGACY_DIRECT";
+ case SoftInputShowHideReason.RESET_NEW_CONFIGURATION:
+ return "RESET_NEW_CONFIGURATION";
+ case SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY:
+ return "UPDATE_CANDIDATES_VIEW_VISIBILITY";
+ case SoftInputShowHideReason.CONTROLS_CHANGED:
+ return "CONTROLS_CHANGED";
+ case SoftInputShowHideReason.DISPLAY_CONFIGURATION_CHANGED:
+ return "DISPLAY_CONFIGURATION_CHANGED";
+ case SoftInputShowHideReason.DISPLAY_INSETS_CHANGED:
+ return "DISPLAY_INSETS_CHANGED";
+ case SoftInputShowHideReason.DISPLAY_CONTROLS_CHANGED:
+ return "DISPLAY_CONTROLS_CHANGED";
+ case SoftInputShowHideReason.UNBIND_CURRENT_METHOD:
+ return "UNBIND_CURRENT_METHOD";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED:
+ return "HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED";
+ case SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL:
+ return "HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL";
+ case SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT:
+ return "SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT";
+ case SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION:
+ return "SHOW_SOFT_INPUT_IMM_DEPRECATION";
default:
return "Unknown=" + reason;
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 792388d..635a227 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -252,20 +252,21 @@
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput(int, int, AndroidFuture)}
- *
- * @param reason the reason to hide soft input
+ * Calls {@link IInputMethodPrivilegedOperations#hideMySoftInput}
*/
@AnyThread
- public void hideMySoftInput(@InputMethodManager.HideFlags int flags,
- @SoftInputShowHideReason int reason) {
+ public void hideMySoftInput(@NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
+ ImeTracker.forLogging().onFailed(statsToken,
+ ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
try {
final AndroidFuture<Void> future = new AndroidFuture<>();
- ops.hideMySoftInput(flags, reason, future);
+ ops.hideMySoftInput(statsToken, flags, reason, future);
CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -273,17 +274,21 @@
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, AndroidFuture)}
+ * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput}
*/
@AnyThread
- public void showMySoftInput(@InputMethodManager.ShowFlags int flags) {
+ public void showMySoftInput(@NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
+ ImeTracker.forLogging().onFailed(statsToken,
+ ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
try {
final AndroidFuture<Void> future = new AndroidFuture<>();
- ops.showMySoftInput(flags, future);
+ ops.showMySoftInput(statsToken, flags, reason, future);
CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -379,19 +384,19 @@
* {@link android.view.inputmethod.InputMethodManager#hideSoftInputFromWindow(IBinder,
* int)}
* @param setVisible {@code true} to set IME visible, else hidden.
- * @param statsToken the token tracking the current IME request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request.
*/
@AnyThread
public void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible,
- @Nullable ImeTracker.Token statsToken) {
+ @NonNull ImeTracker.Token statsToken) {
final IInputMethodPrivilegedOperations ops = mOps.getAndWarnIfNull();
if (ops == null) {
ImeTracker.forLogging().onFailed(statsToken,
- ImeTracker.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER);
+ ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
return;
}
ImeTracker.forLogging().onProgress(statsToken,
- ImeTracker.PHASE_IME_APPLY_VISIBILITY_INSETS_CONSUMER);
+ ImeTracker.PHASE_IME_PRIVILEGED_OPERATIONS);
try {
ops.applyImeVisibilityAsync(showOrHideInputToken, setVisible, statsToken);
} catch (RemoteException e) {
diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
index 861b8a7..da738a0 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -34,6 +34,7 @@
*/
@Retention(SOURCE)
@IntDef(value = {
+ SoftInputShowHideReason.NOT_SET,
SoftInputShowHideReason.SHOW_SOFT_INPUT,
SoftInputShowHideReason.ATTACH_NEW_INPUT,
SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME,
@@ -72,8 +73,26 @@
SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE,
SoftInputShowHideReason.HIDE_CLOSE_CURRENT_SESSION,
SoftInputShowHideReason.HIDE_SOFT_INPUT_FROM_VIEW,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_LEGACY_DIRECT,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_LEGACY_DIRECT,
+ SoftInputShowHideReason.SHOW_WINDOW_LEGACY_DIRECT,
+ SoftInputShowHideReason.HIDE_WINDOW_LEGACY_DIRECT,
+ SoftInputShowHideReason.RESET_NEW_CONFIGURATION,
+ SoftInputShowHideReason.UPDATE_CANDIDATES_VIEW_VISIBILITY,
+ SoftInputShowHideReason.CONTROLS_CHANGED,
+ SoftInputShowHideReason.DISPLAY_CONFIGURATION_CHANGED,
+ SoftInputShowHideReason.DISPLAY_INSETS_CHANGED,
+ SoftInputShowHideReason.DISPLAY_CONTROLS_CHANGED,
+ SoftInputShowHideReason.UNBIND_CURRENT_METHOD,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT,
+ SoftInputShowHideReason.SHOW_SOFT_INPUT_IMM_DEPRECATION,
})
public @interface SoftInputShowHideReason {
+ /** Default, undefined reason. */
+ int NOT_SET = ImeProtoEnums.REASON_NOT_SET;
+
/** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */
int SHOW_SOFT_INPUT = ImeProtoEnums.REASON_SHOW_SOFT_INPUT;
@@ -291,4 +310,91 @@
* Hide soft input when {@link InputMethodManager#hideSoftInputFromView(View, int)} gets called.
*/
int HIDE_SOFT_INPUT_FROM_VIEW = ImeProtoEnums.REASON_HIDE_SOFT_INPUT_FROM_VIEW;
+
+ /**
+ * Show soft input by legacy (discouraged) call to
+ * {@link android.inputmethodservice.InputMethodService.InputMethodImpl#showSoftInput}.
+ */
+ int SHOW_SOFT_INPUT_LEGACY_DIRECT = ImeProtoEnums.REASON_SHOW_SOFT_INPUT_LEGACY_DIRECT;
+
+ /**
+ * Hide soft input by legacy (discouraged) call to
+ * {@link android.inputmethodservice.InputMethodService.InputMethodImpl#hideSoftInput}.
+ */
+ int HIDE_SOFT_INPUT_LEGACY_DIRECT = ImeProtoEnums.REASON_HIDE_SOFT_INPUT_LEGACY_DIRECT;
+
+ /**
+ * Show soft input by legacy (discouraged) call to
+ * {@link android.inputmethodservice.InputMethodService#showWindow}.
+ */
+ int SHOW_WINDOW_LEGACY_DIRECT = ImeProtoEnums.REASON_SHOW_WINDOW_LEGACY_DIRECT;
+
+ /**
+ * Hide soft input by legacy (discouraged) call to
+ * {@link android.inputmethodservice.InputMethodService#hideWindow}.
+ */
+ int HIDE_WINDOW_LEGACY_DIRECT = ImeProtoEnums.REASON_HIDE_WINDOW_LEGACY_DIRECT;
+
+ /**
+ * Show / Hide soft input by
+ * {@link android.inputmethodservice.InputMethodService#resetStateForNewConfiguration}.
+ */
+ int RESET_NEW_CONFIGURATION = ImeProtoEnums.REASON_RESET_NEW_CONFIGURATION;
+
+ /**
+ * Show / Hide soft input by
+ * {@link android.inputmethodservice.InputMethodService#updateCandidatesVisibility}.
+ */
+ int UPDATE_CANDIDATES_VIEW_VISIBILITY = ImeProtoEnums.REASON_UPDATE_CANDIDATES_VIEW_VISIBILITY;
+
+ /**
+ * Show / Hide soft input by {@link android.view.InsetsController#onControlsChanged}.
+ */
+ int CONTROLS_CHANGED = ImeProtoEnums.REASON_CONTROLS_CHANGED;
+
+ /**
+ * Show soft input by
+ * {@link com.android.wm.shell.common.DisplayImeController#onDisplayConfigurationChanged}.
+ */
+ int DISPLAY_CONFIGURATION_CHANGED = ImeProtoEnums.REASON_DISPLAY_CONFIGURATION_CHANGED;
+
+ /**
+ * Show soft input by
+ * {@link com.android.wm.shell.common.DisplayImeController.PerDisplay#insetsChanged}.
+ */
+ int DISPLAY_INSETS_CHANGED = ImeProtoEnums.REASON_DISPLAY_INSETS_CHANGED;
+
+ /**
+ * Show / Hide soft input by
+ * {@link com.android.wm.shell.common.DisplayImeController.PerDisplay#insetsControlChanged}.
+ */
+ int DISPLAY_CONTROLS_CHANGED = ImeProtoEnums.REASON_DISPLAY_CONTROLS_CHANGED;
+
+ /** Hide soft input by
+ * {@link com.android.server.inputmethod.InputMethodManagerService#onUnbindCurrentMethodByReset}.
+ */
+ int UNBIND_CURRENT_METHOD = ImeProtoEnums.REASON_UNBIND_CURRENT_METHOD;
+
+ /** Hide soft input by {@link android.view.ImeInsetsSourceConsumer#onAnimationStateChanged}. */
+ int HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED =
+ ImeProtoEnums.REASON_HIDE_SOFT_INPUT_ON_ANIMATION_STATE_CHANGED;
+
+ /** Hide soft input when we already have a {@link android.view.InsetsSourceControl} by
+ * {@link android.view.ImeInsetsSourceConsumer#requestHide}.
+ */
+ int HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL =
+ ImeProtoEnums.REASON_HIDE_SOFT_INPUT_REQUEST_HIDE_WITH_CONTROL;
+
+ /**
+ * Show soft input by
+ * {@link android.inputmethodservice.InputMethodService#onToggleSoftInput(int, int)}.
+ */
+ int SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT =
+ ImeProtoEnums.REASON_SHOW_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT;
+
+ /**
+ * Show soft input by the deprecated
+ * {@link InputMethodManager#showSoftInputFromInputMethod(IBinder, int)}.
+ */
+ int SHOW_SOFT_INPUT_IMM_DEPRECATION = ImeProtoEnums.REASON_SHOW_SOFT_INPUT_IMM_DEPRECATION;
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 1f4503a..dc3b5a8 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -65,12 +65,21 @@
InputMethodSubtype getLastInputMethodSubtype(int userId);
boolean showSoftInput(in IInputMethodClient client, @nullable IBinder windowToken,
- in @nullable ImeTracker.Token statsToken, int flags, int lastClickToolType,
+ in ImeTracker.Token statsToken, int flags, int lastClickToolType,
in @nullable ResultReceiver resultReceiver, int reason);
boolean hideSoftInput(in IInputMethodClient client, @nullable IBinder windowToken,
- in @nullable ImeTracker.Token statsToken, int flags,
+ in ImeTracker.Token statsToken, int flags,
in @nullable ResultReceiver resultReceiver, int reason);
+ /**
+ * A test API for CTS to request hiding the current soft input window, with the request origin
+ * on the server side.
+ */
+ @EnforcePermission("TEST_INPUT_METHOD")
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+ + "android.Manifest.permission.TEST_INPUT_METHOD)")
+ void hideSoftInputFromServerForTest();
+
// TODO(b/293640003): Remove method once Flags.useZeroJankProxy() is enabled.
// If windowToken is null, this just does startInput(). Otherwise this reports that a window
// has gained focus, and if 'editorInfo' is non-null then also does startInput.
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index 8c93fbb..48ba526 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -24,8 +24,10 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.AdditionalMatchers.and;
+import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -36,6 +38,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.WindowManager.BadTokenException;
import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.ImeTracker;
import android.widget.TextView;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -96,12 +99,12 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
// test if setVisibility can show IME
mImeConsumer.onWindowFocusGained(true);
- mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(WindowInsets.Type.ime(), true /* fromIme */, ImeTracker.Token.empty());
mController.cancelExistingAnimations();
assertTrue((mController.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
// test if setVisibility can hide IME
- mController.hide(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+ mController.hide(WindowInsets.Type.ime(), true /* fromIme */, ImeTracker.Token.empty());
mController.cancelExistingAnimations();
assertFalse((mController.getRequestedVisibleTypes() & WindowInsets.Type.ime()) != 0);
});
@@ -114,8 +117,9 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
// Request IME visible before control is available.
+ final var statsToken = ImeTracker.Token.empty();
mImeConsumer.onWindowFocusGained(true);
- mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsToken);
// set control and verify visibility is applied.
InsetsSourceControl control = new InsetsSourceControl(ID_IME,
@@ -124,10 +128,10 @@
// IME show animation should be triggered when control becomes available.
verify(mController).applyAnimation(
eq(WindowInsets.Type.ime()), eq(true) /* show */, eq(true) /* fromIme */,
- any() /* statsToken */);
+ eq(statsToken));
verify(mController, never()).applyAnimation(
eq(WindowInsets.Type.ime()), eq(false) /* show */, eq(true) /* fromIme */,
- any() /* statsToken */);
+ eq(statsToken));
});
}
@@ -152,9 +156,9 @@
// Request IME visible before control is available.
mImeConsumer.onWindowFocusGained(hasWindowFocus);
final boolean imeVisible = hasWindowFocus && hasViewFocus;
+ final var statsToken = ImeTracker.Token.empty();
if (imeVisible) {
- mController.show(WindowInsets.Type.ime(), true /* fromIme */,
- null /* statsToken */);
+ mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsToken);
}
// set control and verify visibility is applied.
@@ -168,23 +172,25 @@
// and expect skip animation state after getAndClearSkipAnimationOnce invoked.
mController.onControlsChanged(new InsetsSourceControl[]{ control });
verify(control).getAndClearSkipAnimationOnce();
+ // This ends up creating a new request when we gain control,
+ // so the statsToken won't match.
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(false) /* fromIme */,
- eq(expectSkipAnim) /* skipAnim */, eq(null) /* statsToken */);
+ eq(expectSkipAnim) /* skipAnim */, and(not(eq(statsToken)), notNull()));
}
// If previously hasViewFocus is false, verify when requesting the IME visible next
// time will not skip animation.
if (!hasViewFocus) {
- mController.show(WindowInsets.Type.ime(), true /* fromIme */,
- null /* statsToken */);
+ final var statsTokenNext = ImeTracker.Token.empty();
+ mController.show(WindowInsets.Type.ime(), true /* fromIme */, statsTokenNext);
mController.onControlsChanged(new InsetsSourceControl[]{ control });
// Verify IME show animation should be triggered when control becomes available and
// the animation will be skipped by getAndClearSkipAnimationOnce invoked.
verify(control).getAndClearSkipAnimationOnce();
verify(mController).applyAnimation(eq(WindowInsets.Type.ime()),
eq(true) /* show */, eq(true) /* fromIme */,
- eq(false) /* skipAnim */, eq(null) /* statsToken */);
+ eq(false) /* skipAnim */, eq(statsTokenNext));
}
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 1568174..316e191 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -256,7 +256,7 @@
mController.setSystemDrivenInsetsAnimationLoggingListener(loggingListener);
mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
// since there is no focused view, forcefully make IME visible.
- mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
// When using the animation thread, this must not invoke onReady()
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
});
@@ -273,14 +273,14 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
// since there is no focused view, forcefully make IME visible.
- mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
mController.show(all());
// quickly jump to final state by cancelling it.
mController.cancelExistingAnimations();
- final @InsetsType int types = navigationBars() | statusBars() | ime();
+ @InsetsType final int types = navigationBars() | statusBars() | ime();
assertEquals(types, mController.getRequestedVisibleTypes() & types);
- mController.hide(ime(), true /* fromIme */, null /* statsToken */);
+ mController.hide(ime(), true /* fromIme */, ImeTracker.Token.empty());
mController.hide(all());
mController.cancelExistingAnimations();
assertEquals(0, mController.getRequestedVisibleTypes() & types);
@@ -295,10 +295,10 @@
mController.onControlsChanged(new InsetsSourceControl[] { ime });
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
- mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
mController.cancelExistingAnimations();
assertTrue(isRequestedVisible(mController, ime()));
- mController.hide(ime(), true /* fromIme */, null /* statsToken */);
+ mController.hide(ime(), true /* fromIme */, ImeTracker.Token.empty());
mController.cancelExistingAnimations();
assertFalse(isRequestedVisible(mController, ime()));
mController.getSourceConsumer(ID_IME, ime()).onWindowFocusLost();
@@ -465,7 +465,7 @@
assertFalse(mController.getState().peekSource(ID_IME).isVisible());
// Pretend IME is calling
- mController.show(ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
// Gaining control shortly after
mController.onControlsChanged(createSingletonControl(ID_IME, ime()));
@@ -489,7 +489,7 @@
mController.onControlsChanged(createSingletonControl(ID_IME, ime()));
// Pretend IME is calling
- mController.show(ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ime()));
mController.cancelExistingAnimations();
@@ -567,7 +567,7 @@
verify(listener, never()).onReady(any(), anyInt());
// Pretend that IME is calling.
- mController.show(ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -651,7 +651,7 @@
mController.onControlsChanged(createSingletonControl(ID_IME, ime()));
// Pretend IME is calling
- mController.show(ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
InsetsState copy = new InsetsState(mController.getState(), true /* copySources */);
copy.peekSource(ID_IME).setFrame(0, 1, 2, 3);
@@ -851,7 +851,7 @@
// Showing invisible ime should only causes insets change once.
clearInvocations(mTestHost);
- mController.show(ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
verify(mTestHost, times(1)).notifyInsetsChanged();
// Sending the same insets state should not cause insets change.
@@ -918,7 +918,7 @@
assertNull(imeInsetsConsumer.getControl());
// Verify IME requested visibility should be updated to IME consumer from controller.
- mController.show(ime(), true /* fromIme */, null /* statsToken */);
+ mController.show(ime(), true /* fromIme */, ImeTracker.Token.empty());
assertTrue(isRequestedVisible(mController, ime()));
mController.hide(ime());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 2ea4316..ad01d0f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -20,12 +20,12 @@
import static android.view.EventLogTags.IMF_IME_REMOTE_ANIM_END;
import static android.view.EventLogTags.IMF_IME_REMOTE_ANIM_START;
import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
-import static android.view.inputmethod.ImeTracker.TOKEN_NONE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.res.Configuration;
@@ -51,6 +51,7 @@
import androidx.annotation.VisibleForTesting;
+import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.wm.shell.sysui.ShellInit;
import java.util.ArrayList;
@@ -122,7 +123,8 @@
}
if (mDisplayController.getDisplayLayout(displayId).rotation()
!= pd.mRotation && isImeShowing(displayId)) {
- pd.startAnimation(true, false /* forceRestart */, null /* statsToken */);
+ pd.startAnimation(true, false /* forceRestart */,
+ SoftInputShowHideReason.DISPLAY_CONFIGURATION_CHANGED);
}
}
@@ -257,7 +259,8 @@
mInsetsState.set(insetsState, true /* copySources */);
if (mImeShowing && !Objects.equals(oldFrame, newFrame) && newSourceVisible) {
if (DEBUG) Slog.d(TAG, "insetsChanged when IME showing, restart animation");
- startAnimation(mImeShowing, true /* forceRestart */, null /* statsToken */);
+ startAnimation(mImeShowing, true /* forceRestart */,
+ SoftInputShowHideReason.DISPLAY_INSETS_CHANGED);
}
}
@@ -291,7 +294,8 @@
final boolean positionChanged =
!imeSourceControl.getSurfacePosition().equals(lastSurfacePosition);
if (positionChanged) {
- startAnimation(mImeShowing, true /* forceRestart */, null /* statsToken */);
+ startAnimation(mImeShowing, true /* forceRestart */,
+ SoftInputShowHideReason.DISPLAY_CONTROLS_CHANGED);
}
} else {
if (!haveSameLeash(mImeSourceControl, imeSourceControl)) {
@@ -384,7 +388,20 @@
}
private void startAnimation(final boolean show, final boolean forceRestart,
- @Nullable ImeTracker.Token statsToken) {
+ @SoftInputShowHideReason int reason) {
+ final var imeSource = mInsetsState.peekSource(InsetsSource.ID_IME);
+ if (imeSource == null || mImeSourceControl == null) {
+ return;
+ }
+ final var statsToken = ImeTracker.forLogging().onStart(
+ show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_WM_SHELL,
+ reason, false /* fromUser */);
+
+ startAnimation(show, forceRestart, statsToken);
+ }
+
+ private void startAnimation(final boolean show, final boolean forceRestart,
+ @NonNull final ImeTracker.Token statsToken) {
final InsetsSource imeSource = mInsetsState.peekSource(InsetsSource.ID_IME);
if (imeSource == null || mImeSourceControl == null) {
ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
@@ -458,7 +475,7 @@
ImeTracker.forLogging().onProgress(statsToken, ImeTracker.PHASE_WM_ANIMATION_CREATE);
mAnimation.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled = false;
- @Nullable
+ @NonNull
private final ImeTracker.Token mStatsToken = statsToken;
@Override
@@ -484,7 +501,7 @@
}
if (DEBUG_IME_VISIBILITY) {
EventLog.writeEvent(IMF_IME_REMOTE_ANIM_START,
- statsToken != null ? statsToken.getTag() : TOKEN_NONE,
+ mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
mDisplayId, mAnimationDirection, alpha, startY , endY,
Objects.toString(mImeSourceControl.getLeash()),
Objects.toString(mImeSourceControl.getInsetsHint()),
@@ -500,7 +517,8 @@
mCancelled = true;
if (DEBUG_IME_VISIBILITY) {
EventLog.writeEvent(IMF_IME_REMOTE_ANIM_CANCEL,
- statsToken != null ? statsToken.getTag() : TOKEN_NONE, mDisplayId,
+ mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
+ mDisplayId,
Objects.toString(mImeSourceControl.getInsetsHint()));
}
}
@@ -528,7 +546,7 @@
}
if (DEBUG_IME_VISIBILITY) {
EventLog.writeEvent(IMF_IME_REMOTE_ANIM_END,
- statsToken != null ? statsToken.getTag() : TOKEN_NONE,
+ mStatsToken != null ? mStatsToken.getTag() : ImeTracker.TOKEN_NONE,
mDisplayId, mAnimationDirection, endY,
Objects.toString(mImeSourceControl.getLeash()),
Objects.toString(mImeSourceControl.getInsetsHint()),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
index 9bdda14..ca06024 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -277,8 +277,7 @@
*
* @param types {@link InsetsType} to show
* @param fromIme true if this request originated from IME (InputMethodService).
- * @param statsToken the token tracking the current IME show request
- * or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*/
default void showInsets(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {}
@@ -288,8 +287,7 @@
*
* @param types {@link InsetsType} to hide
* @param fromIme true if this request originated from IME (InputMethodService).
- * @param statsToken the token tracking the current IME hide request
- * or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*/
default void hideInsets(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
index 01e2f98..2c0aa12 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayImeControllerTest.java
@@ -38,6 +38,7 @@
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.SurfaceControl;
+import android.view.inputmethod.ImeTracker;
import androidx.test.filters.SmallTest;
@@ -51,6 +52,12 @@
import java.util.concurrent.Executor;
+/**
+ * Tests for the display IME controller.
+ *
+ * <p> Build/Install/Run:
+ * atest WMShellUnitTests:DisplayImeControllerTest
+ */
@SmallTest
public class DisplayImeControllerTest extends ShellTestCase {
@@ -99,13 +106,13 @@
@Test
public void showInsets_schedulesNoWorkOnExecutor() {
- mPerDisplay.showInsets(ime(), true /* fromIme */, null /* statsToken */);
+ mPerDisplay.showInsets(ime(), true /* fromIme */, ImeTracker.Token.empty());
verifyZeroInteractions(mExecutor);
}
@Test
public void hideInsets_schedulesNoWorkOnExecutor() {
- mPerDisplay.hideInsets(ime(), true /* fromIme */, null /* statsToken */);
+ mPerDisplay.hideInsets(ime(), true /* fromIme */, ImeTracker.Token.empty());
verifyZeroInteractions(mExecutor);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
index 956f1cd..669e433 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/DisplayInsetsControllerTest.java
@@ -50,6 +50,12 @@
import java.util.List;
+/**
+ * Tests for the display insets controller.
+ *
+ * <p> Build/Install/Run:
+ * atest WMShellUnitTests:DisplayInsetsControllerTest
+ */
@SmallTest
public class DisplayInsetsControllerTest extends ShellTestCase {
@@ -114,9 +120,9 @@
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsChanged(null);
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).insetsControlChanged(null, null);
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).showInsets(0, false,
- null /* statsToken */);
+ ImeTracker.Token.empty());
mInsetsControllersByDisplayId.get(DEFAULT_DISPLAY).hideInsets(0, false,
- null /* statsToken */);
+ ImeTracker.Token.empty());
mExecutor.flushAll();
assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
@@ -136,9 +142,9 @@
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsChanged(null);
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).insetsControlChanged(null, null);
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).showInsets(0, false,
- null /* statsToken */);
+ ImeTracker.Token.empty());
mInsetsControllersByDisplayId.get(SECOND_DISPLAY).hideInsets(0, false,
- null /* statsToken */);
+ ImeTracker.Token.empty());
mExecutor.flushAll();
assertTrue(defaultListener.topFocusedWindowChangedCount == 1);
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
index 02afc54..7966a86 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -34,9 +34,9 @@
private const val passwordCharacterLength = 15
fun createDropdownPresentation(
- context: Context,
- icon: Icon,
- credentialEntryInfo: CredentialEntryInfo
+ context: Context,
+ icon: Icon,
+ credentialEntryInfo: CredentialEntryInfo
): RemoteViews {
var layoutId: Int = com.android.credentialmanager.R.layout
.credman_dropdown_presentation_layout
@@ -45,41 +45,37 @@
return remoteViews
}
setRemoteViewsPaddings(remoteViews, context, /* primaryTextBottomPadding=*/0)
- if (credentialEntryInfo.credentialType == CredentialType.PASSKEY) {
- val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName
- remoteViews.setTextViewText(android.R.id.text1, displayName)
- val secondaryText = if (credentialEntryInfo.displayName != null)
+ val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName
+ remoteViews.setTextViewText(android.R.id.text1, displayName)
+ val secondaryText =
+ if (credentialEntryInfo.displayName != null
+ && (credentialEntryInfo.displayName != credentialEntryInfo.userName))
(credentialEntryInfo.userName + " " + bulletPoint + " "
+ credentialEntryInfo.credentialTypeDisplayName
+ " " + bulletPoint + " " + credentialEntryInfo.providerDisplayName)
else (credentialEntryInfo.credentialTypeDisplayName + " " + bulletPoint + " "
+ credentialEntryInfo.providerDisplayName)
- remoteViews.setTextViewText(android.R.id.text2, secondaryText)
- } else {
- remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName)
- remoteViews.setTextViewText(android.R.id.text2,
- bulletPoint.repeat(passwordCharacterLength))
- }
+ remoteViews.setTextViewText(android.R.id.text2, secondaryText)
val textColorPrimary = ContextCompat.getColor(context,
- com.android.credentialmanager.R.color.text_primary)
+ com.android.credentialmanager.R.color.text_primary)
remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
val textColorSecondary = ContextCompat.getColor(context, com.android
.credentialmanager.R.color.text_secondary)
remoteViews.setTextColor(android.R.id.text2, textColorSecondary)
remoteViews.setImageViewIcon(android.R.id.icon1, icon);
remoteViews.setBoolean(
- android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+ android.R.id.icon1, setAdjustViewBoundsMethodName, true);
remoteViews.setInt(
- android.R.id.icon1,
- setMaxHeightMethodName,
- context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_icon_size));
+ android.R.id.icon1,
+ setMaxHeightMethodName,
+ context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_icon_size));
remoteViews.setContentDescription(android.R.id.icon1, credentialEntryInfo
.providerDisplayName);
val drawableId =
- com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
+ com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
remoteViews.setInt(
- android.R.id.content, setBackgroundResourceMethodName, drawableId);
+ android.R.id.content, setBackgroundResourceMethodName, drawableId);
return remoteViews
}
@@ -89,68 +85,68 @@
val remoteViews = RemoteViews(context.packageName, layoutId)
setRemoteViewsPaddings(remoteViews, context)
remoteViews.setTextViewText(android.R.id.text1, ContextCompat.getString(context,
- com.android.credentialmanager
- .R.string.dropdown_presentation_more_sign_in_options_text))
+ com.android.credentialmanager
+ .R.string.dropdown_presentation_more_sign_in_options_text))
val textColorPrimary = ContextCompat.getColor(context,
- com.android.credentialmanager.R.color.text_primary)
+ com.android.credentialmanager.R.color.text_primary)
remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
val icon = Icon.createWithResource(context, com
.android.credentialmanager.R.drawable.more_horiz_24px)
icon.setTint(ContextCompat.getColor(context,
- com.android.credentialmanager.R.color.sign_in_options_icon_color))
+ com.android.credentialmanager.R.color.sign_in_options_icon_color))
remoteViews.setImageViewIcon(android.R.id.icon1, icon)
remoteViews.setBoolean(
- android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+ android.R.id.icon1, setAdjustViewBoundsMethodName, true);
remoteViews.setInt(
- android.R.id.icon1,
- setMaxHeightMethodName,
- context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_icon_size));
+ android.R.id.icon1,
+ setMaxHeightMethodName,
+ context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_icon_size));
val drawableId =
- com.android.credentialmanager.R.drawable.more_options_list_item
+ com.android.credentialmanager.R.drawable.more_options_list_item
remoteViews.setInt(
- android.R.id.content, setBackgroundResourceMethodName, drawableId);
+ android.R.id.content, setBackgroundResourceMethodName, drawableId);
return remoteViews
}
private fun setRemoteViewsPaddings(
- remoteViews: RemoteViews, context: Context) {
+ remoteViews: RemoteViews, context: Context) {
val bottomPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
+ com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
setRemoteViewsPaddings(remoteViews, context, bottomPadding)
}
private fun setRemoteViewsPaddings(
- remoteViews: RemoteViews, context: Context, primaryTextBottomPadding: Int) {
+ remoteViews: RemoteViews, context: Context, primaryTextBottomPadding: Int) {
val leftPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_left_padding)
+ com.android.credentialmanager.R.dimen.autofill_view_left_padding)
val iconToTextPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding)
+ com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding)
val rightPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_right_padding)
+ com.android.credentialmanager.R.dimen.autofill_view_right_padding)
val topPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_top_padding)
+ com.android.credentialmanager.R.dimen.autofill_view_top_padding)
val bottomPadding = context.resources.getDimensionPixelSize(
- com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
+ com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
remoteViews.setViewPadding(
- android.R.id.icon1,
- leftPadding,
- /* top=*/0,
- /* right=*/0,
- /* bottom=*/0)
+ android.R.id.icon1,
+ leftPadding,
+ /* top=*/0,
+ /* right=*/0,
+ /* bottom=*/0)
remoteViews.setViewPadding(
- android.R.id.text1,
- iconToTextPadding,
- /* top=*/topPadding,
- /* right=*/rightPadding,
- primaryTextBottomPadding)
+ android.R.id.text1,
+ iconToTextPadding,
+ /* top=*/topPadding,
+ /* right=*/rightPadding,
+ primaryTextBottomPadding)
remoteViews.setViewPadding(
- android.R.id.text2,
- iconToTextPadding,
- /* top=*/0,
- /* right=*/rightPadding,
- /* bottom=*/bottomPadding)
+ android.R.id.text2,
+ iconToTextPadding,
+ /* top=*/0,
+ /* right=*/rightPadding,
+ /* bottom=*/bottomPadding)
}
private fun isDarkMode(context: Context): Boolean {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 61c3ce7..c2c82b3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1764,40 +1764,4 @@
boolean getUnpairing() {
return mUnpairing;
}
-
- ListenableFuture<Void> syncProfileForMemberDevice() {
- return ThreadUtils.getBackgroundExecutor()
- .submit(
- () -> {
- List<Pair<LocalBluetoothProfile, Boolean>> toSync =
- Stream.of(
- mProfileManager.getA2dpProfile(),
- mProfileManager.getHeadsetProfile(),
- mProfileManager.getHearingAidProfile(),
- mProfileManager.getLeAudioProfile(),
- mProfileManager.getLeAudioBroadcastAssistantProfile())
- .filter(Objects::nonNull)
- .map(profile -> new Pair<>(profile, profile.isEnabled(mDevice)))
- .toList();
-
- for (var t : toSync) {
- LocalBluetoothProfile profile = t.first;
- boolean enabledForMain = t.second;
-
- for (var member : mMemberDevices) {
- BluetoothDevice btDevice = member.getDevice();
-
- if (enabledForMain != profile.isEnabled(btDevice)) {
- Log.d(TAG, "Syncing profile " + profile + " to "
- + enabledForMain + " for member device "
- + btDevice.getAnonymizedAddress() + " of main device "
- + mDevice.getAnonymizedAddress());
- profile.setEnabled(btDevice, enabledForMain);
- }
- }
- }
- return null;
- }
- );
- }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 32eec7e..4e52c77 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -363,7 +363,6 @@
if (profileId == BluetoothProfile.HEADSET
|| profileId == BluetoothProfile.A2DP
|| profileId == BluetoothProfile.LE_AUDIO
- || profileId == BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT
|| profileId == BluetoothProfile.CSIP_SET_COORDINATOR) {
return mCsipDeviceManager.onProfileConnectionStateChangedIfProcessed(cachedDevice,
state);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index e67ec48..a49314a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -379,7 +379,6 @@
if (hasChanged) {
log("addMemberDevicesIntoMainDevice: After changed, CachedBluetoothDevice list: "
+ mCachedDevices);
- preferredMainDevice.syncProfileForMemberDevice();
}
return hasChanged;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index ca47efd..1069b71 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -346,11 +346,15 @@
} else {
long hiSyncId = asha.getHiSyncId(cachedDevice.getDevice());
if (isValidHiSyncId(hiSyncId)) {
- final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+ final HearingAidInfo info = new HearingAidInfo.Builder()
.setAshaDeviceSide(asha.getDeviceSide(cachedDevice.getDevice()))
.setAshaDeviceMode(asha.getDeviceMode(cachedDevice.getDevice()))
- .setHiSyncId(hiSyncId);
- return infoBuilder.build();
+ .setHiSyncId(hiSyncId)
+ .build();
+ if (DEBUG) {
+ Log.d(TAG, "generateHearingAidInfo, " + cachedDevice + ", info=" + info);
+ }
+ return info;
}
}
@@ -358,15 +362,20 @@
final LeAudioProfile leAudioProfile = profileManager.getLeAudioProfile();
if (hapClientProfile == null || leAudioProfile == null) {
Log.w(TAG, "HapClientProfile or LeAudioProfile is not supported on this device");
- } else {
+ } else if (cachedDevice.getProfiles().stream().anyMatch(
+ p -> p instanceof HapClientProfile)) {
int audioLocation = leAudioProfile.getAudioLocation(cachedDevice.getDevice());
int hearingAidType = hapClientProfile.getHearingAidType(cachedDevice.getDevice());
if (audioLocation != BluetoothLeAudio.AUDIO_LOCATION_INVALID
&& hearingAidType != HapClientProfile.HearingAidType.TYPE_INVALID) {
- final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+ final HearingAidInfo info = new HearingAidInfo.Builder()
.setLeAudioLocation(audioLocation)
- .setHapDeviceType(hearingAidType);
- return infoBuilder.build();
+ .setHapDeviceType(hearingAidType)
+ .build();
+ if (DEBUG) {
+ Log.d(TAG, "generateHearingAidInfo, " + cachedDevice + ", info=" + info);
+ }
+ return info;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
index 7d614f0..65b73ca 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt
@@ -15,6 +15,7 @@
*/
package com.android.settingslib.wifi
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
@@ -22,14 +23,23 @@
import android.net.wifi.ScanResult
import android.net.wifi.WifiConfiguration
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus
+import android.net.wifi.WifiManager
import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo
import android.os.Bundle
import android.os.SystemClock
import android.util.Log
import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
import com.android.settingslib.R
import com.android.settingslib.flags.Flags.newStatusBarIcons
import java.util.Locale
+import kotlin.coroutines.resume
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
open class WifiUtils {
@@ -146,7 +156,6 @@
}
}
-
@JvmStatic
fun buildLoggingSummary(accessPoint: AccessPoint, config: WifiConfiguration?): String {
val summary = StringBuilder()
@@ -458,5 +467,40 @@
arguments["count"] = connectedDevices
return msgFormat.format(arguments)
}
+
+ @JvmStatic
+ fun checkWepAllowed(
+ context: Context,
+ lifecycleOwner: LifecycleOwner,
+ ssid: String,
+ onAllowed: () -> Unit,
+ ) {
+ lifecycleOwner.lifecycleScope.launch {
+ val wifiManager = context.getSystemService(WifiManager::class.java) ?: return@launch
+ if (wifiManager.queryWepAllowed()) {
+ onAllowed()
+ } else {
+ val intent = Intent(Intent.ACTION_MAIN).apply {
+ component = ComponentName(
+ "com.android.settings",
+ "com.android.settings.network.WepNetworkDialogActivity"
+ )
+ putExtra(SSID, ssid)
+ }
+ context.startActivity(intent)
+ }
+ }
+ }
+
+ private suspend fun WifiManager.queryWepAllowed(): Boolean =
+ withContext(Dispatchers.Default) {
+ suspendCancellableCoroutine { continuation ->
+ queryWepAllowed(Dispatchers.Default.asExecutor()) {
+ continuation.resume(it)
+ }
+ }
+ }
+
+ const val SSID = "ssid"
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 461ecf5d..5996dbb 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -18,9 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -58,8 +56,6 @@
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
-import java.util.concurrent.ExecutionException;
-
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class})
public class CachedBluetoothDeviceTest {
@@ -1823,52 +1819,6 @@
assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
}
- @Test
- public void syncProfileForMemberDevice_hasDiff_shouldSync()
- throws ExecutionException, InterruptedException {
- mCachedDevice.addMemberDevice(mSubCachedDevice);
- when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
- when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
- when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
-
- when(mA2dpProfile.isEnabled(mDevice)).thenReturn(true);
- when(mHearingAidProfile.isEnabled(mDevice)).thenReturn(true);
- when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
-
- when(mA2dpProfile.isEnabled(mSubDevice)).thenReturn(true);
- when(mHearingAidProfile.isEnabled(mSubDevice)).thenReturn(false);
- when(mLeAudioProfile.isEnabled(mSubDevice)).thenReturn(false);
-
- mCachedDevice.syncProfileForMemberDevice().get();
-
- verify(mA2dpProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
- verify(mHearingAidProfile).setEnabled(any(BluetoothDevice.class), eq(true));
- verify(mLeAudioProfile).setEnabled(any(BluetoothDevice.class), eq(true));
- }
-
- @Test
- public void syncProfileForMemberDevice_noDiff_shouldNotSync()
- throws ExecutionException, InterruptedException {
- mCachedDevice.addMemberDevice(mSubCachedDevice);
- when(mProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
- when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
- when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
-
- when(mA2dpProfile.isEnabled(mDevice)).thenReturn(false);
- when(mHearingAidProfile.isEnabled(mDevice)).thenReturn(false);
- when(mLeAudioProfile.isEnabled(mDevice)).thenReturn(true);
-
- when(mA2dpProfile.isEnabled(mSubDevice)).thenReturn(false);
- when(mHearingAidProfile.isEnabled(mSubDevice)).thenReturn(false);
- when(mLeAudioProfile.isEnabled(mSubDevice)).thenReturn(true);
-
- mCachedDevice.syncProfileForMemberDevice().get();
-
- verify(mA2dpProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
- verify(mHearingAidProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
- verify(mLeAudioProfile, never()).setEnabled(any(BluetoothDevice.class), anyBoolean());
- }
-
private HearingAidInfo getLeftAshaHearingAidInfo() {
return new HearingAidInfo.Builder()
.setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
index 4c972e9..a3371d3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModelTest.kt
@@ -42,6 +42,25 @@
val underTest = kosmos.aodToGoneTransitionViewModel
@Test
+ fun lockscreenAlpha() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor(alpha = { 0.5f })
+ val alpha by collectValues(underTest.lockscreenAlpha(viewState))
+
+ repository.sendTransitionSteps(
+ from = KeyguardState.AOD,
+ to = KeyguardState.GONE,
+ testScope
+ )
+
+ assertThat(alpha[0]).isEqualTo(0.5f)
+ // Fades out just prior to halfway
+ assertThat(alpha[1]).isEqualTo(0f)
+ // Must finish at 0
+ assertThat(alpha[2]).isEqualTo(0f)
+ }
+
+ @Test
fun deviceEntryParentViewHides() =
testScope.runTest {
val deviceEntryParentViewAlpha by collectValues(underTest.deviceEntryParentViewAlpha)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt
index 7e937db..79671b8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt
@@ -51,6 +51,25 @@
}
@Test
+ fun lockscreenAlpha() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor(alpha = { 0.6f })
+ val alpha by collectValues(underTest.lockscreenAlpha(viewState))
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.DOZING,
+ to = KeyguardState.GONE,
+ testScope
+ )
+
+ assertThat(alpha[0]).isEqualTo(0.6f)
+ // Fades out just prior to halfway
+ assertThat(alpha[1]).isEqualTo(0f)
+ // Must finish at 0
+ assertThat(alpha[2]).isEqualTo(0f)
+ }
+
+ @Test
fun deviceEntryParentViewDisappear() =
testScope.runTest {
val values by collectValues(underTest.deviceEntryParentViewAlpha)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index deff313..979d504 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -328,4 +328,42 @@
shadeRepository.setQsExpansion(0.5f)
assertThat(alpha).isEqualTo(0f)
}
+
+ @Test
+ fun alpha_idleOnOccluded_isZero() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha(viewState))
+ assertThat(alpha).isEqualTo(1f)
+
+ // Go to OCCLUDED state
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.OCCLUDED,
+ testScope = testScope,
+ )
+ assertThat(alpha).isEqualTo(0f)
+
+ // Try pulling down shade and ensure the value doesn't change
+ shadeRepository.setQsExpansion(0.5f)
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun alpha_idleOnGone_isZero() =
+ testScope.runTest {
+ val alpha by collectLastValue(underTest.alpha(viewState))
+ assertThat(alpha).isEqualTo(1f)
+
+ // Go to GONE state
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ testScope = testScope,
+ )
+ assertThat(alpha).isEqualTo(0f)
+
+ // Try pulling down shade and ensure the value doesn't change
+ shadeRepository.setQsExpansion(0.5f)
+ assertThat(alpha).isEqualTo(0f)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
index c01f1c7..8aa0e3fc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ActivityStarterImplTest.kt
@@ -35,10 +35,10 @@
import com.android.systemui.plugins.ActivityStarter.OnDismissAction
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeController
-import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.shade.data.repository.ShadeAnimationRepository
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -76,7 +76,7 @@
@Mock private lateinit var biometricUnlockController: BiometricUnlockController
@Mock private lateinit var keyguardViewMediator: KeyguardViewMediator
@Mock private lateinit var shadeController: ShadeController
- @Mock private lateinit var shadeViewController: ShadeViewController
+ @Mock private lateinit var commandQueue: CommandQueue
@Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
@Mock private lateinit var mActivityTransitionAnimator: ActivityTransitionAnimator
@Mock private lateinit var lockScreenUserManager: NotificationLockscreenUserManager
@@ -105,7 +105,7 @@
Lazy { biometricUnlockController },
Lazy { keyguardViewMediator },
Lazy { shadeController },
- Lazy { shadeViewController },
+ commandQueue,
shadeAnimationInteractor,
Lazy { statusBarKeyguardViewManager },
Lazy { notifShadeWindowController },
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index e0b5c0e..617982f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -27,12 +27,14 @@
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
+import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
@SysUISingleton
@@ -45,6 +47,7 @@
@Background bgDispatcher: CoroutineDispatcher,
@Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
+ private val powerInteractor: PowerInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.AOD,
@@ -68,15 +71,16 @@
*/
private fun listenForAodToOccluded() {
scope.launch {
- keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect {
- (isOccluded, startedKeyguardState) ->
- if (isOccluded && startedKeyguardState == KeyguardState.AOD) {
- startTransitionTo(
- toState = KeyguardState.OCCLUDED,
- modeOnCanceled = TransitionModeOnCanceled.RESET
- )
+ keyguardInteractor.isKeyguardOccluded
+ .sample(startedKeyguardTransitionStep, ::Pair)
+ .collect { (isOccluded, lastStartedStep) ->
+ if (isOccluded && lastStartedStep.to == KeyguardState.AOD) {
+ startTransitionTo(
+ toState = KeyguardState.OCCLUDED,
+ modeOnCanceled = TransitionModeOnCanceled.RESET
+ )
+ }
}
- }
}
}
@@ -85,15 +89,18 @@
keyguardInteractor
.dozeTransitionTo(DozeStateModel.FINISH)
.sample(
+ keyguardInteractor.isKeyguardShowing,
startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
keyguardInteractor.biometricUnlockState,
)
- .collect { (_, lastStartedStep, occluded, biometricUnlockState) ->
+ .collect { (_, isKeyguardShowing, lastStartedStep, occluded, biometricUnlockState)
+ ->
if (
lastStartedStep.to == KeyguardState.AOD &&
!occluded &&
- !isWakeAndUnlock(biometricUnlockState)
+ !isWakeAndUnlock(biometricUnlockState) &&
+ isKeyguardShowing
) {
val modeOnCanceled =
if (lastStartedStep.from == KeyguardState.LOCKSCREEN) {
@@ -134,13 +141,31 @@
}
scope.launch {
- keyguardInteractor.biometricUnlockState.sample(finishedKeyguardState, ::Pair).collect {
- (biometricUnlockState, keyguardState) ->
- KeyguardWmStateRefactor.assertInLegacyMode()
- if (keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)) {
- startTransitionTo(KeyguardState.GONE)
+ powerInteractor.isAwake
+ .debounce(50L)
+ .sample(
+ keyguardInteractor.biometricUnlockState,
+ startedKeyguardTransitionStep,
+ keyguardInteractor.isKeyguardShowing,
+ keyguardInteractor.isKeyguardDismissible,
+ )
+ .collect {
+ (
+ isAwake,
+ biometricUnlockState,
+ lastStartedTransitionStep,
+ isKeyguardShowing,
+ isKeyguardDismissible) ->
+ KeyguardWmStateRefactor.assertInLegacyMode()
+ if (
+ isAwake &&
+ lastStartedTransitionStep.to == KeyguardState.AOD &&
+ (isWakeAndUnlock(biometricUnlockState) ||
+ (!isKeyguardShowing && isKeyguardDismissible))
+ ) {
+ startTransitionTo(KeyguardState.GONE)
+ }
}
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index 54d5908..baa865d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -26,13 +26,12 @@
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.toQuad
-import com.android.systemui.util.kotlin.sample
+import com.android.systemui.util.kotlin.Utils.Companion.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.launch
@SysUISingleton
@@ -56,50 +55,47 @@
) {
override fun start() {
- listenForDozingToLockscreenHubOrOccluded()
- listenForDozingToGone()
+ listenForDozingToAny()
listenForTransitionToCamera(scope, keyguardInteractor)
}
- private fun listenForDozingToLockscreenHubOrOccluded() {
+ private fun listenForDozingToAny() {
scope.launch {
powerInteractor.isAwake
+ .debounce(50L)
.sample(
- combine(
- startedKeyguardTransitionStep,
- keyguardInteractor.isKeyguardOccluded,
- communalInteractor.isIdleOnCommunal,
- ::Triple
- ),
- ::toQuad
+ keyguardInteractor.biometricUnlockState,
+ startedKeyguardTransitionStep,
+ keyguardInteractor.isKeyguardOccluded,
+ communalInteractor.isIdleOnCommunal,
+ keyguardInteractor.isKeyguardShowing,
+ keyguardInteractor.isKeyguardDismissible,
)
- .collect { (isAwake, lastStartedTransition, occluded, isIdleOnCommunal) ->
- if (isAwake && lastStartedTransition.to == KeyguardState.DOZING) {
- startTransitionTo(
- if (occluded) {
- KeyguardState.OCCLUDED
- } else if (isIdleOnCommunal) {
- KeyguardState.GLANCEABLE_HUB
- } else {
- KeyguardState.LOCKSCREEN
- }
- )
+ .collect {
+ (
+ isAwake,
+ biometricUnlockState,
+ lastStartedTransition,
+ occluded,
+ isIdleOnCommunal,
+ isKeyguardShowing,
+ isKeyguardDismissible) ->
+ if (!(isAwake && lastStartedTransition.to == KeyguardState.DOZING)) {
+ return@collect
}
- }
- }
- }
-
- private fun listenForDozingToGone() {
- scope.launch {
- keyguardInteractor.biometricUnlockState
- .sample(startedKeyguardTransitionStep, ::Pair)
- .collect { (biometricUnlockState, lastStartedTransition) ->
- if (
- lastStartedTransition.to == KeyguardState.DOZING &&
- isWakeAndUnlock(biometricUnlockState)
- ) {
- startTransitionTo(KeyguardState.GONE)
- }
+ startTransitionTo(
+ if (isWakeAndUnlock(biometricUnlockState)) {
+ KeyguardState.GONE
+ } else if (isKeyguardDismissible && !isKeyguardShowing) {
+ KeyguardState.GONE
+ } else if (occluded) {
+ KeyguardState.OCCLUDED
+ } else if (isIdleOnCommunal) {
+ KeyguardState.GLANCEABLE_HUB
+ } else {
+ KeyguardState.LOCKSCREEN
+ }
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index a03fa38..d81f1f1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -21,6 +21,8 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.core.LogLevel.VERBOSE
import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
@@ -37,6 +39,8 @@
private val keyguardInteractor: KeyguardInteractor,
private val logger: KeyguardLogger,
private val powerInteractor: PowerInteractor,
+ private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
+ private val shadeInteractor: ShadeInteractor,
) {
fun start() {
@@ -47,6 +51,30 @@
}
scope.launch {
+ sharedNotificationContainerViewModel
+ .getMaxNotifications { height, useExtraShelfSpace -> height.toInt() }
+ .collect { logger.log(TAG, VERBOSE, "Notif: max height in px", it) }
+ }
+
+ scope.launch {
+ sharedNotificationContainerViewModel.isOnLockscreen.collect {
+ logger.log(TAG, VERBOSE, "Notif: isOnLockscreen", it)
+ }
+ }
+
+ scope.launch {
+ shadeInteractor.isUserInteracting.collect {
+ logger.log(TAG, VERBOSE, "Shade: isUserInteracting", it)
+ }
+ }
+
+ scope.launch {
+ sharedNotificationContainerViewModel.isOnLockscreenWithoutShade.collect {
+ logger.log(TAG, VERBOSE, "Notif: isOnLockscreenWithoutShade", it)
+ }
+ }
+
+ scope.launch {
keyguardInteractor.primaryBouncerShowing.collect {
logger.log(TAG, VERBOSE, "Primary bouncer showing", it)
}
@@ -75,6 +103,18 @@
}
scope.launch {
+ keyguardInteractor.isKeyguardDismissible.collect {
+ logger.log(TAG, VERBOSE, "isDismissible", it)
+ }
+ }
+
+ scope.launch {
+ keyguardInteractor.isKeyguardShowing.collect {
+ logger.log(TAG, VERBOSE, "isShowing", it)
+ }
+ }
+
+ scope.launch {
keyguardInteractor.dozeTransitionModel.collect {
logger.log(TAG, VERBOSE, "Doze transition", it)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
index b92a9a0..a9eec18 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToGoneTransitionViewModel.kt
@@ -16,13 +16,16 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.util.MathUtils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromAodTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
/** Breaks down AOD->GONE transition into discrete steps for corresponding views to consume. */
@ExperimentalCoroutinesApi
@@ -40,5 +43,15 @@
to = KeyguardState.GONE,
)
+ fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+ var startAlpha = 1f
+ return transitionAnimation.sharedFlow(
+ duration = 200.milliseconds,
+ onStart = { startAlpha = viewState.alpha() },
+ onStep = { MathUtils.lerp(startAlpha, 0f, it) },
+ onFinish = { 0f },
+ )
+ }
+
override val deviceEntryParentViewAlpha = transitionAnimation.immediatelyTransitionTo(0f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt
index fca1604..8851a51 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt
@@ -16,12 +16,14 @@
package com.android.systemui.keyguard.ui.viewmodel
+import android.util.MathUtils
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_GONE_DURATION
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -41,6 +43,16 @@
to = KeyguardState.GONE,
)
+ fun lockscreenAlpha(viewState: ViewStateAccessor): Flow<Float> {
+ var startAlpha = 1f
+ return transitionAnimation.sharedFlow(
+ duration = 200.milliseconds,
+ onStart = { startAlpha = viewState.alpha() },
+ onStep = { MathUtils.lerp(startAlpha, 0f, it) },
+ onFinish = { 0f },
+ )
+ }
+
override val deviceEntryParentViewAlpha: Flow<Float> =
transitionAnimation.immediatelyTransitionTo(0f)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index bdcaf09..38d5e0f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -31,6 +31,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED
import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.ui.StateToValue
@@ -70,7 +71,9 @@
private val notificationsKeyguardInteractor: NotificationsKeyguardInteractor,
private val alternateBouncerToGoneTransitionViewModel:
AlternateBouncerToGoneTransitionViewModel,
+ private val aodToGoneTransitionViewModel: AodToGoneTransitionViewModel,
private val aodToLockscreenTransitionViewModel: AodToLockscreenTransitionViewModel,
+ private val dozingToGoneTransitionViewModel: DozingToGoneTransitionViewModel,
private val dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
private val glanceableHubToLockscreenTransitionViewModel:
GlanceableHubToLockscreenTransitionViewModel,
@@ -120,6 +123,27 @@
}
.distinctUntilChanged()
+ /**
+ * Keyguard should not show while the communal hub is fully visible. This check is added since
+ * at the moment, closing the notification shade will cause the keyguard alpha to be set back to
+ * 1. Also ensure keyguard is never visible when GONE.
+ */
+ private val hideKeyguard: Flow<Boolean> =
+ combine(
+ communalInteractor.isIdleOnCommunal,
+ keyguardTransitionInteractor
+ .transitionValue(GONE)
+ .map { it == 1f }
+ .onStart { emit(false) },
+ keyguardTransitionInteractor
+ .transitionValue(OCCLUDED)
+ .map { it == 1f }
+ .onStart { emit(false) },
+ ) { isIdleOnCommunal, isGone, isOccluded ->
+ isIdleOnCommunal || isGone || isOccluded
+ }
+ .distinctUntilChanged()
+
/** Last point that the root view was tapped */
val lastRootViewTapPosition: Flow<Point?> = keyguardInteractor.lastRootViewTapPosition
@@ -136,19 +160,16 @@
/** An observable for the alpha level for the entire keyguard root view. */
fun alpha(viewState: ViewStateAccessor): Flow<Float> {
return combine(
- communalInteractor.isIdleOnCommunal,
- keyguardTransitionInteractor
- .transitionValue(GONE)
- .map { it == 1f }
- .onStart { emit(false) }
- .distinctUntilChanged(),
+ hideKeyguard,
// The transitions are mutually exclusive, so they are safe to merge to get the last
// value emitted by any of them. Do not add flows that cannot make this guarantee.
merge(
alphaOnShadeExpansion,
keyguardInteractor.dismissAlpha.filterNotNull(),
alternateBouncerToGoneTransitionViewModel.lockscreenAlpha,
+ aodToGoneTransitionViewModel.lockscreenAlpha(viewState),
aodToLockscreenTransitionViewModel.lockscreenAlpha(viewState),
+ dozingToGoneTransitionViewModel.lockscreenAlpha(viewState),
dozingToLockscreenTransitionViewModel.lockscreenAlpha,
glanceableHubToLockscreenTransitionViewModel.keyguardAlpha,
goneToAodTransitionViewModel.enterFromTopAnimationAlpha,
@@ -167,12 +188,8 @@
primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha,
)
.onStart { emit(1f) }
- ) { isIdleOnCommunal, gone, alpha ->
- if (isIdleOnCommunal || gone) {
- // Keyguard should not show while the communal hub is fully visible. This check
- // is added since at the moment, closing the notification shade will cause the
- // keyguard alpha to be set back to 1. Also ensure keyguard is never visible
- // when GONE.
+ ) { hideKeyguard, alpha ->
+ if (hideKeyguard) {
0f
} else {
alpha
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 8b7c85b..f2013be 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -546,7 +546,7 @@
@SysUISingleton
@KeyguardLog
public static LogBuffer provideKeyguardLogBuffer(LogBufferFactory factory) {
- return factory.create("KeyguardLog", 250);
+ return factory.create("KeyguardLog", 500);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
index f1cade7..0b19bab 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
@@ -24,12 +24,14 @@
import android.os.RemoteException
import android.os.ServiceManager
import android.util.Log
+import android.window.WindowContainerToken
+import javax.inject.Inject
/**
* Helper class that handles the media projection service related actions. It simplifies invoking
* the MediaProjectionManagerService and updating the permission consent.
*/
-class MediaProjectionServiceHelper {
+class MediaProjectionServiceHelper @Inject constructor() {
companion object {
private const val TAG = "MediaProjectionServiceHelper"
private val service =
@@ -90,4 +92,16 @@
}
}
}
+
+ /** Updates the projected task to the task that has a matching [WindowContainerToken]. */
+ fun updateTaskRecordingSession(token: WindowContainerToken): Boolean {
+ return try {
+ true
+ // TODO: actually call the service once it is implemented
+ // service.updateTaskRecordingSession(token)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Unable to updateTaskRecordingSession", e)
+ false
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
index 9938f11..cfbcaf9 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/model/MediaProjectionState.kt
@@ -16,11 +16,11 @@
package com.android.systemui.mediaprojection.taskswitcher.data.model
-import android.app.TaskInfo
+import android.app.ActivityManager.RunningTaskInfo
/** Represents the state of media projection. */
sealed interface MediaProjectionState {
object NotProjecting : MediaProjectionState
object EntireScreen : MediaProjectionState
- data class SingleTask(val task: TaskInfo) : MediaProjectionState
+ data class SingleTask(val task: RunningTaskInfo) : MediaProjectionState
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
index 492d482..4ff54d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepository.kt
@@ -17,10 +17,14 @@
package com.android.systemui.mediaprojection.taskswitcher.data.repository
import android.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityOptions
+import android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
import android.app.ActivityTaskManager
+import android.app.IActivityTaskManager
import android.app.TaskStackListener
import android.os.IBinder
import android.util.Log
+import android.view.Display
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
@@ -40,11 +44,24 @@
class ActivityTaskManagerTasksRepository
@Inject
constructor(
- private val activityTaskManager: ActivityTaskManager,
+ private val activityTaskManager: IActivityTaskManager,
@Application private val applicationScope: CoroutineScope,
@Background private val backgroundDispatcher: CoroutineDispatcher,
) : TasksRepository {
+ override suspend fun launchRecentTask(taskInfo: RunningTaskInfo) {
+ withContext(backgroundDispatcher) {
+ val activityOptions = ActivityOptions.makeBasic()
+ activityOptions.pendingIntentBackgroundActivityStartMode =
+ MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ activityOptions.launchDisplayId = taskInfo.displayId
+ activityTaskManager.startActivityFromRecents(
+ taskInfo.taskId,
+ activityOptions.toBundle()
+ )
+ }
+ }
+
override suspend fun findRunningTaskFromWindowContainerToken(
windowContainerToken: IBinder
): RunningTaskInfo? =
@@ -53,7 +70,14 @@
}
private suspend fun getRunningTasks(): List<RunningTaskInfo> =
- withContext(backgroundDispatcher) { activityTaskManager.getTasks(Integer.MAX_VALUE) }
+ withContext(backgroundDispatcher) {
+ activityTaskManager.getTasks(
+ /* maxNum = */ Integer.MAX_VALUE,
+ /* filterForVisibleRecents = */ false,
+ /* keepIntentExtra = */ false,
+ /* displayId = */ Display.INVALID_DISPLAY
+ )
+ }
override val foregroundTask: Flow<RunningTaskInfo> =
conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
index 6480a47..74d1992 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.mediaprojection.taskswitcher.data.repository
+import android.app.ActivityManager.RunningTaskInfo
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
import android.os.Handler
@@ -26,15 +27,19 @@
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.mediaprojection.MediaProjectionServiceHelper
import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
@SysUISingleton
class MediaProjectionManagerRepository
@@ -43,9 +48,21 @@
private val mediaProjectionManager: MediaProjectionManager,
@Main private val handler: Handler,
@Application private val applicationScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
private val tasksRepository: TasksRepository,
+ private val mediaProjectionServiceHelper: MediaProjectionServiceHelper,
) : MediaProjectionRepository {
+ override suspend fun switchProjectedTask(task: RunningTaskInfo) {
+ withContext(backgroundDispatcher) {
+ if (mediaProjectionServiceHelper.updateTaskRecordingSession(task.token)) {
+ Log.d(TAG, "Successfully switched projected task")
+ } else {
+ Log.d(TAG, "Failed to switch projected task")
+ }
+ }
+ }
+
override val mediaProjectionState: Flow<MediaProjectionState> =
conflatedCallbackFlow {
val callback =
@@ -82,7 +99,9 @@
}
val matchingTask =
tasksRepository.findRunningTaskFromWindowContainerToken(
- checkNotNull(session.tokenToRecord)) ?: return MediaProjectionState.EntireScreen
+ checkNotNull(session.tokenToRecord)
+ )
+ ?: return MediaProjectionState.EntireScreen
return MediaProjectionState.SingleTask(matchingTask)
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
index 5bec692..e495466 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionRepository.kt
@@ -16,12 +16,16 @@
package com.android.systemui.mediaprojection.taskswitcher.data.repository
+import android.app.ActivityManager.RunningTaskInfo
import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
import kotlinx.coroutines.flow.Flow
/** Represents a repository to retrieve and change data related to media projection. */
interface MediaProjectionRepository {
+ /** Switches the task that should be projected. */
+ suspend fun switchProjectedTask(task: RunningTaskInfo)
+
/** Represents the current [MediaProjectionState]. */
val mediaProjectionState: Flow<MediaProjectionState>
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt
deleted file mode 100644
index 544eb6b..0000000
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/NoOpMediaProjectionRepository.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.mediaprojection.taskswitcher.data.repository
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.mediaprojection.taskswitcher.data.model.MediaProjectionState
-import javax.inject.Inject
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emptyFlow
-
-/**
- * No-op implementation of [MediaProjectionRepository] that does nothing. Currently used as a
- * placeholder, while the real implementation is not completed.
- */
-@SysUISingleton
-class NoOpMediaProjectionRepository @Inject constructor() : MediaProjectionRepository {
-
- override val mediaProjectionState: Flow<MediaProjectionState> = emptyFlow()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
index 6a535e4..9ef42b4 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/TasksRepository.kt
@@ -23,6 +23,8 @@
/** Repository responsible for retrieving data related to running tasks. */
interface TasksRepository {
+ suspend fun launchRecentTask(taskInfo: RunningTaskInfo)
+
/**
* Tries to find a [RunningTaskInfo] with a matching window container token. Returns `null` when
* no matching task was found.
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
index fc5cf7d..eb9e6a5 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.mediaprojection.taskswitcher.domain.interactor
+import android.app.ActivityManager.RunningTaskInfo
import android.app.TaskInfo
import android.content.Intent
import android.util.Log
@@ -37,10 +38,18 @@
class TaskSwitchInteractor
@Inject
constructor(
- mediaProjectionRepository: MediaProjectionRepository,
+ private val mediaProjectionRepository: MediaProjectionRepository,
private val tasksRepository: TasksRepository,
) {
+ suspend fun switchProjectedTask(task: RunningTaskInfo) {
+ mediaProjectionRepository.switchProjectedTask(task)
+ }
+
+ suspend fun goBackToTask(task: RunningTaskInfo) {
+ tasksRepository.launchRecentTask(task)
+ }
+
/**
* Emits a stream of changes to the state of task switching, in the context of media projection.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
index cd1258e..caabc64 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/domain/model/TaskSwitchState.kt
@@ -16,7 +16,7 @@
package com.android.systemui.mediaprojection.taskswitcher.domain.model
-import android.app.TaskInfo
+import android.app.ActivityManager.RunningTaskInfo
/** Represents tha state of task switching in the context of single task media projection. */
sealed interface TaskSwitchState {
@@ -25,6 +25,8 @@
/** The foreground task is the same as the task that is currently being projected. */
object TaskUnchanged : TaskSwitchState
/** The foreground task is a different one to the task it currently being projected. */
- data class TaskSwitched(val projectedTask: TaskInfo, val foregroundTask: TaskInfo) :
- TaskSwitchState
+ data class TaskSwitched(
+ val projectedTask: RunningTaskInfo,
+ val foregroundTask: RunningTaskInfo
+ ) : TaskSwitchState
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
index 7840da9..dab7439 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinator.kt
@@ -16,23 +16,25 @@
package com.android.systemui.mediaprojection.taskswitcher.ui
+import android.app.ActivityManager.RunningTaskInfo
import android.app.Notification
-import android.app.NotificationChannel
import android.app.NotificationManager
+import android.app.PendingIntent
import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Parcelable
import android.util.Log
-import com.android.systemui.res.R
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.NotShowing
import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState.Showing
import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
+import com.android.systemui.res.R
import com.android.systemui.util.NotificationChannels
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
/** Coordinator responsible for showing/hiding the task switcher notification. */
@@ -43,32 +45,54 @@
private val context: Context,
private val notificationManager: NotificationManager,
@Application private val applicationScope: CoroutineScope,
- @Main private val mainDispatcher: CoroutineDispatcher,
private val viewModel: TaskSwitcherNotificationViewModel,
+ private val broadcastDispatcher: BroadcastDispatcher,
) {
+
fun start() {
applicationScope.launch {
- viewModel.uiState.flowOn(mainDispatcher).collect { uiState ->
- Log.d(TAG, "uiState -> $uiState")
- when (uiState) {
- is Showing -> showNotification()
- is NotShowing -> hideNotification()
+ launch {
+ viewModel.uiState.collect { uiState ->
+ Log.d(TAG, "uiState -> $uiState")
+ when (uiState) {
+ is Showing -> showNotification(uiState)
+ is NotShowing -> hideNotification()
+ }
}
}
+ launch {
+ broadcastDispatcher
+ .broadcastFlow(IntentFilter(SWITCH_ACTION)) { intent, _ ->
+ intent.requireParcelableExtra<RunningTaskInfo>(EXTRA_ACTION_TASK)
+ }
+ .collect { task: RunningTaskInfo ->
+ Log.d(TAG, "Switch action triggered: $task")
+ viewModel.onSwitchTaskClicked(task)
+ }
+ }
+ launch {
+ broadcastDispatcher
+ .broadcastFlow(IntentFilter(GO_BACK_ACTION)) { intent, _ ->
+ intent.requireParcelableExtra<RunningTaskInfo>(EXTRA_ACTION_TASK)
+ }
+ .collect { task ->
+ Log.d(TAG, "Go back action triggered: $task")
+ viewModel.onGoBackToTaskClicked(task)
+ }
+ }
}
}
- private fun showNotification() {
- notificationManager.notify(TAG, NOTIFICATION_ID, createNotification())
+ private fun showNotification(uiState: Showing) {
+ notificationManager.notify(TAG, NOTIFICATION_ID, createNotification(uiState))
}
- private fun createNotification(): Notification {
- // TODO(b/286201261): implement actions
+ private fun createNotification(uiState: Showing): Notification {
val actionSwitch =
Notification.Action.Builder(
/* icon = */ null,
context.getString(R.string.media_projection_task_switcher_action_switch),
- /* intent = */ null
+ createActionPendingIntent(action = SWITCH_ACTION, task = uiState.foregroundTask)
)
.build()
@@ -76,34 +100,40 @@
Notification.Action.Builder(
/* icon = */ null,
context.getString(R.string.media_projection_task_switcher_action_back),
- /* intent = */ null
+ createActionPendingIntent(action = GO_BACK_ACTION, task = uiState.projectedTask)
)
.build()
-
- val channel =
- NotificationChannel(
- NotificationChannels.HINTS,
- context.getString(R.string.media_projection_task_switcher_notification_channel),
- NotificationManager.IMPORTANCE_HIGH
- )
- notificationManager.createNotificationChannel(channel)
- return Notification.Builder(context, channel.id)
+ return Notification.Builder(context, NotificationChannels.ALERTS)
.setSmallIcon(R.drawable.qs_screen_record_icon_on)
.setAutoCancel(true)
.setContentText(context.getString(R.string.media_projection_task_switcher_text))
.addAction(actionSwitch)
.addAction(actionBack)
- .setPriority(Notification.PRIORITY_HIGH)
- .setDefaults(Notification.DEFAULT_VIBRATE)
.build()
}
private fun hideNotification() {
- notificationManager.cancel(NOTIFICATION_ID)
+ notificationManager.cancel(TAG, NOTIFICATION_ID)
}
+ private fun createActionPendingIntent(action: String, task: RunningTaskInfo) =
+ PendingIntent.getBroadcast(
+ context,
+ /* requestCode= */ 0,
+ Intent(action).apply { putExtra(EXTRA_ACTION_TASK, task) },
+ /* flags= */ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
+
companion object {
private const val TAG = "TaskSwitchNotifCoord"
private const val NOTIFICATION_ID = 5566
+
+ private const val EXTRA_ACTION_TASK = "extra_task"
+
+ private const val SWITCH_ACTION = "com.android.systemui.mediaprojection.SWITCH_TASK"
+ private const val GO_BACK_ACTION = "com.android.systemui.mediaprojection.GO_BACK"
}
}
+
+private fun <T : Parcelable> Intent.requireParcelableExtra(key: String) =
+ getParcelableExtra<T>(key)!!
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
index 21aee72..f307761 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/model/TaskSwitcherNotificationUiState.kt
@@ -16,7 +16,7 @@
package com.android.systemui.mediaprojection.taskswitcher.ui.model
-import android.app.TaskInfo
+import android.app.ActivityManager.RunningTaskInfo
/** Represents the UI state for the task switcher notification. */
sealed interface TaskSwitcherNotificationUiState {
@@ -24,7 +24,7 @@
object NotShowing : TaskSwitcherNotificationUiState
/** The notification should be shown. */
data class Showing(
- val projectedTask: TaskInfo,
- val foregroundTask: TaskInfo,
+ val projectedTask: RunningTaskInfo,
+ val foregroundTask: RunningTaskInfo,
) : TaskSwitcherNotificationUiState
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
index d9754d4..cc8cc51 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModel.kt
@@ -16,15 +16,24 @@
package com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel
+import android.app.ActivityManager.RunningTaskInfo
import android.util.Log
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
import com.android.systemui.mediaprojection.taskswitcher.domain.model.TaskSwitchState
import com.android.systemui.mediaprojection.taskswitcher.ui.model.TaskSwitcherNotificationUiState
import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.withContext
-class TaskSwitcherNotificationViewModel @Inject constructor(interactor: TaskSwitchInteractor) {
+class TaskSwitcherNotificationViewModel
+@Inject
+constructor(
+ private val interactor: TaskSwitchInteractor,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
val uiState: Flow<TaskSwitcherNotificationUiState> =
interactor.taskSwitchChanges.map { taskSwitchChange ->
@@ -43,6 +52,13 @@
}
}
+ suspend fun onSwitchTaskClicked(task: RunningTaskInfo) {
+ interactor.switchProjectedTask(task)
+ }
+
+ suspend fun onGoBackToTaskClicked(task: RunningTaskInfo) =
+ withContext(backgroundDispatcher) { interactor.goBackToTask(task) }
+
companion object {
private const val TAG = "TaskSwitchNotifVM"
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 6af9b73..e92630f 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -55,15 +55,15 @@
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
import com.android.systemui.util.settings.SecureSettings;
-import java.util.concurrent.Executor;
-
import dagger.assisted.Assisted;
import dagger.assisted.AssistedFactory;
import dagger.assisted.AssistedInject;
+import java.util.concurrent.Executor;
+
public class BrightnessController implements ToggleSlider.Listener, MirroredBrightnessController {
private static final String TAG = "CentralSurfaces.BrightnessController";
- private static final int SLIDER_ANIMATION_DURATION = 3000;
+ private static final int SLIDER_ANIMATION_DURATION = 1000;
private static final int MSG_UPDATE_SLIDER = 1;
private static final int MSG_ATTACH_LISTENER = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 7bcb1da..cf7c3e0 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -111,8 +111,6 @@
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
import com.android.systemui.Gefingerpoken;
-import com.android.systemui.animation.ActivityTransitionAnimator;
-import com.android.systemui.animation.TransitionAnimator;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
@@ -219,7 +217,6 @@
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.TapAgainViewController;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardQsUserSwitchController;
@@ -259,10 +256,6 @@
private static final boolean DEBUG_DRAWABLE = false;
/** The parallax amount of the quick settings translation when dragging down the panel. */
public static final float QS_PARALLAX_AMOUNT = 0.175f;
- private static final long ANIMATION_DELAY_ICON_FADE_IN =
- ActivityTransitionAnimator.TIMINGS.getTotalDuration()
- - CollapsedStatusBarFragment.FADE_IN_DURATION
- - CollapsedStatusBarFragment.FADE_IN_DELAY - 48;
private static final int NO_FIXED_DURATION = -1;
private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;
private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L;
@@ -463,7 +456,6 @@
*/
private float mLinearDarkAmount;
private boolean mPulsing;
- private boolean mHideIconsDuringLaunchAnimation = true;
private int mStackScrollerMeasuringPass;
/** Non-null if a heads-up notification's position is being tracked. */
@Nullable
@@ -2053,7 +2045,6 @@
mView.animate().cancel();
}
- @Override
public void expandToQs() {
if (mQsController.isExpansionEnabled()) {
mQsController.setExpandImmediate(true);
@@ -2820,7 +2811,6 @@
mQsController.setListening(listening);
}
- @Override
public void expand(boolean animate) {
if (isFullyCollapsed() || isCollapsing()) {
mInstantExpanding = true;
@@ -3159,10 +3149,9 @@
return mUnlockedScreenOffAnimationController.isAnimationPlaying();
}
- @Override
public boolean shouldHideStatusBarIconsWhenExpanded() {
if (isLaunchingActivity()) {
- return mHideIconsDuringLaunchAnimation;
+ return false;
}
if (mHeadsUpAppearanceController != null
&& mHeadsUpAppearanceController.shouldBeVisible()) {
@@ -3260,18 +3249,6 @@
}
@Override
- public void applyLaunchAnimationProgress(float linearProgress) {
- boolean hideIcons = TransitionAnimator.getProgress(ActivityTransitionAnimator.TIMINGS,
- linearProgress, ANIMATION_DELAY_ICON_FADE_IN, 100) == 0.0f;
- if (hideIcons != mHideIconsDuringLaunchAnimation) {
- mHideIconsDuringLaunchAnimation = hideIcons;
- if (!hideIcons) {
- mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
- }
- }
- }
-
- @Override
public void performHapticFeedback(int constant) {
mVibratorHelper.performHapticFeedback(mView, constant);
}
@@ -3482,7 +3459,6 @@
ipw.print("mInterpolatedDarkAmount="); ipw.println(mInterpolatedDarkAmount);
ipw.print("mLinearDarkAmount="); ipw.println(mLinearDarkAmount);
ipw.print("mPulsing="); ipw.println(mPulsing);
- ipw.print("mHideIconsDuringLaunchAnimation="); ipw.println(mHideIconsDuringLaunchAnimation);
ipw.print("mStackScrollerMeasuringPass="); ipw.println(mStackScrollerMeasuringPass);
ipw.print("mPanelAlpha="); ipw.println(mPanelAlpha);
ipw.print("mBottomAreaShadeAlpha="); ipw.println(mBottomAreaShadeAlpha);
@@ -4174,7 +4150,6 @@
return mShadeRepository.getLegacyIsClosing().getValue();
}
- @Override
public void collapseWithDuration(int animationDuration) {
mFixedDuration = animationDuration;
collapse(false /* delayed */, 1.0f /* speedUpFactor */);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index ec4b23a..0a57b64 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -78,6 +78,14 @@
*/
void animateCollapseShade(int flags, boolean force, boolean delayed, float speedUpFactor);
+ /**
+ * Collapses the shade with an animation duration in milliseconds.
+ *
+ * @deprecated use animateCollapseShade with a speed up factor instead
+ */
+ @Deprecated
+ void collapseWithDuration(int animationDuration);
+
/** Expand the shade with an animation. */
void animateExpandShade();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
index 08a0c93..093690f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerEmptyImpl.kt
@@ -33,6 +33,7 @@
delayed: Boolean,
speedUpFactor: Float
) {}
+ override fun collapseWithDuration(animationDuration: Int) {}
override fun animateExpandShade() {}
override fun animateExpandQs() {}
override fun postAnimateCollapseShade() {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index e6555f2e..d99d607 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -147,6 +147,11 @@
}
@Override
+ public void collapseWithDuration(int animationDuration) {
+ mNpvc.get().collapseWithDuration(animationDuration);
+ }
+
+ @Override
protected void expandToNotifications() {
getNpvc().expandToNotifications();
}
@@ -221,7 +226,6 @@
}
}
-
@Override
public void collapseShade(boolean animate) {
if (animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 4d6ade4..27168a7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -97,7 +97,7 @@
}
override fun instantCollapseShade() {
- // TODO(b/315921512) add support for instant transition
+ // TODO(b/325602936) add support for instant transition
sceneInteractor.changeScene(
getCollapseDestinationScene(),
"hide shade",
@@ -134,6 +134,11 @@
}
}
+ override fun collapseWithDuration(animationDuration: Int) {
+ // TODO(b/300258424) inline this. The only caller uses the default duration.
+ animateCollapseShade()
+ }
+
private fun animateCollapseShadeInternal() {
sceneInteractor.changeScene(
getCollapseDestinationScene(),
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
index 44c6a82..7a1637e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewController.kt
@@ -31,12 +31,6 @@
* @see NotificationPanelViewController
*/
interface ShadeViewController {
- /** Expand the shade either animated or instantly. */
- fun expand(animate: Boolean)
-
- /** Animates to an expanded shade with QS expanded. If the shade starts expanded, expands QS. */
- fun expandToQs()
-
/** Returns whether the shade is expanding or collapsing itself or quick settings. */
val isExpandingOrCollapsing: Boolean
@@ -58,9 +52,6 @@
/** Collapses the shade. */
fun collapse(animate: Boolean, delayed: Boolean, speedUpFactor: Float)
- /** Collapses the shade with an animation duration in milliseconds. */
- fun collapseWithDuration(animationDuration: Int)
-
/** Collapses the shade instantly without animation. */
fun instantCollapse()
@@ -102,9 +93,6 @@
/** Returns the StatusBarState. */
val barState: Int
- /** Sets the amount of progress in the status bar launch animation. */
- fun applyLaunchAnimationProgress(linearProgress: Float)
-
/** Sets the alpha value of the shade to a value between 0 and 255. */
fun setAlpha(alpha: Int, animate: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
index 7a181f1..3be3f6b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewControllerEmptyImpl.kt
@@ -28,8 +28,6 @@
/** Empty implementation of ShadeViewController for variants with no shade. */
class ShadeViewControllerEmptyImpl @Inject constructor() :
ShadeViewController, ShadeBackActionInteractor, ShadeLockscreenInteractor {
- override fun expand(animate: Boolean) {}
- override fun expandToQs() {}
override fun expandToNotifications() {}
override val isExpandingOrCollapsing: Boolean = false
override val isExpanded: Boolean = false
@@ -37,7 +35,6 @@
override val isShadeFullyExpanded: Boolean = false
override fun collapse(delayed: Boolean, speedUpFactor: Float) {}
override fun collapse(animate: Boolean, delayed: Boolean, speedUpFactor: Float) {}
- override fun collapseWithDuration(animationDuration: Int) {}
override fun instantCollapse() {}
override fun animateCollapseQs(fullyCollapse: Boolean) {}
override fun canBeCollapsed(): Boolean = false
@@ -55,7 +52,6 @@
override fun dozeTimeTick() {}
override fun resetViews(animate: Boolean) {}
override val barState: Int = 0
- override fun applyLaunchAnimationProgress(linearProgress: Float) {}
override fun closeUserSwitcherIfOpen(): Boolean {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 8d53022..5f3a83a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1761,7 +1761,7 @@
* Constructs an ExpandableNotificationRow. Used by layout inflation.
*
* @param context passed to image resolver
- * @param attrs attributes used to initialize parent view
+ * @param attrs attributes used to initialize parent view
*/
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
this(context, attrs, context);
@@ -1775,9 +1775,9 @@
* AsyncLayoutFactory} in {@link RowInflaterTask}.
*
* @param context context context of the view
- * @param attrs attributes used to initialize parent view
- * @param entry notification that the row will be associated to (determines the user for the
- * ImageResolver)
+ * @param attrs attributes used to initialize parent view
+ * @param entry notification that the row will be associated to (determines the user for the
+ * ImageResolver)
*/
public ExpandableNotificationRow(Context context, AttributeSet attrs, NotificationEntry entry) {
this(context, attrs, userContextForEntry(context, entry));
@@ -2028,7 +2028,7 @@
return traceTag;
}
- return traceTag + "(" + getEntry().getNotificationStyle() + ")";
+ return traceTag + "(" + getEntry().getNotificationStyle() + ")";
}
@Override
@@ -3083,6 +3083,7 @@
onStartedRunnable.run();
}
}
+
@Override
public void onAnimationEnd(Animator animation) {
ExpandableNotificationRow.super.performRemoveAnimation(
@@ -3777,6 +3778,9 @@
pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
pw.print(", mShowNoBackground: " + mShowNoBackground);
pw.println();
+ if (NotificationContentView.INCLUDE_HEIGHTS_TO_DUMP) {
+ dumpHeights(pw);
+ }
showingLayout.dump(pw, args);
if (getViewState() != null) {
@@ -3820,6 +3824,34 @@
});
}
+ private void dumpHeights(IndentingPrintWriter pw) {
+ pw.print("Heights: ");
+ pw.print("intrinsic", getIntrinsicHeight());
+ pw.print("actual", getActualHeight());
+ pw.print("maxContent", getMaxContentHeight());
+ pw.print("maxExpanded", getMaxExpandHeight());
+ pw.print("collapsed", getCollapsedHeight());
+ pw.print("headsup", getHeadsUpHeight());
+ pw.print("headsup without header", getHeadsUpHeightWithoutHeader());
+ pw.print("minHeight", getMinHeight());
+ pw.print("pinned headsup", getPinnedHeadsUpHeight(
+ true /* atLeastMinHeight */));
+ pw.println();
+ pw.print("Intrinsic Height Factors: ");
+ pw.print("isUserLocked()", isUserLocked());
+ pw.print("isChildInGroup()", isChildInGroup());
+ pw.print("isGroupExpanded()", isGroupExpanded());
+ pw.print("sensitive", mSensitive);
+ pw.print("hideSensitiveForIntrinsicHeight", mHideSensitiveForIntrinsicHeight);
+ pw.print("isSummaryWithChildren", mIsSummaryWithChildren);
+ pw.print("canShowHeadsUp()", canShowHeadsUp());
+ pw.print("isHeadsUpState()", isHeadsUpState());
+ pw.print("isPinned()", isPinned());
+ pw.print("headsupDisappearRunning", mHeadsupDisappearRunning);
+ pw.print("isExpanded()", isExpanded());
+ pw.println();
+ }
+
private void logKeepInParentChildDetached(ExpandableNotificationRow child) {
if (mLogger != null) {
mLogger.logKeepInParentChildDetached(child.getEntry(), getEntry());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 50bc3d3..137e1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -70,6 +70,7 @@
import com.android.systemui.statusbar.policy.SmartReplyView;
import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent;
import com.android.systemui.util.Compile;
+import com.android.systemui.util.DumpUtilsKt;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -97,6 +98,8 @@
private static final int UNDEFINED = -1;
+ protected static final boolean INCLUDE_HEIGHTS_TO_DUMP = true;
+
private final Rect mClipBounds = new Rect();
private int mMinContractedHeight;
@@ -2196,6 +2199,11 @@
pw.print("null");
}
pw.println();
+
+ if (INCLUDE_HEIGHTS_TO_DUMP) {
+ dumpContentDimensions(DumpUtilsKt.asIndenting(pw));
+ }
+
pw.println("mBubblesEnabledForUser: " + mBubblesEnabledForUser);
pw.print("RemoteInputViews { ");
@@ -2216,6 +2224,69 @@
pw.println(" }");
}
+ private String visibleTypeToString(int visibleType) {
+ return switch (visibleType) {
+ case VISIBLE_TYPE_CONTRACTED -> "CONTRACTED";
+ case VISIBLE_TYPE_EXPANDED -> "EXPANDED";
+ case VISIBLE_TYPE_HEADSUP -> "HEADSUP";
+ case VISIBLE_TYPE_SINGLELINE -> "SINGLELINE";
+ default -> "NONE";
+ };
+ }
+
+ /** Add content views to dump */
+ private void dumpContentDimensions(IndentingPrintWriter pw) {
+ pw.print("ContentDimensions: ");
+ pw.print("visibleType(String)", visibleTypeToString(mVisibleType));
+ pw.print("measured width", getMeasuredWidth());
+ pw.print("measured height", getMeasuredHeight());
+ pw.print("maxHeight", getMaxHeight());
+ pw.print("minHeight", getMinHeight());
+ pw.println();
+ pw.println("ChildViews:");
+ DumpUtilsKt.withIncreasedIndent(pw, () -> {
+ final View contractedChild = mContractedChild;
+ if (contractedChild != null) {
+ dumpChildViewDimensions(pw, contractedChild, "Contracted Child:");
+ pw.println();
+ }
+
+ final View expandedChild = mExpandedChild;
+ if (expandedChild != null) {
+ dumpChildViewDimensions(pw, expandedChild, "Expanded Child:");
+ pw.println();
+ }
+
+ final View headsUpChild = mHeadsUpChild;
+ if (headsUpChild != null) {
+ dumpChildViewDimensions(pw, headsUpChild, "HeadsUp Child:");
+ pw.println();
+ }
+ final View singleLineView = mSingleLineView;
+ if (singleLineView != null) {
+ dumpChildViewDimensions(pw, singleLineView, "Single Line View:");
+ pw.println();
+ }
+
+ });
+ final int expandedRemoteInputHeight = getExtraRemoteInputHeight(mExpandedRemoteInput);
+ final int headsUpRemoteInputHeight = getExtraRemoteInputHeight(mHeadsUpRemoteInput);
+ pw.print("expandedRemoteInputHeight", expandedRemoteInputHeight);
+ pw.print("headsUpRemoteInputHeight", headsUpRemoteInputHeight);
+ pw.println();
+ }
+
+ private void dumpChildViewDimensions(IndentingPrintWriter pw, View view,
+ String name) {
+ pw.print(name + " ");
+ DumpUtilsKt.withIncreasedIndent(pw, () -> {
+ pw.print("width", view.getWidth());
+ pw.print("height", view.getHeight());
+ pw.print("measuredWidth", view.getMeasuredWidth());
+ pw.print("measuredHeight", view.getMeasuredHeight());
+ });
+ }
+
/** Add any existing SmartReplyView to the dump */
public void dumpSmartReplies(IndentingPrintWriter pw) {
if (mHeadsUpSmartReplyView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
index 09f52ca..8d1cdfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
@@ -20,10 +20,12 @@
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.common.shared.model.NotificationContainerBounds
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import com.android.systemui.util.kotlin.FlowDumperImpl
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
@@ -35,10 +37,11 @@
class NotificationStackAppearanceViewModel
@Inject
constructor(
+ dumpManager: DumpManager,
stackAppearanceInteractor: NotificationStackAppearanceInteractor,
shadeInteractor: ShadeInteractor,
sceneInteractor: SceneInteractor,
-) {
+) : FlowDumperImpl(dumpManager) {
/**
* The expansion fraction of the notification stack. It should go from 0 to 1 when transitioning
* from Gone to Shade scenes, and remain at 1 when in Lockscreen or Shade scenes and while
@@ -72,10 +75,12 @@
}
}
.distinctUntilChanged()
+ .dumpWhileCollecting("expandFraction")
/** The bounds of the notification stack in the current scene. */
- val stackBounds: Flow<NotificationContainerBounds> = stackAppearanceInteractor.stackBounds
+ val stackBounds: Flow<NotificationContainerBounds> =
+ stackAppearanceInteractor.stackBounds.dumpValue("stackBounds")
/** The y-coordinate in px of top of the contents of the notification stack. */
- val contentTop: StateFlow<Float> = stackAppearanceInteractor.contentTop
+ val contentTop: StateFlow<Float> = stackAppearanceInteractor.contentTop.dumpValue("contentTop")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index b4c88c5..f523793 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -23,6 +23,7 @@
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -60,6 +61,7 @@
import com.android.systemui.keyguard.ui.viewmodel.ViewStateAccessor
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
+import com.android.systemui.util.kotlin.FlowDumperImpl
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -88,6 +90,7 @@
@Inject
constructor(
private val interactor: SharedNotificationContainerInteractor,
+ dumpManager: DumpManager,
@Application applicationScope: CoroutineScope,
private val keyguardInteractor: KeyguardInteractor,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
@@ -116,7 +119,7 @@
private val primaryBouncerToLockscreenTransitionViewModel:
PrimaryBouncerToLockscreenTransitionViewModel,
private val aodBurnInViewModel: AodBurnInViewModel,
-) {
+) : FlowDumperImpl(dumpManager) {
private val statesForConstrainedNotifications: Set<KeyguardState> =
setOf(AOD, LOCKSCREEN, DOZING, ALTERNATE_BOUNCER, PRIMARY_BOUNCER)
@@ -126,6 +129,7 @@
.map { it.transitionState == STARTED || it.transitionState == RUNNING }
.distinctUntilChanged()
.onStart { emit(false) }
+ .dumpWhileCollecting("lockscreenToGlanceableHubRunning")
private val glanceableHubToLockscreenRunning =
keyguardTransitionInteractor
@@ -133,6 +137,7 @@
.map { it.transitionState == STARTED || it.transitionState == RUNNING }
.distinctUntilChanged()
.onStart { emit(false) }
+ .dumpWhileCollecting("glanceableHubToLockscreenRunning")
/**
* Shade locked is a legacy concept, but necessary to mimic current functionality. Listen for
@@ -148,8 +153,10 @@
isShadeLocked && (isQsExpanded || isShadeExpanded)
}
.distinctUntilChanged()
+ .dumpWhileCollecting("isShadeLocked")
- val shadeCollapseFadeInComplete = MutableStateFlow(false)
+ private val shadeCollapseFadeInComplete = MutableStateFlow(false)
+ .dumpValue("shadeCollapseFadeInComplete")
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
interactor.configurationBasedDimensions
@@ -171,6 +178,7 @@
)
}
.distinctUntilChanged()
+ .dumpWhileCollecting("configurationBasedDimensions")
/** If the user is visually on one of the unoccluded lockscreen states. */
val isOnLockscreen: Flow<Boolean> =
@@ -186,6 +194,7 @@
constrainedNotificationState || transitioningToOrFromLockscreen
}
.distinctUntilChanged()
+ .dumpWhileCollecting("isOnLockscreen")
/** Are we purely on the keyguard without the shade/qs? */
val isOnLockscreenWithoutShade: Flow<Boolean> =
@@ -204,6 +213,7 @@
started = SharingStarted.Eagerly,
initialValue = false,
)
+ .dumpValue("isOnLockscreenWithoutShade")
/** Are we purely on the glanceable hub without the shade/qs? */
val isOnGlanceableHubWithoutShade: Flow<Boolean> =
@@ -222,6 +232,7 @@
started = SharingStarted.WhileSubscribed(),
initialValue = false,
)
+ .dumpWhileCollecting("isOnGlanceableHubWithoutShade")
/**
* Fade in if the user swipes the shade back up, not if collapsed by going to AOD. This is
@@ -284,6 +295,7 @@
started = SharingStarted.WhileSubscribed(),
initialValue = false,
)
+ .dumpWhileCollecting("shadeCollapseFadeIn")
/**
* The container occupies the entire screen, and must be positioned relative to other elements.
@@ -322,6 +334,7 @@
started = SharingStarted.Lazily,
initialValue = NotificationContainerBounds(),
)
+ .dumpValue("bounds")
/**
* Ensure view is visible when the shade/qs are expanded. Also, as QS is expanding, fade out
@@ -345,6 +358,7 @@
}
}
.onStart { emit(0f) }
+ .dumpWhileCollecting("alphaForShadeAndQsExpansion")
private val alphaWhenGoneAndShadeState: Flow<Float> =
combineTransform(
@@ -357,6 +371,7 @@
emit(1f)
}
}
+ .dumpWhileCollecting("alphaWhenGoneAndShadeState")
fun expansionAlpha(viewState: ViewStateAccessor): Flow<Float> {
// All transition view models are mututally exclusive, and safe to merge
@@ -389,7 +404,9 @@
isOnLockscreenWithoutShade,
shadeCollapseFadeIn,
alphaForShadeAndQsExpansion,
- keyguardInteractor.dismissAlpha,
+ keyguardInteractor.dismissAlpha.dumpWhileCollecting(
+ "keyguardInteractor.keyguardAlpha"
+ ),
) {
isOnLockscreenWithoutShade,
shadeCollapseFadeIn,
@@ -405,6 +422,7 @@
},
)
.distinctUntilChanged()
+ .dumpWhileCollecting("expansionAlpha")
}
/**
@@ -438,6 +456,7 @@
}
}
}
+ .dumpWhileCollecting("glanceableHubAlpha")
/**
* Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
@@ -458,6 +477,7 @@
0f
}
}
+ .dumpWhileCollecting("translationY")
}
/**
@@ -469,6 +489,7 @@
lockscreenToGlanceableHubTransitionViewModel.notificationTranslationX,
glanceableHubToLockscreenTransitionViewModel.notificationTranslationX,
)
+ .dumpWhileCollecting("translationX")
/**
* When on keyguard, there is limited space to display notifications so calculate how many could
@@ -510,6 +531,7 @@
}
}
.distinctUntilChanged()
+ .dumpWhileCollecting("maxNotifications")
}
fun notificationStackChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
index 270b94b..23a080b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarterImpl.kt
@@ -45,8 +45,8 @@
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeController
-import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -71,7 +71,7 @@
private val biometricUnlockControllerLazy: Lazy<BiometricUnlockController>,
private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>,
private val shadeControllerLazy: Lazy<ShadeController>,
- private val shadeViewControllerLazy: Lazy<ShadeViewController>,
+ private val commandQueue: CommandQueue,
private val shadeAnimationInteractor: ShadeAnimationInteractor,
private val statusBarKeyguardViewManagerLazy: Lazy<StatusBarKeyguardViewManager>,
private val notifShadeWindowControllerLazy: Lazy<NotificationShadeWindowController>,
@@ -853,10 +853,11 @@
if (dismissShade) {
return StatusBarTransitionAnimatorController(
animationController,
- shadeViewControllerLazy.get(),
shadeAnimationInteractor,
shadeControllerLazy.get(),
notifShadeWindowControllerLazy.get(),
+ commandQueue,
+ displayId,
isLaunchForActivity
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 3669ba8..560d5ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -309,7 +309,7 @@
if (mVibrateOnOpening) {
vibrateOnNavigationKeyDown();
}
- mShadeViewController.expand(true /* animate */);
+ mShadeController.animateExpandShade();
mNotificationStackScrollLayoutController.setWillExpand(true);
mHeadsUpManager.unpinAll(true /* userUnpinned */);
mMetricsLogger.count("panel_open", 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index 68a0e9c..f29ec8f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -91,7 +91,7 @@
if (event.source == InputDevice.SOURCE_MOUSE) {
if (event.action == MotionEvent.ACTION_UP) {
v.performClick()
- shadeViewController.expand(/* animate= */ true)
+ shadeController.animateExpandShade()
}
return true
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 5610ed9..b5ab4e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -63,6 +63,7 @@
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeViewController;
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -105,6 +106,7 @@
private final NotificationVisibilityProvider mVisibilityProvider;
private final HeadsUpManager mHeadsUpManager;
private final ActivityStarter mActivityStarter;
+ private final CommandQueue mCommandQueue;
private final NotificationClickNotifier mClickNotifier;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final KeyguardManager mKeyguardManager;
@@ -143,6 +145,7 @@
NotificationVisibilityProvider visibilityProvider,
HeadsUpManager headsUpManager,
ActivityStarter activityStarter,
+ CommandQueue commandQueue,
NotificationClickNotifier clickNotifier,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
KeyguardManager keyguardManager,
@@ -175,6 +178,7 @@
mVisibilityProvider = visibilityProvider;
mHeadsUpManager = headsUpManager;
mActivityStarter = activityStarter;
+ mCommandQueue = commandQueue;
mClickNotifier = clickNotifier;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardManager = keyguardManager;
@@ -444,10 +448,11 @@
ActivityTransitionAnimator.Controller animationController =
new StatusBarTransitionAnimatorController(
mNotificationAnimationProvider.getAnimatorController(row, null),
- mShadeViewController,
mShadeAnimationInteractor,
mShadeController,
mNotificationShadeWindowController,
+ mCommandQueue,
+ mDisplayId,
isActivityIntent);
mActivityTransitionAnimator.startPendingIntentWithAnimation(
animationController,
@@ -486,10 +491,11 @@
ActivityTransitionAnimator.Controller animationController =
new StatusBarTransitionAnimatorController(
mNotificationAnimationProvider.getAnimatorController(row),
- mShadeViewController,
mShadeAnimationInteractor,
mShadeController,
mNotificationShadeWindowController,
+ mCommandQueue,
+ mDisplayId,
true /* isActivityIntent */);
mActivityTransitionAnimator.startIntentWithAnimation(
@@ -537,10 +543,11 @@
viewController == null ? null
: new StatusBarTransitionAnimatorController(
viewController,
- mShadeViewController,
mShadeAnimationInteractor,
mShadeController,
mNotificationShadeWindowController,
+ mCommandQueue,
+ mDisplayId,
true /* isActivityIntent */);
mActivityTransitionAnimator.startIntentWithAnimation(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt
index 7e907d8..705a11d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTransitionAnimatorController.kt
@@ -3,10 +3,13 @@
import android.view.View
import com.android.systemui.animation.ActivityTransitionAnimator
import com.android.systemui.animation.TransitionAnimator
+import com.android.systemui.animation.TransitionAnimator.Companion.getProgress
+import com.android.systemui.dagger.qualifiers.DisplayId
import com.android.systemui.shade.ShadeController
-import com.android.systemui.shade.ShadeViewController
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor
+import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment
/**
* A [ActivityTransitionAnimator.Controller] that takes care of collapsing the status bar at the
@@ -14,12 +17,15 @@
*/
class StatusBarTransitionAnimatorController(
private val delegate: ActivityTransitionAnimator.Controller,
- private val shadeViewController: ShadeViewController,
private val shadeAnimationInteractor: ShadeAnimationInteractor,
private val shadeController: ShadeController,
private val notificationShadeWindowController: NotificationShadeWindowController,
+ private val commandQueue: CommandQueue,
+ @DisplayId private val displayId: Int,
private val isLaunchForActivity: Boolean = true
) : ActivityTransitionAnimator.Controller by delegate {
+ private var hideIconsDuringLaunchAnimation: Boolean = true
+
// Always sync the opening window with the shade, given that we draw a hole punch in the shade
// of the same size and position as the opening app to make it visible.
override val openingWindowSyncView: View?
@@ -38,7 +44,7 @@
delegate.onTransitionAnimationStart(isExpandingFullyAbove)
shadeAnimationInteractor.setIsLaunchingActivity(true)
if (!isExpandingFullyAbove) {
- shadeViewController.collapseWithDuration(
+ shadeController.collapseWithDuration(
ActivityTransitionAnimator.TIMINGS.totalDuration.toInt()
)
}
@@ -56,7 +62,19 @@
linearProgress: Float
) {
delegate.onTransitionAnimationProgress(state, progress, linearProgress)
- shadeViewController.applyLaunchAnimationProgress(linearProgress)
+ val hideIcons =
+ getProgress(
+ ActivityTransitionAnimator.TIMINGS,
+ linearProgress,
+ ANIMATION_DELAY_ICON_FADE_IN,
+ 100
+ ) == 0.0f
+ if (hideIcons != hideIconsDuringLaunchAnimation) {
+ hideIconsDuringLaunchAnimation = hideIcons
+ if (!hideIcons) {
+ commandQueue.recomputeDisableFlags(displayId, true /* animate */)
+ }
+ }
}
override fun onTransitionAnimationCancelled(newKeyguardOccludedState: Boolean?) {
@@ -64,4 +82,12 @@
shadeAnimationInteractor.setIsLaunchingActivity(false)
shadeController.onLaunchAnimationCancelled(isLaunchForActivity)
}
+
+ companion object {
+ val ANIMATION_DELAY_ICON_FADE_IN =
+ (ActivityTransitionAnimator.TIMINGS.totalDuration -
+ CollapsedStatusBarFragment.FADE_IN_DURATION -
+ CollapsedStatusBarFragment.FADE_IN_DELAY -
+ 48)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index 31e7774..eae0467 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -169,6 +169,7 @@
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
+ powerInteractor = powerInteractor,
)
.apply { start() }
@@ -574,8 +575,9 @@
runCurrent()
// WHEN the device begins to wake
+ keyguardRepository.setKeyguardShowing(true)
powerInteractor.setAwakeForTest()
- runCurrent()
+ advanceTimeBy(60L)
assertThat(transitionRepository)
.startedTransition(
@@ -630,15 +632,42 @@
}
@Test
- fun dozingToGone() =
+ fun dozingToGoneWithUnlock() =
testScope.runTest {
// GIVEN a prior transition has run to DOZING
runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
+ runCurrent()
// WHEN biometrics succeeds with wake and unlock mode
+ powerInteractor.setAwakeForTest()
keyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+ advanceTimeBy(60L)
+
+ assertThat(transitionRepository)
+ .startedTransition(
+ to = KeyguardState.GONE,
+ from = KeyguardState.DOZING,
+ ownerName = "FromDozingTransitionInteractor",
+ animatorAssertion = { it.isNotNull() }
+ )
+
+ coroutineContext.cancelChildren()
+ }
+
+ /** This handles security method NONE and screen off with lock timeout */
+ @Test
+ fun dozingToGoneWithKeyguardNotShowing() =
+ testScope.runTest {
+ // GIVEN a prior transition has run to DOZING
+ runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.DOZING)
runCurrent()
+ // WHEN the device wakes up without a keyguard
+ keyguardRepository.setKeyguardShowing(false)
+ keyguardRepository.setKeyguardDismissible(true)
+ powerInteractor.setAwakeForTest()
+ advanceTimeBy(60L)
+
assertThat(transitionRepository)
.startedTransition(
to = KeyguardState.GONE,
@@ -666,8 +695,9 @@
runCurrent()
// WHEN the device begins to wake
+ keyguardRepository.setKeyguardShowing(true)
powerInteractor.setAwakeForTest()
- runCurrent()
+ advanceTimeBy(60L)
assertThat(transitionRepository)
.startedTransition(
@@ -1335,8 +1365,9 @@
// WHEN the keyguard is occluded and device wakes up
keyguardRepository.setKeyguardOccluded(true)
+ keyguardRepository.setKeyguardShowing(true)
powerInteractor.setAwakeForTest()
- runCurrent()
+ advanceTimeBy(60L)
// THEN a transition to OCCLUDED should occur
assertThat(transitionRepository)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
index 83932b0..dbfab64 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/ActivityTaskManagerTasksRepositoryTest.kt
@@ -49,6 +49,19 @@
)
@Test
+ fun launchRecentTask_taskIsMovedToForeground() =
+ testScope.runTest {
+ val currentForegroundTask by collectLastValue(repo.foregroundTask)
+ val newForegroundTask = createTask(taskId = 1)
+ val backgroundTask = createTask(taskId = 2)
+ fakeActivityTaskManager.addRunningTasks(backgroundTask, newForegroundTask)
+
+ repo.launchRecentTask(newForegroundTask)
+
+ assertThat(currentForegroundTask).isEqualTo(newForegroundTask)
+ }
+
+ @Test
fun findRunningTaskFromWindowContainerToken_noMatch_returnsNull() {
fakeActivityTaskManager.addRunningTasks(createTask(taskId = 1), createTask(taskId = 2))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
index 1c4870b..920e5ee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeActivityTaskManager.kt
@@ -17,7 +17,7 @@
package com.android.systemui.mediaprojection.taskswitcher.data.repository
import android.app.ActivityManager.RunningTaskInfo
-import android.app.ActivityTaskManager
+import android.app.IActivityTaskManager
import android.app.TaskStackListener
import android.content.Intent
import android.window.IWindowContainerToken
@@ -31,7 +31,7 @@
private val runningTasks = mutableListOf<RunningTaskInfo>()
private val taskTaskListeners = mutableListOf<TaskStackListener>()
- val activityTaskManager = mock<ActivityTaskManager>()
+ val activityTaskManager = mock<IActivityTaskManager>()
init {
whenever(activityTaskManager.registerTaskStackListener(any())).thenAnswer {
@@ -42,10 +42,20 @@
taskTaskListeners -= it.arguments[0] as TaskStackListener
return@thenAnswer Unit
}
- whenever(activityTaskManager.getTasks(any())).thenAnswer {
+ whenever(activityTaskManager.getTasks(any(), any(), any(), any())).thenAnswer {
val maxNumTasks = it.arguments[0] as Int
return@thenAnswer runningTasks.take(maxNumTasks)
}
+ whenever(activityTaskManager.startActivityFromRecents(any(), any())).thenAnswer {
+ val taskId = it.arguments[0] as Int
+ val runningTask = runningTasks.find { runningTask -> runningTask.taskId == taskId }
+ if (runningTask != null) {
+ moveTaskToForeground(runningTask)
+ return@thenAnswer 0
+ } else {
+ return@thenAnswer -1
+ }
+ }
}
fun moveTaskToForeground(task: RunningTaskInfo) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
index 44c411f..28393e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/FakeMediaProjectionManager.kt
@@ -22,6 +22,8 @@
import android.os.IBinder
import android.os.UserHandle
import android.view.ContentRecordingSession
+import android.window.WindowContainerToken
+import com.android.systemui.mediaprojection.MediaProjectionServiceHelper
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -29,6 +31,7 @@
class FakeMediaProjectionManager {
val mediaProjectionManager = mock<MediaProjectionManager>()
+ val helper = mock<MediaProjectionServiceHelper>()
private val callbacks = mutableListOf<MediaProjectionManager.Callback>()
@@ -41,6 +44,11 @@
callbacks -= it.arguments[0] as MediaProjectionManager.Callback
return@thenAnswer Unit
}
+ whenever(helper.updateTaskRecordingSession(any())).thenAnswer {
+ val token = it.arguments[0] as WindowContainerToken
+ dispatchOnSessionSet(session = createSingleTaskSession(token.asBinder()))
+ return@thenAnswer true
+ }
}
fun dispatchOnStart(info: MediaProjectionInfo = DEFAULT_INFO) {
@@ -61,6 +69,7 @@
companion object {
fun createDisplaySession(): ContentRecordingSession =
ContentRecordingSession.createDisplaySession(/* displayToMirror = */ 123)
+
fun createSingleTaskSession(token: IBinder = Binder()): ContentRecordingSession =
ContentRecordingSession.createTaskSession(token)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
index 7bd97ce..fdd434a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/data/repository/MediaProjectionManagerRepositoryTest.kt
@@ -28,9 +28,8 @@
import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createToken
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -40,7 +39,7 @@
@SmallTest
class MediaProjectionManagerRepositoryTest : SysuiTestCase() {
- private val dispatcher = StandardTestDispatcher()
+ private val dispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(dispatcher)
private val fakeMediaProjectionManager = FakeMediaProjectionManager()
@@ -58,14 +57,27 @@
mediaProjectionManager = fakeMediaProjectionManager.mediaProjectionManager,
handler = Handler.getMain(),
applicationScope = testScope.backgroundScope,
- tasksRepository = tasksRepo
+ tasksRepository = tasksRepo,
+ backgroundDispatcher = dispatcher,
+ mediaProjectionServiceHelper = fakeMediaProjectionManager.helper
)
@Test
+ fun switchProjectedTask_stateIsUpdatedWithNewTask() =
+ testScope.runTest {
+ val task = createTask(taskId = 1)
+ val state by collectLastValue(repo.mediaProjectionState)
+
+ fakeActivityTaskManager.addRunningTasks(task)
+ repo.switchProjectedTask(task)
+
+ assertThat(state).isEqualTo(MediaProjectionState.SingleTask(task))
+ }
+
+ @Test
fun mediaProjectionState_onStart_emitsNotProjecting() =
testScope.runTest {
val state by collectLastValue(repo.mediaProjectionState)
- runCurrent()
fakeMediaProjectionManager.dispatchOnStart()
@@ -76,7 +88,6 @@
fun mediaProjectionState_onStop_emitsNotProjecting() =
testScope.runTest {
val state by collectLastValue(repo.mediaProjectionState)
- runCurrent()
fakeMediaProjectionManager.dispatchOnStop()
@@ -87,7 +98,6 @@
fun mediaProjectionState_onSessionSet_sessionNull_emitsNotProjecting() =
testScope.runTest {
val state by collectLastValue(repo.mediaProjectionState)
- runCurrent()
fakeMediaProjectionManager.dispatchOnSessionSet(session = null)
@@ -98,7 +108,6 @@
fun mediaProjectionState_onSessionSet_contentToRecordDisplay_emitsEntireScreen() =
testScope.runTest {
val state by collectLastValue(repo.mediaProjectionState)
- runCurrent()
fakeMediaProjectionManager.dispatchOnSessionSet(
session = ContentRecordingSession.createDisplaySession(/* displayToMirror= */ 123)
@@ -111,7 +120,6 @@
fun mediaProjectionState_sessionSet_taskWithToken_noMatchingRunningTask_emitsEntireScreen() =
testScope.runTest {
val state by collectLastValue(repo.mediaProjectionState)
- runCurrent()
val taskWindowContainerToken = Binder()
fakeMediaProjectionManager.dispatchOnSessionSet(
@@ -128,7 +136,6 @@
val task = createTask(taskId = 1, token = token)
fakeActivityTaskManager.addRunningTasks(task)
val state by collectLastValue(repo.mediaProjectionState)
- runCurrent()
fakeMediaProjectionManager.dispatchOnSessionSet(
session = ContentRecordingSession.createTaskSession(token.asBinder())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
index b2ebe1bc..dfb688b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/domain/interactor/TaskSwitchInteractorTest.kt
@@ -61,6 +61,8 @@
handler = Handler.getMain(),
applicationScope = testScope.backgroundScope,
tasksRepository = tasksRepo,
+ backgroundDispatcher = dispatcher,
+ mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
)
private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
@@ -118,6 +120,40 @@
}
@Test
+ fun taskSwitchChanges_projectingTask_foregroundTaskDifferent_thenSwitched_emitsUnchanged() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1)
+ val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(token = projectedTask.token.asBinder())
+ )
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+ interactor.switchProjectedTask(foregroundTask)
+
+ assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
+ }
+
+ @Test
+ fun taskSwitchChanges_projectingTask_foregroundTaskDifferent_thenWentBack_emitsUnchanged() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 0)
+ val foregroundTask = createTask(taskId = 1)
+ val taskSwitchState by collectLastValue(interactor.taskSwitchChanges)
+
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(token = projectedTask.token.asBinder())
+ )
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+ interactor.goBackToTask(projectedTask)
+
+ assertThat(taskSwitchState).isEqualTo(TaskSwitchState.TaskUnchanged)
+ }
+
+ @Test
fun taskSwitchChanges_projectingTask_foregroundTaskLauncher_emitsTaskUnchanged() =
testScope.runTest {
val projectedTask = createTask(taskId = 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
index d0c6d7c..c4e9393 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/TaskSwitcherNotificationCoordinatorTest.kt
@@ -21,14 +21,15 @@
import android.os.Handler
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
-import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.mediaprojection.taskswitcher.data.repository.ActivityTaskManagerTasksRepository
import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager
+import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeActivityTaskManager.Companion.createTask
import com.android.systemui.mediaprojection.taskswitcher.data.repository.FakeMediaProjectionManager
import com.android.systemui.mediaprojection.taskswitcher.data.repository.MediaProjectionManagerRepository
import com.android.systemui.mediaprojection.taskswitcher.domain.interactor.TaskSwitchInteractor
import com.android.systemui.mediaprojection.taskswitcher.ui.viewmodel.TaskSwitcherNotificationViewModel
+import com.android.systemui.res.R
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
@@ -42,6 +43,7 @@
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
@OptIn(ExperimentalCoroutinesApi::class)
@@ -49,7 +51,7 @@
@SmallTest
class TaskSwitcherNotificationCoordinatorTest : SysuiTestCase() {
- private val notificationManager: NotificationManager = mock()
+ private val notificationManager = mock<NotificationManager>()
private val dispatcher = UnconfinedTestDispatcher()
private val testScope = TestScope(dispatcher)
@@ -70,22 +72,26 @@
handler = Handler.getMain(),
applicationScope = testScope.backgroundScope,
tasksRepository = tasksRepo,
+ backgroundDispatcher = dispatcher,
+ mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
)
private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
- private val viewModel = TaskSwitcherNotificationViewModel(interactor)
+ private val viewModel =
+ TaskSwitcherNotificationViewModel(interactor, backgroundDispatcher = dispatcher)
- private val coordinator =
- TaskSwitcherNotificationCoordinator(
- context,
- notificationManager,
- testScope.backgroundScope,
- dispatcher,
- viewModel
- )
+ private lateinit var coordinator: TaskSwitcherNotificationCoordinator
@Before
fun setup() {
+ coordinator =
+ TaskSwitcherNotificationCoordinator(
+ context,
+ notificationManager,
+ testScope.backgroundScope,
+ viewModel,
+ fakeBroadcastDispatcher,
+ )
coordinator.start()
}
@@ -105,7 +111,7 @@
testScope.runTest {
fakeMediaProjectionManager.dispatchOnStop()
- verify(notificationManager).cancel(any())
+ verify(notificationManager).cancel(any(), any())
}
}
@@ -114,7 +120,7 @@
testScope.runTest {
fakeMediaProjectionManager.dispatchOnStop()
val idCancel = argumentCaptor<Int>()
- verify(notificationManager).cancel(idCancel.capture())
+ verify(notificationManager).cancel(any(), idCancel.capture())
switchTask()
val idNotify = argumentCaptor<Int>()
@@ -124,9 +130,55 @@
}
}
+ @Test
+ fun switchTaskAction_hidesNotification() =
+ testScope.runTest {
+ switchTask()
+ val notification = argumentCaptor<Notification>()
+ verify(notificationManager).notify(any(), any(), notification.capture())
+ verify(notificationManager, never()).cancel(any(), any())
+
+ val action = findSwitchAction(notification.value)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ action.actionIntent.intent
+ )
+
+ verify(notificationManager).cancel(any(), any())
+ }
+
+ @Test
+ fun goBackAction_hidesNotification() =
+ testScope.runTest {
+ switchTask()
+ val notification = argumentCaptor<Notification>()
+ verify(notificationManager).notify(any(), any(), notification.capture())
+ verify(notificationManager, never()).cancel(any(), any())
+
+ val action = findGoBackAction(notification.value)
+ fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+ context,
+ action.actionIntent.intent
+ )
+
+ verify(notificationManager).cancel(any(), any())
+ }
+
+ private fun findSwitchAction(notification: Notification): Notification.Action {
+ return notification.actions.first {
+ it.title == context.getString(R.string.media_projection_task_switcher_action_switch)
+ }
+ }
+
+ private fun findGoBackAction(notification: Notification): Notification.Action {
+ return notification.actions.first {
+ it.title == context.getString(R.string.media_projection_task_switcher_action_back)
+ }
+ }
+
private fun switchTask() {
- val projectedTask = FakeActivityTaskManager.createTask(taskId = 1)
- val foregroundTask = FakeActivityTaskManager.createTask(taskId = 2)
+ val projectedTask = createTask(taskId = 1)
+ val foregroundTask = createTask(taskId = 2)
fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
fakeMediaProjectionManager.dispatchOnSessionSet(
session =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
index 7d38de4..5dadf21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/taskswitcher/ui/viewmodel/TaskSwitcherNotificationViewModelTest.kt
@@ -63,11 +63,14 @@
handler = Handler.getMain(),
applicationScope = testScope.backgroundScope,
tasksRepository = tasksRepo,
+ backgroundDispatcher = dispatcher,
+ mediaProjectionServiceHelper = fakeMediaProjectionManager.helper,
)
private val interactor = TaskSwitchInteractor(mediaRepo, tasksRepo)
- private val viewModel = TaskSwitcherNotificationViewModel(interactor)
+ private val viewModel =
+ TaskSwitcherNotificationViewModel(interactor, backgroundDispatcher = dispatcher)
@Test
fun uiState_notProjecting_emitsNotShowing() =
@@ -135,6 +138,40 @@
}
@Test
+ fun uiState_projectingTask_foregroundTaskChanged_thenTaskSwitched_emitsNotShowing() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 1)
+ val foregroundTask = createTask(taskId = 2)
+ val uiState by collectLastValue(viewModel.uiState)
+
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(projectedTask.token.asBinder())
+ )
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+ viewModel.onSwitchTaskClicked(foregroundTask)
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ @Test
+ fun uiState_projectingTask_foregroundTaskChanged_thenGoBack_emitsNotShowing() =
+ testScope.runTest {
+ val projectedTask = createTask(taskId = 1)
+ val foregroundTask = createTask(taskId = 2)
+ val uiState by collectLastValue(viewModel.uiState)
+
+ fakeActivityTaskManager.addRunningTasks(projectedTask, foregroundTask)
+ fakeMediaProjectionManager.dispatchOnSessionSet(
+ session = createSingleTaskSession(projectedTask.token.asBinder())
+ )
+ fakeActivityTaskManager.moveTaskToForeground(foregroundTask)
+ viewModel.onGoBackToTaskClicked(projectedTask)
+
+ assertThat(uiState).isEqualTo(TaskSwitcherNotificationUiState.NotShowing)
+ }
+
+ @Test
fun uiState_projectingTask_foregroundTaskChanged_same_emitsNotShowing() =
testScope.runTest {
val projectedTask = createTask(taskId = 1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index 3792d5c..443dd6a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -234,21 +234,16 @@
}
@Test
- fun shadeIsExpandedOnStatusIconClick() {
+ fun shadeIsExpandedOnStatusIconMouseClick() {
val view = createViewMock()
InstrumentationRegistry.getInstrumentation().runOnMainSync {
controller = createAndInitController(view)
}
val statusContainer = view.requireViewById<View>(R.id.system_icons)
statusContainer.dispatchTouchEvent(
- getMotionEventFromSource(
- MotionEvent.ACTION_UP,
- 0,
- 0,
- InputDevice.SOURCE_MOUSE
- )
+ getActionUpEventFromSource(InputDevice.SOURCE_MOUSE)
)
- verify(shadeViewController).expand(any())
+ verify(shadeControllerImpl).animateExpandShade()
}
@Test
@@ -259,18 +254,13 @@
}
val statusContainer = view.requireViewById<View>(R.id.system_icons)
val handled = statusContainer.dispatchTouchEvent(
- getMotionEventFromSource(
- MotionEvent.ACTION_UP,
- 0,
- 0,
- InputDevice.SOURCE_TOUCHSCREEN
- )
+ getActionUpEventFromSource(InputDevice.SOURCE_TOUCHSCREEN)
)
assertThat(handled).isFalse()
}
- private fun getMotionEventFromSource(action: Int, x: Int, y: Int, source: Int): MotionEvent {
- val ev = MotionEvent.obtain(0, 0, action, x.toFloat(), y.toFloat(), 0)
+ private fun getActionUpEventFromSource(source: Int): MotionEvent {
+ val ev = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0f, 0f, 0)
ev.source = source
return ev
}
@@ -282,7 +272,7 @@
controller = createAndInitController(view)
}
view.performClick()
- verify(shadeViewController, never()).expand(any())
+ verify(shadeControllerImpl, never()).animateExpandShade()
}
private fun getCommandQueueCallback(): CommandQueue.Callbacks {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 41514ce..938b2f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -79,6 +79,7 @@
import com.android.systemui.shade.data.repository.FakeShadeRepository;
import com.android.systemui.shade.data.repository.ShadeAnimationRepository;
import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractorLegacyImpl;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -130,6 +131,8 @@
@Mock
private ActivityStarter mActivityStarter;
@Mock
+ private CommandQueue mCommandQueue;
+ @Mock
private NotificationClickNotifier mClickNotifier;
@Mock
private StatusBarStateController mStatusBarStateController;
@@ -236,6 +239,7 @@
mVisibilityProvider,
headsUpManager,
mActivityStarter,
+ mCommandQueue,
mClickNotifier,
mStatusBarKeyguardViewManager,
mock(KeyguardManager.class),
@@ -257,7 +261,9 @@
mock(NotificationShadeWindowController.class),
mActivityTransitionAnimator,
new ShadeAnimationInteractorLegacyImpl(
- new ShadeAnimationRepository(), new FakeShadeRepository()),
+ new ShadeAnimationRepository(),
+ new FakeShadeRepository()
+ ),
notificationAnimationProvider,
mock(LaunchFullScreenIntentProvider.class),
mPowerInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
index da5cd67..2477415 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorKosmos.kt
@@ -20,6 +20,7 @@
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.domain.interactor.powerInteractor
val Kosmos.fromAodTransitionInteractor by
Kosmos.Fixture {
@@ -30,5 +31,6 @@
bgDispatcher = testDispatcher,
mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
+ powerInteractor = powerInteractor,
)
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
index 8ca53e6..d5d357f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelKosmos.kt
@@ -39,7 +39,9 @@
keyguardTransitionInteractor = keyguardTransitionInteractor,
notificationsKeyguardInteractor = notificationsKeyguardInteractor,
alternateBouncerToGoneTransitionViewModel = alternateBouncerToGoneTransitionViewModel,
+ aodToGoneTransitionViewModel = aodToGoneTransitionViewModel,
aodToLockscreenTransitionViewModel = aodToLockscreenTransitionViewModel,
+ dozingToGoneTransitionViewModel = dozingToGoneTransitionViewModel,
dozingToLockscreenTransitionViewModel = dozingToLockscreenTransitionViewModel,
glanceableHubToLockscreenTransitionViewModel = glanceableHubToLockscreenTransitionViewModel,
goneToAodTransitionViewModel = goneToAodTransitionViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt
index d79633a..bada2a6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModelKosmos.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
+import com.android.systemui.dump.dumpManager
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -24,6 +25,7 @@
val Kosmos.notificationStackAppearanceViewModel by Fixture {
NotificationStackAppearanceViewModel(
+ dumpManager = dumpManager,
stackAppearanceInteractor = notificationStackAppearanceInteractor,
shadeInteractor = shadeInteractor,
sceneInteractor = sceneInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
index 832344d..106e85c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelKosmos.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.dump.dumpManager
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerToGoneTransitionViewModel
@@ -48,6 +49,7 @@
val Kosmos.sharedNotificationContainerViewModel by Fixture {
SharedNotificationContainerViewModel(
interactor = sharedNotificationContainerInteractor,
+ dumpManager = dumpManager,
applicationScope = applicationCoroutineScope,
keyguardInteractor = keyguardInteractor,
keyguardTransitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
index 41c11ad6..7a86c4f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterKosmos.kt
@@ -33,6 +33,7 @@
import com.android.systemui.shade.domain.interactor.shadeAnimationInteractor
import com.android.systemui.shade.shadeController
import com.android.systemui.shade.shadeViewController
+import com.android.systemui.statusbar.commandQueue
import com.android.systemui.statusbar.notification.collection.provider.launchFullScreenIntentProvider
import com.android.systemui.statusbar.notification.collection.render.notificationVisibilityProvider
import com.android.systemui.statusbar.notification.notificationTransitionAnimatorControllerProvider
@@ -59,6 +60,7 @@
notificationVisibilityProvider,
headsUpManager,
activityStarter,
+ commandQueue,
notificationClickNotifier,
statusBarKeyguardViewManager,
keyguardManager,
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 6ca60be..f31eb44 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -39,9 +39,7 @@
import android.content.SharedPreferences;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
-import android.graphics.Point;
import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -51,22 +49,16 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
-import android.view.Display;
-import android.view.DisplayInfo;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
-import com.android.modules.utils.TypedXmlPullParser;
-import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -110,9 +102,6 @@
@VisibleForTesting
static final String WALLPAPER_INFO_STAGE = "wallpaper-info-stage";
- @VisibleForTesting
- static final String WALLPAPER_BACKUP_DEVICE_INFO_STAGE = "wallpaper-backup-device-info-stage";
-
static final String EMPTY_SENTINEL = "empty";
static final String QUOTA_SENTINEL = "quota";
@@ -121,11 +110,6 @@
static final String SYSTEM_GENERATION = "system_gen";
static final String LOCK_GENERATION = "lock_gen";
- /**
- * An approximate area threshold to compare device dimension similarity
- */
- static final int AREA_THRESHOLD = 50; // TODO: determine appropriate threshold
-
// If this file exists, it means we exceeded our quota last time
private File mQuotaFile;
private boolean mQuotaExceeded;
@@ -137,8 +121,6 @@
private boolean mSystemHasLiveComponent;
private boolean mLockHasLiveComponent;
- private DisplayManager mDisplayManager;
-
@Override
public void onCreate() {
if (DEBUG) {
@@ -155,8 +137,6 @@
mBackupManager = new BackupManager(getBaseContext());
mEventLogger = new WallpaperEventLogger(mBackupManager, /* wallpaperAgent */ this);
-
- mDisplayManager = getSystemService(DisplayManager.class);
}
@Override
@@ -195,7 +175,6 @@
mSystemHasLiveComponent = mWallpaperManager.getWallpaperInfo(FLAG_SYSTEM) != null;
mLockHasLiveComponent = mWallpaperManager.getWallpaperInfo(FLAG_LOCK) != null;
- backupDeviceInfoFile(data);
backupWallpaperInfoFile(/* sysOrLockChanged= */ sysChanged || lockChanged, data);
backupSystemWallpaperFile(sharedPrefs, sysChanged, sysGeneration, data);
backupLockWallpaperFileIfItExists(sharedPrefs, lockChanged, lockGeneration, data);
@@ -212,50 +191,6 @@
}
}
- /**
- * This method backs up the device dimension information. The device data will always get
- * overwritten when triggering a backup
- */
- private void backupDeviceInfoFile(FullBackupDataOutput data)
- throws IOException {
- final File deviceInfoStage = new File(getFilesDir(), WALLPAPER_BACKUP_DEVICE_INFO_STAGE);
-
- // save the dimensions of the device with xml formatting
- Point dimensions = getScreenDimensions();
- Point secondaryDimensions = getRealSize(getSmallerDisplay());
-
- deviceInfoStage.createNewFile();
- FileOutputStream fstream = new FileOutputStream(deviceInfoStage, false);
- TypedXmlSerializer out = Xml.resolveSerializer(fstream);
- out.startDocument(null, true);
- out.startTag(null, "dimensions");
-
- out.startTag(null, "width");
- out.text(String.valueOf(dimensions.x));
- out.endTag(null, "width");
-
- out.startTag(null, "height");
- out.text(String.valueOf(dimensions.y));
- out.endTag(null, "height");
-
- out.startTag(null, "secondarywidth");
- out.text(String.valueOf(secondaryDimensions != null ? secondaryDimensions.x : 0));
- out.endTag(null, "secondarywidth");
-
- out.startTag(null, "secondaryheight");
- out.text(String.valueOf(secondaryDimensions != null ? secondaryDimensions.y : 0));
- out.endTag(null, "secondaryheight");
-
- out.endTag(null, "dimensions");
- out.endDocument();
- fstream.flush();
- FileUtils.sync(fstream);
- fstream.close();
-
- if (DEBUG) Slog.v(TAG, "Storing device dimension data");
- backupFile(deviceInfoStage, data);
- }
-
private void backupWallpaperInfoFile(boolean sysOrLockChanged, FullBackupDataOutput data)
throws IOException {
final ParcelFileDescriptor wallpaperInfoFd = mWallpaperManager.getWallpaperInfoFile();
@@ -429,22 +364,9 @@
final File infoStage = new File(filesDir, WALLPAPER_INFO_STAGE);
final File imageStage = new File(filesDir, SYSTEM_WALLPAPER_STAGE);
final File lockImageStage = new File(filesDir, LOCK_WALLPAPER_STAGE);
- final File deviceDimensionsStage = new File(filesDir, WALLPAPER_BACKUP_DEVICE_INFO_STAGE);
boolean lockImageStageExists = lockImageStage.exists();
try {
- // Parse the device dimensions of the source device and compare with target to
- // to identify whether we need to skip the remainder of the restore process
- Pair<Point, Point> sourceDeviceDimensions = parseDeviceDimensions(
- deviceDimensionsStage);
-
- Point targetDeviceDimensions = getScreenDimensions();
- if (sourceDeviceDimensions != null
- && isSourceDeviceSignificantlySmallerThanTarget(sourceDeviceDimensions.first,
- targetDeviceDimensions)) {
- Slog.d(TAG, "The source device is significantly smaller than target");
- }
-
// First parse the live component name so that we know for logging if we care about
// logging errors with the image restore.
ComponentName wpService = parseWallpaperComponent(infoStage, "wp");
@@ -478,7 +400,6 @@
infoStage.delete();
imageStage.delete();
lockImageStage.delete();
- deviceDimensionsStage.delete();
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
prefs.edit()
@@ -488,66 +409,6 @@
}
}
- /**
- * This method parses the given file for the backed up device dimensions
- *
- * @param deviceDimensions the file which holds the device dimensions
- * @return the backed up device dimensions
- */
- private Pair<Point, Point> parseDeviceDimensions(File deviceDimensions) {
- int width = 0, height = 0, secondaryHeight = 0, secondaryWidth = 0;
- try {
- TypedXmlPullParser parser = Xml.resolvePullParser(
- new FileInputStream(deviceDimensions));
-
- while (parser.next() != XmlPullParser.END_TAG) {
- if (parser.getEventType() != XmlPullParser.START_TAG) {
- continue;
- }
-
- String name = parser.getName();
-
- switch (name) {
- case "width":
- String widthText = readText(parser);
- width = Integer.valueOf(widthText);
- break;
-
- case "height":
- String textHeight = readText(parser);
- height = Integer.valueOf(textHeight);
- break;
-
- case "secondarywidth":
- String secondaryWidthText = readText(parser);
- secondaryWidth = Integer.valueOf(secondaryWidthText);
- break;
-
- case "secondaryheight":
- String secondaryHeightText = readText(parser);
- secondaryHeight = Integer.valueOf(secondaryHeightText);
- break;
- default:
- break;
- }
- }
- return new Pair<>(new Point(width, height), new Point(secondaryWidth, secondaryHeight));
-
- } catch (Exception e) {
- return null;
- }
- }
-
- private static String readText(TypedXmlPullParser parser)
- throws IOException, XmlPullParserException {
- String result = "";
- if (parser.next() == XmlPullParser.TEXT) {
- result = parser.getText();
- parser.nextTag();
- }
- return result;
- }
-
@VisibleForTesting
void updateWallpaperComponent(ComponentName wpService, int which)
throws IOException {
@@ -639,7 +500,6 @@
mEventLogger.onLockImageWallpaperRestoreFailed(error);
}
}
-
private Rect parseCropHint(File wallpaperInfo, String sectionTag) {
Rect cropHint = new Rect();
try (FileInputStream stream = new FileInputStream(wallpaperInfo)) {
@@ -677,7 +537,7 @@
if (type != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
if (!sectionTag.equals(tag)) continue;
- for (Pair<Integer, String> pair : List.of(
+ for (Pair<Integer, String> pair: List.of(
new Pair<>(WallpaperManager.PORTRAIT, "Portrait"),
new Pair<>(WallpaperManager.LANDSCAPE, "Landscape"),
new Pair<>(WallpaperManager.SQUARE_PORTRAIT, "SquarePortrait"),
@@ -831,94 +691,6 @@
};
}
- /**
- * This method retrieves the dimensions of the largest display of the device
- *
- * @return a @{Point} object that contains the dimensions of the largest display on the device
- */
- private Point getScreenDimensions() {
- Point largetDimensions = null;
- int maxArea = 0;
-
- for (Display display : getInternalDisplays()) {
- Point displaySize = getRealSize(display);
-
- int width = displaySize.x;
- int height = displaySize.y;
- int area = width * height;
-
- if (area > maxArea) {
- maxArea = area;
- largetDimensions = displaySize;
- }
- }
-
- return largetDimensions;
- }
-
- private Point getRealSize(Display display) {
- DisplayInfo displayInfo = new DisplayInfo();
- display.getDisplayInfo(displayInfo);
- return new Point(displayInfo.logicalWidth, displayInfo.logicalHeight);
- }
-
- /**
- * This method returns the smaller display on a multi-display device
- *
- * @return Display that corresponds to the smaller display on a device or null if ther is only
- * one Display on a device
- */
- private Display getSmallerDisplay() {
- List<Display> internalDisplays = getInternalDisplays();
- Point largestDisplaySize = getScreenDimensions();
-
- // Find the first non-matching internal display
- for (Display display : internalDisplays) {
- Point displaySize = getRealSize(display);
- if (displaySize.x != largestDisplaySize.x || displaySize.y != largestDisplaySize.y) {
- return display;
- }
- }
-
- // If no smaller display found, return null, as there is only a single display
- return null;
- }
-
- /**
- * This method retrieves the collection of Display objects available in the device.
- * i.e. non-external displays are ignored
- *
- * @return list of displays corresponding to each display in the device
- */
- private List<Display> getInternalDisplays() {
- Display[] allDisplays = mDisplayManager.getDisplays(
- DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
-
- List<Display> internalDisplays = new ArrayList<>();
- for (Display display : allDisplays) {
- if (display.getType() == Display.TYPE_INTERNAL) {
- internalDisplays.add(display);
- }
- }
- return internalDisplays;
- }
-
- /**
- * This method compares the source and target dimensions, and returns true if there is a
- * significant difference in area between them and the source dimensions are smaller than the
- * target dimensions.
- *
- * @param sourceDimensions is the dimensions of the source device
- * @param targetDimensions is the dimensions of the target device
- */
- @VisibleForTesting
- boolean isSourceDeviceSignificantlySmallerThanTarget(Point sourceDimensions,
- Point targetDimensions) {
- int rawAreaDelta = (targetDimensions.x * targetDimensions.y)
- - (sourceDimensions.x * sourceDimensions.y);
- return rawAreaDelta > AREA_THRESHOLD;
- }
-
@VisibleForTesting
boolean isDeviceInRestore() {
try {
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
index 79e7bf0..3ecdf3f 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/WallpaperBackupAgentTest.java
@@ -59,7 +59,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
@@ -677,7 +676,7 @@
mWallpaperBackupAgent.onRestoreFinished();
- for (String wallpaper : List.of(WALLPAPER_IMG_LOCK, WALLPAPER_IMG_SYSTEM)) {
+ for (String wallpaper: List.of(WALLPAPER_IMG_LOCK, WALLPAPER_IMG_SYSTEM)) {
DataTypeResult result = getLoggingResult(wallpaper,
mWallpaperBackupAgent.getBackupRestoreEventLogger().getLoggingResults());
assertThat(result).isNotNull();
@@ -841,26 +840,6 @@
testParseCropHints(testMap);
}
- @Test
- public void test_sourceDimensionsAreLargerThanTarget() {
- // source device is larger than target, expecting to get false
- Point sourceDimensions = new Point(2208, 1840);
- Point targetDimensions = new Point(1080, 2092);
- boolean isSourceSmaller = mWallpaperBackupAgent
- .isSourceDeviceSignificantlySmallerThanTarget(sourceDimensions, targetDimensions);
- assertThat(isSourceSmaller).isEqualTo(false);
- }
-
- @Test
- public void test_sourceDimensionsMuchSmallerThanTarget() {
- // source device is smaller than target, expecting to get true
- Point sourceDimensions = new Point(1080, 2092);
- Point targetDimensions = new Point(2208, 1840);
- boolean isSourceSmaller = mWallpaperBackupAgent
- .isSourceDeviceSignificantlySmallerThanTarget(sourceDimensions, targetDimensions);
- assertThat(isSourceSmaller).isEqualTo(true);
- }
-
private void testParseCropHints(Map<Integer, Rect> testMap) throws Exception {
assumeTrue(multiCrop());
mockRestoredStaticWallpaperFile(testMap);
@@ -955,7 +934,7 @@
TypedXmlSerializer out = Xml.resolveSerializer(fstream);
out.startDocument(null, true);
out.startTag(null, "wp");
- for (Map.Entry<Integer, Rect> entry : crops.entrySet()) {
+ for (Map.Entry<Integer, Rect> entry: crops.entrySet()) {
String orientation = switch (entry.getKey()) {
case WallpaperManager.PORTRAIT -> "Portrait";
case WallpaperManager.LANDSCAPE -> "Landscape";
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 19dd7b7..d4f04b5 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3713,7 +3713,7 @@
&& AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
- Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
+ Log.d(TAG, "adjustStreamVolume: postSetAvrcpAbsoluteVolumeIndex index="
+ newIndex + "stream=" + streamType);
}
mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(newIndex / 10);
@@ -3727,7 +3727,7 @@
&& streamType == getBluetoothContextualVolumeStream()
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
- Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
+ Log.d(TAG, "adjustStreamVolume postSetLeAudioVolumeIndex index="
+ newIndex + " stream=" + streamType);
}
mDeviceBroker.postSetLeAudioVolumeIndex(newIndex,
@@ -3740,7 +3740,7 @@
// the one expected by the hearing aid
if (streamType == getBluetoothContextualVolumeStream()) {
if (DEBUG_VOL) {
- Log.d(TAG, "adjustSreamVolume postSetHearingAidVolumeIndex index="
+ Log.d(TAG, "adjustStreamVolume postSetHearingAidVolumeIndex index="
+ newIndex + " stream=" + streamType);
}
mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType);
@@ -4722,7 +4722,7 @@
&& streamType == getBluetoothContextualVolumeStream()
&& (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
if (DEBUG_VOL) {
- Log.d(TAG, "adjustSreamVolume postSetLeAudioVolumeIndex index="
+ Log.d(TAG, "setStreamVolume postSetLeAudioVolumeIndex index="
+ index + " stream=" + streamType);
}
mDeviceBroker.postSetLeAudioVolumeIndex(index, mStreamStates[streamType].getMaxIndex(),
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index fb4976d..b2a738f 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -463,12 +463,6 @@
boolean userChangedAutoBrightnessAdjustment, int displayPolicy,
boolean shouldResetShortTermModel) {
mState = state;
- // While dozing, the application processor may be suspended which will prevent us from
- // receiving new information from the light sensor. On some devices, we may be able to
- // switch to a wake-up light sensor instead but for now we will simply disable the sensor
- // and hold onto the last computed screen auto brightness. We save the dozing flag for
- // debugging purposes.
- boolean dozing = (displayPolicy == DisplayPowerRequest.POLICY_DOZE);
boolean changed = setBrightnessConfiguration(configuration, shouldResetShortTermModel);
changed |= setDisplayPolicy(displayPolicy);
if (userChangedAutoBrightnessAdjustment) {
@@ -482,10 +476,10 @@
}
final boolean userInitiatedChange =
userChangedBrightness || userChangedAutoBrightnessAdjustment;
- if (userInitiatedChange && enable && !dozing) {
+ if (userInitiatedChange && enable) {
prepareBrightnessAdjustmentSample();
}
- changed |= setLightSensorEnabled(enable && !dozing);
+ changed |= setLightSensorEnabled(enable);
if (mIsBrightnessThrottled != mBrightnessThrottler.isThrottled()) {
// Maximum brightness has changed, so recalculate display brightness.
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 76f3035..2010aca 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1485,8 +1485,7 @@
}
// Use default brightness when dozing unless overridden.
- if ((Float.isNaN(brightnessState))
- && Display.isDozeState(state)) {
+ if (Float.isNaN(brightnessState) && mPowerRequest.policy == POLICY_DOZE) {
rawBrightnessState = mScreenBrightnessDozeConfig;
brightnessState = clampScreenBrightness(rawBrightnessState);
mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 8eaecef..d1ca49b 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -15,6 +15,8 @@
*/
package com.android.server.display.brightness.strategy;
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.display.BrightnessConfiguration;
@@ -102,8 +104,7 @@
boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
final boolean autoBrightnessEnabledInDoze =
- allowAutoBrightnessWhileDozingConfig
- && Display.isDozeState(targetDisplayState);
+ allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE;
mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
&& (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze)
&& brightnessReason != BrightnessReason.REASON_OVERRIDE
diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
index f1698dd..8826e3d 100644
--- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java
@@ -36,6 +36,7 @@
import android.os.ResultReceiver;
import android.util.EventLog;
import android.util.Slog;
+import android.view.MotionEvent;
import android.view.inputmethod.ImeTracker;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
@@ -75,7 +76,7 @@
@GuardedBy("ImfLock.class")
@Override
- public void performShowIme(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+ public void performShowIme(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
@InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
@@ -88,7 +89,8 @@
// TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
if (DEBUG_IME_VISIBILITY) {
- EventLog.writeEvent(IMF_SHOW_IME, statsToken.getTag(),
+ EventLog.writeEvent(IMF_SHOW_IME,
+ statsToken != null ? statsToken.getTag() : ImeTracker.TOKEN_NONE,
Objects.toString(mService.mCurFocusedWindow),
InputMethodDebug.softInputDisplayReasonToString(reason),
InputMethodDebug.softInputModeToString(
@@ -102,7 +104,7 @@
@GuardedBy("ImfLock.class")
@Override
- public void performHideIme(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
+ public void performHideIme(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
if (curMethod != null) {
@@ -118,7 +120,8 @@
// TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
if (curMethod.hideSoftInput(hideInputToken, statsToken, 0, resultReceiver)) {
if (DEBUG_IME_VISIBILITY) {
- EventLog.writeEvent(IMF_HIDE_IME, statsToken.getTag(),
+ EventLog.writeEvent(IMF_HIDE_IME,
+ statsToken != null ? statsToken.getTag() : ImeTracker.TOKEN_NONE,
Objects.toString(mService.mCurFocusedWindow),
InputMethodDebug.softInputDisplayReasonToString(reason),
InputMethodDebug.softInputModeToString(
@@ -132,14 +135,16 @@
@GuardedBy("ImfLock.class")
@Override
- public void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ public void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
@ImeVisibilityStateComputer.VisibilityState int state) {
- applyImeVisibility(windowToken, statsToken, state, -1 /* ignore reason */);
+ applyImeVisibility(windowToken, statsToken, state,
+ SoftInputShowHideReason.NOT_SET /* ignore reason */);
}
@GuardedBy("ImfLock.class")
void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
- @ImeVisibilityStateComputer.VisibilityState int state, int reason) {
+ @ImeVisibilityStateComputer.VisibilityState int state,
+ @SoftInputShowHideReason int reason) {
switch (state) {
case STATE_SHOW_IME:
ImeTracker.forLogging().onProgress(statsToken,
@@ -164,18 +169,20 @@
}
break;
case STATE_HIDE_IME_EXPLICIT:
- mService.hideCurrentInputLocked(windowToken, statsToken, 0, null, reason);
+ mService.hideCurrentInputLocked(windowToken, statsToken,
+ 0 /* flags */, null /* resultReceiver */, reason);
break;
case STATE_HIDE_IME_NOT_ALWAYS:
mService.hideCurrentInputLocked(windowToken, statsToken,
- InputMethodManager.HIDE_NOT_ALWAYS, null, reason);
+ InputMethodManager.HIDE_NOT_ALWAYS, null /* resultReceiver */, reason);
break;
case STATE_SHOW_IME_IMPLICIT:
mService.showCurrentInputLocked(windowToken, statsToken,
- InputMethodManager.SHOW_IMPLICIT, null, reason);
+ InputMethodManager.SHOW_IMPLICIT, MotionEvent.TOOL_TYPE_UNKNOWN,
+ null /* resultReceiver */, reason);
break;
case STATE_SHOW_IME_SNAPSHOT:
- showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked(), null);
+ showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked());
break;
case STATE_REMOVE_IME_SNAPSHOT:
removeImeScreenshot(mService.getDisplayIdToShowImeLocked());
@@ -187,11 +194,10 @@
@GuardedBy("ImfLock.class")
@Override
- public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId,
- @Nullable ImeTracker.Token statsToken) {
+ public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) {
if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) {
mService.onShowHideSoftInputRequested(false /* show */, imeTarget,
- SHOW_IME_SCREENSHOT_FROM_IMMS, statsToken);
+ SHOW_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */);
return true;
}
return false;
@@ -202,7 +208,7 @@
public boolean removeImeScreenshot(int displayId) {
if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) {
mService.onShowHideSoftInputRequested(false /* show */, mService.mCurFocusedWindow,
- REMOVE_IME_SCREENSHOT_FROM_IMMS, null);
+ REMOVE_IME_SCREENSHOT_FROM_IMMS, null /* statsToken */);
return true;
}
return false;
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index 776184f..a380bc1 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -201,7 +201,7 @@
// TODO(b/192412909): Convert this back to void method
@AnyThread
- boolean showSoftInput(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+ boolean showSoftInput(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
@InputMethod.ShowFlags int flags, ResultReceiver resultReceiver) {
try {
mTarget.showSoftInput(showInputToken, statsToken, flags, resultReceiver);
@@ -214,8 +214,8 @@
// TODO(b/192412909): Convert this back to void method
@AnyThread
- boolean hideSoftInput(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken, int flags,
- ResultReceiver resultReceiver) {
+ boolean hideSoftInput(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
+ int flags, ResultReceiver resultReceiver) {
try {
mTarget.hideSoftInput(hideInputToken, statsToken, flags, resultReceiver);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
index d06c31c..85ab773 100644
--- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
+++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
@@ -75,34 +75,12 @@
@NonNull
@Override
- public ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
+ public ImeTracker.Token onStart(@NonNull String tag, int uid, @ImeTracker.Type int type,
@ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
final var binder = new Binder();
final var token = new ImeTracker.Token(binder, tag);
- final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_SHOW, ImeTracker.STATUS_RUN,
- origin, reason, fromUser);
- synchronized (mLock) {
- mHistory.addEntry(binder, entry);
-
- // Register a delayed task to handle the case where the new entry times out.
- mHandler.postDelayed(() -> {
- synchronized (mLock) {
- mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT,
- ImeTracker.PHASE_NOT_SET);
- }
- }, TIMEOUT_MS);
- }
- return token;
- }
-
- @NonNull
- @Override
- public ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
- @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
- final var binder = new Binder();
- final var token = new ImeTracker.Token(binder, tag);
- final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_HIDE, ImeTracker.STATUS_RUN,
- origin, reason, fromUser);
+ final var entry = new History.Entry(tag, uid, type, ImeTracker.STATUS_RUN, origin, reason,
+ fromUser);
synchronized (mLock) {
mHistory.addEntry(binder, entry);
@@ -158,7 +136,7 @@
/**
* Updates the IME request tracking token with new information available in IMMS.
*
- * @param statsToken the token corresponding to the current IME request.
+ * @param statsToken the token tracking the current IME request.
* @param requestWindowName the name of the window that created the IME request.
*/
public void onImmsUpdate(@NonNull ImeTracker.Token statsToken,
@@ -223,7 +201,7 @@
* Sets the live entry corresponding to the tracking token, if it exists, as finished,
* and uploads the data for metrics.
*
- * @param statsToken the token corresponding to the current IME request.
+ * @param statsToken the token tracking the current IME request.
* @param status the finish status of the IME request.
* @param phase the phase the IME request finished at, if it exists
* (or {@link ImeTracker#PHASE_NOT_SET} otherwise).
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
index 29fa369..9f2b84d 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java
@@ -17,7 +17,6 @@
package com.android.server.inputmethod;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.view.inputmethod.ImeTracker;
@@ -34,12 +33,12 @@
* Performs showing IME on top of the given window.
*
* @param showInputToken A token that represents the requester to show IME.
- * @param statsToken A token that tracks the progress of an IME request.
+ * @param statsToken The token tracking the current IME request.
* @param resultReceiver If non-null, this will be called back to the caller when
* it has processed request to tell what it has done.
* @param reason The reason for requesting to show IME.
*/
- default void performShowIme(IBinder showInputToken, @Nullable ImeTracker.Token statsToken,
+ default void performShowIme(IBinder showInputToken, @NonNull ImeTracker.Token statsToken,
@InputMethod.ShowFlags int showFlags, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {}
@@ -47,12 +46,12 @@
* Performs hiding IME to the given window
*
* @param hideInputToken A token that represents the requester to hide IME.
- * @param statsToken A token that tracks the progress of an IME request.
+ * @param statsToken The token tracking the current IME request.
* @param resultReceiver If non-null, this will be called back to the caller when
* it has processed request to tell what it has done.
* @param reason The reason for requesting to hide IME.
*/
- default void performHideIme(IBinder hideInputToken, @Nullable ImeTracker.Token statsToken,
+ default void performHideIme(IBinder hideInputToken, @NonNull ImeTracker.Token statsToken,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}
/**
@@ -60,10 +59,10 @@
* according to the given visibility state.
*
* @param windowToken The token of a window for applying the IME visibility
- * @param statsToken A token that tracks the progress of an IME request.
+ * @param statsToken The token tracking the current IME request.
* @param state The new IME visibility state for the applier to handle
*/
- default void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
+ default void applyImeVisibility(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
@ImeVisibilityStateComputer.VisibilityState int state) {}
/**
@@ -84,11 +83,9 @@
*
* @param windowToken The token of a window to show the IME screenshot.
* @param displayId The unique id to identify the display
- * @param statsToken A token that tracks the progress of an IME request.
* @return {@code true} if success, {@code false} otherwise.
*/
- default boolean showImeScreenshot(@NonNull IBinder windowToken, int displayId,
- @Nullable ImeTracker.Token statsToken) {
+ default boolean showImeScreenshot(@NonNull IBinder windowToken, int displayId) {
return false;
}
diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
index 0dd48ae..743b8e3 100644
--- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
+++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java
@@ -212,9 +212,11 @@
boolean visibleRequested, boolean removed) {
if (mCurVisibleImeInputTarget == imeInputTarget && (!visibleRequested || removed)
&& mCurVisibleImeLayeringOverlay != null) {
- mService.onApplyImeVisibilityFromComputer(imeInputTarget,
- new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT,
- SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE));
+ final int reason = SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE;
+ final var statsToken = ImeTracker.forLogging().onStart(ImeTracker.TYPE_HIDE,
+ ImeTracker.ORIGIN_SERVER, reason, false /* fromUser */);
+ mService.onApplyImeVisibilityFromComputer(imeInputTarget, statsToken,
+ new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT, reason));
}
mCurVisibleImeInputTarget = (visibleRequested && !removed) ? imeInputTarget : null;
}
@@ -224,7 +226,7 @@
/**
* Called when {@link InputMethodManagerService} is processing the show IME request.
*
- * @param statsToken The token for tracking this show request.
+ * @param statsToken The token tracking the current IME request.
* @return {@code true} when the show request can proceed.
*/
boolean onImeShowFlags(@NonNull ImeTracker.Token statsToken,
@@ -250,7 +252,7 @@
/**
* Called when {@link InputMethodManagerService} is processing the hide IME request.
*
- * @param statsToken The token for tracking this hide request.
+ * @param statsToken The token tracking the current IME request.
* @return {@code true} when the hide request can proceed.
*/
boolean canHideIme(@NonNull ImeTracker.Token statsToken,
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3dedca9..1564b2f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -578,7 +578,10 @@
return mBindingController.hasMainConnection();
}
- /** The token tracking the current IME request or {@code null} otherwise. */
+ /**
+ * The token tracking the current IME show request that is waiting for a connection to an IME,
+ * otherwise {@code null}.
+ */
@Nullable
private ImeTracker.Token mCurStatsToken;
@@ -1128,11 +1131,10 @@
mVisibilityStateComputer.getImePolicy().setA11yRequestNoSoftKeyboard(
accessibilitySoftKeyboardSetting);
if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
- 0 /* flags */, null /* resultReceiver */,
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE);
} else if (isShowRequestedForCurrentWindow()) {
- showCurrentInputImplicitLocked(mCurFocusedWindow,
+ showCurrentInputLocked(mCurFocusedWindow, InputMethodManager.SHOW_IMPLICIT,
SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE);
}
} else if (stylusHandwritingEnabledUri.equals(uri)) {
@@ -1627,8 +1629,8 @@
}
// Hide soft input before user switch task since switch task may block main handler a while
// and delayed the hideCurrentInputLocked().
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
- null /* resultReceiver */, SoftInputShowHideReason.HIDE_SWITCH_USER);
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */,
+ SoftInputShowHideReason.HIDE_SWITCH_USER);
final UserSwitchHandlerTask task = new UserSwitchHandlerTask(this, userId,
clientToBeReset);
mUserSwitchHandlerTask = task;
@@ -2216,8 +2218,8 @@
clearClientSessionLocked(client);
clearClientSessionForAccessibilityLocked(client);
if (mCurClient == client) {
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
- null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */,
+ SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
if (mBoundToMethod) {
mBoundToMethod = false;
IInputMethodInvoker curMethod = getCurMethodLocked();
@@ -2291,8 +2293,9 @@
// service, that wouldn't make the attached IME token validity check in time)
// As a result, we have to notify WM to apply IME visibility before clearing the
// binding states in the first place.
- mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, mCurStatsToken,
- STATE_HIDE_IME);
+ final var statsToken = createStatsTokenForFocusedClient(false /* show */,
+ SoftInputShowHideReason.UNBIND_CURRENT_METHOD);
+ mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, statsToken, STATE_HIDE_IME);
}
}
@@ -2369,10 +2372,12 @@
if (isShowRequestedForCurrentWindow()) {
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
// Re-use current statsToken, if it exists.
- final ImeTracker.Token statsToken = mCurStatsToken;
+ final var statsToken = mCurStatsToken != null ? mCurStatsToken
+ : createStatsTokenForFocusedClient(true /* show */,
+ SoftInputShowHideReason.ATTACH_NEW_INPUT);
mCurStatsToken = null;
showCurrentInputLocked(mCurFocusedWindow, statsToken,
- mVisibilityStateComputer.getShowFlags(),
+ mVisibilityStateComputer.getShowFlags(), MotionEvent.TOOL_TYPE_UNKNOWN,
null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT);
}
@@ -2464,8 +2469,7 @@
}
if (mVisibilityStateComputer.getImePolicy().isImeHiddenByDisplayPolicy()) {
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
- null /* resultReceiver */,
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_DISPLAY_IME_POLICY_HIDE);
return InputBindResult.NO_IME;
}
@@ -3385,8 +3389,8 @@
@Override
public boolean showSoftInput(IInputMethodClient client, IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
- int lastClickTooType, ResultReceiver resultReceiver,
+ @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+ int lastClickToolType, ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showSoftInput");
int uid = Binder.getCallingUid();
@@ -3402,7 +3406,7 @@
final long ident = Binder.clearCallingIdentity();
try {
if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
- return showCurrentInputLocked(windowToken, statsToken, flags, lastClickTooType,
+ return showCurrentInputLocked(windowToken, statsToken, flags, lastClickToolType,
resultReceiver, reason);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -3644,24 +3648,18 @@
}
@GuardedBy("ImfLock.class")
- boolean showCurrentInputLocked(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
- @InputMethodManager.ShowFlags int flags, ResultReceiver resultReceiver,
- @SoftInputShowHideReason int reason) {
+ private boolean showCurrentInputLocked(IBinder windowToken,
+ @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) {
+ final var statsToken = createStatsTokenForFocusedClient(true /* show */, reason);
return showCurrentInputLocked(windowToken, statsToken, flags,
- MotionEvent.TOOL_TYPE_UNKNOWN, resultReceiver, reason);
+ MotionEvent.TOOL_TYPE_UNKNOWN, null /* resultReceiver */, reason);
}
@GuardedBy("ImfLock.class")
- private boolean showCurrentInputLocked(IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
- int lastClickToolType, ResultReceiver resultReceiver,
+ boolean showCurrentInputLocked(IBinder windowToken,
+ @NonNull ImeTracker.Token statsToken, @InputMethodManager.ShowFlags int flags,
+ int lastClickToolType, @Nullable ResultReceiver resultReceiver,
@SoftInputShowHideReason int reason) {
- // Create statsToken is none exists.
- if (statsToken == null) {
- statsToken = createStatsTokenForFocusedClient(true /* show */,
- ImeTracker.ORIGIN_SERVER_START_INPUT, reason, false /* fromUser */);
- }
-
if (!mVisibilityStateComputer.onImeShowFlags(statsToken, flags)) {
return false;
}
@@ -3699,7 +3697,7 @@
@Override
public boolean hideSoftInput(IInputMethodClient client, IBinder windowToken,
- @Nullable ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
+ @NonNull ImeTracker.Token statsToken, @InputMethodManager.HideFlags int flags,
ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
int uid = Binder.getCallingUid();
ImeTracing.getInstance().triggerManagerServiceDump(
@@ -3728,17 +3726,29 @@
}
}
- @GuardedBy("ImfLock.class")
- boolean hideCurrentInputLocked(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
- @InputMethodManager.HideFlags int flags, ResultReceiver resultReceiver,
- @SoftInputShowHideReason int reason) {
- // Create statsToken is none exists.
- if (statsToken == null) {
- final boolean fromUser = reason == SoftInputShowHideReason.HIDE_SOFT_INPUT_BY_BACK_KEY;
- statsToken = createStatsTokenForFocusedClient(false /* show */,
- ImeTracker.ORIGIN_SERVER_HIDE_INPUT, reason, fromUser);
- }
+ @Override
+ @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
+ public void hideSoftInputFromServerForTest() {
+ super.hideSoftInputFromServerForTest_enforcePermission();
+ synchronized (ImfLock.class) {
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */,
+ SoftInputShowHideReason.HIDE_SOFT_INPUT);
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
+ private boolean hideCurrentInputLocked(IBinder windowToken,
+ @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) {
+ final var statsToken = createStatsTokenForFocusedClient(false /* show */, reason);
+ return hideCurrentInputLocked(windowToken, statsToken, flags, null /* resultReceiver */,
+ reason);
+ }
+
+ @GuardedBy("ImfLock.class")
+ boolean hideCurrentInputLocked(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.HideFlags int flags, @Nullable ResultReceiver resultReceiver,
+ @SoftInputShowHideReason int reason) {
if (!mVisibilityStateComputer.canHideIme(statsToken, flags)) {
return false;
}
@@ -3915,9 +3925,7 @@
Slog.w(TAG, "If you need to impersonate a foreground user/profile from"
+ " a background user, use EditorInfo.targetInputMethodUser with"
+ " INTERACT_ACROSS_USERS_FULL permission.");
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
- 0 /* flags */,
- null /* resultReceiver */,
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_INVALID_USER);
return InputBindResult.INVALID_USER;
}
@@ -4025,11 +4033,14 @@
final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.computeState(windowState,
isSoftInputModeStateVisibleAllowed(unverifiedTargetSdkVersion, startInputFlags));
if (imeVisRes != null) {
+ boolean isShow = false;
switch (imeVisRes.getReason()) {
case SoftInputShowHideReason.SHOW_RESTORE_IME_VISIBILITY:
case SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV:
case SoftInputShowHideReason.SHOW_STATE_VISIBLE_FORWARD_NAV:
case SoftInputShowHideReason.SHOW_STATE_ALWAYS_VISIBLE:
+ isShow = true;
+
if (editorInfo != null) {
res = startInputUncheckedLocked(cs, inputContext,
remoteAccessibilityInputConnection, editorInfo, startInputFlags,
@@ -4039,8 +4050,8 @@
}
break;
}
-
- mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null /* statsToken */,
+ final var statsToken = createStatsTokenForFocusedClient(isShow, imeVisRes.getReason());
+ mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, statsToken,
imeVisRes.getState(), imeVisRes.getReason());
if (imeVisRes.getReason() == SoftInputShowHideReason.HIDE_UNSPECIFIED_WINDOW) {
@@ -4068,13 +4079,6 @@
}
@GuardedBy("ImfLock.class")
- private void showCurrentInputImplicitLocked(@NonNull IBinder windowToken,
- @SoftInputShowHideReason int reason) {
- showCurrentInputLocked(windowToken, null /* statsToken */, InputMethodManager.SHOW_IMPLICIT,
- null /* resultReceiver */, reason);
- }
-
- @GuardedBy("ImfLock.class")
private boolean canInteractWithImeLocked(int uid, IInputMethodClient client, String methodName,
@Nullable ImeTracker.Token statsToken) {
if (mCurClient == null || client == null
@@ -4776,15 +4780,17 @@
@BinderThread
private void applyImeVisibility(IBinder token, IBinder windowToken, boolean setVisible,
- @Nullable ImeTracker.Token statsToken) {
+ @NonNull ImeTracker.Token statsToken) {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.applyImeVisibility");
synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
ImeTracker.forLogging().onFailed(statsToken,
- ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
+ ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
final IBinder requestToken = mVisibilityStateComputer.getWindowTokenFrom(
windowToken);
mVisibilityApplier.applyImeVisibility(requestToken, statsToken,
@@ -4862,17 +4868,21 @@
}
@BinderThread
- private void hideMySoftInput(@NonNull IBinder token, @InputMethodManager.HideFlags int flags,
- @SoftInputShowHideReason int reason) {
+ private void hideMySoftInput(@NonNull IBinder token, @NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason) {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.hideMySoftInput");
synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
+ ImeTracker.forLogging().onFailed(statsToken,
+ ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
final long ident = Binder.clearCallingIdentity();
try {
- hideCurrentInputLocked(mLastImeTargetWindow, null /* statsToken */, flags,
+ hideCurrentInputLocked(mLastImeTargetWindow, statsToken, flags,
null /* resultReceiver */, reason);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -4884,18 +4894,22 @@
}
@BinderThread
- private void showMySoftInput(@NonNull IBinder token, @InputMethodManager.ShowFlags int flags) {
+ private void showMySoftInput(@NonNull IBinder token, @NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason) {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.showMySoftInput");
synchronized (ImfLock.class) {
if (!calledWithValidTokenLocked(token)) {
+ ImeTracker.forLogging().onFailed(statsToken,
+ ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_SERVER_CURRENT_ACTIVE_IME);
final long ident = Binder.clearCallingIdentity();
try {
- showCurrentInputLocked(mLastImeTargetWindow, null /* statsToken */, flags,
- null /* resultReceiver */,
- SoftInputShowHideReason.SHOW_SOFT_INPUT_FROM_IME);
+ showCurrentInputLocked(mLastImeTargetWindow, statsToken, flags,
+ MotionEvent.TOOL_TYPE_UNKNOWN, null /* resultReceiver */, reason);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4912,10 +4926,10 @@
}
}
- void onApplyImeVisibilityFromComputer(IBinder windowToken,
+ void onApplyImeVisibilityFromComputer(IBinder windowToken, @NonNull ImeTracker.Token statsToken,
@NonNull ImeVisibilityResult result) {
synchronized (ImfLock.class) {
- mVisibilityApplier.applyImeVisibility(windowToken, null, result.getState(),
+ mVisibilityApplier.applyImeVisibility(windowToken, statsToken, result.getState(),
result.getReason());
}
}
@@ -5016,9 +5030,8 @@
case MSG_HIDE_ALL_INPUT_METHODS:
synchronized (ImfLock.class) {
- final @SoftInputShowHideReason int reason = (int) msg.obj;
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
- null /* resultReceiver */, reason);
+ @SoftInputShowHideReason final int reason = (int) msg.obj;
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */, reason);
}
return true;
@@ -5176,7 +5189,8 @@
final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged(
mCurFocusedWindow, interactive);
if (imeVisRes != null) {
- mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null,
+ // Pass in a null statsToken as the IME snapshot is not tracked by ImeTracker.
+ mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null /* statsToken */,
imeVisRes.getState(), imeVisRes.getReason());
}
// Eligible IME processes use new "setInteractive" protocol.
@@ -6684,8 +6698,7 @@
final String nextIme;
final List<InputMethodInfo> nextEnabledImes;
if (userId == mSettings.getUserId()) {
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */,
- 0 /* flags */, null /* resultReceiver */,
+ hideCurrentInputLocked(mCurFocusedWindow, 0 /* flags */,
SoftInputShowHideReason.HIDE_RESET_SHELL_COMMAND);
mBindingController.unbindCurrentMethod();
@@ -6814,13 +6827,11 @@
* Creates an IME request tracking token for the current focused client.
*
* @param show whether this is a show or a hide request.
- * @param origin the origin of the IME request.
* @param reason the reason why the IME request was created.
- * @param fromUser whether this request was created directly from user interaction.
*/
@NonNull
private ImeTracker.Token createStatsTokenForFocusedClient(boolean show,
- @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason, boolean fromUser) {
+ @SoftInputShowHideReason int reason) {
final int uid = mCurFocusedWindowClient != null
? mCurFocusedWindowClient.mUid
: -1;
@@ -6828,13 +6839,9 @@
? mCurFocusedWindowEditorInfo.packageName
: "uid(" + uid + ")";
- if (show) {
- return ImeTracker.forLogging()
- .onRequestShow(packageName, uid, origin, reason, fromUser);
- } else {
- return ImeTracker.forLogging()
- .onRequestHide(packageName, uid, origin, reason, fromUser);
- }
+ return ImeTracker.forLogging().onStart(packageName, uid,
+ show ? ImeTracker.TYPE_SHOW : ImeTracker.TYPE_HIDE, ImeTracker.ORIGIN_SERVER,
+ reason, false /* fromUser */);
}
private static final class InputMethodPrivilegedOperationsImpl
@@ -6909,12 +6916,13 @@
@BinderThread
@Override
- public void hideMySoftInput(@InputMethodManager.HideFlags int flags,
- @SoftInputShowHideReason int reason, AndroidFuture future /* T=Void */) {
+ public void hideMySoftInput(@NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.HideFlags int flags, @SoftInputShowHideReason int reason,
+ AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
- mImms.hideMySoftInput(mToken, flags, reason);
+ mImms.hideMySoftInput(mToken, statsToken, flags, reason);
typedFuture.complete(null);
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
@@ -6923,12 +6931,13 @@
@BinderThread
@Override
- public void showMySoftInput(@InputMethodManager.ShowFlags int flags,
+ public void showMySoftInput(@NonNull ImeTracker.Token statsToken,
+ @InputMethodManager.ShowFlags int flags, @SoftInputShowHideReason int reason,
AndroidFuture future /* T=Void */) {
@SuppressWarnings("unchecked")
final AndroidFuture<Void> typedFuture = future;
try {
- mImms.showMySoftInput(mToken, flags);
+ mImms.showMySoftInput(mToken, statsToken, flags, reason);
typedFuture.complete(null);
} catch (Throwable e) {
typedFuture.completeExceptionally(e);
@@ -6987,7 +6996,7 @@
@BinderThread
@Override
public void applyImeVisibilityAsync(IBinder windowToken, boolean setVisible,
- @Nullable ImeTracker.Token statsToken) {
+ @NonNull ImeTracker.Token statsToken) {
mImms.applyImeVisibility(mToken, windowToken, setVisible, statsToken);
}
diff --git a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
index db6a9af..9caf5cf 100644
--- a/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
+++ b/services/core/java/com/android/server/inputmethod/ZeroJankProxy.java
@@ -184,6 +184,13 @@
return true;
}
+ @Override
+ @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
+ public void hideSoftInputFromServerForTest() throws RemoteException {
+ super.hideSoftInputFromServerForTest_enforcePermission();
+ mInner.hideSoftInputFromServerForTest();
+ }
+
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@Override
public void startInputOrWindowGainedFocusAsync(
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 1f7d549..2a48785 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -851,7 +851,6 @@
}
}
- @RequiresPermission(value = Manifest.permission.MEDIA_ROUTING_CONTROL, conditional = true)
private boolean checkMediaRoutingControlPermission(
int callerUid, int callerPid, @Nullable String callerPackageName) {
return PermissionChecker.checkPermissionForDataDelivery(
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 7af5c08..1dc86f2 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -56,7 +56,6 @@
private boolean mIsClosed;
private final int mPid;
- private final ForegroundServiceDelegationOptions mForegroundServiceDelegationOptions;
public MediaSession2Record(
Session2Token sessionToken,
@@ -76,25 +75,6 @@
.build();
mPid = pid;
mPolicies = policies;
- mForegroundServiceDelegationOptions =
- new ForegroundServiceDelegationOptions.Builder()
- .setClientPid(mPid)
- .setClientUid(getUid())
- .setClientPackageName(getPackageName())
- .setClientAppThread(null)
- .setSticky(false)
- .setClientInstanceName(
- "MediaSessionFgsDelegate_"
- + getUid()
- + "_"
- + mPid
- + "_"
- + getPackageName())
- .setForegroundServiceTypes(0)
- .setDelegationService(
- ForegroundServiceDelegationOptions
- .DELEGATION_SERVICE_MEDIA_PLAYBACK)
- .build();
}
}
@@ -119,7 +99,10 @@
@Override
public ForegroundServiceDelegationOptions getForegroundServiceDelegationOptions() {
- return mForegroundServiceDelegationOptions;
+ // For an app to be eligible for FGS delegation, it needs a media session liked to a media
+ // notification. Currently, notifications cannot be linked to MediaSession2 so it is not
+ // supported.
+ return null;
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index b00bc59..e2163c5 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -626,9 +626,7 @@
}
ForegroundServiceDelegationOptions foregroundServiceDelegationOptions =
record.getForegroundServiceDelegationOptions();
- if (foregroundServiceDelegationOptions == null
- || foregroundServiceDelegationOptions.mClientPid == Process.INVALID_PID) {
- // This record doesn't support FGS delegation. In practice, this is MediaSession2.
+ if (foregroundServiceDelegationOptions == null) {
return;
}
if (allowRunningInForeground) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e9a7fe1..ec4b38b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3504,7 +3504,7 @@
if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
- statusbar.moveFocusedTaskToFullscreen(event.getDisplayId());
+ statusbar.moveFocusedTaskToFullscreen(getTargetDisplayIdForKeyEvent(event));
logKeyboardSystemsEvent(event, KeyboardLogEvent.MULTI_WINDOW_NAVIGATION);
return true;
}
@@ -3514,7 +3514,7 @@
if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
- statusbar.enterDesktop(event.getDisplayId());
+ statusbar.enterDesktop(getTargetDisplayIdForKeyEvent(event));
logKeyboardSystemsEvent(event, KeyboardLogEvent.DESKTOP_MODE);
return true;
}
@@ -6951,4 +6951,18 @@
== PERMISSION_GRANTED;
}
}
+
+ private int getTargetDisplayIdForKeyEvent(KeyEvent event) {
+ int displayId = event.getDisplayId();
+
+ if (displayId == INVALID_DISPLAY) {
+ displayId = mTopFocusedDisplayId;
+ }
+
+ if (displayId == INVALID_DISPLAY) {
+ return DEFAULT_DISPLAY;
+ } else {
+ return displayId;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/power/Android.bp b/services/core/java/com/android/server/power/Android.bp
index 607d435..863ff76 100644
--- a/services/core/java/com/android/server/power/Android.bp
+++ b/services/core/java/com/android/server/power/Android.bp
@@ -9,4 +9,5 @@
java_aconfig_library {
name: "backstage_power_flags_lib",
aconfig_declarations: "backstage_power_flags",
+ sdk_version: "system_current",
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
index 596de68..1f9d265 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
@@ -96,6 +96,9 @@
private boolean mWebViewPackageDirty = false;
private boolean mAnyWebViewInstalled = false;
+ // Keeps track of whether we attempted to repair WebView before.
+ private boolean mAttemptedToRepairBefore = false;
+
private static final int NUMBER_OF_RELROS_UNKNOWN = Integer.MAX_VALUE;
// The WebView package currently in use (or the one we are preparing).
@@ -136,6 +139,7 @@
boolean removedOrChangedOldPackage = false;
String oldProviderName = null;
PackageInfo newPackage = null;
+ boolean repairNeeded = false;
synchronized (mLock) {
try {
newPackage = findPreferredWebViewPackage();
@@ -161,6 +165,7 @@
Slog.e(TAG, "Could not find valid WebView package to create relro with "
+ e);
}
+ repairNeeded = shouldTriggerRepairLocked();
}
if (updateWebView && !removedOrChangedOldPackage
&& oldProviderName != null) {
@@ -170,12 +175,18 @@
// only kills dependents of packages that are being removed.
mSystemInterface.killPackageDependents(oldProviderName);
}
+ if (repairNeeded) {
+ attemptRepair();
+ }
return;
}
}
}
private boolean shouldTriggerRepairLocked() {
+ if (mAttemptedToRepairBefore) {
+ return false;
+ }
if (mCurrentWebViewPackage == null) {
return true;
}
@@ -189,6 +200,26 @@
}
}
+ private void attemptRepair() {
+ // We didn't find a valid WebView implementation. Try explicitly re-installing and
+ // re-enabling the default package for all users in case it was disabled. If this actually
+ // changes the state, we will see the PackageManager broadcast shortly and try again.
+ synchronized (mLock) {
+ if (mAttemptedToRepairBefore) {
+ return;
+ }
+ mAttemptedToRepairBefore = true;
+ }
+ Slog.w(
+ TAG,
+ "No provider available for all users, trying to install and enable "
+ + mDefaultProvider.packageName);
+ mSystemInterface.installExistingPackageForAllUsers(
+ mContext, mDefaultProvider.packageName);
+ mSystemInterface.enablePackageForAllUsers(
+ mContext, mDefaultProvider.packageName, true);
+ }
+
@Override
public void prepareWebViewInSystemServer() {
try {
@@ -211,18 +242,7 @@
}
if (repairNeeded) {
- // We didn't find a valid WebView implementation. Try explicitly re-installing and
- // re-enabling the default package for all users in case it was disabled, even if we
- // already did the one-time migration before. If this actually changes the state, we
- // will see the PackageManager broadcast shortly and try again.
- Slog.w(
- TAG,
- "No provider available for all users, trying to install and enable "
- + mDefaultProvider.packageName);
- mSystemInterface.installExistingPackageForAllUsers(
- mContext, mDefaultProvider.packageName);
- mSystemInterface.enablePackageForAllUsers(
- mContext, mDefaultProvider.packageName, true);
+ attemptRepair();
}
} catch (Throwable t) {
@@ -332,6 +352,7 @@
PackageInfo oldPackage = null;
PackageInfo newPackage = null;
boolean providerChanged = false;
+ boolean repairNeeded = false;
synchronized (mLock) {
oldPackage = mCurrentWebViewPackage;
@@ -354,11 +375,19 @@
if (providerChanged) {
onWebViewProviderChanged(newPackage);
}
+ // Choosing another provider shouldn't break our state. Only check if repair
+ // is needed if this function is called as a result of a user change.
+ if (newProviderName == null) {
+ repairNeeded = shouldTriggerRepairLocked();
+ }
}
// Kill apps using the old provider only if we changed provider
if (providerChanged && oldPackage != null) {
mSystemInterface.killPackageDependents(oldPackage.packageName);
}
+ if (repairNeeded) {
+ attemptRepair();
+ }
// Return the new provider, this is not necessarily the one we were asked to switch to,
// but the persistent setting will now be pointing to the provider we were asked to
// switch to anyway.
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index ea31e63..9fee343 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -215,11 +215,11 @@
* when {@link android.inputmethodservice.InputMethodService} requests to show IME
* on {@param imeTarget}.
*
- * @param imeTarget imeTarget on which IME show request is coming from.
- * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+ * @param imeTarget imeTarget on which IME request is coming from.
+ * @param statsToken the token tracking the current IME request.
*/
void scheduleShowImePostLayout(InsetsControlTarget imeTarget,
- @Nullable ImeTracker.Token statsToken) {
+ @NonNull ImeTracker.Token statsToken) {
boolean targetChanged = isTargetChangedWithinActivity(imeTarget);
mImeRequester = imeTarget;
// Cancel the pre-existing stats token, if any.
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index b74eb56..cc3de7a 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -60,8 +60,8 @@
* Instructs the control target to show inset sources.
*
* @param types to specify which types of insets source window should be shown.
- * @param fromIme {@code true} if IME show request originated from {@link InputMethodService}.
- * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+ * @param fromIme {@code true} if the IME request originated from {@link InputMethodService}.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*/
default void showInsets(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {
@@ -71,8 +71,8 @@
* Instructs the control target to hide inset sources.
*
* @param types to specify which types of insets source window should be hidden.
- * @param fromIme {@code true} if IME hide request originated from {@link InputMethodService}.
- * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+ * @param fromIme {@code true} if the IME request originated from {@link InputMethodService}.
+ * @param statsToken the token tracking the current IME request or {@code null} otherwise.
*/
default void hideInsets(@InsetsType int types, boolean fromIme,
@Nullable ImeTracker.Token statsToken) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 5df2edc..77319cc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -829,20 +829,20 @@
* Show IME on imeTargetWindow once IME has finished layout.
*
* @param imeTargetWindowToken token of the (IME target) window which IME should be shown.
- * @param statsToken the token tracking the current IME show request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request.
*/
public abstract void showImePostLayout(IBinder imeTargetWindowToken,
- @Nullable ImeTracker.Token statsToken);
+ @NonNull ImeTracker.Token statsToken);
/**
* Hide IME using imeTargetWindow when requested.
*
- * @param imeTargetWindowToken token of the (IME target) window on which requests hiding IME.
+ * @param imeTargetWindowToken token of the (IME target) window which requests hiding IME.
* @param displayId the id of the display the IME is on.
- * @param statsToken the token tracking the current IME hide request or {@code null} otherwise.
+ * @param statsToken the token tracking the current IME request.
*/
public abstract void hideIme(IBinder imeTargetWindowToken, int displayId,
- @Nullable ImeTracker.Token statsToken);
+ @NonNull ImeTracker.Token statsToken);
/**
* Tell window manager about a package that should be running with a restricted range of
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7e061298..ae5a5cb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8258,12 +8258,17 @@
@Override
public void showImePostLayout(IBinder imeTargetWindowToken,
- @Nullable ImeTracker.Token statsToken) {
+ @NonNull ImeTracker.Token statsToken) {
synchronized (mGlobalLock) {
InputTarget imeTarget = getInputTargetFromWindowTokenLocked(imeTargetWindowToken);
if (imeTarget == null) {
+ ImeTracker.forLogging().onFailed(statsToken,
+ ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
return;
}
+ ImeTracker.forLogging().onProgress(statsToken,
+ ImeTracker.PHASE_WM_HAS_IME_INSETS_CONTROL_TARGET);
+
Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.showImePostLayout", 0);
final InsetsControlTarget controlTarget = imeTarget.getImeControlTarget();
imeTarget = controlTarget.getWindow();
@@ -8278,7 +8283,7 @@
@Override
public void hideIme(IBinder imeTargetWindowToken, int displayId,
- @Nullable ImeTracker.Token statsToken) {
+ @NonNull ImeTracker.Token statsToken) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WMS.hideIme");
synchronized (mGlobalLock) {
WindowState imeTarget = mWindowMap.get(imeTargetWindowToken);
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
index 1c71a62..1d225ba 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java
@@ -30,7 +30,10 @@
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT;
import static org.junit.Assert.assertThrows;
-import static org.mockito.Mockito.any;
+import static org.mockito.AdditionalMatchers.and;
+import static org.mockito.AdditionalMatchers.not;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -40,6 +43,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Display;
+import android.view.inputmethod.ImeTracker;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -56,7 +60,7 @@
* Test the behavior of {@link DefaultImeVisibilityApplier} when performing or applying the IME
* visibility state.
*
- * Build/Install/Run:
+ * <p>Build/Install/Run:
* atest FrameworksInputMethodSystemServerTests:DefaultImeVisibilityApplierTest
*/
@RunWith(AndroidJUnit4.class)
@@ -75,7 +79,8 @@
public void testPerformShowIme() throws Exception {
synchronized (ImfLock.class) {
mVisibilityApplier.performShowIme(new Binder() /* showInputToken */,
- null /* statsToken */, 0 /* showFlags */, null, SHOW_SOFT_INPUT);
+ ImeTracker.Token.empty(), 0 /* showFlags */, null /* resultReceiver */,
+ SHOW_SOFT_INPUT);
}
verifyShowSoftInput(false, true, 0 /* showFlags */);
}
@@ -84,46 +89,66 @@
public void testPerformHideIme() throws Exception {
synchronized (ImfLock.class) {
mVisibilityApplier.performHideIme(new Binder() /* hideInputToken */,
- null /* statsToken */, null, HIDE_SOFT_INPUT);
+ ImeTracker.Token.empty(), null /* resultReceiver */, HIDE_SOFT_INPUT);
}
verifyHideSoftInput(false, true);
}
@Test
public void testApplyImeVisibility_throwForInvalidState() {
- assertThrows(IllegalArgumentException.class,
- () -> mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_INVALID));
+ assertThrows(IllegalArgumentException.class, () -> {
+ synchronized (ImfLock.class) {
+ mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+ STATE_INVALID);
+ }
+ });
}
@Test
public void testApplyImeVisibility_showIme() {
- mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME);
- verify(mMockWindowManagerInternal).showImePostLayout(eq(mWindowToken), any());
+ final var statsToken = ImeTracker.Token.empty();
+ synchronized (ImfLock.class) {
+ mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_SHOW_IME);
+ }
+ verify(mMockWindowManagerInternal).showImePostLayout(eq(mWindowToken), eq(statsToken));
}
@Test
public void testApplyImeVisibility_hideIme() {
- mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME);
- verify(mMockWindowManagerInternal).hideIme(eq(mWindowToken), anyInt(), any());
+ final var statsToken = ImeTracker.Token.empty();
+ synchronized (ImfLock.class) {
+ mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME);
+ }
+ verify(mMockWindowManagerInternal).hideIme(eq(mWindowToken), anyInt() /* displayId */,
+ eq(statsToken));
}
@Test
public void testApplyImeVisibility_hideImeExplicit() throws Exception {
mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
- mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME_EXPLICIT);
+ synchronized (ImfLock.class) {
+ mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+ STATE_HIDE_IME_EXPLICIT);
+ }
verifyHideSoftInput(true, true);
}
@Test
public void testApplyImeVisibility_hideNotAlways() throws Exception {
mInputMethodManagerService.mImeWindowVis = IME_ACTIVE;
- mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME_NOT_ALWAYS);
+ synchronized (ImfLock.class) {
+ mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+ STATE_HIDE_IME_NOT_ALWAYS);
+ }
verifyHideSoftInput(true, true);
}
@Test
public void testApplyImeVisibility_showImeImplicit() throws Exception {
- mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_SHOW_IME_IMPLICIT);
+ synchronized (ImfLock.class) {
+ mVisibilityApplier.applyImeVisibility(mWindowToken, ImeTracker.Token.empty(),
+ STATE_SHOW_IME_IMPLICIT);
+ }
verifyShowSoftInput(true, true, 0 /* showFlags */);
}
@@ -135,21 +160,21 @@
mInputMethodManagerService.setAttachedClientForTesting(null);
startInputOrWindowGainedFocus(mWindowToken, SOFT_INPUT_STATE_ALWAYS_VISIBLE);
+ final var statsToken = ImeTracker.Token.empty();
synchronized (ImfLock.class) {
final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked();
// Verify hideIme will apply the expected displayId when the default IME
// visibility applier app STATE_HIDE_IME.
- mVisibilityApplier.applyImeVisibility(mWindowToken, null, STATE_HIDE_IME);
+ mVisibilityApplier.applyImeVisibility(mWindowToken, statsToken, STATE_HIDE_IME);
verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
- eq(mWindowToken), eq(displayIdToShowIme), eq(null));
+ eq(mWindowToken), eq(displayIdToShowIme), eq(statsToken));
}
}
@Test
public void testShowImeScreenshot() {
synchronized (ImfLock.class) {
- mVisibilityApplier.showImeScreenshot(mWindowToken, Display.DEFAULT_DISPLAY,
- null /* statsToken */);
+ mVisibilityApplier.showImeScreenshot(mWindowToken, Display.DEFAULT_DISPLAY);
}
verify(mMockImeTargetVisibilityPolicy).showImeScreenshot(eq(mWindowToken),
@@ -174,17 +199,20 @@
synchronized (ImfLock.class) {
// Simulate the system hides the IME when switching IME services in different users.
// (e.g. unbinding the IME from the current user to the profile user)
+ final var statsToken = ImeTracker.Token.empty();
final int displayIdToShowIme = mInputMethodManagerService.getDisplayIdToShowImeLocked();
- mInputMethodManagerService.hideCurrentInputLocked(mWindowToken, null, 0, null,
+ mInputMethodManagerService.hideCurrentInputLocked(mWindowToken,
+ statsToken, 0 /* flags */, null /* resultReceiver */,
HIDE_SWITCH_USER);
mInputMethodManagerService.onUnbindCurrentMethodByReset();
// Expects applyImeVisibility() -> hideIme() will be called to notify WM for syncing
// the IME hidden state.
- verify(mVisibilityApplier).applyImeVisibility(eq(mWindowToken), any(),
- eq(STATE_HIDE_IME));
+ // The unbind will cancel the previous stats token, and create a new one internally.
+ verify(mVisibilityApplier).applyImeVisibility(
+ eq(mWindowToken), any(), eq(STATE_HIDE_IME));
verify(mInputMethodManagerService.mWindowManagerInternal).hideIme(
- eq(mWindowToken), eq(displayIdToShowIme), eq(null));
+ eq(mWindowToken), eq(displayIdToShowIme), and(not(eq(statsToken)), notNull()));
}
}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
index fae5f86..a22cacb 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java
@@ -39,9 +39,12 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.notNull;
+
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.inputmethod.ImeTracker;
import android.view.inputmethod.InputMethodManager;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -58,7 +61,7 @@
* Test the behavior of {@link ImeVisibilityStateComputer} and {@link ImeVisibilityApplier} when
* requesting the IME visibility.
*
- * Build/Install/Run:
+ * <p> Build/Install/Run:
* atest FrameworksInputMethodSystemServerTests:ImeVisibilityStateComputerTest
*/
@RunWith(AndroidJUnit4.class)
@@ -91,7 +94,8 @@
@Test
public void testRequestImeVisibility_showImplicit() {
initImeTargetWindowState(mWindowToken);
- boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+ boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(),
+ InputMethodManager.SHOW_IMPLICIT);
mComputer.requestImeVisibility(mWindowToken, res);
final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -106,7 +110,7 @@
@Test
public void testRequestImeVisibility_showExplicit() {
initImeTargetWindowState(mWindowToken);
- boolean res = mComputer.onImeShowFlags(null, 0 /* showFlags */);
+ boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(), 0 /* showFlags */);
mComputer.requestImeVisibility(mWindowToken, res);
final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -125,7 +129,7 @@
@Test
public void testRequestImeVisibility_showExplicit_thenShowImplicit() {
initImeTargetWindowState(mWindowToken);
- mComputer.onImeShowFlags(null, 0 /* showFlags */);
+ mComputer.onImeShowFlags(ImeTracker.Token.empty(), 0 /* showFlags */);
assertThat(mComputer.mRequestedShowExplicitly).isTrue();
mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
@@ -139,10 +143,10 @@
@Test
public void testRequestImeVisibility_showForced_thenShowExplicit() {
initImeTargetWindowState(mWindowToken);
- mComputer.onImeShowFlags(null, InputMethodManager.SHOW_FORCED);
+ mComputer.onImeShowFlags(ImeTracker.Token.empty(), InputMethodManager.SHOW_FORCED);
assertThat(mComputer.mShowForced).isTrue();
- mComputer.onImeShowFlags(null, 0 /* showFlags */);
+ mComputer.onImeShowFlags(ImeTracker.Token.empty(), 0 /* showFlags */);
assertThat(mComputer.mShowForced).isTrue();
}
@@ -152,7 +156,8 @@
mComputer.getImePolicy().setA11yRequestNoSoftKeyboard(SHOW_MODE_HIDDEN);
initImeTargetWindowState(mWindowToken);
- boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+ boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(),
+ InputMethodManager.SHOW_IMPLICIT);
mComputer.requestImeVisibility(mWindowToken, res);
final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -170,7 +175,8 @@
mComputer.getImePolicy().setImeHiddenByDisplayPolicy(true);
initImeTargetWindowState(mWindowToken);
- boolean res = mComputer.onImeShowFlags(null, InputMethodManager.SHOW_IMPLICIT);
+ boolean res = mComputer.onImeShowFlags(ImeTracker.Token.empty(),
+ InputMethodManager.SHOW_IMPLICIT);
mComputer.requestImeVisibility(mWindowToken, res);
final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -188,7 +194,8 @@
mComputer.setInputShown(true);
initImeTargetWindowState(mWindowToken);
- assertThat(mComputer.canHideIme(null, InputMethodManager.HIDE_NOT_ALWAYS)).isTrue();
+ assertThat(mComputer.canHideIme(ImeTracker.Token.empty(),
+ InputMethodManager.HIDE_NOT_ALWAYS)).isTrue();
mComputer.requestImeVisibility(mWindowToken, false);
final ImeTargetWindowState state = mComputer.getWindowStateOrNull(mWindowToken);
@@ -281,7 +288,7 @@
final ArgumentCaptor<ImeVisibilityResult> resultCaptor = ArgumentCaptor.forClass(
ImeVisibilityResult.class);
verify(mInputMethodManagerService).onApplyImeVisibilityFromComputer(targetCaptor.capture(),
- resultCaptor.capture());
+ notNull() /* statsToken */, resultCaptor.capture());
final IBinder imeInputTarget = targetCaptor.getValue();
final ImeVisibilityResult result = resultCaptor.getValue();
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
index a1be00a..f4d95af 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -27,6 +27,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -277,8 +278,9 @@
.setCurrentMethodVisible();
}
verify(mMockInputMethod, times(showSoftInput ? 1 : 0))
- .showSoftInput(any(), any(),
- showFlags != NO_VERIFY_SHOW_FLAGS ? eq(showFlags) : anyInt(), any());
+ .showSoftInput(any() /* showInputToken */ , notNull() /* statsToken */,
+ showFlags != NO_VERIFY_SHOW_FLAGS ? eq(showFlags) : anyInt() /* flags*/,
+ any() /* resultReceiver */);
}
protected void verifyHideSoftInput(boolean setNotVisible, boolean hideSoftInput)
@@ -288,6 +290,7 @@
.setCurrentMethodNotVisible();
}
verify(mMockInputMethod, times(hideSoftInput ? 1 : 0))
- .hideSoftInput(any(), any(), anyInt(), any());
+ .hideSoftInput(any() /* hideInputToken */, notNull() /* statsToken */,
+ anyInt() /* flags */, any() /* resultReceiver */);
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index fcee70f..e9315c8 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1727,6 +1727,27 @@
/* ignoreAnimationLimits= */ anyBoolean());
}
+ @Test
+ public void testDefaultDozeBrightness() {
+ float brightness = 0.121f;
+ when(mPowerManagerMock.getBrightnessConstraint(
+ PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE)).thenReturn(brightness);
+ mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+ when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+ when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+ any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ when(mHolder.hbmController.getCurrentBrightnessMax())
+ .thenReturn(PowerManager.BRIGHTNESS_MAX);
+
+ DisplayPowerRequest dpr = new DisplayPowerRequest();
+ dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+ mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+ advanceTime(1); // Run updatePowerState
+
+ verify(mHolder.animator).animateTo(eq(brightness), /* linearSecondTarget= */ anyFloat(),
+ eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false));
+ }
+
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 8867806..ba462e3 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -215,7 +215,7 @@
mAutomaticBrightnessStrategy.setUseAutoBrightness(true);
int targetDisplayState = Display.STATE_DOZE;
boolean allowAutoBrightnessWhileDozing = true;
- int brightnessReason = BrightnessReason.REASON_DOZE;
+ int brightnessReason = BrightnessReason.REASON_UNKNOWN;
int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
float lastUserSetBrightness = 0.2f;
boolean userSetBrightnessChanged = true;
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 2039f93..54d1138 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -96,6 +96,9 @@
return;
}
PackageInfo packageInfo = userPackages.get(userId);
+ if (packageInfo == null) {
+ return;
+ }
packageInfo.applicationInfo.enabled = enable;
setPackageInfoForUser(userId, packageInfo);
}
@@ -106,6 +109,9 @@
return;
}
PackageInfo packageInfo = userPackages.get(userId);
+ if (packageInfo == null) {
+ return;
+ }
packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
packageInfo.applicationInfo.privateFlags &= (~ApplicationInfo.PRIVATE_FLAG_HIDDEN);
setPackageInfoForUser(userId, packageInfo);
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index c535ec5..e181a51 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -1551,7 +1551,7 @@
@Test
@RequiresFlagsEnabled("android.webkit.update_service_v2")
- public void testDefaultWebViewPackageInstalling() {
+ public void testDefaultWebViewPackageInstallingDuringStartUp() {
String testPackage = "testDefault";
WebViewProviderInfo[] packages =
new WebViewProviderInfo[] {
@@ -1574,6 +1574,68 @@
Matchers.anyObject(), Mockito.eq(testPackage));
}
+ @Test
+ @RequiresFlagsEnabled("android.webkit.update_service_v2")
+ public void testDefaultWebViewPackageInstallingAfterStartUp() {
+ String testPackage = "testDefault";
+ WebViewProviderInfo[] packages =
+ new WebViewProviderInfo[] {
+ new WebViewProviderInfo(
+ testPackage,
+ "",
+ true /* default available */,
+ false /* fallback */,
+ null)
+ };
+ checkCertainPackageUsedAfterWebViewBootPreparation(testPackage, packages);
+
+ // uninstall the default package.
+ mTestSystemImpl.setPackageInfo(
+ createPackageInfo(
+ testPackage, true /* enabled */, true /* valid */, false /* installed */));
+ mWebViewUpdateServiceImpl.packageStateChanged(testPackage,
+ WebViewUpdateService.PACKAGE_REMOVED, 0);
+
+ // Check that we try to re-install the default package.
+ Mockito.verify(mTestSystemImpl)
+ .installExistingPackageForAllUsers(
+ Matchers.anyObject(), Mockito.eq(testPackage));
+ }
+
+ /**
+ * Ensures that adding a new user for which the current WebView package is uninstalled triggers
+ * the repair logic.
+ */
+ @Test
+ @RequiresFlagsEnabled("android.webkit.update_service_v2")
+ public void testAddingNewUserWithDefaultdPackageNotInstalled() {
+ String testPackage = "testDefault";
+ WebViewProviderInfo[] packages =
+ new WebViewProviderInfo[] {
+ new WebViewProviderInfo(
+ testPackage,
+ "",
+ true /* default available */,
+ false /* fallback */,
+ null)
+ };
+ checkCertainPackageUsedAfterWebViewBootPreparation(testPackage, packages);
+
+ // Add new user with the default package not installed.
+ int newUser = 100;
+ mTestSystemImpl.addUser(newUser);
+ mTestSystemImpl.setPackageInfoForUser(newUser,
+ createPackageInfo(testPackage, true /* enabled */, true /* valid */,
+ false /* installed */));
+
+ mWebViewUpdateServiceImpl.handleNewUser(newUser);
+
+ // Check that we try to re-install the default package for all users.
+ Mockito.verify(mTestSystemImpl)
+ .installExistingPackageForAllUsers(
+ Matchers.anyObject(), Mockito.eq(testPackage));
+ }
+
private void testDefaultPackageChosen(PackageInfo packageInfo) {
WebViewProviderInfo[] packages =
new WebViewProviderInfo[] {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
index 20bb549..faa6d97 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java
@@ -27,6 +27,7 @@
import android.graphics.PixelFormat;
import android.platform.test.annotations.Presubmit;
import android.view.InsetsSource;
+import android.view.inputmethod.ImeTracker;
import androidx.test.filters.SmallTest;
@@ -34,6 +35,12 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+/**
+ * Tests for the {@link ImeInsetsSourceProvider} class.
+ *
+ * <p> Build/Install/Run:
+ * atest WmTests:ImeInsetsSourceProviderTest
+ */
@SmallTest
@Presubmit
@RunWith(WindowTestRunner.class)
@@ -56,7 +63,7 @@
mDisplayContent.setImeControlTarget(popup);
mDisplayContent.setImeLayeringTarget(appWin);
popup.mAttrs.format = PixelFormat.TRANSPARENT;
- mImeProvider.scheduleShowImePostLayout(appWin, null /* statsToken */);
+ mImeProvider.scheduleShowImePostLayout(appWin, ImeTracker.Token.empty());
assertTrue(mImeProvider.isReadyToShowIme());
}
@@ -65,7 +72,7 @@
WindowState target = createWindow(null, TYPE_APPLICATION, "app");
mDisplayContent.setImeLayeringTarget(target);
mDisplayContent.updateImeInputAndControlTarget(target);
- mImeProvider.scheduleShowImePostLayout(target, null /* statsToken */);
+ mImeProvider.scheduleShowImePostLayout(target, ImeTracker.Token.empty());
assertTrue(mImeProvider.isReadyToShowIme());
}
@@ -79,7 +86,7 @@
mDisplayContent.setImeLayeringTarget(target);
mDisplayContent.setImeControlTarget(target);
- mImeProvider.scheduleShowImePostLayout(target, null /* statsToken */);
+ mImeProvider.scheduleShowImePostLayout(target, ImeTracker.Token.empty());
assertFalse(mImeProvider.isImeShowing());
mImeProvider.checkShowImePostLayout();
assertTrue(mImeProvider.isImeShowing());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index cd3ce91..c8ad4bd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -104,6 +104,7 @@
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.view.inputmethod.ImeTracker;
import android.window.ClientWindowFrames;
import android.window.ITaskFragmentOrganizer;
import android.window.TaskFragmentOrganizer;
@@ -126,7 +127,7 @@
/**
* Tests for the {@link WindowState} class.
*
- * Build/Install/Run:
+ * <p> Build/Install/Run:
* atest WmTests:WindowStateTests
*/
@SmallTest
@@ -1099,7 +1100,7 @@
mDisplayContent.setImeInputTarget(app);
app.setRequestedVisibleTypes(ime(), ime());
assertTrue(mDisplayContent.shouldImeAttachedToApp());
- controller.getImeSourceProvider().scheduleShowImePostLayout(app, null /* statsToken */);
+ controller.getImeSourceProvider().scheduleShowImePostLayout(app, ImeTracker.Token.empty());
controller.getImeSourceProvider().getSource().setVisible(true);
controller.updateAboveInsetsState(false);
@@ -1137,7 +1138,7 @@
mDisplayContent.setImeInputTarget(app);
app.setRequestedVisibleTypes(ime(), ime());
assertTrue(mDisplayContent.shouldImeAttachedToApp());
- controller.getImeSourceProvider().scheduleShowImePostLayout(app, null /* statsToken */);
+ controller.getImeSourceProvider().scheduleShowImePostLayout(app, ImeTracker.Token.empty());
controller.getImeSourceProvider().getSource().setVisible(true);
controller.updateAboveInsetsState(false);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 44f4068..883c702 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -383,7 +383,7 @@
return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
} else {
// Multiple packages means we need to go manual
- final int appId = UserHandle.getUserId(appInfo.uid);
+ final int appId = UserHandle.getAppId(appInfo.uid);
final String[] packageNames = new String[] { packageName };
final long[] ceDataInodes = new long[1];
String[] codePaths = new String[0];