Merge "Fix javadoc error in ApplicationExitInfo#getDefiningUid()" into rvc-dev
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index fe270a4..fed9c43 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -68,6 +68,8 @@
private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
+ private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
+
/**
* Change the system dialer package name if a package name was specified,
* Example: adb shell telecom set-system-dialer <PACKAGE>
@@ -115,6 +117,8 @@
+ "usage: telecom set-sim-count <COUNT>\n"
+ "usage: telecom get-sim-config\n"
+ "usage: telecom get-max-phones\n"
+ + "usage: telecom stop-block-suppression: Stop suppressing the blocked number"
+ + " provider after a call to emergency services.\n"
+ "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
+ "\n"
+ "telecom set-phone-account-enabled: Enables the given phone account, if it has"
@@ -207,6 +211,9 @@
case COMMAND_UNREGISTER_PHONE_ACCOUNT:
runUnregisterPhoneAccount();
break;
+ case COMMAND_STOP_BLOCK_SUPPRESSION:
+ runStopBlockSuppression();
+ break;
case COMMAND_SET_DEFAULT_DIALER:
runSetDefaultDialer();
break;
@@ -324,8 +331,13 @@
System.out.println("Success - " + handle + " unregistered.");
}
+ private void runStopBlockSuppression() throws RemoteException {
+ mTelecomService.stopBlockSuppression();
+ }
+
private void runSetDefaultDialer() throws RemoteException {
- final String packageName = nextArgRequired();
+ String packageName = nextArg();
+ if ("default".equals(packageName)) packageName = null;
mTelecomService.setTestDefaultDialer(packageName);
System.out.println("Success - " + packageName + " set as override default dialer.");
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a828aac..505b498 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1900,26 +1900,31 @@
@Override
public Object getSystemService(String name) {
- // We may override this API from outer context.
- final boolean isUiContext = isUiContext() || getOuterContext().isUiContext();
- // Check incorrect Context usage.
- if (isUiComponent(name) && !isUiContext && vmIncorrectContextUseEnabled()) {
- final String errorMessage = "Tried to access visual service "
- + SystemServiceRegistry.getSystemServiceClassName(name)
- + " from a non-visual Context:" + getOuterContext();
- final String message = "Visual services, such as WindowManager, WallpaperService or "
- + "LayoutInflater should be accessed from Activity or other visual Context. "
- + "Use an Activity or a Context created with "
- + "Context#createWindowContext(int, Bundle), which are adjusted to the "
- + "configuration and visual bounds of an area on screen.";
- final Exception exception = new IllegalAccessException(errorMessage);
- StrictMode.onIncorrectContextUsed(message, exception);
- Log.e(TAG, errorMessage + message, exception);
+ if (vmIncorrectContextUseEnabled()) {
+ // We may override this API from outer context.
+ final boolean isUiContext = isUiContext() || isOuterUiContext();
+ // Check incorrect Context usage.
+ if (isUiComponent(name) && !isUiContext) {
+ final String errorMessage = "Tried to access visual service "
+ + SystemServiceRegistry.getSystemServiceClassName(name)
+ + " from a non-visual Context:" + getOuterContext();
+ final String message = "Visual services, such as WindowManager, WallpaperService "
+ + "or LayoutInflater should be accessed from Activity or other visual "
+ + "Context. Use an Activity or a Context created with "
+ + "Context#createWindowContext(int, Bundle), which are adjusted to "
+ + "the configuration and visual bounds of an area on screen.";
+ final Exception exception = new IllegalAccessException(errorMessage);
+ StrictMode.onIncorrectContextUsed(message, exception);
+ Log.e(TAG, errorMessage + " " + message, exception);
+ }
}
-
return SystemServiceRegistry.getSystemService(this, name);
}
+ private boolean isOuterUiContext() {
+ return getOuterContext() != null && getOuterContext().isUiContext();
+ }
+
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return SystemServiceRegistry.getSystemServiceName(serviceClass);
@@ -2371,7 +2376,7 @@
context.setResources(createResources(mToken, mPackageInfo, mSplitName, displayId,
overrideConfiguration, getDisplayAdjustments(displayId).getCompatibilityInfo(),
mResources.getLoaders()));
- context.mIsUiContext = isUiContext() || getOuterContext().isUiContext();
+ context.mIsUiContext = isUiContext() || isOuterUiContext();
return context;
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 5dc41e4..89abfc9 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1151,6 +1151,9 @@
*/
@Override
public boolean isUiContext() {
+ if (mBase == null) {
+ return false;
+ }
return mBase.isUiContext();
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c577d0e..53e75d4 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -4666,8 +4666,7 @@
* Marks an application exempt from having its permissions be automatically revoked when
* the app is unused for an extended period of time.
*
- * Only the installer on record that installed the given package, or a holder of
- * {@code WHITELIST_AUTO_REVOKE_PERMISSIONS} is allowed to call this.
+ * Only the installer on record that installed the given package is allowed to call this.
*
* Packages start in whitelisted state, and it is the installer's responsibility to
* un-whitelist the packages it installs, unless auto-revoking permissions from that package
diff --git a/core/java/android/inputmethodservice/InlineSuggestionSession.java b/core/java/android/inputmethodservice/InlineSuggestionSession.java
index 509cbe0..90d0ff0a 100644
--- a/core/java/android/inputmethodservice/InlineSuggestionSession.java
+++ b/core/java/android/inputmethodservice/InlineSuggestionSession.java
@@ -149,6 +149,11 @@
*/
@MainThread
void invalidate() {
+ try {
+ mCallback.onInlineSuggestionsSessionInvalidated();
+ } catch (RemoteException e) {
+ Log.w(TAG, "onInlineSuggestionsSessionInvalidated() remote exception:" + e);
+ }
if (mResponseCallback != null) {
consumeInlineSuggestionsResponse(EMPTY_RESPONSE);
mResponseCallback.invalidate();
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/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/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..2b7044d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2725,7 +2725,6 @@
mAttachInfo.mThreadedRenderer.isEnabled()) {
mAttachInfo.mThreadedRenderer.destroy();
}
- notifySurfaceDestroyed();
} else if ((surfaceReplaced
|| surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
&& mSurfaceHolder == null
@@ -2956,6 +2955,10 @@
}
}
+ if (surfaceDestroyed) {
+ notifySurfaceDestroyed();
+ }
+
if (triggerGlobalLayoutListener) {
mAttachInfo.mRecomputeGlobalAttributes = false;
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
@@ -9377,6 +9380,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..3be0a4d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -2109,28 +2109,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 +2148,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/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index ff3ac073..9eb63087 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -174,12 +174,9 @@
int touchSlop = config.getScaledTouchSlop();
mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop;
if (mMovedEnoughForDrag) {
- // If the direction of the swipe motion is within 30 degrees of vertical, it is
- // considered a vertical drag. We don't actually have to compute the angle to
- // implement the check though. When the angle is exactly 30 degrees from
- // vertical, 2*deltaX = distance. When the angle is less than 30 degrees from
- // vertical, 2*deltaX < distance.
- mIsDragCloseToVertical = (4 * deltaXSquared) <= distanceSquared;
+ // If the direction of the swipe motion is within 45 degrees of vertical, it is
+ // considered a vertical drag.
+ mIsDragCloseToVertical = Math.abs(deltaX) <= Math.abs(deltaY);
}
}
} else if (action == MotionEvent.ACTION_CANCEL) {
diff --git a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
index cf1220c..03948a9 100644
--- a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
+++ b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl
@@ -58,4 +58,7 @@
// #onFinishInput()} is called on the field specified by the earlier
// {@link #onInputMethodStartInput(AutofillId)}.
void onInputMethodFinishInput();
+
+ // Indicates that the current IME changes inline suggestion session.
+ void onInlineSuggestionsSessionInvalidated();
}
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/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index 17d1389..777f4a3 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -23,6 +23,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.app.ActivityThread;
@@ -180,4 +181,26 @@
VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY);
return virtualDisplay.getDisplay();
}
+
+ @Test
+ public void testIsUiContext_ContextWrapper() {
+ ContextWrapper wrapper = new ContextWrapper(null /* base */);
+
+ assertFalse(wrapper.isUiContext());
+
+ wrapper = new ContextWrapper(new TestUiContext());
+
+ assertTrue(wrapper.isUiContext());
+ }
+
+ private static class TestUiContext extends ContextWrapper {
+ TestUiContext() {
+ super(null /* base */);
+ }
+
+ @Override
+ public boolean isUiContext() {
+ return true;
+ }
+ }
}
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/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index 89cc6e7..838f600 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -145,7 +145,7 @@
// Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
// the handle as the touch moves downwards (and because we have some slop to avoid jumping
// across lines), the cursor position will end up higher than the finger position.
- onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
+ onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
// Swipe right-down along a very steep diagonal path. This should not drag the cursor.
@@ -181,7 +181,7 @@
// Swipe along a diagonal path. This should drag the cursor. Because we snap the finger to
// the handle as the touch moves downwards (and because we have some slop to avoid jumping
// across lines), the cursor position will end up higher than the finger position.
- onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("3")));
+ onView(withId(R.id.textview)).perform(dragOnText(text.indexOf("line1"), text.indexOf("2")));
onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("1")));
// Swipe right-down along a very steep diagonal path. This should not drag the cursor.
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index ec75e40..35fd4bd 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -326,9 +326,9 @@
mTouchState.update(event1, mConfig);
assertSingleTap(mTouchState, 0f, 0f, 0, 0);
- // Simulate an ACTION_MOVE event that is > 30 deg from vertical.
+ // Simulate an ACTION_MOVE event that is > 45 deg from vertical.
long event2Time = 1002;
- MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 173f);
+ MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f);
mTouchState.update(event2, mConfig);
assertDrag(mTouchState, 0f, 0f, 0, 0, false);
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
index 278b57d..e5ea446 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
@@ -41,7 +41,7 @@
private final Bitmap mBitmap;
private final int mSize;
- private final Paint mPaint;
+ private Paint mIconPaint;
private float mScale;
private Rect mSrcRect;
@@ -75,18 +75,18 @@
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
// opaque circle matte
- mPaint = new Paint();
- mPaint.setAntiAlias(true);
- mPaint.setColor(Color.BLACK);
- mPaint.setStyle(Paint.Style.FILL);
- canvas.drawPath(fillPath, mPaint);
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setColor(Color.BLACK);
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawPath(fillPath, paint);
// mask in the icon where the bitmap is opaque
- mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
- canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(icon, cropRect, circleRect, paint);
// prepare paint for frame drawing
- mPaint.setXfermode(null);
+ paint.setXfermode(null);
mScale = 1f;
@@ -100,7 +100,7 @@
final float pad = (mSize - inside) / 2f;
mDstRect.set(pad, pad, mSize - pad, mSize - pad);
- canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
+ canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, mIconPaint);
}
public void setScale(float scale) {
@@ -122,8 +122,12 @@
@Override
public void setColorFilter(ColorFilter cf) {
+ if (mIconPaint == null) {
+ mIconPaint = new Paint();
+ }
+ mIconPaint.setColorFilter(cf);
}
-
+
@Override
public int getIntrinsicWidth() {
return mSize;
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 597644b..4527c6c 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -53,6 +53,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="4dp"
+ android:importantForAccessibility="no"
android:layout_weight="1">
<com.android.systemui.qs.QSPanel
android:id="@+id/quick_settings_panel"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
index 279a200..1e50580 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java
@@ -26,6 +26,7 @@
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.GraphicBuffer;
+import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
import android.util.Log;
@@ -63,10 +64,12 @@
public ThumbnailData(TaskSnapshot snapshot) {
final GraphicBuffer buffer = snapshot.getSnapshot();
- if (buffer != null && (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
+ if (buffer == null || (buffer.getUsage() & HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE) == 0) {
// TODO(b/157562905): Workaround for a crash when we get a snapshot without this state
- Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE");
- thumbnail = Bitmap.createBitmap(buffer.getWidth(), buffer.getHeight(), ARGB_8888);
+ Log.e("ThumbnailData", "Unexpected snapshot without USAGE_GPU_SAMPLED_IMAGE: "
+ + buffer);
+ Point taskSize = snapshot.getTaskSize();
+ thumbnail = Bitmap.createBitmap(taskSize.x, taskSize.y, ARGB_8888);
thumbnail.eraseColor(Color.BLACK);
} else {
thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 127c5dd..e12b7dd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -5,6 +5,7 @@
import android.content.res.Configuration
import android.graphics.Color
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
+import android.util.Log
import android.util.MathUtils
import android.view.LayoutInflater
import android.view.View
@@ -25,6 +26,7 @@
import javax.inject.Provider
import javax.inject.Singleton
+private const val TAG = "MediaCarouselController"
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
/**
@@ -236,7 +238,9 @@
val oldData = mediaPlayers[oldKey]
if (oldData != null) {
val oldData = mediaPlayers.remove(oldKey)
- mediaPlayers.put(key, oldData!!)
+ mediaPlayers.put(key, oldData!!)?.let {
+ Log.wtf(TAG, "new key $key already exists when migrating from $oldKey")
+ }
}
var existingPlayer = mediaPlayers[key]
if (existingPlayer == null) {
@@ -271,6 +275,11 @@
updatePageIndicator()
mediaCarouselScrollHandler.onPlayersChanged()
mediaCarousel.requiresRemeasuring = true
+ // Check postcondition: mediaContent should have the same number of children as there are
+ // elements in mediaPlayers.
+ if (mediaPlayers.size != mediaContent.childCount) {
+ Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
+ }
}
private fun removePlayer(key: String) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 8cb93bf..299ae5b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -517,22 +517,36 @@
fun onNotificationRemoved(key: String) {
Assert.isMainThread()
- if (useMediaResumption && mediaEntries.get(key)?.resumeAction != null) {
+ val removed = mediaEntries.remove(key)
+ if (useMediaResumption && removed?.resumeAction != null) {
Log.d(TAG, "Not removing $key because resumable")
- // Move to resume key aka package name
- val data = mediaEntries.remove(key)!!
- val resumeAction = getResumeMediaAction(data.resumeAction!!)
- val updated = data.copy(token = null, actions = listOf(resumeAction),
+ // Move to resume key (aka package name) if that key doesn't already exist.
+ val resumeAction = getResumeMediaAction(removed.resumeAction!!)
+ val updated = removed.copy(token = null, actions = listOf(resumeAction),
actionsToShowInCompact = listOf(0), active = false, resumption = true)
- mediaEntries.put(data.packageName, updated)
- // Notify listeners of "new" controls
+ val pkg = removed?.packageName
+ val migrate = mediaEntries.put(pkg, updated) == null
+ // Notify listeners of "new" controls when migrating or removed and update when not
val listenersCopy = listeners.toSet()
- listenersCopy.forEach {
- it.onMediaDataLoaded(data.packageName, key, updated)
+ if (migrate) {
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(pkg, key, updated)
+ }
+ } else {
+ // Since packageName is used for the key of the resumption controls, it is
+ // possible that another notification has already been reused for the resumption
+ // controls of this package. In this case, rather than renaming this player as
+ // packageName, just remove it and then send a update to the existing resumption
+ // controls.
+ listenersCopy.forEach {
+ it.onMediaDataRemoved(key)
+ }
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(pkg, pkg, updated)
+ }
}
return
}
- val removed = mediaEntries.remove(key)
if (removed != null) {
val listenersCopy = listeners.toSet()
listenersCopy.forEach {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index c454048..daf8ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -104,4 +104,13 @@
public void showBackground() {
mBackground.showSecondLayer();
}
+
+ /**
+ * Cancels the animator if it's running.
+ */
+ public void cancelAnimator() {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 3e2f9de..e5ed88c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -208,6 +208,7 @@
public void showImmediately() {
if (!isShown) {
setVisibility(VISIBLE);
+ mClipper.cancelAnimator();
mClipper.showBackground();
isShown = true;
setTileSpecs();
@@ -230,6 +231,10 @@
mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
isShown = false;
mToolbar.dismissPopupMenus();
+ mClipper.cancelAnimator();
+ // Make sure we're not opening (because we're closing). Nobody can think we are
+ // customizing after the next two lines.
+ mOpening = false;
setCustomizing(false);
save();
if (animate) {
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 fba7a22..2ef6934 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
@@ -33,6 +32,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
import com.android.systemui.qs.PseudoGridView;
import com.android.systemui.qs.QSUserSwitcherEvent;
@@ -100,7 +100,8 @@
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+ int avatarSize = (int) v.getResources().getDimension(R.dimen.qs_framed_avatar_size);
+ Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
drawable.setColorFilter(
item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
v.bind(name, drawable, item.info.id);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index 732f25f..e942d85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -371,12 +371,26 @@
float vectorVel = (float) Math.hypot(
mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
- boolean expand = flingExpands(vel, vectorVel, x, y)
- || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel;
+ final boolean onKeyguard =
+ mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
+
+ final boolean expand;
+ if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
+ // If we get a cancel, put the shade back to the state it was in when the gesture
+ // started
+ if (onKeyguard) {
+ expand = true;
+ } else {
+ expand = !mPanelClosedOnDown;
+ }
+ } else {
+ expand = flingExpands(vel, vectorVel, x, y);
+ }
+
mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
mStatusBar.isFalsingThresholdNeeded(), mStatusBar.isWakeUpComingFromTouch());
// Log collapse gesture if on lock screen.
- if (!expand && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+ if (!expand && onKeyguard) {
float displayDensity = mStatusBar.getDisplayDensity();
int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity);
int velocityDp = (int) Math.abs(vel / displayDensity);
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 512d0f3..5ec5ec6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -24,7 +24,6 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
@@ -36,6 +35,7 @@
import android.widget.FrameLayout;
import com.android.settingslib.animation.AppearAnimationUtils;
+import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -288,7 +288,8 @@
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId());
} else {
- Drawable drawable = new BitmapDrawable(v.getResources(), item.picture);
+ int avatarSize = (int) v.getResources().getDimension(R.dimen.kg_framed_avatar_size);
+ Drawable drawable = new CircleFramedDrawable(item.picture, avatarSize);
drawable.setColorFilter(
item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter());
v.bind(name, drawable, item.info.id);
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/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 6761b28..59c2d0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -31,6 +31,7 @@
import org.mockito.Mockito.`when` as whenever
private const val KEY = "KEY"
+private const val KEY_2 = "KEY_2"
private const val PACKAGE_NAME = "com.android.systemui"
private const val APP_NAME = "SystemUI"
private const val SESSION_ARTIST = "artist"
@@ -156,8 +157,43 @@
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
mediaDataManager.onNotificationRemoved(KEY)
- // THEN the media data indicates that it is
+ // THEN the media data indicates that it is for resumption
assertThat(listener.data!!.resumption).isTrue()
+ // AND the new key is the package name
+ assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.oldKey!!).isEqualTo(KEY)
+ assertThat(listener.removedKey).isNull()
+ }
+
+ @Test
+ fun testOnNotificationRemoved_twoWithResumption() {
+ // GIVEN that the manager has two notifications with resume actions
+ val listener = TestListener()
+ mediaDataManager.addListener(listener)
+ whenever(controller.metadata).thenReturn(metadataBuilder.build())
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataManager.onNotificationAdded(KEY_2, mediaNotification)
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
+ val data = listener.data!!
+ assertThat(data.resumption).isFalse()
+ val resumableData = data.copy(resumeAction = Runnable {})
+ mediaDataManager.onMediaDataLoaded(KEY, null, resumableData)
+ mediaDataManager.onMediaDataLoaded(KEY_2, null, resumableData)
+ // WHEN the first is removed
+ mediaDataManager.onNotificationRemoved(KEY)
+ // THEN the data is for resumption and the key is migrated to the package name
+ assertThat(listener.data!!.resumption).isTrue()
+ assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.oldKey!!).isEqualTo(KEY)
+ assertThat(listener.removedKey).isNull()
+ // WHEN the second is removed
+ mediaDataManager.onNotificationRemoved(KEY_2)
+ // THEN the data is for resumption and the second key is removed
+ assertThat(listener.data!!.resumption).isTrue()
+ assertThat(listener.key!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.oldKey!!).isEqualTo(PACKAGE_NAME)
+ assertThat(listener.removedKey!!).isEqualTo(KEY_2)
}
@Test
@@ -190,6 +226,7 @@
var data: MediaData? = null
var key: String? = null
var oldKey: String? = null
+ var removedKey: String? = null
override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
this.key = key
@@ -198,9 +235,7 @@
}
override fun onMediaDataRemoved(key: String) {
- this.key = key
- oldKey = null
- data = null
+ removedKey = key
}
}
}
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 74df113..e10bab4 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -42,6 +42,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.system.Os;
import android.util.Log;
@@ -224,9 +225,19 @@
}
+ private boolean isAdbOverNetwork() {
+ // If adb TCP port opened, this test may running by adb over network.
+ return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
+ || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
+ }
+
@Test
public void testPhysicalEthernet() throws Exception {
assumeTrue(mEm.isAvailable());
+ // Do not run this test if adb is over network and ethernet is connected.
+ // It is likely the adb run over ethernet, the adb would break when ethernet is switching
+ // from client mode to server mode. See b/160389275.
+ assumeFalse(isAdbOverNetwork());
// Get an interface to use.
final String iface = mTetheredInterfaceRequester.getInterface();
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index c8cee10..070626be 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -322,6 +322,12 @@
return true;
}
+ void clear() {
+ mLongPressingPointerId = -1;
+ mLongPressingPointerDeltaX = 0;
+ mLongPressingPointerDeltaY = 0;
+ }
+
public void clickWithTouchEvents(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
final int pointerIndex = event.getActionIndex();
final int pointerId = event.getPointerId(pointerIndex);
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index 6f2e626..fbc986b 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -809,6 +809,7 @@
// Announce the end of a the touch interaction.
mAms.onTouchInteractionEnd();
+ mDispatcher.clear();
mDispatcher.sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
} break;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 68eeb0a..b2daae4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -103,6 +103,8 @@
private boolean mDestroyed = false;
@GuardedBy("mLock")
private boolean mPreviousHasNonPinSuggestionShow;
+ @GuardedBy("mLock")
+ private boolean mImeSessionInvalidated = false;
AutofillInlineSuggestionsRequestSession(
@NonNull InputMethodManagerInternal inputMethodManagerInternal, int userId,
@@ -157,7 +159,7 @@
Slog.d(TAG,
"onInlineSuggestionsResponseLocked called for:" + inlineFillUi.getAutofillId());
}
- if (mImeRequest == null || mResponseCallback == null) {
+ if (mImeRequest == null || mResponseCallback == null || mImeSessionInvalidated) {
return false;
}
// TODO(b/151123764): each session should only correspond to one field.
@@ -191,6 +193,7 @@
if (mDestroyed) {
return;
}
+ mImeSessionInvalidated = false;
if (sDebug) Slog.d(TAG, "onCreateInlineSuggestionsRequestLocked called: " + mAutofillId);
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(mUserId,
new InlineSuggestionsRequestInfo(mComponentName, mAutofillId, mUiExtras),
@@ -291,6 +294,7 @@
return;
}
mImeRequestReceived = true;
+ mImeSessionInvalidated = false;
if (request != null && callback != null) {
mImeRequest = request;
@@ -346,6 +350,20 @@
}
}
+ /**
+ * Handles the IME session status received from the IME.
+ *
+ * <p> Should only be invoked in the {@link #mHandler} thread.
+ */
+ private void handleOnReceiveImeSessionInvalidated() {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ return;
+ }
+ mImeSessionInvalidated = true;
+ }
+ }
+
private static final class InlineSuggestionsRequestCallbackImpl extends
IInlineSuggestionsRequestCallback.Stub {
@@ -433,6 +451,18 @@
session, false, false));
}
}
+
+ @BinderThread
+ @Override
+ public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+ if (sDebug) Slog.d(TAG, "onInlineSuggestionsSessionInvalidated() called.");
+ final AutofillInlineSuggestionsRequestSession session = mSession.get();
+ if (session != null) {
+ session.mHandler.sendMessage(obtainMessage(
+ AutofillInlineSuggestionsRequestSession
+ ::handleOnReceiveImeSessionInvalidated, session));
+ }
+ }
}
private static boolean match(@Nullable AutofillId autofillId,
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 15e8a92..d8ee32e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -211,6 +211,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;
@@ -2128,6 +2129,11 @@
public void onInputMethodFinishInput() throws RemoteException {
mCallback.onInputMethodFinishInput();
}
+
+ @Override
+ public void onInlineSuggestionsSessionInvalidated() throws RemoteException {
+ mCallback.onInlineSuggestionsSessionInvalidated();
+ }
}
/**
@@ -4000,6 +4006,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) {
@@ -4273,11 +4286,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;
}
@@ -5111,6 +5140,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/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 3a203d5..c3c2e5e 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -708,12 +708,15 @@
return ret;
}
+ /**
+ * This method recomputes all component / intent-based visibility and is intended to match the
+ * relevant logic of {@link #addPackageInternal(PackageSetting, ArrayMap)}
+ */
private void recomputeComponentVisibility(ArrayMap<String, PackageSetting> existingSettings) {
mQueriesViaComponent.clear();
for (int i = existingSettings.size() - 1; i >= 0; i--) {
PackageSetting setting = existingSettings.valueAt(i);
- if (setting.pkg == null
- || mForceQueryable.contains(setting.appId)) {
+ if (setting.pkg == null || requestsQueryAllPackages(setting.pkg)) {
continue;
}
for (int j = existingSettings.size() - 1; j >= 0; j--) {
@@ -721,7 +724,7 @@
continue;
}
final PackageSetting otherSetting = existingSettings.valueAt(j);
- if (otherSetting.pkg == null) {
+ if (otherSetting.pkg == null || mForceQueryable.contains(otherSetting.appId)) {
continue;
}
if (canQueryViaComponents(setting.pkg, otherSetting.pkg, mProtectedBroadcasts)) {
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 2df4a92..eddab76 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -18,6 +18,7 @@
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import android.annotation.Nullable;
import android.content.Context;
@@ -42,10 +43,9 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
/**
* A service for A/B OTA dexopting.
@@ -123,15 +123,20 @@
}
final List<PackageSetting> important;
final List<PackageSetting> others;
+ Predicate<PackageSetting> isPlatformPackage = pkgSetting ->
+ PLATFORM_PACKAGE_NAME.equals(pkgSetting.pkg.getPackageName());
synchronized (mPackageManagerService.mLock) {
// Important: the packages we need to run with ab-ota compiler-reason.
important = PackageManagerServiceUtils.getPackagesForDexopt(
mPackageManagerService.mSettings.mPackages.values(), mPackageManagerService,
DEBUG_DEXOPT);
+ // Remove Platform Package from A/B OTA b/160735835.
+ important.removeIf(isPlatformPackage);
// Others: we should optimize this with the (first-)boot compiler-reason.
others = new ArrayList<>(mPackageManagerService.mSettings.mPackages.values());
others.removeAll(important);
others.removeIf(PackageManagerServiceUtils.REMOVE_IF_NULL_PKG);
+ others.removeIf(isPlatformPackage);
// Pre-size the array list by over-allocating by a factor of 1.5.
mDexoptCommands = new ArrayList<>(3 * mPackageManagerService.mPackages.size() / 2);
@@ -147,7 +152,7 @@
throw new IllegalStateException("Found a core app that's not important");
}
mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.pkg, pkgSetting,
- PackageManagerService.REASON_FIRST_BOOT));
+ PackageManagerService.REASON_FIRST_BOOT));
}
completeSize = mDexoptCommands.size();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 91b2ea1..08cdd8f 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/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index c38d649..4b3ddd8 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -114,7 +114,7 @@
private static final boolean DEBUG = false;
private static final String TAG = "UriGrantsManagerService";
// Maximum number of persisted Uri grants a package is allowed
- private static final int MAX_PERSISTED_URI_GRANTS = 128;
+ private static final int MAX_PERSISTED_URI_GRANTS = 512;
private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
private final Object mLock = new Object();
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index db4c3ea..e9768a2 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2443,7 +2443,7 @@
forAllActivities(ActivityRecord::removeLaunchTickRunnable);
}
- private void updateTransitLocked(int transit, ActivityOptions options) {
+ private void updateTransitLocked(int transit, ActivityOptions options, boolean forceOverride) {
if (options != null) {
ActivityRecord r = topRunningActivity();
if (r != null && !r.isState(RESUMED)) {
@@ -2452,7 +2452,8 @@
ActivityOptions.abort(options);
}
}
- getDisplay().mDisplayContent.prepareAppTransition(transit, false);
+ getDisplay().mDisplayContent.prepareAppTransition(transit, false,
+ 0 /* flags */, forceOverride);
}
final void moveTaskToFront(Task tr, boolean noAnimation, ActivityOptions options,
@@ -2472,8 +2473,17 @@
// nothing to do!
if (noAnimation) {
ActivityOptions.abort(options);
+ } else if (isSingleTaskInstance()) {
+ // When a task is moved front on the display which can only contain one task, start
+ // a special transition.
+ // {@link AppTransitionController#handleAppTransitionReady} later picks up the
+ // transition, and schedules
+ // {@link ITaskStackListener#onSingleTaskDisplayDrawn} callback which is triggered
+ // after contents are drawn on the display.
+ updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options,
+ true /* forceOverride */);
} else {
- updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
+ updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */);
}
return;
}
@@ -2519,9 +2529,13 @@
mStackSupervisor.mNoAnimActivities.add(r);
}
ActivityOptions.abort(options);
+ } else if (isSingleTaskInstance()) {
+ updateTransitLocked(TRANSIT_SHOW_SINGLE_TASK_DISPLAY, options,
+ true /* forceOverride */);
} else {
- updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
+ updateTransitLocked(TRANSIT_TASK_TO_FRONT, options, false /* forceOverride */);
}
+
// If a new task is moved to the front, then mark the existing top activity as
// supporting
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/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c7ffc06..4700864 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2375,7 +2375,8 @@
// triggered after contents are drawn on the display.
if (display.isSingleTaskInstance()) {
display.mDisplayContent.prepareAppTransition(
- TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false);
+ TRANSIT_SHOW_SINGLE_TASK_DISPLAY, false,
+ 0 /* flags */, true /* forceOverride*/);
}
stack.awakeFromSleepingLocked();
if (display.isSingleTaskInstance()) {
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");
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 285cf43..dee5a98 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -277,6 +277,11 @@
boolean setDefaultDialer(in String packageName);
/**
+ * Stop suppressing blocked numbers after a call to emergency services. Shell only.
+ */
+ void stopBlockSuppression();
+
+ /**
* @see TelecomServiceImpl#createManageBlockedNumbersIntent
**/
Intent createManageBlockedNumbersIntent();