Merge "Fix deadlock in StagingManager.getSessions() method" into rvc-dev
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index cfe0aff..e7b3e14 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -502,7 +502,7 @@
* Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
* {@link #getPackageUid}, if an external service has the
* {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set
- * to <code>true<code> and was bound with the flag
+ * to <code>true</code> and was bound with the flag
* {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here will
* be the kernel user identifier of the external service provider.
*/
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 79da1f6..ee9bd3d 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -1168,7 +1168,12 @@
public int match(Uri data, boolean wildcardSupported) {
String host = data.getHost();
if (host == null) {
- return NO_MATCH_DATA;
+ if (wildcardSupported && mWild) {
+ // special case, if no host is provided, but the Authority is wildcard, match
+ return MATCH_CATEGORY_HOST;
+ } else {
+ return NO_MATCH_DATA;
+ }
}
if (false) Log.v("IntentFilter",
"Match host " + host + ": " + mHost);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index bc9c71e..ab0ed51 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1510,7 +1510,7 @@
Uri data = null;
String dataType = null;
- String host = IntentFilter.WILDCARD;
+ String host = null;
final int numActions = intentInfo.countActions();
final int numSchemes = intentInfo.countDataSchemes();
final int numTypes = intentInfo.countDataTypes();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 5647bf9..c5a11abe 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -605,9 +605,6 @@
if (DEBUG) Log.v(TAG, "unbindInput(): binding=" + mInputBinding
+ " ic=" + mInputConnection);
// Unbind input is per process per display.
- // TODO(b/150902448): free-up IME surface when target is changing.
- // e.g. DisplayContent#setInputMethodTarget()
- removeImeSurface();
onUnbindInput();
mInputBinding = null;
mInputConnection = null;
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 0e10c42..0eb3c1e 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -38,7 +38,9 @@
* Representation of a MAC address.
*
* This class only supports 48 bits long addresses and does not support 64 bits long addresses.
- * Instances of this class are immutable.
+ * Instances of this class are immutable. This class provides implementations of hashCode()
+ * and equals() that make it suitable for use as keys in standard implementations of
+ * {@link java.util.Map}.
*/
public final class MacAddress implements Parcelable {
@@ -122,12 +124,22 @@
}
/**
+ * Convert this MacAddress to a byte array.
+ *
+ * The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6,
+ * the returned array is [1, 2, 3, 4, 5, 6].
+ *
* @return a byte array representation of this MacAddress.
*/
public @NonNull byte[] toByteArray() {
return byteAddrFromLongAddr(mAddr);
}
+ /**
+ * Returns a human-readable representation of this MacAddress.
+ * The exact format is implementation-dependent and should not be assumed to have any
+ * particular format.
+ */
@Override
public @NonNull String toString() {
return stringAddrFromLongAddr(mAddr);
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 825077ff..ad43f95 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -125,11 +125,11 @@
final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView;
onViewFocusChanged(viewForWindowFocus, true);
- // Skip starting input when the next focused view is same as served view and the served
- // input connection still exists.
+ // Starting new input when the next focused view is same as served view but the
+ // editor is not aligned with the same editor or editor is inactive.
final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView;
- if (nextFocusIsServedView && immDelegate.isAcceptingText()) {
- forceFocus = false;
+ if (nextFocusIsServedView && !immDelegate.isSameEditorAndAcceptingText(focusedView)) {
+ forceFocus = true;
}
immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus,
@@ -254,7 +254,7 @@
void setCurrentRootView(ViewRootImpl rootView);
boolean isCurrentRootView(ViewRootImpl rootView);
boolean isRestartOnNextWindowFocus(boolean reset);
- boolean isAcceptingText();
+ boolean isSameEditorAndAcceptingText(View view);
}
public View getServedView() {
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index ef9d990..c1998c6 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -119,11 +119,11 @@
// If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
// this code here means that we now got control, so we can start the animation immediately.
// If client window is trying to control IME and IME is already visible, it is immediate.
- if (fromIme || mState.getSource(getType()).isVisible()) {
+ if (fromIme || mState.getSource(getType()).isVisible() && getControl() != null) {
return ShowResult.SHOW_IMMEDIATELY;
}
- return getImm().requestImeShow(null /* resultReceiver */)
+ return getImm().requestImeShow(mController.getHost().getWindowToken())
? ShowResult.IME_SHOW_DELAYED : ShowResult.IME_SHOW_FAILED;
}
@@ -132,12 +132,15 @@
*/
@Override
void notifyHidden() {
- getImm().notifyImeHidden();
+ getImm().notifyImeHidden(mController.getHost().getWindowToken());
}
@Override
public void removeSurface() {
- getImm().removeImeSurface();
+ final IBinder window = mController.getHost().getWindowToken();
+ if (window != null) {
+ getImm().removeImeSurface(window);
+ }
}
@Override
@@ -146,6 +149,7 @@
super.setControl(control, showTypes, hideTypes);
if (control == null && !mIsRequestedVisibleAwaitingControl) {
hide();
+ removeSurface();
}
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c6be91f..a679b37 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -737,7 +737,7 @@
}
}
- final boolean hasControl = mTmpControlArray.size() > 0;
+ boolean requestedStateStale = false;
final int[] showTypes = new int[1];
final int[] hideTypes = new int[1];
@@ -754,9 +754,26 @@
// Ensure to create source consumers if not available yet.
for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = mTmpControlArray.valueAt(i);
- InsetsSourceConsumer consumer = getSourceConsumer(control.getType());
+ final @InternalInsetsType int type = control.getType();
+ final InsetsSourceConsumer consumer = getSourceConsumer(type);
consumer.setControl(control, showTypes, hideTypes);
+ if (!requestedStateStale) {
+ final boolean requestedVisible = consumer.isRequestedVisible();
+
+ // We might have changed our requested visibilities while we don't have the control,
+ // so we need to update our requested state once we have control. Otherwise, our
+ // requested state at the server side might be incorrect.
+ final boolean requestedVisibilityChanged =
+ requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type);
+
+ // The IME client visibility will be reset by insets source provider while updating
+ // control, so if IME is requested visible, we need to send the request to server.
+ final boolean imeRequestedVisible = type == ITYPE_IME && requestedVisible;
+
+ requestedStateStale = requestedVisibilityChanged || imeRequestedVisible;
+ }
+
}
mTmpControlArray.clear();
@@ -772,10 +789,7 @@
if (hideTypes[0] != 0) {
applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
}
- if (hasControl && mRequestedState.hasSources()) {
- // We might have changed our requested visibilities while we don't have the control,
- // so we need to update our requested state once we have control. Otherwise, our
- // requested state at the server side might be incorrect.
+ if (requestedStateStale) {
updateRequestedState();
}
}
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 40e6f4b..700dc66 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -153,6 +153,9 @@
if (oldLeash == null || newLeash == null || !oldLeash.isSameSurface(newLeash)) {
applyHiddenToControl();
}
+ if (!requestedVisible && !mIsAnimationPending) {
+ removeSurface();
+ }
}
}
if (lastControl != null) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a586425..fefe564 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1824,13 +1824,19 @@
/**
* Called after window layout to update the bounds surface. If the surface insets have changed
* or the surface has resized, update the bounds surface.
+ *
+ * @param shouldReparent Whether it should reparent the bounds layer to the main SurfaceControl.
*/
- private void updateBoundsLayer() {
+ private void updateBoundsLayer(boolean shouldReparent) {
if (mBoundsLayer != null) {
setBoundsLayerCrop();
- mTransaction.deferTransactionUntil(mBoundsLayer,
- getRenderSurfaceControl(), mSurface.getNextFrameNumber())
- .apply();
+ mTransaction.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
+ mSurface.getNextFrameNumber());
+
+ if (shouldReparent) {
+ mTransaction.reparent(mBoundsLayer, getRenderSurfaceControl());
+ }
+ mTransaction.apply();
}
}
@@ -2725,7 +2731,6 @@
mAttachInfo.mThreadedRenderer.isEnabled()) {
mAttachInfo.mThreadedRenderer.destroy();
}
- notifySurfaceDestroyed();
} else if ((surfaceReplaced
|| surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
&& mSurfaceHolder == null
@@ -2913,7 +2918,16 @@
}
if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
- updateBoundsLayer();
+ // If the surface has been replaced, there's a chance the bounds layer is not parented
+ // to the new layer. When updating bounds layer, also reparent to the main VRI
+ // SurfaceControl to ensure it's correctly placed in the hierarchy.
+ //
+ // This needs to be done on the client side since WMS won't reparent the children to the
+ // new surface if it thinks the app is closing. WMS gets the signal that the app is
+ // stopping, but on the client side it doesn't get stopped since it's restarted quick
+ // enough. WMS doesn't want to keep around old children since they will leak when the
+ // client creates new children.
+ updateBoundsLayer(surfaceReplaced);
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
@@ -2956,6 +2970,10 @@
}
}
+ if (surfaceDestroyed) {
+ notifySurfaceDestroyed();
+ }
+
if (triggerGlobalLayoutListener) {
mAttachInfo.mRecomputeGlobalAttributes = false;
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
@@ -9377,6 +9395,11 @@
return mInputEventReceiver.getToken();
}
+ @NonNull
+ public IBinder getWindowToken() {
+ return mAttachInfo.mWindowToken;
+ }
+
/**
* Class for managing the accessibility interaction connection
* based on the global accessibility state.
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index aedb59b..37b3529 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -633,20 +633,21 @@
// we'll just do a window focus gain and call it a day.
try {
View servedView = controller.getServedView();
- boolean nextFocusIsServedView = servedView != null && servedView == focusedView;
+ boolean nextFocusSameEditor = servedView != null && servedView == focusedView
+ && isSameEditorAndAcceptingText(focusedView);
if (DEBUG) {
Log.v(TAG, "Reporting focus gain, without startInput"
- + ", nextFocusIsServedView=" + nextFocusIsServedView);
+ + ", nextFocusIsServedView=" + nextFocusSameEditor);
}
final int startInputReason =
- nextFocusIsServedView ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
+ nextFocusSameEditor ? WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
: WINDOW_FOCUS_GAIN_REPORT_WITHOUT_EDITOR;
mService.startInputOrWindowGainedFocus(
startInputReason, mClient,
focusedView.getWindowToken(), startInputFlags, softInputMode,
windowFlags,
- nextFocusIsServedView ? mCurrentTextBoxAttribute : null,
- nextFocusIsServedView ? mServedInputConnectionWrapper : null,
+ null,
+ null,
0 /* missingMethodFlags */,
mCurRootView.mContext.getApplicationInfo().targetSdkVersion);
} catch (RemoteException e) {
@@ -671,10 +672,6 @@
@Override
public void setCurrentRootView(ViewRootImpl rootView) {
synchronized (mH) {
- if (mCurRootView != null) {
- // Restart the input when the next window focus state of the root view changed.
- mRestartOnNextWindowFocus = true;
- }
mCurRootView = rootView;
}
}
@@ -704,14 +701,33 @@
}
/**
- * For {@link ImeFocusController} to check if the currently served view is accepting full
- * text edits.
+ * For {@link ImeFocusController} to check if the given focused view aligns with the same
+ * editor and the editor is active to accept the text input.
+ *
+ * TODO(b/160968797): Remove this method and move mCurrentTextBoxAttritube to
+ * ImeFocusController.
+ * In the long-term, we should make mCurrentTextBoxAtrtribue as per-window base instance,
+ * so that we we can directly check if the current focused view aligned with the same editor
+ * in the window without using this checking.
+ *
+ * Note that this method is only use for fixing start new input may ignored issue
+ * (e.g. b/160391516), DO NOT leverage this method to do another check.
*/
- @Override
- public boolean isAcceptingText() {
+ public boolean isSameEditorAndAcceptingText(View view) {
synchronized (mH) {
- return mServedInputConnectionWrapper != null
- && mServedInputConnectionWrapper.getInputConnection() != null;
+ if (!hasServedByInputMethodLocked(view) || mCurrentTextBoxAttribute == null) {
+ return false;
+ }
+
+ final EditorInfo ic = mCurrentTextBoxAttribute;
+ // This sameEditor checking is based on using object hash comparison to check if
+ // some fields of the current EditorInfo (e.g. autoFillId, OpPackageName) the
+ // hash code is same as the given focused view.
+ final boolean sameEditor = view.onCheckIsTextEditor() && view.getId() == ic.fieldId
+ && view.getAutofillId() == ic.autofillId
+ && view.getContext().getOpPackageName() == ic.packageName;
+ return sameEditor && mServedInputConnectionWrapper != null
+ && mServedInputConnectionWrapper.isActive();
}
}
}
@@ -2109,28 +2125,36 @@
/**
* Call showSoftInput with currently focused view.
- * @return {@code true} if IME can be shown.
+ *
+ * @param windowToken the window from which this request originates. If this doesn't match the
+ * currently served view, the request is ignored and returns {@code false}.
+ *
+ * @return {@code true} if IME can (eventually) be shown, {@code false} otherwise.
* @hide
*/
- public boolean requestImeShow(ResultReceiver resultReceiver) {
+ public boolean requestImeShow(IBinder windowToken) {
synchronized (mH) {
final View servedView = getServedViewLocked();
- if (servedView == null) {
+ if (servedView == null || servedView.getWindowToken() != windowToken) {
return false;
}
- showSoftInput(servedView, 0 /* flags */, resultReceiver);
+ showSoftInput(servedView, 0 /* flags */, null /* resultReceiver */);
return true;
}
}
/**
* Notify IME directly that it is no longer visible.
+ *
+ * @param windowToken the window from which this request originates. If this doesn't match the
+ * currently served view, the request is ignored.
* @hide
*/
- public void notifyImeHidden() {
+ public void notifyImeHidden(IBinder windowToken) {
synchronized (mH) {
try {
- if (mCurMethod != null) {
+ if (mCurMethod != null && mCurRootView != null
+ && mCurRootView.getWindowToken() == windowToken) {
mCurMethod.notifyImeHidden();
}
} catch (RemoteException re) {
@@ -2140,15 +2164,15 @@
/**
* Notify IME directly to remove surface as it is no longer visible.
+ * @param windowToken The client window token that requests the IME to remove its surface.
* @hide
*/
- public void removeImeSurface() {
+ public void removeImeSurface(IBinder windowToken) {
synchronized (mH) {
try {
- if (mCurMethod != null) {
- mCurMethod.removeImeSurface();
- }
- } catch (RemoteException re) {
+ mService.removeImeSurfaceFromWindow(windowToken);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index c5729b0..046981c 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -21,8 +21,6 @@
import static android.view.View.SYSTEM_UI_LAYOUT_FLAGS;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowInsets.Type.ime;
-import static android.view.WindowInsets.Type.systemBars;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -34,8 +32,6 @@
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -146,17 +142,7 @@
if ((view.getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) != 0) {
return new Pair<>(Insets.NONE, insets);
}
-
- boolean includeIme = (view.getViewRootImpl().mWindowAttributes.softInputMode
- & SOFT_INPUT_MASK_ADJUST)
- == SOFT_INPUT_ADJUST_RESIZE;
- Insets insetsToApply;
- if (ViewRootImpl.sNewInsetsMode == 0) {
- insetsToApply = insets.getSystemWindowInsets();
- } else {
- insetsToApply = insets.getInsets(systemBars() | (includeIme ? ime() : 0));
- }
- insets = insets.inset(insetsToApply);
+ Insets insetsToApply = insets.getSystemWindowInsets();
return new Pair<>(insetsToApply,
insets.inset(insetsToApply).consumeSystemWindowInsets());
};
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 8ec51b8..a1cbd3f 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -73,5 +73,8 @@
in float[] matrixValues);
oneway void reportPerceptible(in IBinder windowToken, boolean perceptible);
+ /** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */
void removeImeSurface();
+ /** Remove the IME surface. Requires passing the currently focused window. */
+ void removeImeSurfaceFromWindow(in IBinder windowToken);
}
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 4640e4b..5e245de 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1149,7 +1149,7 @@
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Capturar imagen con %1$s"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Capturar imagen"</string>
<string name="alwaysUse" msgid="3153558199076112903">"Usar siempre para esta acción"</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"Utiliza otra aplicación"</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"Usar otra aplicación"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"Para borrar los valores predeterminados, accede a Ajustes del sistema > Aplicaciones > Descargadas."</string>
<string name="chooseActivity" msgid="8563390197659779956">"Selecciona una acción"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"Elegir una aplicación para el dispositivo USB"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index c26cc66..cf08d24 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1926,7 +1926,7 @@
<string name="time_picker_header_text" msgid="9073802285051516688">"Ezarri ordua"</string>
<string name="time_picker_input_error" msgid="8386271930742451034">"Idatzi balio duen ordu bat"</string>
<string name="time_picker_prompt_label" msgid="303588544656363889">"Idatzi ordua"</string>
- <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Aldatu testu modura ordua zehazteko."</string>
+ <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Ordua idazteko, aldatu testua idazteko metodora."</string>
<string name="time_picker_radial_mode_description" msgid="1222342577115016953">"Aldatu erloju modura ordua zehazteko."</string>
<string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Betetze automatikoaren aukerak"</string>
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Gorde betetze automatikoarekin erabiltzeko"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 77a1fec7..1732d08 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -854,7 +854,7 @@
<string name="emergency_calls_only" msgid="3057351206678279851">"Só chamadas de emerxencia"</string>
<string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Bloqueada pola rede"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"A tarxeta SIM está bloqueada con código PUK."</string>
- <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta a guía do usuario ou ponte en contacto co servizo de asistencia ao cliente."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consulta a guía para usuarios ou ponte en contacto co servizo de asistencia ao cliente."</string>
<string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"A tarxeta SIM está bloqueada."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"Desbloqueando tarxeta SIM…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f5686c2..1604bea 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1149,7 +1149,7 @@
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"「%1$s」を使用して画像をキャプチャ"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"画像をキャプチャ"</string>
<string name="alwaysUse" msgid="3153558199076112903">"常にこの操作で使用する"</string>
- <string name="use_a_different_app" msgid="4987790276170972776">"別のアプリの使用"</string>
+ <string name="use_a_different_app" msgid="4987790276170972776">"別のアプリを使用"</string>
<string name="clearDefaultHintMsg" msgid="1325866337702524936">"[システム設定]>[アプリ]>[ダウンロード済み]でデフォルト設定をクリアします。"</string>
<string name="chooseActivity" msgid="8563390197659779956">"操作の選択"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USBデバイス用アプリを選択"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 28409e0..c55946e 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"Жіберілуде..."</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Браузер қосылсын ба?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Қоңырауды қабылдау?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"Үнемі"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"Әрқашан"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Бір рет қана"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s жұмыс профилін қолдамайды"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Планшет"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index a866362..5908475 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -536,7 +536,7 @@
<string name="permdesc_imagesWrite" msgid="5195054463269193317">"Колдонмого сүрөт жыйнагыңызды өзгөртүүгө мүмкүнчүлүк берет."</string>
<string name="permlab_mediaLocation" msgid="7368098373378598066">"медиа жыйнагыңыз сакталган жерлерди окуу"</string>
<string name="permdesc_mediaLocation" msgid="597912899423578138">"Колдонмого медиа жыйнагыңыз сакталган жерлерди окууга мүмкүнчүлүк берет."</string>
- <string name="biometric_dialog_default_title" msgid="55026799173208210">"Сиз экениңизди ырастаңыз"</string>
+ <string name="biometric_dialog_default_title" msgid="55026799173208210">"Өзүңүздү ырастаңыз"</string>
<string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Биометрикалык аппарат жеткиликсиз"</string>
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"Аныктыгын текшерүү жокко чыгарылды"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"Таанылган жок"</string>
@@ -1547,7 +1547,7 @@
<string name="sending" msgid="206925243621664438">"Жөнөтүлүүдө…"</string>
<string name="launchBrowserDefault" msgid="6328349989932924119">"Серепчи иштетилсинби?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Чалуу кабыл алынсынбы?"</string>
- <string name="activity_resolver_use_always" msgid="5575222334666843269">"Дайыма"</string>
+ <string name="activity_resolver_use_always" msgid="5575222334666843269">"Ар дайым"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Бир жолу гана"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s жумуш профилин колдоого албайт"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Планшет"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 0533758..e07a81d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1090,7 +1090,7 @@
<string name="elapsed_time_short_format_mm_ss" msgid="8689459651807876423">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="1532369154488982046">"Hammasini belgilash"</string>
- <string name="cut" msgid="2561199725874745819">"Kesish"</string>
+ <string name="cut" msgid="2561199725874745819">"Kesib olish"</string>
<string name="copy" msgid="5472512047143665218">"Nusxa olish"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Vaqtinchalik xotiraga nusxalab bo‘lmadi"</string>
<string name="paste" msgid="461843306215520225">"Joylash"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 69358d4..72dd458 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1792,8 +1792,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
- <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
- <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,節約耗電量功能會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
+ <string name="battery_saver_description_with_learn_more" msgid="5997766757551917769">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞\n\n"<annotation id="url">"瞭解詳情"</annotation></string>
+ <string name="battery_saver_description" msgid="8587408568232177204">"為了延長電池續航力,省電模式會執行以下動作:\n\n•開啟深色主題\n•關閉或限制背景活動、部分視覺效果和其他功能,例如「Hey Google」啟動字詞"</string>
<string name="data_saver_description" msgid="4995164271550590517">"「數據節省模式」可防止部分應用程式在背景收發資料,以節省數據用量。你目前使用的應用程式可以存取資料,但存取頻率可能不如平時高。舉例來說,圖片可能不會自動顯示,在你輕觸後才會顯示。"</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"要開啟數據節省模式嗎?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"開啟"</string>
@@ -1999,9 +1999,9 @@
<string name="notification_appops_overlay_active" msgid="5571732753262836481">"顯示在畫面上的其他應用程式上層"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"電池電力可能會在你平常的充電時間前耗盡"</string>
- <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用節約耗電量模式以延長電池續航力"</string>
- <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"節約耗電量"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"節約耗電量模式已關閉"</string>
+ <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"已啟用省電模式以延長電池續航力"</string>
+ <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"省電模式"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"省電模式已關閉"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"手機電力充足,各項功能不再受到限制。"</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"平板電腦電力充足,各項功能不再受到限制。"</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"裝置電力充足,各項功能不再受到限制。"</string>
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 702f2fa..c36f106 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -691,18 +691,57 @@
@Test
public void testRequestedState() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+
+ // The modified state can be controlled when we have control.
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
mController.hide(statusBars());
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
- mController.onControlsChanged(new InsetsSourceControl[0]);
+
+ // The modified state won't be changed while losing control.
+ mController.onControlsChanged(null /* activeControls */);
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+ // The modified state won't be changed while state changed while we don't have control.
InsetsState newState = new InsetsState(mController.getState(), true /* copySource */);
mController.onStateChanged(newState);
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+ // The modified state won't be changed while controlling an insets without having the
+ // control.
mController.show(statusBars());
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+ // The modified state can be updated while gaining control.
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
assertTrue(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+ // The modified state can still be updated if the local state and the requested state
+ // are the same.
+ mController.onControlsChanged(null /* activeControls */);
+ mController.hide(statusBars());
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_STATUS_BAR).setVisible(false);
+ mController.onStateChanged(newState);
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
+ assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
+
+ // The modified state will always be updated while receiving IME control if IME is
+ // requested visible.
+ mController.getSourceConsumer(ITYPE_IME).show(false /* fromIme */);
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_IME).setVisible(true);
+ newState.getSource(ITYPE_IME).setFrame(1, 2, 3, 4);
+ mController.onStateChanged(newState);
+ mController.onControlsChanged(createSingletonControl(ITYPE_IME));
+ assertEquals(newState.getSource(ITYPE_IME),
+ mTestHost.getModifiedState().peekSource(ITYPE_IME));
+ newState = new InsetsState(mController.getState(), true /* copySource */);
+ newState.getSource(ITYPE_IME).setVisible(true);
+ newState.getSource(ITYPE_IME).setFrame(5, 6, 7, 8);
+ mController.onStateChanged(newState);
+ mController.onControlsChanged(createSingletonControl(ITYPE_IME));
+ assertEquals(newState.getSource(ITYPE_IME),
+ mTestHost.getModifiedState().peekSource(ITYPE_IME));
});
}
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 1b32725..7efd616 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -71,6 +71,9 @@
private SurfaceControl mLeash;
@Mock Transaction mMockTransaction;
private InsetsSource mSpyInsetsSource;
+ private boolean mRemoveSurfaceCalled = false;
+ private InsetsController mController;
+ private InsetsState mState;
@Before
public void setup() {
@@ -89,13 +92,19 @@
} catch (BadTokenException e) {
// activity isn't running, lets ignore BadTokenException.
}
- InsetsState state = new InsetsState();
+ mState = new InsetsState();
mSpyInsetsSource = Mockito.spy(new InsetsSource(ITYPE_STATUS_BAR));
- state.addSource(mSpyInsetsSource);
+ mState.addSource(mSpyInsetsSource);
- mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, state,
- () -> mMockTransaction,
- new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl)));
+ mController = new InsetsController(new ViewRootInsetsControllerHost(viewRootImpl));
+ mConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mState,
+ () -> mMockTransaction, mController) {
+ @Override
+ public void removeSurface() {
+ super.removeSurface();
+ mRemoveSurfaceCalled = true;
+ }
+ };
});
instrumentation.waitForIdleSync();
@@ -171,6 +180,25 @@
mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
new int[1], hideTypes);
assertEquals(statusBars(), hideTypes[0]);
+ assertFalse(mRemoveSurfaceCalled);
});
}
+
+ @Test
+ public void testRestore_noAnimation() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mConsumer.hide();
+ mController.onStateChanged(mState);
+ mConsumer.setControl(null, new int[1], new int[1]);
+ reset(mMockTransaction);
+ verifyZeroInteractions(mMockTransaction);
+ mRemoveSurfaceCalled = false;
+ int[] hideTypes = new int[1];
+ mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+ new int[1], hideTypes);
+ assertTrue(mRemoveSurfaceCalled);
+ assertEquals(0, hideTypes[0]);
+ });
+
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 2ef6934..201ed9c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -100,7 +100,8 @@
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- int avatarSize = (int) v.getResources().getDimension(R.dimen.qs_framed_avatar_size);
+ int avatarSize =
+ (int) mContext.getResources().getDimension(R.dimen.qs_framed_avatar_size);
Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
drawable.setColorFilter(
item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 5ec5ec6..f52a6e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -288,7 +288,8 @@
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- int avatarSize = (int) v.getResources().getDimension(R.dimen.kg_framed_avatar_size);
+ int avatarSize =
+ (int) mContext.getResources().getDimension(R.dimen.kg_framed_avatar_size);
Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
drawable.setColorFilter(
item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 8ba5b99..c0089e5 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -226,6 +226,8 @@
if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
&& mAnimation != null) {
startAnimation(mImeShowing, true /* forceRestart */);
+ } else if (!mImeShowing) {
+ removeImeSurface();
}
});
}
@@ -370,16 +372,7 @@
dispatchEndPositioning(mDisplayId, mCancelled, t);
if (mAnimationDirection == DIRECTION_HIDE && !mCancelled) {
t.hide(mImeSourceControl.getLeash());
- final IInputMethodManager imms = getImms();
- if (imms != null) {
- try {
- // Remove the IME surface to make the insets invisible for
- // non-client controlled insets.
- imms.removeImeSurface();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to remove IME surface.", e);
- }
- }
+ removeImeSurface();
}
t.apply();
mTransactionPool.release(t);
@@ -402,6 +395,19 @@
}
}
+ void removeImeSurface() {
+ final IInputMethodManager imms = getImms();
+ if (imms != null) {
+ try {
+ // Remove the IME surface to make the insets invisible for
+ // non-client controlled insets.
+ imms.removeImeSurface();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to remove IME surface.", e);
+ }
+ }
+ }
+
/**
* Allows other things to synchronize with the ime position
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index 6d6a4d8..f48b3fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
@@ -25,6 +25,8 @@
import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.util.UserIcons
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.qs.QSUserSwitcherEvent
import com.android.systemui.statusbar.policy.UserSwitcherController
@@ -50,10 +52,10 @@
@Mock private lateinit var mOtherView: View
@Mock private lateinit var mInflatedUserDetailItemView: UserDetailItemView
@Mock private lateinit var mUserInfo: UserInfo
- @Mock private lateinit var mPicture: Bitmap
@Mock private lateinit var mLayoutInflater: LayoutInflater
private lateinit var adapter: UserDetailView.Adapter
private lateinit var uiEventLogger: UiEventLoggerFake
+ private lateinit var mPicture: Bitmap
@Before
fun setUp() {
@@ -64,6 +66,7 @@
`when`(mLayoutInflater.inflate(anyInt(), any(ViewGroup::class.java), anyBoolean()))
.thenReturn(mInflatedUserDetailItemView)
adapter = UserDetailView.Adapter(mContext, mUserSwitcherController, uiEventLogger)
+ mPicture = UserIcons.convertToBitmap(mContext.getDrawable(R.drawable.ic_avatar_user))
}
private fun clickableTest(
@@ -141,4 +144,4 @@
false /* isAddUser */,
false /* isRestricted */,
true /* isSwitchToEnabled */)
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5124c4a..a2eea13 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -470,22 +470,23 @@
// if this receiver was slow, impose deferral policy on the app. This will kick in
// when processNextBroadcastLocked() next finds this uid as a receiver identity.
if (!r.timeoutExempt) {
- if (mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
+ // r.curApp can be null if finish has raced with process death - benign
+ // edge case, and we just ignore it because we're already cleaning up
+ // as expected.
+ if (r.curApp != null
+ && mConstants.SLOW_TIME > 0 && elapsed > mConstants.SLOW_TIME) {
// Core system packages are exempt from deferral policy
if (!UserHandle.isCore(r.curApp.uid)) {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Broadcast receiver " + (r.nextReceiver - 1)
+ " was slow: " + receiver + " br=" + r);
}
- if (r.curApp != null) {
- mDispatcher.startDeferring(r.curApp.uid);
- } else {
- Slog.d(TAG_BROADCAST, "finish receiver curApp is null? " + r);
- }
+ mDispatcher.startDeferring(r.curApp.uid);
} else {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Core uid " + r.curApp.uid
- + " receiver was slow but not deferring: " + receiver + " br=" + r);
+ + " receiver was slow but not deferring: "
+ + receiver + " br=" + r);
}
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
index 70f0399..05cf40a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerInternal.java
@@ -120,6 +120,11 @@
public abstract void reportImeControl(@Nullable IBinder windowToken);
/**
+ * Destroys the IME surface.
+ */
+ public abstract void removeImeSurface();
+
+ /**
* Fake implementation of {@link InputMethodManagerInternal}. All the methods do nothing.
*/
private static final InputMethodManagerInternal NOP =
@@ -166,6 +171,10 @@
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
+
+ @Override
+ public void removeImeSurface() {
+ }
};
/**
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c027ebc..0154fe0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -18,8 +18,6 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.internal.inputmethod.StartInputReason.WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR;
-
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.Manifest;
@@ -211,6 +209,7 @@
static final int MSG_INITIALIZE_IME = 1040;
static final int MSG_CREATE_SESSION = 1050;
static final int MSG_REMOVE_IME_SURFACE = 1060;
+ static final int MSG_REMOVE_IME_SURFACE_FROM_WINDOW = 1061;
static final int MSG_START_INPUT = 2000;
@@ -718,11 +717,6 @@
*/
int mImeWindowVis;
- /**
- * Checks if the client needs to start input.
- */
- private boolean mCurClientNeedStartInput = false;
-
private AlertDialog.Builder mDialogBuilder;
private AlertDialog mSwitchingDialog;
private IBinder mSwitchingDialogToken = new Binder();
@@ -3466,20 +3460,14 @@
if (mCurFocusedWindow == windowToken) {
if (DEBUG) {
Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
- + " attribute=" + attribute + ", token = " + windowToken);
+ + " attribute=" + attribute + ", token = " + windowToken
+ + ", startInputReason="
+ + InputMethodDebug.startInputReasonToString(startInputReason));
}
- // Needs to start input when the same window focus gain but not with the same editor,
- // or when the current client needs to start input (e.g. when focusing the same
- // window after device turned screen on).
- if (attribute != null && (startInputReason != WINDOW_FOCUS_GAIN_REPORT_WITH_SAME_EDITOR
- || mCurClientNeedStartInput)) {
- if (mIsInteractive) {
- mCurClientNeedStartInput = false;
- }
+ if (attribute != null) {
return startInputUncheckedLocked(cs, inputContext, missingMethods,
attribute, startInputFlags, startInputReason);
}
-
return new InputBindResult(
InputBindResult.ResultCode.SUCCESS_REPORT_WINDOW_FOCUS_ONLY,
null, null, null, -1, null);
@@ -4005,6 +3993,13 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
}
+ @Override
+ public void removeImeSurfaceFromWindow(IBinder windowToken) {
+ // No permission check, because we'll only execute the request if the calling window is
+ // also the current IME client.
+ mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE_FROM_WINDOW, windowToken).sendToTarget();
+ }
+
@BinderThread
private void notifyUserAction(@NonNull IBinder token) {
if (DEBUG) {
@@ -4278,11 +4273,27 @@
return true;
}
case MSG_REMOVE_IME_SURFACE: {
- try {
- if (mEnabledSession != null && mEnabledSession.session != null) {
- mEnabledSession.session.removeImeSurface();
+ synchronized (mMethodMap) {
+ try {
+ if (mEnabledSession != null && mEnabledSession.session != null
+ && !mShowRequested) {
+ mEnabledSession.session.removeImeSurface();
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
+ }
+ return true;
+ }
+ case MSG_REMOVE_IME_SURFACE_FROM_WINDOW: {
+ IBinder windowToken = (IBinder) msg.obj;
+ synchronized (mMethodMap) {
+ try {
+ if (windowToken == mCurFocusedWindow
+ && mEnabledSession != null && mEnabledSession.session != null) {
+ mEnabledSession.session.removeImeSurface();
+ }
+ } catch (RemoteException e) {
+ }
}
return true;
}
@@ -4435,9 +4446,6 @@
private void handleSetInteractive(final boolean interactive) {
synchronized (mMethodMap) {
mIsInteractive = interactive;
- if (!interactive) {
- mCurClientNeedStartInput = true;
- }
updateSystemUiLocked(interactive ? mImeWindowVis : 0, mBackDisposition);
// Inform the current client of the change in active status
@@ -5116,6 +5124,11 @@
public void reportImeControl(@Nullable IBinder windowToken) {
mService.reportImeControl(windowToken);
}
+
+ @Override
+ public void removeImeSurface() {
+ mService.mHandler.sendMessage(mService.mHandler.obtainMessage(MSG_REMOVE_IME_SURFACE));
+ }
}
@BinderThread
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 2e3d396..19dff98 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -225,6 +225,11 @@
@Override
public void reportImeControl(@Nullable IBinder windowToken) {
}
+
+ @Override
+ public void removeImeSurface() {
+ reportNotSupported();
+ }
});
}
@@ -1473,6 +1478,12 @@
@BinderThread
@Override
+ public void removeImeSurfaceFromWindow(IBinder windowToken) {
+ reportNotSupported();
+ }
+
+ @BinderThread
+ @Override
public boolean showSoftInput(
IInputMethodClient client, IBinder token, int flags,
ResultReceiver resultReceiver) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2f14926..330f995 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -589,12 +589,12 @@
}
}
- if (mBypassNextStagedInstallerCheck) {
- mBypassNextStagedInstallerCheck = false;
- } else if (params.isStaged
- && !isCalledBySystemOrShell(callingUid)
- && !isWhitelistedStagedInstaller(requestedInstallerPackageName)) {
- throw new SecurityException("Installer not allowed to commit staged install");
+ if (params.isStaged && !isCalledBySystemOrShell(callingUid)) {
+ if (mBypassNextStagedInstallerCheck) {
+ mBypassNextStagedInstallerCheck = false;
+ } else if (!isStagedInstallerAllowed(requestedInstallerPackageName)) {
+ throw new SecurityException("Installer not allowed to commit staged install");
+ }
}
if (!params.isMultiPackage) {
@@ -725,7 +725,7 @@
|| callingUid == Process.SHELL_UID;
}
- private boolean isWhitelistedStagedInstaller(String installerName) {
+ private boolean isStagedInstallerAllowed(String installerName) {
return SystemConfig.getInstance().getWhitelistedStagedInstallers().contains(installerName);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e8a4234..b94fb04 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3574,12 +3574,11 @@
}
}
- private void updateImeControlTarget() {
+ void updateImeControlTarget() {
mInputMethodControlTarget = computeImeControlTarget();
mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget);
- final WindowState win = mInputMethodControlTarget != null
- ? mInputMethodControlTarget.getWindow() : null;
+ final WindowState win = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
final IBinder token = win != null ? win.mClient.asBinder() : null;
// Note: not allowed to call into IMMS with the WM lock held, hence the post.
mWmService.mH.post(() ->
@@ -3603,6 +3602,17 @@
if (!isImeControlledByApp() && mRemoteInsetsControlTarget != null) {
return mRemoteInsetsControlTarget;
} else {
+ // Now, a special case -- if the last target's window is in the process of exiting, but
+ // not removed, keep on the last target to avoid IME flicker.
+ final WindowState cur = InsetsControlTarget.asWindowOrNull(mInputMethodControlTarget);
+ if (cur != null && !cur.mRemoved && cur.isDisplayedLw() && cur.isClosing()
+ && !cur.isActivityTypeHome()) {
+ if (DEBUG_INPUT_METHOD) {
+ Slog.v(TAG_WM, "Not changing control while current window"
+ + " is closing and not removed");
+ }
+ return cur;
+ }
// Otherwise, we just use the ime target as received from IME.
return mInputMethodInputTarget;
}
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 8298763..99ee5e1 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -18,13 +18,14 @@
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME;
-import android.graphics.PixelFormat;
import android.view.InsetsSource;
import android.view.WindowInsets;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.protolog.common.ProtoLog;
+import java.io.PrintWriter;
+
/**
* Controller for IME inset source on the server. It's called provider as it provides the
* {@link InsetsSource} to the client that uses it in {@link InsetsSourceConsumer}.
@@ -132,8 +133,17 @@
|| (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme
&& dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer)
|| mImeTargetFromIme == mDisplayContent.getImeFallback()
- // If IME target is transparent but control target matches requesting window.
- || (controlTarget == mImeTargetFromIme
- && PixelFormat.formatHasAlpha(dcTarget.mAttrs.format));
+ || (!mImeTargetFromIme.isClosing() && controlTarget == mImeTargetFromIme);
+ }
+
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ super.dump(pw, prefix);
+ if (mImeTargetFromIme != null) {
+ pw.print(prefix);
+ pw.print("showImePostLayout pending for mImeTargetFromIme=");
+ pw.print(mImeTargetFromIme);
+ pw.println();
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8734b5e..0216db4 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,13 +16,14 @@
package com.android.server.wm;
-import static android.os.Process.myPid;
-import static android.os.Process.myUid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
@@ -477,12 +478,18 @@
mService.getRecentsAnimationController();
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
+ final int type = w.mAttrs.type;
+ final boolean isVisible = w.isVisibleLw();
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
|| (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
if (w.mWinAnimator.hasSurface()) {
+ // Assign an InputInfo with type to the overlay window which can't receive input
+ // event. This is used to omit Surfaces from occlusion detection.
+ populateOverlayInputInfo(mInvalidInputWindow, w.getName(), type, isVisible);
mInputTransaction.setInputWindowInfo(
- w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
- mInvalidInputWindow);
+ w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
+ mInvalidInputWindow);
+ return;
}
// Skip this window because it cannot possibly receive input.
return;
@@ -490,9 +497,7 @@
final int flags = w.mAttrs.flags;
final int privateFlags = w.mAttrs.privateFlags;
- final int type = w.mAttrs.type;
final boolean hasFocus = w.isFocused();
- final boolean isVisible = w.isVisibleLw();
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
@@ -555,6 +560,26 @@
}
}
+ // This would reset InputWindowHandle fields to prevent it could be found by input event.
+ // We need to check if any new field of InputWindowHandle could impact the result.
+ private static void populateOverlayInputInfo(final InputWindowHandle inputWindowHandle,
+ final String name, final int type, final boolean isVisible) {
+ inputWindowHandle.name = name;
+ inputWindowHandle.layoutParamsType = type;
+ inputWindowHandle.dispatchingTimeoutNanos =
+ WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ inputWindowHandle.visible = isVisible;
+ inputWindowHandle.canReceiveKeys = false;
+ inputWindowHandle.hasFocus = false;
+ inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
+ inputWindowHandle.scaleFactor = 1;
+ inputWindowHandle.layoutParamsFlags =
+ FLAG_NOT_TOUCH_MODAL | FLAG_NOT_TOUCHABLE | FLAG_NOT_FOCUSABLE;
+ inputWindowHandle.portalToDisplayId = INVALID_DISPLAY;
+ inputWindowHandle.touchableRegion.setEmpty();
+ inputWindowHandle.setTouchableRegionCrop(null);
+ }
+
/**
* Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input
* info will not have an input channel or be touchable, but is used to omit Surfaces
@@ -564,16 +589,7 @@
static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t,
int displayId, String name) {
InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId);
- inputWindowHandle.name = name;
- inputWindowHandle.layoutParamsType = TYPE_SECURE_SYSTEM_OVERLAY;
- inputWindowHandle.dispatchingTimeoutNanos = -1;
- inputWindowHandle.visible = true;
- inputWindowHandle.canReceiveKeys = false;
- inputWindowHandle.hasFocus = false;
- inputWindowHandle.ownerPid = myPid();
- inputWindowHandle.ownerUid = myUid();
- inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL;
- inputWindowHandle.scaleFactor = 1;
+ populateOverlayInputInfo(inputWindowHandle, name, TYPE_SECURE_SYSTEM_OVERLAY, true);
t.setInputWindowInfo(sc, inputWindowHandle);
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index c50f296..3ffc26a 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -62,4 +62,8 @@
return false;
}
+ /** Returns {@code target.getWindow()}, or null if {@code target} is {@code null}. */
+ static WindowState asWindowOrNull(InsetsControlTarget target) {
+ return target != null ? target.getWindow() : null;
+ }
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 63083fa..77bd4a4 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -44,6 +44,7 @@
import android.view.InsetsState.InternalInsetsType;
import android.view.WindowManager;
+import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -74,7 +75,21 @@
w.notifyInsetsChanged();
}
};
- private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() { };
+ private final InsetsControlTarget mEmptyImeControlTarget = new InsetsControlTarget() {
+ @Override
+ public void notifyInsetsControlChanged() {
+ InsetsSourceControl[] controls = getControlsForDispatch(this);
+ if (controls == null) {
+ return;
+ }
+ for (InsetsSourceControl control : controls) {
+ if (control.getType() == ITYPE_IME) {
+ mDisplayContent.mWmService.mH.post(() ->
+ InputMethodManagerInternal.get().removeImeSurface());
+ }
+ }
+ }
+ };
InsetsStateController(DisplayContent displayContent) {
mDisplayContent = displayContent;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 837fafe..00be75f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2170,6 +2170,9 @@
if (isInputMethodTarget()) {
dc.computeImeTarget(true /* updateImeTarget */);
}
+ if (dc.mInputMethodControlTarget == this) {
+ dc.updateImeControlTarget();
+ }
final int type = mAttrs.type;
if (WindowManagerService.excludeWindowTypeFromTapOutTask(type)) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 77e3c59..d64fdb8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -898,6 +898,26 @@
}
@Test
+ public void testComputeImeControlTarget_exitingApp() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+
+ WindowState exitingWin = createWindow(null, TYPE_BASE_APPLICATION, "exiting app");
+ makeWindowVisible(exitingWin);
+ exitingWin.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+ exitingWin.mAnimatingExit = true;
+
+ dc.mInputMethodControlTarget = exitingWin;
+ dc.mInputMethodTarget = dc.mInputMethodInputTarget =
+ createWindow(null, TYPE_BASE_APPLICATION, "starting app");
+
+ assertEquals(exitingWin, dc.computeImeControlTarget());
+
+ exitingWin.removeImmediately();
+
+ assertEquals(dc.mInputMethodInputTarget, dc.computeImeControlTarget());
+ }
+
+ @Test
public void testComputeImeControlTarget_splitscreen() throws Exception {
final DisplayContent dc = createNewDisplay();
dc.mInputMethodInputTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");