diff options
103 files changed, 1825 insertions, 887 deletions
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 3312294865d6..9e59ee496de1 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2547,7 +2547,7 @@ public class AppOpsManager { .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), new AppOpInfo.Builder(OP_TURN_SCREEN_ON, OPSTR_TURN_SCREEN_ON, "TURN_SCREEN_ON") .setPermission(Manifest.permission.TURN_SCREEN_ON) - .setDefaultMode(AppOpsManager.MODE_ERRORED).build(), + .setDefaultMode(AppOpsManager.MODE_DEFAULT).build(), new AppOpInfo.Builder(OP_GET_ACCOUNTS, OPSTR_GET_ACCOUNTS, "GET_ACCOUNTS") .setPermission(Manifest.permission.GET_ACCOUNTS) .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 63da0a231286..d37576092af2 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2916,6 +2916,14 @@ public class Notification implements Parcelable } } + if (isStyle(CallStyle.class) & extras != null) { + Person callPerson = extras.getParcelable(EXTRA_CALL_PERSON); + if (callPerson != null) { + visitor.accept(callPerson.getIconUri()); + } + visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON)); + } + if (mBubbleMetadata != null) { visitIconUri(visitor, mBubbleMetadata.getIcon()); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 74a69a623790..307f30619be2 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -12349,7 +12349,9 @@ public class Intent implements Parcelable, Cloneable { null, new String[] { getType() }, new ClipData.Item(text, htmlText, null, stream)); setClipData(clipData); - addFlags(FLAG_GRANT_READ_URI_PERMISSION); + if (stream != null) { + addFlags(FLAG_GRANT_READ_URI_PERMISSION); + } return true; } } catch (ClassCastException e) { @@ -12388,7 +12390,9 @@ public class Intent implements Parcelable, Cloneable { } setClipData(clipData); - addFlags(FLAG_GRANT_READ_URI_PERMISSION); + if (streams != null) { + addFlags(FLAG_GRANT_READ_URI_PERMISSION); + } return true; } } catch (ClassCastException e) { diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java index a5e708642c9f..b65c1a17e26b 100644 --- a/core/java/android/widget/ScrollView.java +++ b/core/java/android/widget/ScrollView.java @@ -845,11 +845,7 @@ public class ScrollView extends FrameLayout { // Calling overScrollBy will call onOverScrolled, which // calls onScrollChanged if applicable. - if (overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true) - && !hasNestedScrollingParent()) { - // Break our velocity if we hit a scroll barrier. - mVelocityTracker.clear(); - } + overScrollBy(0, deltaY, 0, mScrollY, 0, range, 0, mOverscrollDistance, true); final int scrolledDeltaY = mScrollY - oldY; final int unconsumedY = deltaY - scrolledDeltaY; @@ -894,6 +890,7 @@ public class ScrollView extends FrameLayout { mActivePointerId = INVALID_POINTER; endDrag(); + velocityTracker.clear(); } break; case MotionEvent.ACTION_CANCEL: diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java index e0ee68337061..e44f43609256 100644 --- a/core/java/android/window/BackNavigationInfo.java +++ b/core/java/android/window/BackNavigationInfo.java @@ -94,26 +94,29 @@ public final class BackNavigationInfo implements Parcelable { @Nullable private final IOnBackInvokedCallback mOnBackInvokedCallback; private final boolean mPrepareRemoteAnimation; + private final boolean mAnimationCallback; @Nullable private final CustomAnimationInfo mCustomAnimationInfo; /** * Create a new {@link BackNavigationInfo} instance. * - * @param type The {@link BackTargetType} of the destination (what will be - * @param onBackNavigationDone The callback to be called once the client is done with the - * back preview. - * @param onBackInvokedCallback The back callback registered by the current top level window. + * @param type The {@link BackTargetType} of the destination (what will be + * @param onBackNavigationDone The callback to be called once the client is done with the + * back preview. + * @param onBackInvokedCallback The back callback registered by the current top level window. */ private BackNavigationInfo(@BackTargetType int type, @Nullable RemoteCallback onBackNavigationDone, @Nullable IOnBackInvokedCallback onBackInvokedCallback, boolean isPrepareRemoteAnimation, + boolean isAnimationCallback, @Nullable CustomAnimationInfo customAnimationInfo) { mType = type; mOnBackNavigationDone = onBackNavigationDone; mOnBackInvokedCallback = onBackInvokedCallback; mPrepareRemoteAnimation = isPrepareRemoteAnimation; + mAnimationCallback = isAnimationCallback; mCustomAnimationInfo = customAnimationInfo; } @@ -122,6 +125,7 @@ public final class BackNavigationInfo implements Parcelable { mOnBackNavigationDone = in.readTypedObject(RemoteCallback.CREATOR); mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder()); mPrepareRemoteAnimation = in.readBoolean(); + mAnimationCallback = in.readBoolean(); mCustomAnimationInfo = in.readTypedObject(CustomAnimationInfo.CREATOR); } @@ -132,6 +136,7 @@ public final class BackNavigationInfo implements Parcelable { dest.writeTypedObject(mOnBackNavigationDone, flags); dest.writeStrongInterface(mOnBackInvokedCallback); dest.writeBoolean(mPrepareRemoteAnimation); + dest.writeBoolean(mAnimationCallback); dest.writeTypedObject(mCustomAnimationInfo, flags); } @@ -159,7 +164,7 @@ public final class BackNavigationInfo implements Parcelable { } /** - * Return true if the core is preparing a back gesture nimation. + * Return true if the core is preparing a back gesture animation. * @hide */ public boolean isPrepareRemoteAnimation() { @@ -167,6 +172,14 @@ public final class BackNavigationInfo implements Parcelable { } /** + * Return true if the callback is {@link OnBackAnimationCallback}. + * @hide + */ + public boolean isAnimationCallback() { + return mAnimationCallback; + } + + /** * Callback to be called when the back preview is finished in order to notify the server that * it can clean up the resources created for the animation. * @hide @@ -214,6 +227,8 @@ public final class BackNavigationInfo implements Parcelable { + "mType=" + typeToString(mType) + " (" + mType + ")" + ", mOnBackNavigationDone=" + mOnBackNavigationDone + ", mOnBackInvokedCallback=" + mOnBackInvokedCallback + + ", mPrepareRemoteAnimation=" + mPrepareRemoteAnimation + + ", mAnimationCallback=" + mAnimationCallback + ", mCustomizeAnimationInfo=" + mCustomAnimationInfo + '}'; } @@ -343,6 +358,7 @@ public final class BackNavigationInfo implements Parcelable { private IOnBackInvokedCallback mOnBackInvokedCallback = null; private boolean mPrepareRemoteAnimation; private CustomAnimationInfo mCustomAnimationInfo; + private boolean mAnimationCallback = false; /** * @see BackNavigationInfo#getType() @@ -387,6 +403,7 @@ public final class BackNavigationInfo implements Parcelable { mCustomAnimationInfo.mWindowAnimations = windowAnimations; return this; } + /** * Set resources ids for customize activity animation. */ @@ -402,12 +419,21 @@ public final class BackNavigationInfo implements Parcelable { } /** + * @param isAnimationCallback whether the callback is {@link OnBackAnimationCallback} + */ + public Builder setAnimationCallback(boolean isAnimationCallback) { + mAnimationCallback = isAnimationCallback; + return this; + } + + /** * Builds and returns an instance of {@link BackNavigationInfo} */ public BackNavigationInfo build() { return new BackNavigationInfo(mType, mOnBackNavigationDone, mOnBackInvokedCallback, mPrepareRemoteAnimation, + mAnimationCallback, mCustomAnimationInfo); } } diff --git a/core/java/android/window/OnBackInvokedCallbackInfo.java b/core/java/android/window/OnBackInvokedCallbackInfo.java index 6480da336590..bb5fe96fdec1 100644 --- a/core/java/android/window/OnBackInvokedCallbackInfo.java +++ b/core/java/android/window/OnBackInvokedCallbackInfo.java @@ -28,15 +28,20 @@ public final class OnBackInvokedCallbackInfo implements Parcelable { @NonNull private final IOnBackInvokedCallback mCallback; private @OnBackInvokedDispatcher.Priority int mPriority; + private final boolean mIsAnimationCallback; - public OnBackInvokedCallbackInfo(@NonNull IOnBackInvokedCallback callback, int priority) { + public OnBackInvokedCallbackInfo(@NonNull IOnBackInvokedCallback callback, + int priority, + boolean isAnimationCallback) { mCallback = callback; mPriority = priority; + mIsAnimationCallback = isAnimationCallback; } private OnBackInvokedCallbackInfo(@NonNull Parcel in) { mCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder()); mPriority = in.readInt(); + mIsAnimationCallback = in.readBoolean(); } @Override @@ -48,6 +53,7 @@ public final class OnBackInvokedCallbackInfo implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeStrongInterface(mCallback); dest.writeInt(mPriority); + dest.writeBoolean(mIsAnimationCallback); } public static final Creator<OnBackInvokedCallbackInfo> CREATOR = @@ -77,9 +83,16 @@ public final class OnBackInvokedCallbackInfo implements Parcelable { return mPriority; } + public boolean isAnimationCallback() { + return mIsAnimationCallback; + } + @Override public String toString() { return "OnBackInvokedCallbackInfo{" - + "mCallback=" + mCallback + ", mPriority=" + mPriority + '}'; + + "mCallback=" + mCallback + + ", mPriority=" + mPriority + + ", mIsAnimationCallback=" + mIsAnimationCallback + + '}'; } } diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index 8066f5085a01..51382a4b265f 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -193,7 +193,10 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { ? ((ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) callback).getIOnBackInvokedCallback() : new OnBackInvokedCallbackWrapper(callback); - callbackInfo = new OnBackInvokedCallbackInfo(iCallback, priority); + callbackInfo = new OnBackInvokedCallbackInfo( + iCallback, + priority, + callback instanceof OnBackAnimationCallback); } mWindowSession.setOnBackInvokedCallbackInfo(mWindow, callbackInfo); } catch (RemoteException e) { diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java index 1b4afd6dd39f..bb8bdf57ac62 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java +++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java @@ -255,6 +255,12 @@ public final class InputMethodDebug { return "HIDE_SOFT_INPUT_IMM_DEPRECATION"; case SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR: return "HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR"; + case SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS: + return "SHOW_IME_SCREENSHOT_FROM_IMMS"; + case SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS: + return "REMOVE_IME_SCREENSHOT_FROM_IMMS"; + case SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE: + return "HIDE_WHEN_INPUT_TARGET_INVISIBLE"; default: return "Unknown=" + reason; } diff --git a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java index ec9184b72ed1..6e9cd44b7818 100644 --- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java +++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java @@ -65,7 +65,10 @@ import java.lang.annotation.Retention; SoftInputShowHideReason.HIDE_SOFT_INPUT_IME_TOGGLE_SOFT_INPUT, SoftInputShowHideReason.HIDE_SOFT_INPUT_EXTRACT_INPUT_CHANGED, SoftInputShowHideReason.HIDE_SOFT_INPUT_IMM_DEPRECATION, - SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR + SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR, + SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS, + SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS, + SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE, }) public @interface SoftInputShowHideReason { /** Show soft input by {@link android.view.inputmethod.InputMethodManager#showSoftInput}. */ @@ -259,4 +262,20 @@ public @interface SoftInputShowHideReason { */ int HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR = ImeProtoEnums.REASON_HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR; + + /** + * Shows ime screenshot by {@link com.android.server.inputmethod.InputMethodManagerService}. + */ + int SHOW_IME_SCREENSHOT_FROM_IMMS = ImeProtoEnums.REASON_SHOW_IME_SCREENSHOT_FROM_IMMS; + + /** + * Removes ime screenshot by {@link com.android.server.inputmethod.InputMethodManagerService}. + */ + int REMOVE_IME_SCREENSHOT_FROM_IMMS = ImeProtoEnums.REASON_REMOVE_IME_SCREENSHOT_FROM_IMMS; + + /** + * Hide soft input when the input target being removed or being obscured by an non-IME + * focusable overlay window. + */ + int HIDE_WHEN_INPUT_TARGET_INVISIBLE = ImeProtoEnums.REASON_HIDE_WHEN_INPUT_TARGET_INVISIBLE; } diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index bb3089bb397a..325ebbe885b4 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -458,6 +458,7 @@ message WindowStateProto { optional float global_scale = 44; repeated .android.graphics.RectProto keep_clear_areas = 45; repeated .android.graphics.RectProto unrestricted_keep_clear_areas = 46; + repeated .android.view.InsetsSourceProto mergedLocalInsetsSources = 47; } message IdentifierProto { diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index b2d734e93f80..c928a82de32e 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1466,6 +1466,9 @@ <!-- Allows an application to initiate a phone call without going through the Dialer user interface for the user to confirm the call. + <p> + <em>Note: An app holding this permission can also call carrier MMI codes to change settings + such as call forwarding or call waiting preferences. <p>Protection level: dangerous --> <permission android:name="android.permission.CALL_PHONE" @@ -2539,7 +2542,7 @@ <permission android:name="android.permission.TURN_SCREEN_ON" android:label="@string/permlab_turnScreenOn" android:description="@string/permdesc_turnScreenOn" - android:protectionLevel="normal|appop" /> + android:protectionLevel="signature|privileged|appop" /> <!-- ==================================================== --> <!-- Permissions related to changing audio settings --> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index c7395ddf1fbb..a57a0517c58d 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -146,10 +146,6 @@ <bool name="config_enhanced_iwlan_handover_check">true</bool> <java-symbol type="bool" name="config_enhanced_iwlan_handover_check" /> - <!-- Whether using the new SubscriptionManagerService or the old SubscriptionController --> - <bool name="config_using_subscription_manager_service">true</bool> - <java-symbol type="bool" name="config_using_subscription_manager_service" /> - <!-- Whether asynchronously update the subscription database or not. Async mode increases the performance, but sync mode reduces the chance of database/cache out-of-sync. --> <bool name="config_subscription_database_async_update">true</bool> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 362d8596ebb8..c6462f15ec50 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1452,7 +1452,8 @@ without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your - confirmation.</string> + confirmation, or dial carrier codes which cause incoming calls to be + automatically forwarded to another number.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_accessImsCallService">access IMS call service</string> @@ -5896,9 +5897,9 @@ <string name="resolver_cant_access_personal_apps_explanation">This content can\u2019t be opened with personal apps</string> <!-- Error message. This text lets the user know that they need to turn on work apps in order to share or open content. There's also a button a user can tap to turn on the apps. [CHAR LIMIT=NONE] --> - <string name="resolver_turn_on_work_apps">Work profile is paused</string> - <!-- Button text. This button turns on a user's work profile so they can access their work apps and data. [CHAR LIMIT=NONE] --> - <string name="resolver_switch_on_work">Tap to turn on</string> + <string name="resolver_turn_on_work_apps">Work apps are paused</string> + <!-- Button text. This button unpauses a user's work apps and data. [CHAR LIMIT=NONE] --> + <string name="resolver_switch_on_work">Unpause</string> <!-- Error message. This text lets the user know that their current work apps don't support the specific content. [CHAR LIMIT=NONE] --> <string name="resolver_no_work_apps_available">No work apps</string> diff --git a/core/tests/coretests/res/drawable-nodpi/test_too_big.png b/core/tests/coretests/res/drawable-nodpi/test_too_big.png Binary files differnew file mode 100644 index 000000000000..3754072b8e31 --- /dev/null +++ b/core/tests/coretests/res/drawable-nodpi/test_too_big.png diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java index 75390a282af9..5d922961aa8b 100644 --- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java +++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.RecordingCanvas; import android.graphics.Region; import android.os.Handler; import android.os.HandlerThread; @@ -371,6 +372,90 @@ public class IconTest extends AndroidTestCase { } } + private int getMaxWidth(int origWidth, int origHeight, int maxNumPixels) { + float aspRatio = (float) origWidth / (float) origHeight; + int newHeight = (int) Math.sqrt(maxNumPixels / aspRatio); + return (int) (newHeight * aspRatio); + } + + private int getMaxHeight(int origWidth, int origHeight, int maxNumPixels) { + float aspRatio = (float) origWidth / (float) origHeight; + return (int) Math.sqrt(maxNumPixels / aspRatio); + } + + @SmallTest + public void testScaleDownMaxSizeWithBitmap() throws Exception { + final int bmpWidth = 13_000; + final int bmpHeight = 10_000; + final int bmpBpp = 4; + final int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bmpBpp; + final int maxWidth = getMaxWidth(bmpWidth, bmpHeight, maxNumPixels); + final int maxHeight = getMaxHeight(bmpWidth, bmpHeight, maxNumPixels); + + final Bitmap bm = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888); + final Icon ic = Icon.createWithBitmap(bm); + final Drawable drawable = ic.loadDrawable(mContext); + + assertThat(drawable.getIntrinsicWidth()).isEqualTo(maxWidth); + assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight); + } + + @SmallTest + public void testScaleDownMaxSizeWithAdaptiveBitmap() throws Exception { + final int bmpWidth = 20_000; + final int bmpHeight = 10_000; + final int bmpBpp = 4; + final int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bmpBpp; + final int maxWidth = getMaxWidth(bmpWidth, bmpHeight, maxNumPixels); + final int maxHeight = getMaxHeight(bmpWidth, bmpHeight, maxNumPixels); + + final Bitmap bm = Bitmap.createBitmap(bmpWidth, bmpHeight, Bitmap.Config.ARGB_8888); + final Icon ic = Icon.createWithAdaptiveBitmap(bm); + final AdaptiveIconDrawable adaptiveDrawable = (AdaptiveIconDrawable) ic.loadDrawable( + mContext); + final Drawable drawable = adaptiveDrawable.getForeground(); + + assertThat(drawable.getIntrinsicWidth()).isEqualTo(maxWidth); + assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight); + } + + @SmallTest + public void testScaleDownMaxSizeWithResource() throws Exception { + final Icon ic = Icon.createWithResource(getContext(), R.drawable.test_too_big); + final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext); + + assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE); + } + + @SmallTest + public void testScaleDownMaxSizeWithFile() throws Exception { + final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.test_too_big)) + .getBitmap(); + final File dir = getContext().getExternalFilesDir(null); + final File file1 = new File(dir, "file1-too-big.png"); + bit1.compress(Bitmap.CompressFormat.PNG, 100, + new FileOutputStream(file1)); + + final Icon ic = Icon.createWithFilePath(file1.toString()); + final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext); + + assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE); + } + + @SmallTest + public void testScaleDownMaxSizeWithData() throws Exception { + final int bmpBpp = 4; + final Bitmap originalBits = ((BitmapDrawable) getContext().getDrawable( + R.drawable.test_too_big)).getBitmap(); + final ByteArrayOutputStream ostream = new ByteArrayOutputStream( + originalBits.getWidth() * originalBits.getHeight() * bmpBpp); + originalBits.compress(Bitmap.CompressFormat.PNG, 100, ostream); + final byte[] pngdata = ostream.toByteArray(); + final Icon ic = Icon.createWithData(pngdata, 0, pngdata.length); + final BitmapDrawable drawable = (BitmapDrawable) ic.loadDrawable(mContext); + + assertThat(drawable.getBitmap().getByteCount()).isAtMost(RecordingCanvas.MAX_BITMAP_SIZE); + } // ======== utils ======== diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index a76d74edc0f4..708feeb9e421 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -35,6 +35,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BlendMode; import android.graphics.PorterDuff; +import android.graphics.RecordingCanvas; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -70,6 +71,7 @@ import java.util.Objects; public final class Icon implements Parcelable { private static final String TAG = "Icon"; + private static final boolean DEBUG = false; /** * An icon that was created using {@link Icon#createWithBitmap(Bitmap)}. @@ -361,15 +363,52 @@ public final class Icon implements Parcelable { } /** + * Resizes image if size too large for Canvas to draw + * @param bitmap Bitmap to be resized if size > {@link RecordingCanvas.MAX_BITMAP_SIZE} + * @return resized bitmap + */ + private Bitmap fixMaxBitmapSize(Bitmap bitmap) { + if (bitmap != null && bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) { + int bytesPerPixel = bitmap.getRowBytes() / bitmap.getWidth(); + int maxNumPixels = RecordingCanvas.MAX_BITMAP_SIZE / bytesPerPixel; + float aspRatio = (float) bitmap.getWidth() / (float) bitmap.getHeight(); + int newHeight = (int) Math.sqrt(maxNumPixels / aspRatio); + int newWidth = (int) (newHeight * aspRatio); + + if (DEBUG) { + Log.d(TAG, + "Image size too large: " + bitmap.getByteCount() + ". Resizing bitmap to: " + + newWidth + " " + newHeight); + } + + return scaleDownIfNecessary(bitmap, newWidth, newHeight); + } + return bitmap; + } + + /** + * Resizes BitmapDrawable if size too large for Canvas to draw + * @param drawable Drawable to be resized if size > {@link RecordingCanvas.MAX_BITMAP_SIZE} + * @return resized Drawable + */ + private Drawable fixMaxBitmapSize(Resources res, Drawable drawable) { + if (drawable instanceof BitmapDrawable) { + Bitmap scaledBmp = fixMaxBitmapSize(((BitmapDrawable) drawable).getBitmap()); + return new BitmapDrawable(res, scaledBmp); + } + return drawable; + } + + /** * Do the heavy lifting of loading the drawable, but stop short of applying any tint. */ private Drawable loadDrawableInner(Context context) { switch (mType) { case TYPE_BITMAP: - return new BitmapDrawable(context.getResources(), getBitmap()); + return new BitmapDrawable(context.getResources(), fixMaxBitmapSize(getBitmap())); case TYPE_ADAPTIVE_BITMAP: return new AdaptiveIconDrawable(null, - new BitmapDrawable(context.getResources(), getBitmap())); + new BitmapDrawable(context.getResources(), fixMaxBitmapSize(getBitmap()))); case TYPE_RESOURCE: if (getResources() == null) { // figure out where to load resources from @@ -400,7 +439,8 @@ public final class Icon implements Parcelable { } } try { - return getResources().getDrawable(getResId(), context.getTheme()); + return fixMaxBitmapSize(getResources(), + getResources().getDrawable(getResId(), context.getTheme())); } catch (RuntimeException e) { Log.e(TAG, String.format("Unable to load resource 0x%08x from pkg=%s", getResId(), @@ -409,21 +449,21 @@ public final class Icon implements Parcelable { } break; case TYPE_DATA: - return new BitmapDrawable(context.getResources(), - BitmapFactory.decodeByteArray(getDataBytes(), getDataOffset(), getDataLength()) - ); + return new BitmapDrawable(context.getResources(), fixMaxBitmapSize( + BitmapFactory.decodeByteArray(getDataBytes(), getDataOffset(), + getDataLength()))); case TYPE_URI: InputStream is = getUriInputStream(context); if (is != null) { return new BitmapDrawable(context.getResources(), - BitmapFactory.decodeStream(is)); + fixMaxBitmapSize(BitmapFactory.decodeStream(is))); } break; case TYPE_URI_ADAPTIVE_BITMAP: is = getUriInputStream(context); if (is != null) { return new AdaptiveIconDrawable(null, new BitmapDrawable(context.getResources(), - BitmapFactory.decodeStream(is))); + fixMaxBitmapSize(BitmapFactory.decodeStream(is)))); } break; } diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml index dcce4698c252..ab64f9e359b0 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml @@ -67,7 +67,7 @@ <!-- Temporarily extending the background to show an edu text hint for opening the menu --> <FrameLayout - android:id="@+id/tv_pip_menu_edu_text_drawer_placeholder" + android:id="@+id/tv_pip_menu_edu_text_container" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/tv_pip" diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java index 4970fa0cb087..56616cb6bd88 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java @@ -165,6 +165,10 @@ public class SplitDecorManager extends WindowlessWindowManager { t.remove(mGapBackgroundLeash); mGapBackgroundLeash = null; } + if (mScreenshot != null) { + t.remove(mScreenshot); + mScreenshot = null; + } mHostLeash = null; mIcon = null; mResizingIconView = null; @@ -324,6 +328,8 @@ public class SplitDecorManager extends WindowlessWindowManager { if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) { if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) { mScreenshotAnimator.cancel(); + } else if (mScreenshot != null) { + t.remove(mScreenshot); } mTempRect.set(mOldBounds); @@ -340,6 +346,8 @@ public class SplitDecorManager extends WindowlessWindowManager { if (!mShown && mIsResizing && !mOldBounds.equals(mResizingBounds)) { if (mScreenshotAnimator != null && mScreenshotAnimator.isRunning()) { mScreenshotAnimator.cancel(); + } else if (mScreenshot != null) { + t.remove(mScreenshot); } mScreenshot = screenshot; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index 713ace6ee1c0..c8062bcf8519 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -623,11 +623,11 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, * Removes PiP immediately. */ public void removePip() { - if (!mPipTransitionState.isInPip() || mToken == null) { + if (!mPipTransitionState.isInPip() || mToken == null || mLeash == null) { ProtoLog.wtf(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: Not allowed to removePip in current state" - + " mState=%d mToken=%s", TAG, mPipTransitionState.getTransitionState(), - mToken); + + " mState=%d mToken=%s mLeash=%s", TAG, + mPipTransitionState.getTransitionState(), mToken, mLeash); return; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java index 6eef22562caa..f86f987039ba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuEduTextDrawer.java @@ -23,6 +23,7 @@ import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE; +import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.drawable.Drawable; @@ -115,6 +116,10 @@ class TvPipMenuEduTextDrawer extends FrameLayout { scheduleLifecycleEvents(); } + int getEduTextDrawerHeight() { + return getVisibility() == GONE ? 0 : getHeight(); + } + private void scheduleLifecycleEvents() { final int startScrollDelay = mContext.getResources().getInteger( R.integer.pip_edu_text_start_scroll_delay); @@ -226,20 +231,41 @@ class TvPipMenuEduTextDrawer extends FrameLayout { .start(); // Start animation to close the drawer by animating its height to 0 - final ValueAnimator heightAnimation = ValueAnimator.ofInt(getHeight(), 0); - heightAnimation.setDuration(eduTextSlideExitAnimationDuration); - heightAnimation.setInterpolator(TvPipInterpolators.BROWSE); - heightAnimation.addUpdateListener(animator -> { + final ValueAnimator heightAnimator = ValueAnimator.ofInt(getHeight(), 0); + heightAnimator.setDuration(eduTextSlideExitAnimationDuration); + heightAnimator.setInterpolator(TvPipInterpolators.BROWSE); + heightAnimator.addUpdateListener(animator -> { final ViewGroup.LayoutParams params = getLayoutParams(); params.height = (int) animator.getAnimatedValue(); setLayoutParams(params); - if (params.height == 0) { - setVisibility(GONE); + }); + heightAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(@NonNull Animator animator) { + } + + @Override + public void onAnimationEnd(@NonNull Animator animator) { + onCloseEduTextAnimationEnd(); + } + + @Override + public void onAnimationCancel(@NonNull Animator animator) { + onCloseEduTextAnimationEnd(); + } + + @Override + public void onAnimationRepeat(@NonNull Animator animator) { } }); - heightAnimation.start(); + heightAnimator.start(); + + mListener.onCloseEduTextAnimationStart(); + } - mListener.onCloseEduText(); + public void onCloseEduTextAnimationEnd() { + setVisibility(GONE); + mListener.onCloseEduTextAnimationEnd(); } /** @@ -270,11 +296,8 @@ class TvPipMenuEduTextDrawer extends FrameLayout { * A listener for edu text drawer event states. */ interface Listener { - /** - * The edu text closing impacts the size of the Picture-in-Picture window and influences - * how it is positioned on the screen. - */ - void onCloseEduText(); + void onCloseEduTextAnimationStart(); + void onCloseEduTextAnimationEnd(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java index 6eb719ba60a3..d07641892552 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java @@ -57,7 +57,8 @@ import java.util.List; * A View that represents Pip Menu on TV. It's responsible for displaying the Pip menu actions from * the TvPipActionsProvider as well as the buttons for manually moving the PiP. */ -public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.Listener { +public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.Listener, + TvPipMenuEduTextDrawer.Listener { private static final String TAG = "TvPipMenuView"; private final TvPipMenuView.Listener mListener; @@ -76,6 +77,7 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L private final View mDimLayer; private final TvPipMenuEduTextDrawer mEduTextDrawer; + private final ViewGroup mEduTextContainer; private final int mPipMenuOuterSpace; private final int mPipMenuBorderWidth; @@ -139,9 +141,9 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L mPipMenuBorderWidth = context.getResources() .getDimensionPixelSize(R.dimen.pip_menu_border_width); - mEduTextDrawer = new TvPipMenuEduTextDrawer(mContext, mainHandler, mListener); - ((FrameLayout) findViewById(R.id.tv_pip_menu_edu_text_drawer_placeholder)) - .addView(mEduTextDrawer); + mEduTextDrawer = new TvPipMenuEduTextDrawer(mContext, mainHandler, this); + mEduTextContainer = (ViewGroup) findViewById(R.id.tv_pip_menu_edu_text_container); + mEduTextContainer.addView(mEduTextDrawer); } void onPipTransitionToTargetBoundsStarted(Rect targetBounds) { @@ -235,11 +237,13 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L * pip menu when it gains focus. */ private void updatePipFrameBounds() { - final ViewGroup.LayoutParams pipFrameParams = mPipFrameView.getLayoutParams(); - if (pipFrameParams != null) { - pipFrameParams.width = mCurrentPipBounds.width() + 2 * mPipMenuBorderWidth; - pipFrameParams.height = mCurrentPipBounds.height() + 2 * mPipMenuBorderWidth; - mPipFrameView.setLayoutParams(pipFrameParams); + if (mPipFrameView.getVisibility() == VISIBLE) { + final ViewGroup.LayoutParams pipFrameParams = mPipFrameView.getLayoutParams(); + if (pipFrameParams != null) { + pipFrameParams.width = mCurrentPipBounds.width() + 2 * mPipMenuBorderWidth; + pipFrameParams.height = mCurrentPipBounds.height() + 2 * mPipMenuBorderWidth; + mPipFrameView.setLayoutParams(pipFrameParams); + } } final ViewGroup.LayoutParams pipViewParams = mPipView.getLayoutParams(); @@ -262,7 +266,7 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L Rect getPipMenuContainerBounds(Rect pipBounds) { final Rect menuUiBounds = new Rect(pipBounds); menuUiBounds.inset(-mPipMenuOuterSpace, -mPipMenuOuterSpace); - menuUiBounds.bottom += mEduTextDrawer.getHeight(); + menuUiBounds.bottom += mEduTextDrawer.getEduTextDrawerHeight(); return menuUiBounds; } @@ -406,6 +410,17 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L } @Override + public void onCloseEduTextAnimationStart() { + mListener.onCloseEduText(); + } + + @Override + public void onCloseEduTextAnimationEnd() { + mPipFrameView.setVisibility(GONE); + mEduTextContainer.setVisibility(GONE); + } + + @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == ACTION_UP) { @@ -551,7 +566,7 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L } } - interface Listener extends TvPipMenuEduTextDrawer.Listener { + interface Listener { void onBackPress(); @@ -573,5 +588,11 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L * has lost focus. */ void onPipWindowFocusChanged(boolean focused); + + /** + * The edu text closing impacts the size of the Picture-in-Picture window and influences + * how it is positioned on the screen. + */ + void onCloseEduText(); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java index c9b3a1af6507..c4a0e9cf5a74 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java @@ -32,6 +32,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM_SHELL), WM_SHELL_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM_SHELL), + WM_SHELL_RECENTS_TRANSITION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, + Consts.TAG_WM_SHELL), WM_SHELL_DRAG_AND_DROP(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM_SHELL), WM_SHELL_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index a8b209fc7da6..b55487258220 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -47,7 +47,9 @@ import android.window.TransitionRequestInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; +import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.util.TransitionUtil; @@ -96,6 +98,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { void startRecentsTransition(PendingIntent intent, Intent fillIn, Bundle options, IApplicationThread appThread, IRecentsAnimationRunner listener) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsTransitionHandler.startRecentsTransition"); // only care about latest one. mAnimApp = appThread; WindowContainerTransaction wct = new WindowContainerTransaction(); @@ -116,7 +120,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { mixer.setRecentsTransition(transition); } if (transition == null) { - controller.cancel(); + controller.cancel("startRecentsTransition"); return; } controller.setTransition(transition); @@ -127,6 +131,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { public WindowContainerTransaction handleRequest(IBinder transition, TransitionRequestInfo request) { // do not directly handle requests. Only entry point should be via startRecentsTransition + Slog.e(TAG, "RecentsTransitionHandler.handleRequest: Unexpected transition request"); return null; } @@ -143,11 +148,17 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { SurfaceControl.Transaction finishTransaction, Transitions.TransitionFinishCallback finishCallback) { final int controllerIdx = findController(transition); - if (controllerIdx < 0) return false; + if (controllerIdx < 0) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsTransitionHandler.startAnimation: no controller found"); + return false; + } final RecentsController controller = mControllers.get(controllerIdx); Transitions.setRunningRemoteTransitionDelegate(mAnimApp); mAnimApp = null; if (!controller.start(info, startTransaction, finishTransaction, finishCallback)) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsTransitionHandler.startAnimation: failed to start animation"); return false; } return true; @@ -168,7 +179,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { SurfaceControl.Transaction finishTransaction) { final int idx = findController(transition); if (idx < 0) return; - mControllers.get(idx).cancel(); + mControllers.get(idx).cancel("onTransitionConsumed"); } /** There is only one of these and it gets reset on finish. */ @@ -213,27 +224,38 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { RecentsController(IRecentsAnimationRunner listener) { mListener = listener; - mDeathHandler = () -> finish(mWillFinishToHome, false /* leaveHint */); + mDeathHandler = () -> { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.DeathRecipient: binder died"); + finish(mWillFinishToHome, false /* leaveHint */); + }; try { mListener.asBinder().linkToDeath(mDeathHandler, 0 /* flags */); } catch (RemoteException e) { + Slog.e(TAG, "RecentsController: failed to link to death", e); mListener = null; } } void setTransition(IBinder transition) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.setTransition: id=%s", transition); mTransition = transition; } - void cancel() { + void cancel(String reason) { // restoring (to-home = false) involves submitting more WM changes, so by default, use // toHome = true when canceling. - cancel(true /* toHome */); + cancel(true /* toHome */, reason); } - void cancel(boolean toHome) { + void cancel(boolean toHome, String reason) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.cancel: toHome=%b reason=%s", toHome, reason); if (mListener != null) { try { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.cancel: calling onAnimationCanceled"); mListener.onAnimationCanceled(null, null); } catch (RemoteException e) { Slog.e(TAG, "Error canceling recents animation", e); @@ -267,6 +289,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } } try { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.cancel: calling onAnimationCanceled with snapshots"); mListener.onAnimationCanceled(taskIds, snapshots); } catch (RemoteException e) { Slog.e(TAG, "Error canceling recents animation", e); @@ -276,6 +300,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } void cleanUp() { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.cleanup"); if (mListener != null && mDeathHandler != null) { mListener.asBinder().unlinkToDeath(mDeathHandler, 0 /* flags */); mDeathHandler = null; @@ -299,6 +324,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { boolean start(TransitionInfo info, SurfaceControl.Transaction t, SurfaceControl.Transaction finishT, Transitions.TransitionFinishCallback finishCB) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.start"); if (mListener == null || mTransition == null) { cleanUp(); return false; @@ -358,6 +384,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { info.getChanges().size() - i, info, t, mLeashMap); apps.add(target); if (TransitionUtil.isClosingType(change.getMode())) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " adding pausing taskId=%d", taskInfo.taskId); // raise closing (pausing) task to "above" layer so it isn't covered t.setLayer(target.leash, info.getChanges().size() * 3 - i); mPausingTasks.add(new TaskState(change, target.leash)); @@ -372,19 +400,23 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { } else if (taskInfo != null && taskInfo.topActivityType == ACTIVITY_TYPE_HOME) { // do nothing } else if (TransitionUtil.isOpeningType(change.getMode())) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " adding opening taskId=%d", taskInfo.taskId); mOpeningTasks.add(new TaskState(change, target.leash)); } } } t.apply(); try { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.start: calling onAnimationStart"); mListener.onAnimationStart(this, apps.toArray(new RemoteAnimationTarget[apps.size()]), wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]), new Rect(0, 0, 0, 0), new Rect()); } catch (RemoteException e) { Slog.e(TAG, "Error starting recents animation", e); - cancel(); + cancel("onAnimationStart() failed"); } return true; } @@ -393,14 +425,19 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { void merge(TransitionInfo info, SurfaceControl.Transaction t, Transitions.TransitionFinishCallback finishCallback) { if (mFinishCB == null) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.merge: skip, no finish callback"); // This was no-op'd (likely a repeated start) and we've already sent finish. return; } if (info.getType() == TRANSIT_SLEEP) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.merge: transit_sleep"); // A sleep event means we need to stop animations immediately, so cancel here. - cancel(); + cancel("transit_sleep"); return; } + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, "RecentsController.merge"); ArrayList<TransitionInfo.Change> openingTasks = null; ArrayList<TransitionInfo.Change> closingTasks = null; mOpeningSeparateHome = false; @@ -417,7 +454,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { && taskInfo.configuration.windowConfiguration.isAlwaysOnTop()) { // Tasks that are always on top (e.g. bubbles), will handle their own transition // as they are on top of everything else. So cancel the merge here. - cancel(); + cancel("task #" + taskInfo.taskId + " is always_on_top"); return; } hasTaskChange = hasTaskChange || taskInfo != null; @@ -448,7 +485,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // Finish recents animation if the display is changed, so the default // transition handler can play the animation such as rotation effect. if (change.hasFlags(TransitionInfo.FLAG_IS_DISPLAY)) { - cancel(mWillFinishToHome); + cancel(mWillFinishToHome, "display change"); return; } // Don't consider order-only changes as changing apps. @@ -492,7 +529,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { + " something unexpected: " + change.getTaskInfo().taskId); continue; } - mPausingTasks.add(mOpeningTasks.remove(openingIdx)); + final TaskState openingTask = mOpeningTasks.remove(openingIdx); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " pausing opening taskId=%d", openingTask.mTaskInfo.taskId); + mPausingTasks.add(openingTask); didMergeThings = true; } } @@ -509,7 +549,10 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { // Something is showing/opening a previously-pausing app. appearedTargets[i] = TransitionUtil.newTarget( change, layer, mPausingTasks.get(pausingIdx).mLeash); - mOpeningTasks.add(mPausingTasks.remove(pausingIdx)); + final TaskState pausingTask = mPausingTasks.remove(pausingIdx); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " opening pausing taskId=%d", pausingTask.mTaskInfo.taskId); + mOpeningTasks.add(pausingTask); // Setup hides opening tasks initially, so make it visible again (since we // are already showing it). t.show(change.getLeash()); @@ -522,6 +565,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { final int rootIdx = TransitionUtil.rootIndexFor(change, mInfo); t.reparent(appearedTargets[i].leash, mInfo.getRoot(rootIdx).getLeash()); t.setLayer(appearedTargets[i].leash, layer); + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + " opening new taskId=%d", appearedTargets[i].taskId); mOpeningTasks.add(new TaskState(change, appearedTargets[i].leash)); } } @@ -539,7 +584,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { + foundRecentsClosing); if (foundRecentsClosing) { mWillFinishToHome = false; - cancel(false /* toHome */); + cancel(false /* toHome */, "didn't merge"); } return; } @@ -549,6 +594,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { info.releaseAnimSurfaces(); if (appearedTargets == null) return; try { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.merge: calling onTasksAppeared"); mListener.onTasksAppeared(appearedTargets); } catch (RemoteException e) { Slog.e(TAG, "Error sending appeared tasks to recents animation", e); @@ -572,6 +619,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { @Override public TaskSnapshot screenshotTask(int taskId) { try { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.screenshotTask: taskId=%d", taskId); return ActivityTaskManager.getService().takeTaskSnapshot(taskId); } catch (RemoteException e) { Slog.e(TAG, "Failed to screenshot task", e); @@ -582,12 +631,19 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { @Override public void setInputConsumerEnabled(boolean enabled) { mExecutor.execute(() -> { - if (mFinishCB == null || !enabled) return; + if (mFinishCB == null || !enabled) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.setInputConsumerEnabled: skip, cb?=%b enabled?=%b", + mFinishCB != null, enabled); + return; + } // transient launches don't receive focus automatically. Since we are taking over // the gesture now, take focus explicitly. // This also moves recents back to top if the user gestured before a switch // animation finished. try { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.setInputConsumerEnabled: set focus to recents"); ActivityTaskManager.getService().setFocusedTask(mRecentsTaskId); } catch (RemoteException e) { Slog.e(TAG, "Failed to set focused task", e); @@ -602,6 +658,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { @Override public void setFinishTaskTransaction(int taskId, PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.setFinishTaskTransaction: taskId=%d", taskId); mExecutor.execute(() -> { if (mFinishCB == null) return; mPipTransaction = finishTransaction; @@ -619,6 +677,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { Slog.e(TAG, "Duplicate call to finish"); return; } + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.finishInner: toHome=%b userLeaveHint=%b willFinishToHome=%b", + toHome, sendUserLeaveHint, mWillFinishToHome); final Transitions.TransitionFinishCallback finishCB = mFinishCB; mFinishCB = null; @@ -630,6 +691,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { else wct.restoreTransientOrder(mRecentsTask); } if (!toHome && !mWillFinishToHome && mPausingTasks != null && mState == STATE_NORMAL) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " returning to app"); // The gesture is returning to the pausing-task(s) rather than continuing with // recents, so end the transition by moving the app back to the top (and also // re-showing it's task). @@ -642,6 +704,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { wct.restoreTransientOrder(mRecentsTask); } } else if (toHome && mOpeningSeparateHome && mPausingTasks != null) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " 3p launching home"); // Special situation where 3p launcher was changed during recents (this happens // during tapltests...). Here we get both "return to home" AND "home opening". // This is basically going home, but we have to restore the recents and home order. @@ -660,6 +723,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { wct.restoreTransientOrder(mRecentsTask); } } else { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, " normal finish"); // The general case: committing to recents, going home, or switching tasks. for (int i = 0; i < mOpeningTasks.size(); ++i) { t.show(mOpeningTasks.get(i).mTaskSurface); @@ -716,6 +780,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler { */ @Override public void detachNavigationBarFromApp(boolean moveHomeToTop) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION, + "RecentsController.detachNavigationBarFromApp"); mExecutor.execute(() -> { if (mTransition == null) return; try { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt index 7581b5c0aa91..8b9c8b9a768f 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt @@ -40,9 +40,7 @@ import com.android.credentialmanager.common.ui.Snackbar import com.android.credentialmanager.createflow.CreateCredentialScreen import com.android.credentialmanager.createflow.hasContentToDisplay import com.android.credentialmanager.getflow.GetCredentialScreen -import com.android.credentialmanager.getflow.GetGenericCredentialScreen import com.android.credentialmanager.getflow.hasContentToDisplay -import com.android.credentialmanager.getflow.isFallbackScreen import com.android.credentialmanager.ui.theme.PlatformTheme @ExperimentalMaterialApi @@ -161,19 +159,11 @@ class CredentialSelectorActivity : ComponentActivity() { providerActivityLauncher = launcher ) } else if (getCredentialUiState != null && hasContentToDisplay(getCredentialUiState)) { - if (isFallbackScreen(getCredentialUiState)) { - GetGenericCredentialScreen( - viewModel = viewModel, - getCredentialUiState = getCredentialUiState, - providerActivityLauncher = launcher - ) - } else { - GetCredentialScreen( - viewModel = viewModel, - getCredentialUiState = getCredentialUiState, - providerActivityLauncher = launcher - ) - } + GetCredentialScreen( + viewModel = viewModel, + getCredentialUiState = getCredentialUiState, + providerActivityLauncher = launcher + ) } else { Log.d(Constants.LOG_TAG, "UI wasn't able to render neither get nor create flow") reportInstantiationErrorAndFinishActivity(credManRepo) diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt index 516c1a3bb1e3..74933c9e3da6 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -200,18 +200,31 @@ fun PrimarySelectionCard( authenticationEntryList.isEmpty()) || (sortedUserNameToCredentialEntryList.isEmpty() && authenticationEntryList.size == 1) item { - HeadlineText( - text = stringResource( - if (hasSingleEntry) { - if (sortedUserNameToCredentialEntryList.firstOrNull() - ?.sortedCredentialEntryList?.first()?.credentialType - == CredentialType.PASSKEY - ) R.string.get_dialog_title_use_passkey_for - else R.string.get_dialog_title_use_sign_in_for - } else R.string.get_dialog_title_choose_sign_in_for, - requestDisplayInfo.appName - ), - ) + if (requestDisplayInfo.preferIdentityDocUi) { + HeadlineText( + text = stringResource( + if (hasSingleEntry) { + R.string.get_dialog_title_use_info_on + } else { + R.string.get_dialog_title_choose_option_for + }, + requestDisplayInfo.appName + ), + ) + } else { + HeadlineText( + text = stringResource( + if (hasSingleEntry) { + if (sortedUserNameToCredentialEntryList.firstOrNull() + ?.sortedCredentialEntryList?.first()?.credentialType + == CredentialType.PASSKEY + ) R.string.get_dialog_title_use_passkey_for + else R.string.get_dialog_title_use_sign_in_for + } else R.string.get_dialog_title_choose_sign_in_for, + requestDisplayInfo.appName + ), + ) + } } item { Divider(thickness = 24.dp, color = Color.Transparent) } item { diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt deleted file mode 100644 index 57fefbe577b4..000000000000 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetGenericCredentialComponents.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.credentialmanager.getflow - -import androidx.activity.compose.ManagedActivityResultLauncher -import androidx.activity.result.ActivityResult -import androidx.activity.result.IntentSenderRequest -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.Divider -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.core.graphics.drawable.toBitmap -import com.android.compose.rememberSystemUiController -import com.android.credentialmanager.CredentialSelectorViewModel -import com.android.credentialmanager.R -import com.android.credentialmanager.common.BaseEntry -import com.android.credentialmanager.common.ProviderActivityState -import com.android.credentialmanager.common.ui.ConfirmButton -import com.android.credentialmanager.common.ui.CredentialContainerCard -import com.android.credentialmanager.common.ui.CtaButtonRow -import com.android.credentialmanager.common.ui.HeadlineIcon -import com.android.credentialmanager.common.ui.HeadlineText -import com.android.credentialmanager.common.ui.LargeLabelTextOnSurfaceVariant -import com.android.credentialmanager.common.ui.ModalBottomSheet -import com.android.credentialmanager.common.ui.SheetContainerCard -import com.android.credentialmanager.common.ui.setBottomSheetSystemBarsColor -import com.android.credentialmanager.logging.GetCredentialEvent -import com.android.internal.logging.UiEventLogger - - -@Composable -fun GetGenericCredentialScreen( - viewModel: CredentialSelectorViewModel, - getCredentialUiState: GetCredentialUiState, - providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult> -) { - val sysUiController = rememberSystemUiController() - setBottomSheetSystemBarsColor(sysUiController) - ModalBottomSheet( - sheetContent = { - when (viewModel.uiState.providerActivityState) { - ProviderActivityState.NOT_APPLICABLE -> { - PrimarySelectionCardGeneric( - requestDisplayInfo = getCredentialUiState.requestDisplayInfo, - providerDisplayInfo = getCredentialUiState.providerDisplayInfo, - providerInfoList = getCredentialUiState.providerInfoList, - onEntrySelected = viewModel::getFlowOnEntrySelected, - onConfirm = viewModel::getFlowOnConfirmEntrySelected, - onLog = { viewModel.logUiEvent(it) }, - ) - viewModel.uiMetrics.log(GetCredentialEvent - .CREDMAN_GET_CRED_SCREEN_PRIMARY_SELECTION) - } - ProviderActivityState.READY_TO_LAUNCH -> { - // Launch only once per providerActivityState change so that the provider - // UI will not be accidentally launched twice. - LaunchedEffect(viewModel.uiState.providerActivityState) { - viewModel.launchProviderUi(providerActivityLauncher) - } - viewModel.uiMetrics.log(GetCredentialEvent - .CREDMAN_GET_CRED_PROVIDER_ACTIVITY_READY_TO_LAUNCH) - } - ProviderActivityState.PENDING -> { - // Hide our content when the provider activity is active. - viewModel.uiMetrics.log(GetCredentialEvent - .CREDMAN_GET_CRED_PROVIDER_ACTIVITY_PENDING) - } - } - }, - onDismiss = viewModel::onUserCancel, - ) -} - -@Composable -fun PrimarySelectionCardGeneric( - requestDisplayInfo: RequestDisplayInfo, - providerDisplayInfo: ProviderDisplayInfo, - providerInfoList: List<ProviderInfo>, - onEntrySelected: (BaseEntry) -> Unit, - onConfirm: () -> Unit, - onLog: @Composable (UiEventLogger.UiEventEnum) -> Unit, -) { - val sortedUserNameToCredentialEntryList = - providerDisplayInfo.sortedUserNameToCredentialEntryList - val totalEntriesCount = sortedUserNameToCredentialEntryList - .flatMap { it.sortedCredentialEntryList }.size - SheetContainerCard { - // When only one provider (not counting the remote-only provider) exists, display that - // provider's icon + name up top. - if (providerInfoList.size <= 2) { // It's only possible to be the single provider case - // if we are started with no more than 2 providers. - val nonRemoteProviderList = providerInfoList.filter( - { it.credentialEntryList.isNotEmpty() || it.authenticationEntryList.isNotEmpty() } - ) - if (nonRemoteProviderList.size == 1) { - val providerInfo = nonRemoteProviderList.firstOrNull() // First should always work - // but just to be safe. - if (providerInfo != null) { - item { - HeadlineIcon( - bitmap = providerInfo.icon.toBitmap().asImageBitmap(), - tint = Color.Unspecified, - ) - } - item { Divider(thickness = 4.dp, color = Color.Transparent) } - item { LargeLabelTextOnSurfaceVariant(text = providerInfo.displayName) } - item { Divider(thickness = 16.dp, color = Color.Transparent) } - } - } - } - - item { - HeadlineText( - text = stringResource( - if (totalEntriesCount == 1) { - R.string.get_dialog_title_use_info_on - } else { - R.string.get_dialog_title_choose_option_for - }, - requestDisplayInfo.appName - ), - ) - } - item { Divider(thickness = 24.dp, color = Color.Transparent) } - item { - CredentialContainerCard { - Column(verticalArrangement = Arrangement.spacedBy(2.dp)) { - sortedUserNameToCredentialEntryList.forEach { - // TODO(b/275375861): fallback UI merges entries by account names. - // Need a strategy to be able to show all entries. - CredentialEntryRow( - credentialEntryInfo = it.sortedCredentialEntryList.first(), - onEntrySelected = onEntrySelected, - enforceOneLine = true, - ) - } - } - } - } - item { Divider(thickness = 24.dp, color = Color.Transparent) } - item { - if (totalEntriesCount == 1) { - CtaButtonRow( - rightButton = { - ConfirmButton( - stringResource(R.string.get_dialog_button_label_continue), - onClick = onConfirm - ) - } - ) - } - } - } - onLog(GetCredentialEvent.CREDMAN_GET_CRED_PRIMARY_SELECTION_CARD) -} diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt index a4a163bbabc3..716f47450ae9 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetModel.kt @@ -41,10 +41,6 @@ internal fun hasContentToDisplay(state: GetCredentialUiState): Boolean { !state.requestDisplayInfo.preferImmediatelyAvailableCredentials) } -internal fun isFallbackScreen(state: GetCredentialUiState): Boolean { - return state.requestDisplayInfo.preferIdentityDocUi -} - internal fun findAutoSelectEntry(providerDisplayInfo: ProviderDisplayInfo): CredentialEntryInfo? { if (providerDisplayInfo.authenticationEntryList.isNotEmpty()) { return null diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt index 1786d139e966..91c0a5b635c9 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt @@ -19,17 +19,11 @@ data class RippleAnimationConfig( val maxHeight: Float = 0f, val pixelDensity: Float = 1f, var color: Int = Color.WHITE, - val opacity: Int = RIPPLE_DEFAULT_ALPHA, - val sparkleStrength: Float = RIPPLE_SPARKLE_STRENGTH, + val opacity: Int = RippleShader.RIPPLE_DEFAULT_ALPHA, + val sparkleStrength: Float = RippleShader.RIPPLE_SPARKLE_STRENGTH, // Null means it uses default fade parameter values. val baseRingFadeParams: RippleShader.FadeParams? = null, val sparkleRingFadeParams: RippleShader.FadeParams? = null, val centerFillFadeParams: RippleShader.FadeParams? = null, val shouldDistort: Boolean = true -) { - companion object { - const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f - const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt() - const val RIPPLE_DEFAULT_ALPHA: Int = 115 // full opacity is 255. - } -} +) diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt index b5b6037aeae4..7e56f4b3d2b2 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt @@ -60,6 +60,10 @@ class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) : const val DEFAULT_CENTER_FILL_FADE_OUT_START = 0f const val DEFAULT_CENTER_FILL_FADE_OUT_END = 0.6f + const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f + const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt() + const val RIPPLE_DEFAULT_ALPHA: Int = 115 // full opacity is 255. + private const val SHADER_UNIFORMS = """ uniform vec2 in_center; diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt index ef5ad436ec38..b89912709576 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt @@ -72,9 +72,9 @@ open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, a this.rippleShape = rippleShape rippleShader = RippleShader(rippleShape) - rippleShader.color = RippleAnimationConfig.RIPPLE_DEFAULT_COLOR + rippleShader.color = RippleShader.RIPPLE_DEFAULT_COLOR rippleShader.rawProgress = 0f - rippleShader.sparkleStrength = RippleAnimationConfig.RIPPLE_SPARKLE_STRENGTH + rippleShader.sparkleStrength = RippleShader.RIPPLE_SPARKLE_STRENGTH rippleShader.pixelDensity = resources.displayMetrics.density ripplePaint.shader = rippleShader @@ -209,7 +209,7 @@ open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, a * * The alpha value of the color will be applied to the ripple. The alpha range is [0-255]. */ - fun setColor(color: Int, alpha: Int = RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA) { + fun setColor(color: Int, alpha: Int = RippleShader.RIPPLE_DEFAULT_ALPHA) { rippleShader.color = ColorUtils.setAlphaComponent(color, alpha) } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt index 5b0e29005d82..461d390fd477 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt @@ -41,10 +41,10 @@ data class KeyguardFaceListenModel( var listeningForFaceAssistant: Boolean = false, var occludingAppRequestingFaceAuth: Boolean = false, var postureAllowsListening: Boolean = false, - var primaryUser: Boolean = false, var secureCameraLaunched: Boolean = false, var supportsDetect: Boolean = false, var switchingUser: Boolean = false, + var systemUser: Boolean = false, var udfpsFingerDown: Boolean = false, var userNotTrustedOrDetectionIsNeeded: Boolean = false, ) : KeyguardListenModel() { @@ -69,11 +69,11 @@ data class KeyguardFaceListenModel( keyguardGoingAway.toString(), listeningForFaceAssistant.toString(), occludingAppRequestingFaceAuth.toString(), - primaryUser.toString(), postureAllowsListening.toString(), secureCameraLaunched.toString(), supportsDetect.toString(), switchingUser.toString(), + systemUser.toString(), alternateBouncerShowing.toString(), udfpsFingerDown.toString(), userNotTrustedOrDetectionIsNeeded.toString(), @@ -109,12 +109,11 @@ data class KeyguardFaceListenModel( keyguardGoingAway = model.keyguardGoingAway listeningForFaceAssistant = model.listeningForFaceAssistant occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth - primaryUser = model.primaryUser postureAllowsListening = model.postureAllowsListening secureCameraLaunched = model.secureCameraLaunched supportsDetect = model.supportsDetect switchingUser = model.switchingUser - switchingUser = model.switchingUser + systemUser = model.systemUser udfpsFingerDown = model.udfpsFingerDown userNotTrustedOrDetectionIsNeeded = model.userNotTrustedOrDetectionIsNeeded } @@ -153,11 +152,11 @@ data class KeyguardFaceListenModel( "keyguardGoingAway", "listeningForFaceAssistant", "occludingAppRequestingFaceAuth", - "primaryUser", "postureAllowsListening", "secureCameraLaunched", "supportsDetect", "switchingUser", + "systemUser", "udfpsBouncerShowing", "udfpsFingerDown", "userNotTrustedOrDetectionIsNeeded", diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt index b8c0ccbd8aaa..f2685c5200ad 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt @@ -41,11 +41,11 @@ data class KeyguardFingerprintListenModel( var keyguardIsVisible: Boolean = false, var keyguardOccluded: Boolean = false, var occludingAppRequestingFp: Boolean = false, - var primaryUser: Boolean = false, var shouldListenSfpsState: Boolean = false, var shouldListenForFingerprintAssistant: Boolean = false, var strongerAuthRequired: Boolean = false, var switchingUser: Boolean = false, + var systemUser: Boolean = false, var udfps: Boolean = false, var userDoesNotHaveTrust: Boolean = false, ) : KeyguardListenModel() { @@ -72,11 +72,11 @@ data class KeyguardFingerprintListenModel( keyguardIsVisible.toString(), keyguardOccluded.toString(), occludingAppRequestingFp.toString(), - primaryUser.toString(), shouldListenSfpsState.toString(), shouldListenForFingerprintAssistant.toString(), strongerAuthRequired.toString(), switchingUser.toString(), + systemUser.toString(), udfps.toString(), userDoesNotHaveTrust.toString(), ) @@ -112,11 +112,11 @@ data class KeyguardFingerprintListenModel( keyguardIsVisible = model.keyguardIsVisible keyguardOccluded = model.keyguardOccluded occludingAppRequestingFp = model.occludingAppRequestingFp - primaryUser = model.primaryUser shouldListenSfpsState = model.shouldListenSfpsState shouldListenForFingerprintAssistant = model.shouldListenForFingerprintAssistant strongerAuthRequired = model.strongerAuthRequired switchingUser = model.switchingUser + systemUser = model.systemUser udfps = model.udfps userDoesNotHaveTrust = model.userDoesNotHaveTrust } @@ -158,11 +158,11 @@ data class KeyguardFingerprintListenModel( "keyguardIsVisible", "keyguardOccluded", "occludingAppRequestingFp", - "primaryUser", "shouldListenSidFingerprintState", "shouldListenForFingerprintAssistant", "strongAuthRequired", "switchingUser", + "systemUser", "underDisplayFingerprint", "userDoesNotHaveTrust", ) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java index 76e051ea25f3..693268d730a4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java @@ -178,6 +178,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard @Override public void onUserInput() { + mKeyguardFaceAuthInteractor.onPrimaryBouncerUserInput(); mUpdateMonitor.cancelFaceAuth(); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index ea043763c5b9..10c08bc3e8b3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -297,7 +297,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final Context mContext; private final UserTracker mUserTracker; private final KeyguardUpdateMonitorLogger mLogger; - private final boolean mIsPrimaryUser; + private final boolean mIsSystemUser; private final AuthController mAuthController; private final UiEventLogger mUiEventLogger; private final Set<Integer> mFaceAcquiredInfoIgnoreList; @@ -2522,7 +2522,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ON_KEYGUARD_INIT); TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener); - mIsPrimaryUser = mUserManager.isPrimaryUser(); + mIsSystemUser = mUserManager.isSystemUser(); int user = mUserTracker.getUserId(); mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user)); mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled(); @@ -2968,7 +2968,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || (mKeyguardOccluded && userDoesNotHaveTrust && mKeyguardShowing && (mOccludingAppRequestingFp || isUdfps || mAlternateBouncerShowing)); - // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an + // Only listen if this KeyguardUpdateMonitor belongs to the system user. There is an // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware. final boolean biometricEnabledForUser = mBiometricEnabledForUser.get(user); final boolean userCanSkipBouncer = getUserCanSkipBouncer(user); @@ -2977,7 +2977,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab !mSwitchingUser && !fingerprintDisabledForUser && (!mKeyguardGoingAway || !mDeviceInteractive) - && mIsPrimaryUser + && mIsSystemUser && biometricEnabledForUser && !isUserInLockdown(user); final boolean strongerAuthRequired = !isUnlockingWithFingerprintAllowed(); @@ -3021,11 +3021,11 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab isKeyguardVisible(), mKeyguardOccluded, mOccludingAppRequestingFp, - mIsPrimaryUser, shouldListenSideFpsState, shouldListenForFingerprintAssistant, strongerAuthRequired, mSwitchingUser, + mIsSystemUser, isUdfps, userDoesNotHaveTrust)); @@ -3070,7 +3070,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab final boolean shouldListenForFaceAssistant = shouldListenForFaceAssistant(); final boolean isUdfpsFingerDown = mAuthController.isUdfpsFingerDown(); final boolean isPostureAllowedForFaceAuth = doesPostureAllowFaceAuth(mPostureState); - // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an + // Only listen if this KeyguardUpdateMonitor belongs to the system user. There is an // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware. final boolean shouldListen = (mPrimaryBouncerFullyShown @@ -3082,7 +3082,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab || mAlternateBouncerShowing) && !mSwitchingUser && !faceDisabledForUser && userNotTrustedOrDetectionIsNeeded && !mKeyguardGoingAway && biometricEnabledForUser - && faceAuthAllowedOrDetectionIsNeeded && mIsPrimaryUser + && faceAuthAllowedOrDetectionIsNeeded && mIsSystemUser && (!mSecureCameraLaunched || mAlternateBouncerShowing) && faceAndFpNotAuthenticated && !mGoingToSleep @@ -3108,10 +3108,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab shouldListenForFaceAssistant, mOccludingAppRequestingFace, isPostureAllowedForFaceAuth, - mIsPrimaryUser, mSecureCameraLaunched, supportsDetect, mSwitchingUser, + mIsSystemUser, isUdfpsFingerDown, userNotTrustedOrDetectionIsNeeded)); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java index b6ee4cbc7641..3349fe5f1147 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationSettingsController.java @@ -24,6 +24,7 @@ import android.content.ComponentCallbacks; import android.content.Context; import android.content.res.Configuration; import android.util.Range; +import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.graphics.SfVsyncFrameCallbackProvider; @@ -68,14 +69,18 @@ public class MagnificationSettingsController implements ComponentCallbacks { @NonNull Callback settingsControllerCallback, SecureSettings secureSettings, WindowMagnificationSettings windowMagnificationSettings) { - mContext = context; + mContext = context.createWindowContext( + context.getDisplay(), + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + null); + mContext.setTheme(com.android.systemui.R.style.Theme_SystemUI); mDisplayId = mContext.getDisplayId(); - mConfiguration = new Configuration(context.getResources().getConfiguration()); + mConfiguration = new Configuration(mContext.getResources().getConfiguration()); mSettingsControllerCallback = settingsControllerCallback; if (windowMagnificationSettings != null) { mWindowMagnificationSettings = windowMagnificationSettings; } else { - mWindowMagnificationSettings = new WindowMagnificationSettings(context, + mWindowMagnificationSettings = new WindowMagnificationSettings(mContext, mWindowMagnificationSettingsCallback, sfVsyncFrameProvider, secureSettings); } diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java index 71c5f247b899..6e8275f64eea 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java @@ -559,7 +559,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest final LayoutParams params = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, - LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY, + LayoutParams.TYPE_NAVIGATION_BAR_PANEL, LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT); params.gravity = Gravity.TOP | Gravity.START; diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java index 98a3e4b55256..11ef749573b7 100644 --- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java +++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java @@ -34,7 +34,6 @@ import com.android.settingslib.Utils; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.shared.recents.utilities.Utilities; -import com.android.systemui.surfaceeffects.ripple.RippleAnimationConfig; import com.android.systemui.surfaceeffects.ripple.RippleShader; import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape; import com.android.systemui.surfaceeffects.ripple.RippleView; @@ -177,7 +176,7 @@ final class WirelessChargingLayout extends FrameLayout { mRippleView.setBlur(6.5f, 2.5f); } else { mRippleView.setDuration(CIRCLE_RIPPLE_ANIMATION_DURATION); - mRippleView.setColor(color, RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA); + mRippleView.setColor(color, RippleShader.RIPPLE_DEFAULT_ALPHA); } OnAttachStateChangeListener listener = new OnAttachStateChangeListener() { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt index 05ab01bf2b9a..5f2178df4346 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepository.kt @@ -225,10 +225,17 @@ constructor( } private fun observeFaceAuthResettingConditions() { - // Clear auth status when keyguard is going away or when the user is switching. - merge(keyguardRepository.isKeyguardGoingAway, userRepository.userSwitchingInProgress) - .onEach { goingAwayOrUserSwitchingInProgress -> - if (goingAwayOrUserSwitchingInProgress) { + // Clear auth status when keyguard is going away or when the user is switching or device + // starts going to sleep. + merge( + keyguardRepository.wakefulness.map { + WakefulnessModel.isSleepingOrStartingToSleep(it) + }, + keyguardRepository.isKeyguardGoingAway, + userRepository.userSwitchingInProgress + ) + .onEach { anyOfThemIsTrue -> + if (anyOfThemIsTrue) { _isAuthenticated.value = false retryCount = 0 halErrorRetryJob?.cancel() @@ -248,8 +255,8 @@ constructor( "nonStrongBiometricIsNotAllowed", faceDetectLog ), - // We don't want to run face detect if it's not possible to authenticate with FP - // from the bouncer. UDFPS is the only fp sensor type that won't support this. + // We don't want to run face detect if fingerprint can be used to unlock the device + // but it's not possible to authenticate with FP from the bouncer (UDFPS) logAndObserve( and(isUdfps(), deviceEntryFingerprintAuthRepository.isRunning).isFalse(), "udfpsAuthIsNotPossibleAnymore", @@ -306,7 +313,7 @@ constructor( logAndObserve( combine( keyguardInteractor.isSecureCameraActive, - alternateBouncerInteractor.isVisible, + alternateBouncerInteractor.isVisible ) { a, b -> !a || b }, @@ -334,12 +341,12 @@ constructor( logAndObserve(isLockedOut.isFalse(), "isNotInLockOutState", faceAuthLog), logAndObserve( deviceEntryFingerprintAuthRepository.isLockedOut.isFalse(), - "fpLockedOut", + "fpIsNotLockedOut", faceAuthLog ), logAndObserve( trustRepository.isCurrentUserTrusted.isFalse(), - "currentUserTrusted", + "currentUserIsNotTrusted", faceAuthLog ), logAndObserve( @@ -347,11 +354,6 @@ constructor( "nonStrongBiometricIsAllowed", faceAuthLog ), - logAndObserve( - userRepository.selectedUserInfo.map { it.isPrimary }, - "userIsPrimaryUser", - faceAuthLog - ), ) .reduce(::and) .distinctUntilChanged() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt index 06ae11fe810c..74ef7a50fd44 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractor.kt @@ -59,6 +59,7 @@ interface KeyguardFaceAuthInteractor { fun onQsExpansionStared() fun onNotificationPanelClicked() fun onSwipeUpOnBouncer() + fun onPrimaryBouncerUserInput() } /** diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt index cad40aac00d3..5005b6c7f0df 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/NoopKeyguardFaceAuthInteractor.kt @@ -59,4 +59,5 @@ class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInt override fun onNotificationPanelClicked() {} override fun onSwipeUpOnBouncer() {} + override fun onPrimaryBouncerUserInput() {} } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt index 20ebb711c42d..6b515dab79f6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/SystemUIKeyguardFaceAuthInteractor.kt @@ -151,6 +151,10 @@ constructor( return featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR) } + override fun onPrimaryBouncerUserInput() { + repository.cancel() + } + /** Provide the status of face authentication */ override val authenticationStatus = repository.authenticationStatus diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt index 5770f3ee8876..ddce516a0fb2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModel.kt @@ -47,6 +47,7 @@ constructor( duration = TO_LOCKSCREEN_DURATION, onStep = { value -> -translatePx + value * translatePx }, interpolator = EMPHASIZED_DECELERATE, + onCancel = { 0f }, ) } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index ed40eed54978..2962c14b813a 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -291,7 +291,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId); when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true); - when(mUserManager.isPrimaryUser()).thenReturn(true); + currentUserIsSystem(); when(mStrongAuthTracker.getStub()).thenReturn(mock(IStrongAuthTracker.Stub.class)); when(mStrongAuthTracker .isUnlockingWithBiometricAllowed(anyBoolean() /* isClass3Biometric */)) @@ -960,7 +960,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void requestFaceAuth_whenFaceAuthWasStarted_returnsTrue() throws RemoteException { // This satisfies all the preconditions to run face auth. keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1467,7 +1467,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Preconditions for sfps auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1503,7 +1503,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // GIVEN Preconditions for sfps auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1532,7 +1532,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // GIVEN Preconditions for sfps auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1684,7 +1684,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Face auth should run when the following is true. keyguardNotGoingAway(); occludingAppRequestsFaceAuth(); - currentUserIsPrimary(); + currentUserIsSystem(); primaryAuthNotRequiredByStrongAuthTracker(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); @@ -1705,7 +1705,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Face auth should run when the following is true. bouncerFullyVisibleAndNotGoingToSleep(); keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); primaryAuthNotRequiredByStrongAuthTracker(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); @@ -1728,7 +1728,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Face auth should run when the following is true. bouncerFullyVisibleAndNotGoingToSleep(); keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); primaryAuthNotRequiredByStrongAuthTracker(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); @@ -1749,7 +1749,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void testShouldListenForFace_whenUserIsNotPrimary_returnsFalse() throws RemoteException { cleanupKeyguardUpdateMonitor(); // This disables face auth - when(mUserManager.isPrimaryUser()).thenReturn(false); + when(mUserManager.isSystemUser()).thenReturn(false); mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext); @@ -1773,7 +1773,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Face auth should run when the following is true. keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); biometricsEnabledForCurrentUser(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); @@ -1791,7 +1791,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1813,7 +1813,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Face auth should run when the following is true. keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1833,7 +1833,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1854,7 +1854,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { // Face auth should run when the following is true. keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1876,7 +1876,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { // Face auth should run when the following is true. keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1896,7 +1896,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { // Face auth should run when the following is true. keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1915,7 +1915,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void testShouldListenForFace_whenKeyguardIsAwake_returnsTrue() throws RemoteException { // Preconditions for face auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1940,7 +1940,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { public void testShouldListenForFace_whenUdfpsFingerDown_returnsTrue() throws RemoteException { // Preconditions for face auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1959,7 +1959,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { // Preconditions for face auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -1977,7 +1977,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { // Preconditions for face auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -2002,7 +2002,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { // Preconditions for face auth to run keyguardNotGoingAway(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -2324,7 +2324,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { throws RemoteException { keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -2455,7 +2455,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED; keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -2479,7 +2479,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_UNKNOWN; keyguardNotGoingAway(); bouncerFullyVisibleAndNotGoingToSleep(); - currentUserIsPrimary(); + currentUserIsSystem(); currentUserDoesNotHaveTrust(); biometricsNotDisabledThroughDevicePolicyManager(); biometricsEnabledForCurrentUser(); @@ -2877,8 +2877,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { new FaceManager.AuthenticationResult(null, null, mCurrentUserId, false)); } - private void currentUserIsPrimary() { - when(mUserManager.isPrimaryUser()).thenReturn(true); + private void currentUserIsSystem() { + when(mUserManager.isSystemUser()).thenReturn(true); } private void biometricsNotDisabledThroughDevicePolicyManager() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt index a76d03b8ba93..fa40fc431b5f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFaceAuthRepositoryTest.kt @@ -72,7 +72,6 @@ import com.google.common.truth.Truth.assertThat import java.io.PrintWriter import java.io.StringWriter import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.TestScope @@ -542,14 +541,6 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test - fun authenticateDoesNotRunWhenCurrentUserIsNotPrimary() = - testScope.runTest { - testGatingCheckForFaceAuth { - launch { fakeUserRepository.setSelectedUserInfo(secondaryUser) } - } - } - - @Test fun authenticateDoesNotRunWhenSecureCameraIsActive() = testScope.runTest { testGatingCheckForFaceAuth { @@ -653,6 +644,58 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() { } @Test + fun isAuthenticatedIsResetToFalseWhenDeviceStartsGoingToSleep() = + testScope.runTest { + initCollectors() + allPreconditionsToRunFaceAuthAreTrue() + + triggerFaceAuth(false) + + authenticationCallback.value.onAuthenticationSucceeded( + mock(FaceManager.AuthenticationResult::class.java) + ) + + assertThat(authenticated()).isTrue() + + keyguardRepository.setWakefulnessModel( + WakefulnessModel( + WakefulnessState.STARTING_TO_SLEEP, + isWakingUpOrAwake = false, + lastWakeReason = WakeSleepReason.POWER_BUTTON, + lastSleepReason = WakeSleepReason.POWER_BUTTON + ) + ) + + assertThat(authenticated()).isFalse() + } + + @Test + fun isAuthenticatedIsResetToFalseWhenDeviceGoesToSleep() = + testScope.runTest { + initCollectors() + allPreconditionsToRunFaceAuthAreTrue() + + triggerFaceAuth(false) + + authenticationCallback.value.onAuthenticationSucceeded( + mock(FaceManager.AuthenticationResult::class.java) + ) + + assertThat(authenticated()).isTrue() + + keyguardRepository.setWakefulnessModel( + WakefulnessModel( + WakefulnessState.ASLEEP, + isWakingUpOrAwake = false, + lastWakeReason = WakeSleepReason.POWER_BUTTON, + lastSleepReason = WakeSleepReason.POWER_BUTTON + ) + ) + + assertThat(authenticated()).isFalse() + } + + @Test fun isAuthenticatedIsResetToFalseWhenUserIsSwitching() = testScope.runTest { initCollectors() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt index 3d1d2f46a65e..5da1a846fbfd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardFaceAuthInteractorTest.kt @@ -279,6 +279,23 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() { } @Test + fun faceAuthIsCancelledWhenUserInputOnPrimaryBouncer() = + testScope.runTest { + underTest.start() + + underTest.onSwipeUpOnBouncer() + + runCurrent() + assertThat(faceAuthRepository.isAuthRunning.value).isTrue() + + underTest.onPrimaryBouncerUserInput() + + runCurrent() + + assertThat(faceAuthRepository.isAuthRunning.value).isFalse() + } + + @Test fun faceAuthIsRequestedWhenSwipeUpOnBouncer() = testScope.runTest { underTest.start() diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt index 0c4e84521a36..efa5f0c966e3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt @@ -92,6 +92,21 @@ class OccludedToLockscreenTransitionViewModelTest : SysuiTestCase() { job.cancel() } + @Test + fun lockscreenTranslationYResettedAfterJobCancelled() = + runTest(UnconfinedTestDispatcher()) { + val values = mutableListOf<Float>() + + val pixels = 100 + val job = + underTest.lockscreenTranslationY(pixels).onEach { values.add(it) }.launchIn(this) + repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED)) + + assertThat(values.last()).isEqualTo(0f) + + job.cancel() + } + private fun step( value: Float, state: TransitionState = TransitionState.RUNNING diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 2a964b8b701f..3bd4547dd3e6 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -56,6 +56,10 @@ import static com.android.server.autofill.Helper.getNumericValue; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sVerbose; import static com.android.server.autofill.Helper.toArray; +import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_RESULT_FAILURE; +import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_RESULT_SUCCESS; +import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_TYPE_DATASET_AUTHENTICATION; +import static com.android.server.autofill.PresentationStatsEventLogger.AUTHENTICATION_TYPE_FULL_AUTHENTICATION; import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_NO_FOCUS; import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_FAILED; import static com.android.server.autofill.PresentationStatsEventLogger.NOT_SHOWN_REASON_REQUEST_TIMEOUT; @@ -75,6 +79,12 @@ import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_O import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_REQUIRED_ID_CHANGE; import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_TRIGGER_ID_SET; import static com.android.server.autofill.SaveEventLogger.SAVE_UI_SHOWN_REASON_UNKNOWN; +import static com.android.server.autofill.SessionCommittedEventLogger.CommitReason; +import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_ACTIVITY_FINISHED; +import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_VIEW_CHANGED; +import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_VIEW_CLICKED; +import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_VIEW_COMMITTED; +import static com.android.server.autofill.SessionCommittedEventLogger.COMMIT_REASON_SESSION_DESTROYED; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS; import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE; @@ -364,6 +374,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState private final long mStartTime; /** + * Count of FillRequests in the session. + */ + private int mRequestCount; + + /** * Starting timestamp of latency logger. * This is set when Session created or when the view is reset. */ @@ -1132,6 +1147,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState int flags) { final FillResponse existingResponse = viewState.getResponse(); mFillRequestEventLogger.startLogForNewRequest(); + mRequestCount++; mFillRequestEventLogger.maybeSetAppPackageUid(uid); mFillRequestEventLogger.maybeSetFlags(mFlags); if(mPreviouslyFillDialogPotentiallyStarted) { @@ -1330,8 +1346,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState this.userId = userId; this.taskId = taskId; this.uid = uid; - mStartTime = SystemClock.elapsedRealtime(); - mLatencyBaseTime = mStartTime; mService = service; mLock = lock; mUi = ui; @@ -1347,11 +1361,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState mComponentName = componentName; mCompatMode = compatMode; mSessionState = STATE_ACTIVE; + // Initiate all loggers & counters. + mStartTime = SystemClock.elapsedRealtime(); + mLatencyBaseTime = mStartTime; + mRequestCount = 0; mPresentationStatsEventLogger = PresentationStatsEventLogger.forSessionId(sessionId); mFillRequestEventLogger = FillRequestEventLogger.forSessionId(sessionId); mFillResponseEventLogger = FillResponseEventLogger.forSessionId(sessionId); mSessionCommittedEventLogger = SessionCommittedEventLogger.forSessionId(sessionId); + mSessionCommittedEventLogger.maybeSetComponentPackageUid(uid); mSaveEventLogger = SaveEventLogger.forSessionId(sessionId); + synchronized (mLock) { mSessionFlags = new SessionFlags(); mSessionFlags.mAugmentedAutofillOnly = forAugmentedAutofillOnly; @@ -1971,6 +1991,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Start a new FillRequest logger for client suggestion fallback. mFillRequestEventLogger.startLogForNewRequest(); + mRequestCount++; mFillRequestEventLogger.maybeSetAppPackageUid(uid); mFillRequestEventLogger.maybeSetFlags( flags & ~FLAG_ENABLED_CLIENT_SUGGESTIONS); @@ -2187,6 +2208,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } final Intent fillInIntent; synchronized (mLock) { + mPresentationStatsEventLogger.maybeSetAuthenticationType( + AUTHENTICATION_TYPE_FULL_AUTHENTICATION); if (mDestroyed) { Slog.w(TAG, "Call to Session#authenticate() rejected - session: " + id + " destroyed"); @@ -2231,7 +2254,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (mDestroyed) { Slog.w(TAG, "Call to Session#save() rejected - session: " + id + " destroyed"); - mSaveEventLogger.logAndEndEvent(); return; } } @@ -2251,7 +2273,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (mDestroyed) { Slog.w(TAG, "Call to Session#cancelSave() rejected - session: " + id + " destroyed"); - mSaveEventLogger.logAndEndEvent(); return; } } @@ -2438,18 +2459,26 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId); if (requestId == AUGMENTED_AUTOFILL_REQUEST_ID) { setAuthenticationResultForAugmentedAutofillLocked(data, authenticationId); + // Augmented autofill is not logged. + mPresentationStatsEventLogger.logAndEndEvent(); return; } if (mResponses == null) { // Typically happens when app explicitly called cancel() while the service was showing // the auth UI. Slog.w(TAG, "setAuthenticationResultLocked(" + authenticationId + "): no responses"); + mPresentationStatsEventLogger.maybeSetAuthenticationResult( + AUTHENTICATION_RESULT_FAILURE); + mPresentationStatsEventLogger.logAndEndEvent(); removeFromService(); return; } final FillResponse authenticatedResponse = mResponses.get(requestId); if (authenticatedResponse == null || data == null) { Slog.w(TAG, "no authenticated response"); + mPresentationStatsEventLogger.maybeSetAuthenticationResult( + AUTHENTICATION_RESULT_FAILURE); + mPresentationStatsEventLogger.logAndEndEvent(); removeFromService(); return; } @@ -2461,6 +2490,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx); if (dataset == null) { Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response"); + mPresentationStatsEventLogger.maybeSetAuthenticationResult( + AUTHENTICATION_RESULT_FAILURE); + mPresentationStatsEventLogger.logAndEndEvent(); removeFromService(); return; } @@ -2477,11 +2509,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } if (result instanceof FillResponse) { logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED); + mPresentationStatsEventLogger.maybeSetAuthenticationResult( + AUTHENTICATION_RESULT_SUCCESS); replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState); } else if (result instanceof Dataset) { if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) { logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED); + mPresentationStatsEventLogger.maybeSetAuthenticationResult( + AUTHENTICATION_RESULT_SUCCESS); if (newClientState != null) { if (sDebug) Slog.d(TAG, "Updating client state from auth dataset"); mClientState = newClientState; @@ -2497,6 +2533,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + authenticationId); logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION); + mPresentationStatsEventLogger.maybeSetAuthenticationResult( + AUTHENTICATION_RESULT_FAILURE); } } else { if (result != null) { @@ -2504,6 +2542,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION); + mPresentationStatsEventLogger.maybeSetAuthenticationResult( + AUTHENTICATION_RESULT_FAILURE); processNullResponseLocked(requestId, 0); } } @@ -4790,6 +4830,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } // Log FillRequest for Augmented Autofill. mFillRequestEventLogger.startLogForNewRequest(); + mRequestCount++; mFillRequestEventLogger.maybeSetAppPackageUid(uid); mFillRequestEventLogger.maybeSetFlags(mFlags); mFillRequestEventLogger.maybeSetRequestId(AUGMENTED_AUTOFILL_REQUEST_ID); @@ -5036,6 +5077,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState if (dataset.getAuthentication() == null) { if (generateEvent) { mService.logDatasetSelected(dataset.getId(), id, mClientState, uiType); + mPresentationStatsEventLogger.maybeSetSelectedDatasetId(datasetIndex); } if (mCurrentViewId != null) { mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId); @@ -5046,6 +5088,8 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // ...or handle authentication. mService.logDatasetAuthenticationSelected(dataset.getId(), id, mClientState, uiType); + mPresentationStatsEventLogger.maybeSetAuthenticationType( + AUTHENTICATION_TYPE_DATASET_AUTHENTICATION); setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false); final Intent fillInIntent = createAuthFillInIntentLocked(requestId, mClientState); if (fillInIntent == null) { @@ -5639,6 +5683,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState */ @GuardedBy("mLock") RemoteFillService destroyLocked() { + // Log unlogged events. + mSessionCommittedEventLogger.maybeSetCommitReason(COMMIT_REASON_SESSION_DESTROYED); + mSessionCommittedEventLogger.maybeSetRequestCount(mRequestCount); + mSessionCommittedEventLogger.maybeSetSessionDurationMillis( + SystemClock.elapsedRealtime() - mStartTime); + mSessionCommittedEventLogger.logAndEndEvent(); + mPresentationStatsEventLogger.logAndEndEvent(); + mSaveEventLogger.logAndEndEvent(); + mFillResponseEventLogger.logAndEndEvent(); + mFillRequestEventLogger.logAndEndEvent(); + if (mDestroyed) { return null; } diff --git a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java index 92d72ac828f3..541ec80e58ae 100644 --- a/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java +++ b/services/autofill/java/com/android/server/autofill/SessionCommittedEventLogger.java @@ -18,6 +18,7 @@ package com.android.server.autofill; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_ACTIVITY_FINISHED; +import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_SESSION_DESTROYED; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_UNKNOWN; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CHANGED; import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CLICKED; @@ -53,7 +54,8 @@ public final class SessionCommittedEventLogger { COMMIT_REASON_ACTIVITY_FINISHED, COMMIT_REASON_VIEW_COMMITTED, COMMIT_REASON_VIEW_CLICKED, - COMMIT_REASON_VIEW_CHANGED + COMMIT_REASON_VIEW_CHANGED, + COMMIT_REASON_SESSION_DESTROYED }) @Retention(RetentionPolicy.SOURCE) public @interface CommitReason { @@ -69,6 +71,8 @@ public final class SessionCommittedEventLogger { AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CLICKED; public static final int COMMIT_REASON_VIEW_CHANGED = AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_VIEW_CHANGED; + public static final int COMMIT_REASON_SESSION_DESTROYED = + AUTOFILL_SESSION_COMMITTED__COMMIT_REASON__COMMIT_REASON_SESSION_DESTROYED; private final int mSessionId; private Optional<SessionCommittedEventInternal> mEventInternal; diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index b042c3024034..ff72476d4bf1 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -397,7 +397,7 @@ public class FullRestoreEngine extends RestoreEngine { setUpPipes(); mAgent = mBackupManagerService.bindToAgentSynchronous(mTargetApp, FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain) - ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL + ? ApplicationThreadConstants.BACKUP_MODE_RESTORE : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, mBackupEligibilityRules.getBackupDestination()); mAgentPackage = pkg; diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 1656b6f0ab9b..77990af50979 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -677,7 +677,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // Good to go! Set up and bind the agent... mAgent = backupManagerService.bindToAgentSynchronous( mCurrentPackage.applicationInfo, - ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, + ApplicationThreadConstants.BACKUP_MODE_RESTORE, mBackupEligibilityRules.getBackupDestination()); if (mAgent == null) { Slog.w(TAG, "Can't find backup agent for " + packageName); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 81dc34611d02..1f80aec3d443 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4603,8 +4603,7 @@ public class ActivityManagerService extends IActivityManager.Stub boolean isRestrictedBackupMode = false; if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) { isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID - && ((backupTarget.backupMode == BackupRecord.RESTORE) - || (backupTarget.backupMode == BackupRecord.RESTORE_FULL) + && ((backupTarget.backupMode == BackupRecord.RESTORE_FULL) || (backupTarget.backupMode == BackupRecord.BACKUP_FULL)); } @@ -13394,7 +13393,8 @@ public class ActivityManagerService extends IActivityManager.Stub BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination); ComponentName hostingName = - (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL) + (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL + || backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) ? new ComponentName(app.packageName, app.backupAgentName) : new ComponentName("android", "FullBackupAgent"); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index a3163e010efa..02c4770ba899 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2284,8 +2284,8 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { mStreamStates[AudioSystem.STREAM_DTMF] .setAllIndexes(mStreamStates[dtmfStreamAlias], caller); - mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName = - System.VOLUME_SETTINGS_INT[a11yStreamAlias]; + mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setSettingName( + System.VOLUME_SETTINGS_INT[a11yStreamAlias]); mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes( mStreamStates[a11yStreamAlias], caller); } @@ -7700,7 +7700,7 @@ public class AudioService extends IAudioService.Stub private int mPublicStreamType = AudioSystem.STREAM_MUSIC; private AudioAttributes mAudioAttributes = AudioProductStrategy.getDefaultAttributes(); private boolean mIsMuted = false; - private final String mSettingName; + private String mSettingName; // No API in AudioSystem to get a device from strategy or from attributes. // Need a valid public stream type to use current API getDeviceForStream @@ -8029,15 +8029,19 @@ public class AudioService extends IAudioService.Stub } private void persistVolumeGroup(int device) { - if (mUseFixedVolume) { + // No need to persist the index if the volume group is backed up + // by a public stream type as this is redundant + if (mUseFixedVolume || mHasValidStreamType) { return; } if (DEBUG_VOL) { Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group " + mAudioVolumeGroup.name() + ", device " + AudioSystem.getOutputDeviceName(device) - + " and User=" + getCurrentUserId()); + + " and User=" + getCurrentUserId() + + " mSettingName: " + mSettingName); } + boolean success = mSettings.putSystemIntForUser(mContentResolver, getSettingNameForDevice(device), getIndex(device), @@ -8100,6 +8104,14 @@ public class AudioService extends IAudioService.Stub return mSettingName + "_" + AudioSystem.getOutputDeviceName(device); } + void setSettingName(String settingName) { + mSettingName = settingName; + } + + String getSettingName() { + return mSettingName; + } + private void dump(PrintWriter pw) { pw.println("- VOLUME GROUP " + mAudioVolumeGroup.name() + ":"); pw.print(" Muted: "); @@ -8242,6 +8254,9 @@ public class AudioService extends IAudioService.Stub */ public void setVolumeGroupState(VolumeGroupState volumeGroupState) { mVolumeGroupState = volumeGroupState; + if (mVolumeGroupState != null) { + mVolumeGroupState.setSettingName(mVolumeIndexSettingName); + } } /** * Update the minimum index that can be used without MODIFY_AUDIO_SETTINGS permission @@ -8315,6 +8330,17 @@ public class AudioService extends IAudioService.Stub return (mVolumeIndexSettingName != null && !mVolumeIndexSettingName.isEmpty()); } + void setSettingName(String settingName) { + mVolumeIndexSettingName = settingName; + if (mVolumeGroupState != null) { + mVolumeGroupState.setSettingName(mVolumeIndexSettingName); + } + } + + String getSettingName() { + return mVolumeIndexSettingName; + } + public void readSettings() { synchronized (mSettingsLock) { synchronized (VolumeStreamState.class) { @@ -8989,7 +9015,7 @@ public class AudioService extends IAudioService.Stub if (streamState.hasValidSettingsName()) { mSettings.putSystemIntForUser(mContentResolver, streamState.getSettingNameForDevice(device), - (streamState.getIndex(device) + 5)/ 10, + (streamState.getIndex(device) + 5) / 10, UserHandle.USER_CURRENT); } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 85b403496645..5d92c7f8cf05 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -119,7 +119,6 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; -import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; import android.util.IntArray; @@ -298,11 +297,10 @@ public final class DisplayManagerService extends SystemService { mDisplayWindowPolicyControllers = new SparseArray<>(); /** - * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by - * {@link DisplayDevice#mUniqueId}. + * Provides {@link HighBrightnessModeMetadata}s for {@link DisplayDevice}s. */ - public final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap = - new ArrayMap<>(); + private final HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper = + new HighBrightnessModeMetadataMapper(); // List of all currently registered display adapters. private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>(); @@ -1823,19 +1821,14 @@ public final class DisplayManagerService extends SystemService { DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { - final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); - if (device == null) { - Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " - + display.getDisplayIdLocked()); - return; - } - final int leadDisplayId = display.getLeadDisplayIdLocked(); updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId); - final String uniqueId = device.getUniqueId(); - HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); - dpc.onDisplayChanged(hbmMetadata, leadDisplayId); + HighBrightnessModeMetadata hbmMetadata = + mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display); + if (hbmMetadata != null) { + dpc.onDisplayChanged(hbmMetadata, leadDisplayId); + } } } @@ -1922,19 +1915,14 @@ public final class DisplayManagerService extends SystemService { final int displayId = display.getDisplayIdLocked(); final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId); if (dpc != null) { - final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); - if (device == null) { - Slog.wtf(TAG, "Display Device is null in DisplayManagerService for display: " - + display.getDisplayIdLocked()); - return; - } - final int leadDisplayId = display.getLeadDisplayIdLocked(); updateDisplayPowerControllerLeaderLocked(dpc, leadDisplayId); - final String uniqueId = device.getUniqueId(); - HighBrightnessModeMetadata hbmMetadata = mHighBrightnessModeMetadataMap.get(uniqueId); - dpc.onDisplayChanged(hbmMetadata, leadDisplayId); + HighBrightnessModeMetadata hbmMetadata = + mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display); + if (hbmMetadata != null) { + dpc.onDisplayChanged(hbmMetadata, leadDisplayId); + } } } @@ -3073,26 +3061,6 @@ public final class DisplayManagerService extends SystemService { mLogicalDisplayMapper.forEachLocked(this::addDisplayPowerControllerLocked); } - private HighBrightnessModeMetadata getHighBrightnessModeMetadata(LogicalDisplay display) { - final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); - if (device == null) { - Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " - + display.getDisplayIdLocked()); - return null; - } - - final String uniqueId = device.getUniqueId(); - - if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) { - return mHighBrightnessModeMetadataMap.get(uniqueId); - } - - // HBM Time info not present. Create a new one for this physical display. - HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata(); - mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo); - return hbmInfo; - } - @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG) private void addDisplayPowerControllerLocked(LogicalDisplay display) { if (mPowerHandler == null) { @@ -3113,7 +3081,13 @@ public final class DisplayManagerService extends SystemService { // We also need to pass a mapping of the HighBrightnessModeTimeInfoMap to // displayPowerController, so the hbm info can be correctly associated // with the corresponding displaydevice. - HighBrightnessModeMetadata hbmMetadata = getHighBrightnessModeMetadata(display); + HighBrightnessModeMetadata hbmMetadata = + mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display); + if (hbmMetadata == null) { + Slog.wtf(TAG, "High Brightness Mode Metadata is null in DisplayManagerService for " + + "display: " + display.getDisplayIdLocked()); + return; + } if (DeviceConfig.getBoolean("display_manager", "use_newly_structured_display_power_controller", true)) { displayPowerController = new DisplayPowerController2( diff --git a/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java b/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java new file mode 100644 index 000000000000..76702d3f6f8c --- /dev/null +++ b/services/core/java/com/android/server/display/HighBrightnessModeMetadataMapper.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import android.util.ArrayMap; +import android.util.Slog; + +/** + * Provides {@link HighBrightnessModeMetadata}s for {@link DisplayDevice}s. This class should only + * be accessed from the display thread. + */ +class HighBrightnessModeMetadataMapper { + + private static final String TAG = "HighBrightnessModeMetadataMapper"; + + /** + * Map of every internal primary display device {@link HighBrightnessModeMetadata}s indexed by + * {@link DisplayDevice#mUniqueId}. + */ + private final ArrayMap<String, HighBrightnessModeMetadata> mHighBrightnessModeMetadataMap = + new ArrayMap<>(); + + HighBrightnessModeMetadata getHighBrightnessModeMetadataLocked(LogicalDisplay display) { + final DisplayDevice device = display.getPrimaryDisplayDeviceLocked(); + if (device == null) { + Slog.wtf(TAG, "Display Device is null in DisplayPowerController for display: " + + display.getDisplayIdLocked()); + return null; + } + + final String uniqueId = device.getUniqueId(); + + if (mHighBrightnessModeMetadataMap.containsKey(uniqueId)) { + return mHighBrightnessModeMetadataMap.get(uniqueId); + } + + // HBM Time info not present. Create a new one for this physical display. + HighBrightnessModeMetadata hbmInfo = new HighBrightnessModeMetadata(); + mHighBrightnessModeMetadataMap.put(uniqueId, hbmInfo); + return hbmInfo; + } +} diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 9eedc4e0f9ee..f47c4b2c24d9 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -682,7 +682,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly private void launchDeviceDiscovery() { assertRunOnServiceThread(); - clearDeviceInfoList(); DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, new DeviceDiscoveryCallback() { @Override @@ -691,13 +690,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mService.getHdmiCecNetwork().addCecDevice(info); } - // Since we removed all devices when it starts and - // device discovery action does not poll local devices, - // we should put device info of local device manually here - for (HdmiCecLocalDevice device : mService.getAllCecLocalDevices()) { - mService.getHdmiCecNetwork().addCecDevice(device.getDeviceInfo()); - } - mSelectRequestBuffer.process(); resetSelectRequestBuffer(); diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 805ff6611c29..75fe63a66206 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1267,6 +1267,7 @@ public class HdmiControlService extends SystemService { // It's now safe to flush existing local devices from mCecController since they were // already moved to 'localDevices'. clearCecLocalDevices(); + mHdmiCecNetwork.clearDeviceList(); allocateLogicalAddress(localDevices, initiatedBy); } @@ -1303,6 +1304,7 @@ public class HdmiControlService extends SystemService { HdmiControlManager.POWER_STATUS_ON, getCecVersion()); localDevice.setDeviceInfo(deviceInfo); mHdmiCecNetwork.addLocalDevice(deviceType, localDevice); + mHdmiCecNetwork.addCecDevice(localDevice.getDeviceInfo()); mCecController.addLogicalAddress(logicalAddress); allocatedDevices.add(localDevice); } diff --git a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java index 0ae1e8076b81..a1b67e105dd4 100644 --- a/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java +++ b/services/core/java/com/android/server/inputmethod/DefaultImeVisibilityApplier.java @@ -18,14 +18,19 @@ package com.android.server.inputmethod; import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY; +import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS; +import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS; import static com.android.server.EventLogTags.IMF_HIDE_IME; import static com.android.server.EventLogTags.IMF_SHOW_IME; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_NOT_ALWAYS; +import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_REMOVE_IME_SNAPSHOT; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME; import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_IMPLICIT; +import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_SNAPSHOT; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.os.ResultReceiver; @@ -38,6 +43,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.inputmethod.InputMethodDebug; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.server.LocalServices; +import com.android.server.wm.ImeTargetVisibilityPolicy; import com.android.server.wm.WindowManagerInternal; import java.util.Objects; @@ -56,10 +62,14 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier { private final WindowManagerInternal mWindowManagerInternal; + @NonNull + private final ImeTargetVisibilityPolicy mImeTargetVisibilityPolicy; + DefaultImeVisibilityApplier(InputMethodManagerService service) { mService = service; mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); + mImeTargetVisibilityPolicy = LocalServices.getService(ImeTargetVisibilityPolicy.class); } @GuardedBy("ImfLock.class") @@ -162,8 +172,37 @@ final class DefaultImeVisibilityApplier implements ImeVisibilityApplier { mService.showCurrentInputLocked(windowToken, statsToken, InputMethodManager.SHOW_IMPLICIT, null, reason); break; + case STATE_SHOW_IME_SNAPSHOT: + showImeScreenshot(windowToken, mService.getDisplayIdToShowImeLocked(), null); + break; + case STATE_REMOVE_IME_SNAPSHOT: + removeImeScreenshot(mService.getDisplayIdToShowImeLocked()); + break; default: throw new IllegalArgumentException("Invalid IME visibility state: " + state); } } + + @GuardedBy("ImfLock.class") + @Override + public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId, + @Nullable ImeTracker.Token statsToken) { + if (mImeTargetVisibilityPolicy.showImeScreenshot(imeTarget, displayId)) { + mService.onShowHideSoftInputRequested(false /* show */, imeTarget, + SHOW_IME_SCREENSHOT_FROM_IMMS, statsToken); + return true; + } + return false; + } + + @GuardedBy("ImfLock.class") + @Override + public boolean removeImeScreenshot(int displayId) { + if (mImeTargetVisibilityPolicy.removeImeScreenshot(displayId)) { + mService.onShowHideSoftInputRequested(false /* show */, mService.mCurFocusedWindow, + REMOVE_IME_SCREENSHOT_FROM_IMMS, null); + return true; + } + return false; + } } diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java index f03e985c07e9..27f6a89a73b3 100644 --- a/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java +++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityApplier.java @@ -16,6 +16,7 @@ package com.android.server.inputmethod; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.os.ResultReceiver; @@ -76,4 +77,27 @@ interface ImeVisibilityApplier { // TODO: add a method in WindowManagerInternal to call DC#updateImeInputAndControlTarget // here to end up updating IME layering after IMMS#attachNewInputLocked called. } + + /** + * Shows the IME screenshot and attach it to the given IME target window. + * + * @param windowToken The token of a window to show the IME screenshot. + * @param displayId The unique id to identify the display + * @param statsToken A token that tracks the progress of an IME request. + * @return {@code true} if success, {@code false} otherwise. + */ + default boolean showImeScreenshot(@NonNull IBinder windowToken, int displayId, + @Nullable ImeTracker.Token statsToken) { + return false; + } + + /** + * Removes the IME screenshot on the given display. + * + * @param displayId The target display of showing IME screenshot. + * @return {@code true} if success, {@code false} otherwise. + */ + default boolean removeImeScreenshot(int displayId) { + return false; + } } diff --git a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java index 61fe6545f139..19d6fa00a270 100644 --- a/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java +++ b/services/core/java/com/android/server/inputmethod/ImeVisibilityStateComputer.java @@ -29,6 +29,8 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFI import static android.view.WindowManager.LayoutParams.SoftInputModeFlags; import static com.android.internal.inputmethod.InputMethodDebug.softInputModeToString; +import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS; +import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS; import static com.android.server.inputmethod.InputMethodManagerService.computeImeDisplayIdForTarget; import android.accessibilityservice.AccessibilityService; @@ -49,6 +51,7 @@ import android.view.inputmethod.InputMethodManager; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.server.LocalServices; +import com.android.server.wm.ImeTargetChangeListener; import com.android.server.wm.WindowManagerInternal; import java.io.PrintWriter; @@ -99,6 +102,18 @@ public final class ImeVisibilityStateComputer { */ private boolean mInputShown; + /** + * Set if we called + * {@link com.android.server.wm.ImeTargetVisibilityPolicy#showImeScreenshot(IBinder, int)}. + */ + private boolean mRequestedImeScreenshot; + + /** The window token of the current visible IME layering target overlay. */ + private IBinder mCurVisibleImeLayeringOverlay; + + /** The window token of the current visible IME input target. */ + private IBinder mCurVisibleImeInputTarget; + /** Represent the invalid IME visibility state */ public static final int STATE_INVALID = -1; @@ -122,6 +137,10 @@ public final class ImeVisibilityStateComputer { public static final int STATE_HIDE_IME_NOT_ALWAYS = 6; public static final int STATE_SHOW_IME_IMPLICIT = 7; + + /** State to handle removing an IME preview surface when necessary. */ + public static final int STATE_REMOVE_IME_SNAPSHOT = 8; + @IntDef({ STATE_INVALID, STATE_HIDE_IME, @@ -132,6 +151,7 @@ public final class ImeVisibilityStateComputer { STATE_HIDE_IME_EXPLICIT, STATE_HIDE_IME_NOT_ALWAYS, STATE_SHOW_IME_IMPLICIT, + STATE_REMOVE_IME_SNAPSHOT, }) @interface VisibilityState {} @@ -172,6 +192,24 @@ public final class ImeVisibilityStateComputer { mWindowManagerInternal = wmService; mImeDisplayValidator = imeDisplayValidator; mPolicy = imePolicy; + mWindowManagerInternal.setInputMethodTargetChangeListener(new ImeTargetChangeListener() { + @Override + public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken, + boolean visible, boolean removed) { + mCurVisibleImeLayeringOverlay = (visible && !removed) ? overlayWindowToken : null; + } + + @Override + public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget, + boolean visibleRequested, boolean removed) { + mCurVisibleImeInputTarget = (visibleRequested && !removed) ? imeInputTarget : null; + if (mCurVisibleImeInputTarget == null && mCurVisibleImeLayeringOverlay != null) { + mService.onApplyImeVisibilityFromComputer(imeInputTarget, + new ImeVisibilityResult(STATE_HIDE_IME_EXPLICIT, + SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE)); + } + } + }); } /** @@ -453,6 +491,21 @@ public final class ImeVisibilityStateComputer { return null; } + @VisibleForTesting + ImeVisibilityResult onInteractiveChanged(IBinder windowToken, boolean interactive) { + final ImeTargetWindowState state = getWindowStateOrNull(windowToken); + if (state != null && state.isRequestedImeVisible() && mInputShown && !interactive) { + mRequestedImeScreenshot = true; + return new ImeVisibilityResult(STATE_SHOW_IME_SNAPSHOT, SHOW_IME_SCREENSHOT_FROM_IMMS); + } + if (interactive && mRequestedImeScreenshot) { + mRequestedImeScreenshot = false; + return new ImeVisibilityResult(STATE_REMOVE_IME_SNAPSHOT, + REMOVE_IME_SCREENSHOT_FROM_IMMS); + } + return null; + } + IBinder getWindowTokenFrom(IBinder requestImeToken) { for (IBinder windowToken : mRequestWindowStateMap.keySet()) { final ImeTargetWindowState state = mRequestWindowStateMap.get(windowToken); diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 24332112ed76..c70d55510493 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -4847,6 +4847,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } } + void onApplyImeVisibilityFromComputer(IBinder windowToken, + @NonNull ImeVisibilityResult result) { + synchronized (ImfLock.class) { + mVisibilityApplier.applyImeVisibility(windowToken, null, result.getState(), + result.getReason()); + } + } + @GuardedBy("ImfLock.class") void setEnabledSessionLocked(SessionState session) { if (mEnabledSession != session) { @@ -5083,6 +5091,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub return; } if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(getCurMethodUidLocked())) { + // Handle IME visibility when interactive changed before finishing the input to + // ensure we preserve the last state as possible. + final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged( + mCurFocusedWindow, interactive); + if (imeVisRes != null) { + mVisibilityApplier.applyImeVisibility(mCurFocusedWindow, null, + imeVisRes.getState(), imeVisRes.getReason()); + } // Eligible IME processes use new "setInteractive" protocol. mCurClient.mClient.setInteractive(mIsInteractive, mInFullscreenMode); } else { diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index b82e3a31567e..c076c0574afe 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -19,6 +19,7 @@ package com.android.server.media; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.ComponentName; +import android.media.MediaRoute2Info; import android.media.MediaRoute2ProviderInfo; import android.media.RouteDiscoveryPreference; import android.media.RoutingSessionInfo; @@ -26,6 +27,7 @@ import android.os.Bundle; import com.android.internal.annotations.GuardedBy; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -108,6 +110,28 @@ abstract class MediaRoute2Provider { && mComponentName.getClassName().equals(className); } + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + getDebugString()); + prefix += " "; + if (mProviderInfo == null) { + pw.println(prefix + "<provider info not received, yet>"); + } else if (mProviderInfo.getRoutes().isEmpty()) { + pw.println(prefix + "<provider info has no routes>"); + } else { + for (MediaRoute2Info route : mProviderInfo.getRoutes()) { + pw.printf("%s%s | %s\n", prefix, route.getId(), route.getName()); + } + } + } + + @Override + public String toString() { + return getDebugString(); + } + + /** Returns a human-readable string describing the instance, for debugging purposes. */ + protected abstract String getDebugString(); + public interface Callback { void onProviderStateChanged(@Nullable MediaRoute2Provider provider); void onSessionCreated(@NonNull MediaRoute2Provider provider, diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index 90451b19d590..72b843672ae8 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -44,7 +44,6 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; -import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Collections; @@ -83,10 +82,6 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider mHandler = new Handler(Looper.myLooper()); } - public void dump(PrintWriter pw, String prefix) { - pw.println(prefix + getDebugString()); - } - public void setManagerScanning(boolean managerScanning) { if (mIsManagerScanning != managerScanning) { mIsManagerScanning = managerScanning; @@ -488,11 +483,7 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } @Override - public String toString() { - return getDebugString(); - } - - private String getDebugString() { + protected String getDebugString() { return TextUtils.formatSimple( "ProviderServiceProxy - package: %s, bound: %b, connection (active:%b, ready:%b)", mComponentName.getPackageName(), diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 3c97aaf87e9c..2d3b97b768d3 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -1751,6 +1751,7 @@ class MediaRouter2ServiceImpl { String indent = prefix + " "; pw.println(indent + "mRunning=" + mRunning); + mSystemProvider.dump(pw, prefix); mWatcher.dump(pw, prefix); } diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 5d5c621eb3f5..6d2d2e405ab9 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -392,6 +392,15 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { mCallback.onSessionUpdated(this, sessionInfo); } + @Override + protected String getDebugString() { + return TextUtils.formatSimple( + "SystemMR2Provider - package: %s, selected route id: %s, bluetooth impl: %s", + mComponentName.getPackageName(), + mSelectedRouteId, + mBluetoothRouteController.getClass().getSimpleName()); + } + private static class SessionCreationRequest { final long mRequestId; final String mRouteId; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ebcbfed93ac7..07891f30abd0 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -10796,7 +10796,8 @@ public class NotificationManagerService extends SystemService { static final String FLAG_SEPARATOR = "\\|"; private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); - ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter> + @GuardedBy("mRequestedNotificationListeners") + private final ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter> mRequestedNotificationListeners = new ArrayMap<>(); private final boolean mIsHeadlessSystemUserMode; @@ -10914,9 +10915,11 @@ public class NotificationManagerService extends SystemService { @Override public void onUserRemoved(int user) { super.onUserRemoved(user); - for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) { - if (mRequestedNotificationListeners.keyAt(i).second == user) { - mRequestedNotificationListeners.removeAt(i); + synchronized (mRequestedNotificationListeners) { + for (int i = mRequestedNotificationListeners.size() - 1; i >= 0; i--) { + if (mRequestedNotificationListeners.keyAt(i).second == user) { + mRequestedNotificationListeners.removeAt(i); + } } } } @@ -10925,31 +10928,34 @@ public class NotificationManagerService extends SystemService { public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) { super.onPackagesChanged(removingPackage, pkgList, uidList); - // Since the default behavior is to allow everything, we don't need to explicitly - // handle package add or update. they will be added to the xml file on next boot or - // when the user tries to change the settings. - if (removingPackage) { - for (int i = 0; i < pkgList.length; i++) { - String pkg = pkgList[i]; - int userId = UserHandle.getUserId(uidList[i]); - for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { - Pair<ComponentName, Integer> key = mRequestedNotificationListeners.keyAt(j); - if (key.second == userId && key.first.getPackageName().equals(pkg)) { - mRequestedNotificationListeners.removeAt(j); + synchronized (mRequestedNotificationListeners) { + // Since the default behavior is to allow everything, we don't need to explicitly + // handle package add or update. they will be added to the xml file on next boot or + // when the user tries to change the settings. + if (removingPackage) { + for (int i = 0; i < pkgList.length; i++) { + String pkg = pkgList[i]; + int userId = UserHandle.getUserId(uidList[i]); + for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { + Pair<ComponentName, Integer> key = + mRequestedNotificationListeners.keyAt(j); + if (key.second == userId && key.first.getPackageName().equals(pkg)) { + mRequestedNotificationListeners.removeAt(j); + } } } } - } - // clean up anything in the disallowed pkgs list - for (int i = 0; i < pkgList.length; i++) { - String pkg = pkgList[i]; - int userId = UserHandle.getUserId(uidList[i]); - for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { - NotificationListenerFilter nlf = mRequestedNotificationListeners.valueAt(j); + // clean up anything in the disallowed pkgs list + for (int i = 0; i < pkgList.length; i++) { + String pkg = pkgList[i]; + for (int j = mRequestedNotificationListeners.size() - 1; j >= 0; j--) { + NotificationListenerFilter nlf = + mRequestedNotificationListeners.valueAt(j); - VersionedPackage ai = new VersionedPackage(pkg, uidList[i]); - nlf.removePackage(ai); + VersionedPackage ai = new VersionedPackage(pkg, uidList[i]); + nlf.removePackage(ai); + } } } } @@ -10997,7 +11003,9 @@ public class NotificationManagerService extends SystemService { } NotificationListenerFilter nlf = new NotificationListenerFilter(approved, disallowedPkgs); - mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf); + synchronized (mRequestedNotificationListeners) { + mRequestedNotificationListeners.put(Pair.create(cn, userId), nlf); + } } } } @@ -11005,72 +11013,81 @@ public class NotificationManagerService extends SystemService { @Override protected void writeExtraXmlTags(TypedXmlSerializer out) throws IOException { out.startTag(null, TAG_REQUESTED_LISTENERS); - for (Pair<ComponentName, Integer> listener : mRequestedNotificationListeners.keySet()) { - NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener); - out.startTag(null, TAG_REQUESTED_LISTENER); - XmlUtils.writeStringAttribute( - out, ATT_COMPONENT, listener.first.flattenToString()); - XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second); - - out.startTag(null, TAG_APPROVED); - XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes()); - out.endTag(null, TAG_APPROVED); - - for (VersionedPackage ai : nlf.getDisallowedPackages()) { - if (!TextUtils.isEmpty(ai.getPackageName())) { - out.startTag(null, TAG_DISALLOWED); - XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName()); - XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode()); - out.endTag(null, TAG_DISALLOWED); + synchronized (mRequestedNotificationListeners) { + for (Pair<ComponentName, Integer> listener : + mRequestedNotificationListeners.keySet()) { + NotificationListenerFilter nlf = mRequestedNotificationListeners.get(listener); + out.startTag(null, TAG_REQUESTED_LISTENER); + XmlUtils.writeStringAttribute( + out, ATT_COMPONENT, listener.first.flattenToString()); + XmlUtils.writeIntAttribute(out, ATT_USER_ID, listener.second); + + out.startTag(null, TAG_APPROVED); + XmlUtils.writeIntAttribute(out, ATT_TYPES, nlf.getTypes()); + out.endTag(null, TAG_APPROVED); + + for (VersionedPackage ai : nlf.getDisallowedPackages()) { + if (!TextUtils.isEmpty(ai.getPackageName())) { + out.startTag(null, TAG_DISALLOWED); + XmlUtils.writeStringAttribute(out, ATT_PKG, ai.getPackageName()); + XmlUtils.writeIntAttribute(out, ATT_UID, ai.getVersionCode()); + out.endTag(null, TAG_DISALLOWED); + } } - } - out.endTag(null, TAG_REQUESTED_LISTENER); + out.endTag(null, TAG_REQUESTED_LISTENER); + } } out.endTag(null, TAG_REQUESTED_LISTENERS); } - protected @Nullable NotificationListenerFilter getNotificationListenerFilter( + @Nullable protected NotificationListenerFilter getNotificationListenerFilter( Pair<ComponentName, Integer> pair) { - return mRequestedNotificationListeners.get(pair); + synchronized (mRequestedNotificationListeners) { + return mRequestedNotificationListeners.get(pair); + } } protected void setNotificationListenerFilter(Pair<ComponentName, Integer> pair, NotificationListenerFilter nlf) { - mRequestedNotificationListeners.put(pair, nlf); + synchronized (mRequestedNotificationListeners) { + mRequestedNotificationListeners.put(pair, nlf); + } } @Override protected void ensureFilters(ServiceInfo si, int userId) { - Pair listener = Pair.create(si.getComponentName(), userId); - NotificationListenerFilter existingNlf = - mRequestedNotificationListeners.get(listener); - if (si.metaData != null) { - if (existingNlf == null) { - // no stored filters for this listener; see if they provided a default - if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) { - String typeList = - si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString(); - if (typeList != null) { - int types = getTypesFromStringList(typeList); - NotificationListenerFilter nlf = - new NotificationListenerFilter(types, new ArraySet<>()); - mRequestedNotificationListeners.put(listener, nlf); + Pair<ComponentName, Integer> listener = Pair.create(si.getComponentName(), userId); + synchronized (mRequestedNotificationListeners) { + NotificationListenerFilter existingNlf = + mRequestedNotificationListeners.get(listener); + if (si.metaData != null) { + if (existingNlf == null) { + // no stored filters for this listener; see if they provided a default + if (si.metaData.containsKey(META_DATA_DEFAULT_FILTER_TYPES)) { + String typeList = + si.metaData.get(META_DATA_DEFAULT_FILTER_TYPES).toString(); + if (typeList != null) { + int types = getTypesFromStringList(typeList); + NotificationListenerFilter nlf = + new NotificationListenerFilter(types, new ArraySet<>()); + mRequestedNotificationListeners.put(listener, nlf); + } } } - } - // also check the types they never want bridged - if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) { - int neverBridge = getTypesFromStringList(si.metaData.get( - META_DATA_DISABLED_FILTER_TYPES).toString()); - if (neverBridge != 0) { - NotificationListenerFilter nlf = - mRequestedNotificationListeners.getOrDefault( - listener, new NotificationListenerFilter()); - nlf.setTypes(nlf.getTypes() & ~neverBridge); - mRequestedNotificationListeners.put(listener, nlf); + // also check the types they never want bridged + if (si.metaData.containsKey(META_DATA_DISABLED_FILTER_TYPES)) { + int neverBridge = getTypesFromStringList(si.metaData.get( + META_DATA_DISABLED_FILTER_TYPES).toString()); + if (neverBridge != 0) { + NotificationListenerFilter nlf = + mRequestedNotificationListeners.getOrDefault( + listener, new NotificationListenerFilter()); + nlf.setTypes(nlf.getTypes() & ~neverBridge); + mRequestedNotificationListeners.put(listener, nlf); + } } } } diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java index 5015985dd747..7198de2f743e 100644 --- a/services/core/java/com/android/server/pm/VerifyingSession.java +++ b/services/core/java/com/android/server/pm/VerifyingSession.java @@ -353,11 +353,10 @@ final class VerifyingSession { PackageInfoLite pkgLite, PackageVerificationState verificationState) { - // TODO: http://b/22976637 - // Apps installed for "all" users use the device owner to verify the app + // Apps installed for "all" users use the current user to verify the app UserHandle verifierUser = getUser(); if (verifierUser == UserHandle.ALL) { - verifierUser = UserHandle.SYSTEM; + verifierUser = UserHandle.of(mPm.mUserManager.getCurrentUserId()); } final int verifierUserId = verifierUser.getIdentifier(); diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index a757d90b75ba..f71f3b128557 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -397,9 +397,21 @@ class ActivityMetricsLogger { /** Returns {@code true} if the incoming activity can belong to this transition. */ boolean canCoalesce(ActivityRecord r) { - return mLastLaunchedActivity.mDisplayContent == r.mDisplayContent - && mLastLaunchedActivity.getTask().getBounds().equals(r.getTask().getBounds()) - && mLastLaunchedActivity.getWindowingMode() == r.getWindowingMode(); + if (mLastLaunchedActivity.mDisplayContent != r.mDisplayContent + || mLastLaunchedActivity.getWindowingMode() != r.getWindowingMode()) { + return false; + } + // The current task should be non-null because it is just launched. While the + // last task can be cleared when starting activity with FLAG_ACTIVITY_CLEAR_TASK. + final Task lastTask = mLastLaunchedActivity.getTask(); + final Task currentTask = r.getTask(); + if (lastTask != null && currentTask != null) { + if (lastTask == currentTask) { + return true; + } + return lastTask.getBounds().equals(currentTask.getBounds()); + } + return mLastLaunchedActivity.isUid(r.launchedFromUid); } /** @return {@code true} if the activity matches a launched activity in this transition. */ diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 2160ce1be729..c6a2e0e51227 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2821,6 +2821,27 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } + @Override + void waitForSyncTransactionCommit(ArraySet<WindowContainer> wcAwaitingCommit) { + super.waitForSyncTransactionCommit(wcAwaitingCommit); + if (mStartingData != null) { + mStartingData.mWaitForSyncTransactionCommit = true; + } + } + + @Override + void onSyncTransactionCommitted(SurfaceControl.Transaction t) { + super.onSyncTransactionCommitted(t); + if (mStartingData == null) { + return; + } + mStartingData.mWaitForSyncTransactionCommit = false; + if (mStartingData.mRemoveAfterTransaction) { + mStartingData.mRemoveAfterTransaction = false; + removeStartingWindowAnimation(mStartingData.mPrepareRemoveAnimation); + } + } + void removeStartingWindowAnimation(boolean prepareAnimation) { mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE; if (task != null) { @@ -2843,6 +2864,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final WindowState startingWindow = mStartingWindow; final boolean animate; if (mStartingData != null) { + if (mStartingData.mWaitForSyncTransactionCommit + || mTransitionController.inCollectingTransition(startingWindow)) { + mStartingData.mRemoveAfterTransaction = true; + mStartingData.mPrepareRemoveAnimation = prepareAnimation; + return; + } animate = prepareAnimation && mStartingData.needRevealAnimation() && mStartingWindow.isVisibleByPolicy(); ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s" @@ -2863,18 +2890,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A this); return; } - - if (animate && mTransitionController.inCollectingTransition(startingWindow)) { - // Defer remove starting window after transition start. - // The surface of app window could really show after the transition finish. - startingWindow.mSyncTransaction.addTransactionCommittedListener(Runnable::run, () -> { - synchronized (mAtmService.mGlobalLock) { - surface.remove(true); - } - }); - } else { - surface.remove(animate); - } + surface.remove(animate); } /** diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java index 5f56af7fd4e0..1208b6ef396f 100644 --- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java +++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java @@ -99,13 +99,15 @@ public class ActivityServiceConnectionsHolder<T> { } public void forEachConnection(Consumer<T> consumer) { + final ArraySet<T> connections; synchronized (mActivity) { if (mConnections == null || mConnections.isEmpty()) { return; } - for (int i = mConnections.size() - 1; i >= 0; i--) { - consumer.accept(mConnections.valueAt(i)); - } + connections = new ArraySet<>(mConnections); + } + for (int i = connections.size() - 1; i >= 0; i--) { + consumer.accept(connections.valueAt(i)); } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index c5e75faf2c6c..a27f3e49457d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2926,8 +2926,7 @@ class ActivityStarter { // If the matching task is already in the adjacent task of the launch target. Adjust to use // the adjacent task as its launch target. So the existing task will be launched into the // closer one and won't be reparent redundantly. - final Task adjacentTargetTask = mTargetRootTask.getAdjacentTaskFragment() != null - ? mTargetRootTask.getAdjacentTaskFragment().asTask() : null; + final Task adjacentTargetTask = mTargetRootTask.getAdjacentTask(); if (adjacentTargetTask != null && intentActivity.isDescendantOf(adjacentTargetTask)) { mTargetRootTask = adjacentTargetTask; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index abf66bc7ccc0..f93afe81f804 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -2008,7 +2008,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } - if (r.isState(RESUMED) && r == mRootWindowContainer.getTopResumedActivity()) { + if ((touchedActivity == null || r == touchedActivity) && r.isState(RESUMED) + && r == mRootWindowContainer.getTopResumedActivity()) { setLastResumedActivityUncheckLocked(r, "setFocusedTask-alreadyTop"); return; } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 597c8bf45132..805bff240f66 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -1030,12 +1030,11 @@ public class AppTransitionController { canPromote = false; } - // If the current window container is task and it have adjacent task, it means - // both tasks will open or close app toghther but we want get their opening or - // closing animation target independently so do not promote. + // If the current window container is a task with adjacent task set, the both + // adjacent tasks will be opened or closed together. To get their opening or + // closing animation target independently, skip promoting their animation targets. if (current.asTask() != null - && current.asTask().getAdjacentTaskFragment() != null - && current.asTask().getAdjacentTaskFragment().asTask() != null) { + && current.asTask().getAdjacentTask() != null) { canPromote = false; } diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index 11d84ffbd064..0c196d7e99e9 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -227,6 +227,7 @@ class BackNavigationController { backType = BackNavigationInfo.TYPE_CALLBACK; } infoBuilder.setOnBackInvokedCallback(callbackInfo.getCallback()); + infoBuilder.setAnimationCallback(callbackInfo.isAnimationCallback()); mNavigationMonitor.startMonitor(window, navigationObserver); } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c2bc4591ce0d..bad64d357b13 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -656,6 +656,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ private InputTarget mLastImeInputTarget; + + /** + * Tracks the windowToken of the input method input target and the corresponding + * {@link WindowContainerListener} for monitoring changes (e.g. the requested visibility + * change). + */ + private @Nullable Pair<IBinder, WindowContainerListener> mImeTargetTokenListenerPair; + /** * This controls the visibility and animation of the input method window. */ @@ -4267,7 +4275,38 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp @VisibleForTesting void setImeInputTarget(InputTarget target) { + if (mImeTargetTokenListenerPair != null) { + // Unregister the listener before changing to the new IME input target. + final WindowToken oldToken = mTokenMap.get(mImeTargetTokenListenerPair.first); + if (oldToken != null) { + oldToken.unregisterWindowContainerListener(mImeTargetTokenListenerPair.second); + } + mImeTargetTokenListenerPair = null; + } mImeInputTarget = target; + // Notify listeners about IME input target window visibility by the target change. + if (target != null) { + // TODO(b/276743705): Let InputTarget register the visibility change of the hierarchy. + final WindowState targetWin = target.getWindowState(); + if (targetWin != null) { + mImeTargetTokenListenerPair = new Pair<>(targetWin.mToken.token, + new WindowContainerListener() { + @Override + public void onVisibleRequestedChanged(boolean isVisibleRequested) { + // Notify listeners for IME input target window visibility change + // requested by the parent container. + mWmService.dispatchImeInputTargetVisibilityChanged( + targetWin.mClient.asBinder(), isVisibleRequested, + targetWin.mActivityRecord != null + && targetWin.mActivityRecord.finishing); + } + }); + targetWin.mToken.registerWindowContainerListener( + mImeTargetTokenListenerPair.second); + mWmService.dispatchImeInputTargetVisibilityChanged(targetWin.mClient.asBinder(), + targetWin.isVisible() /* visible */, false /* removed */); + } + } if (refreshImeSecureFlag(getPendingTransaction())) { mWmService.requestTraversal(); } @@ -4433,6 +4472,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } private void attachImeScreenshotOnTarget(WindowState imeTarget) { + attachImeScreenshotOnTarget(imeTarget, false); + } + + private void attachImeScreenshotOnTarget(WindowState imeTarget, boolean hideImeWindow) { final SurfaceControl.Transaction t = getPendingTransaction(); // Remove the obsoleted IME snapshot first in case the new snapshot happens to // override the current one before the transition finish and the surface never be @@ -4441,6 +4484,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mImeScreenshot = new ImeScreenshot( mWmService.mSurfaceControlFactory.apply(null), imeTarget); mImeScreenshot.attachAndShow(t); + if (mInputMethodWindow != null && hideImeWindow) { + // Hide the IME window when deciding to show IME snapshot on demand. + // InsetsController will make IME visible again before animating it. + mInputMethodWindow.hide(false, false); + } } /** @@ -4458,7 +4506,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp */ @VisibleForTesting void showImeScreenshot(WindowState imeTarget) { - attachImeScreenshotOnTarget(imeTarget); + attachImeScreenshotOnTarget(imeTarget, true /* hideImeWindow */); } /** diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 339b6ec30049..747819e93ff2 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -17,7 +17,6 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; -import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.view.Display.TYPE_INTERNAL; import static android.view.InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE; import static android.view.InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS; @@ -2208,16 +2207,15 @@ public class DisplayPolicy { private int updateSystemBarsLw(WindowState win, int disableFlags) { final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); - final boolean multiWindowTaskVisible = + final boolean adjacentTasksVisible = defaultTaskDisplayArea.getRootTask(task -> task.isVisible() - && task.getTopLeafTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) + && task.getTopLeafTask().getAdjacentTask() != null) != null; final boolean freeformRootTaskVisible = defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_FREEFORM); - // We need to force showing system bars when the multi-window or freeform root task is - // visible. - mForceShowSystemBars = multiWindowTaskVisible || freeformRootTaskVisible; + // We need to force showing system bars when adjacent tasks or freeform roots visible. + mForceShowSystemBars = adjacentTasksVisible || freeformRootTaskVisible; // We need to force the consumption of the system bars if they are force shown or if they // are controlled by a remote insets controller. mForceConsumeSystemBars = mForceShowSystemBars @@ -2238,7 +2236,7 @@ public class DisplayPolicy { int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS; appearance = configureStatusBarOpacity(appearance); - appearance = configureNavBarOpacity(appearance, multiWindowTaskVisible, + appearance = configureNavBarOpacity(appearance, adjacentTasksVisible, freeformRootTaskVisible); // Show immersive mode confirmation if needed. diff --git a/services/core/java/com/android/server/wm/ImeTargetChangeListener.java b/services/core/java/com/android/server/wm/ImeTargetChangeListener.java new file mode 100644 index 000000000000..8bc445bc97bb --- /dev/null +++ b/services/core/java/com/android/server/wm/ImeTargetChangeListener.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wm; + +import android.annotation.NonNull; +import android.os.IBinder; + +/** + * Callback the IME targeting window visibility change state for + * {@link com.android.server.inputmethod.InputMethodManagerService} to manage the IME surface + * visibility and z-ordering. + */ +public interface ImeTargetChangeListener { + /** + * Called when a non-IME-focusable overlay window being the IME layering target (e.g. a + * window with {@link android.view.WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} and + * {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flags) + * has changed its window visibility. + * + * @param overlayWindowToken the window token of the overlay window. + * @param visible the visibility of the overlay window, {@code true} means visible + * and {@code false} otherwise. + * @param removed Whether the IME target overlay window has being removed. + */ + default void onImeTargetOverlayVisibilityChanged(@NonNull IBinder overlayWindowToken, + boolean visible, boolean removed) { + } + + /** + * Called when the visibility of IME input target window has changed. + * + * @param imeInputTarget the window token of the IME input target window. + * @param visible the new window visibility made by {@param imeInputTarget}. visible is + * {@code true} when switching to the new visible IME input target + * window and started input, or the same input target relayout to + * visible from invisible. In contrast, visible is {@code false} when + * closing the input target, or the same input target relayout to + * invisible from visible. + * @param removed Whether the IME input target window has being removed. + */ + default void onImeInputTargetVisibilityChanged(@NonNull IBinder imeInputTarget, boolean visible, + boolean removed) { + } +} diff --git a/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java b/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java index 71dd91785384..1d9f24c4b317 100644 --- a/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java +++ b/services/core/java/com/android/server/wm/ImeTargetVisibilityPolicy.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.view.WindowManager; @@ -36,16 +37,15 @@ public abstract class ImeTargetVisibilityPolicy { * @param displayId A unique id to identify the display. * @return {@code true} if success, {@code false} otherwise. */ - public abstract boolean showImeScreenShot(IBinder imeTarget, int displayId); + public abstract boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId); /** - * Updates the IME parent for target window. + * Removes the IME screenshot on the given display. * - * @param imeTarget The target window to update the IME parent. - * @param displayId A unique id to identify the display. + * @param displayId The target display of showing IME screenshot. * @return {@code true} if success, {@code false} otherwise. */ - public abstract boolean updateImeParent(IBinder imeTarget, int displayId); + public abstract boolean removeImeScreenshot(int displayId); /** * Called when {@link DisplayContent#computeImeParent()} to check if it's valid to keep diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java index 300a894d15c9..cff86add7efc 100644 --- a/services/core/java/com/android/server/wm/StartingData.java +++ b/services/core/java/com/android/server/wm/StartingData.java @@ -41,6 +41,26 @@ public abstract class StartingData { /** Whether the starting window is drawn. */ boolean mIsDisplayed; + /** + * For Shell transition. + * There will be a transition happen on attached activity, do not remove starting window during + * this period, because the transaction to show app window may not apply before remove starting + * window. + * Note this isn't equal to transition playing, the period should be + * Sync finishNow -> Start transaction apply. + */ + boolean mWaitForSyncTransactionCommit; + + /** + * For Shell transition. + * This starting window should be removed after applying the start transaction of transition, + * which ensures the app window has shown. + */ + boolean mRemoveAfterTransaction; + + /** Whether to prepare the removal animation. */ + boolean mPrepareRemoveAnimation; + protected StartingData(WindowManagerService service, int typeParams) { mService = service; mTypeParams = typeParams; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 9363eb5cefc6..5c33e6470024 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -2362,6 +2362,22 @@ class Task extends TaskFragment { return parentTask == null ? null : parentTask.getCreatedByOrganizerTask(); } + /** @return the first adjacent task of this task or its parent. */ + @Nullable + Task getAdjacentTask() { + final TaskFragment adjacentTaskFragment = getAdjacentTaskFragment(); + if (adjacentTaskFragment != null && adjacentTaskFragment.asTask() != null) { + return adjacentTaskFragment.asTask(); + } + + final WindowContainer parent = getParent(); + if (parent == null || parent.asTask() == null) { + return null; + } + + return parent.asTask().getAdjacentTask(); + } + // TODO(task-merge): Figure out what's the right thing to do for places that used it. boolean isRootTask() { return getRootTask() == this; @@ -2747,7 +2763,7 @@ class Task extends TaskFragment { Rect outSurfaceInsets) { // If this task has its adjacent task, it means they should animate together. Use display // bounds for them could move same as full screen task. - if (getAdjacentTaskFragment() != null && getAdjacentTaskFragment().asTask() != null) { + if (getAdjacentTask() != null) { super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); return; } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index b0a879e96dcf..e80cbb302424 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1081,12 +1081,12 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { if (sourceTask != null && sourceTask == candidateTask) { // Do nothing when task that is getting opened is same as the source. } else if (sourceTask != null - && mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment() != null + && mLaunchAdjacentFlagRootTask.getAdjacentTask() != null && (sourceTask == mLaunchAdjacentFlagRootTask || sourceTask.isDescendantOf(mLaunchAdjacentFlagRootTask))) { // If the adjacent launch is coming from the same root, launch to // adjacent root instead. - return mLaunchAdjacentFlagRootTask.getAdjacentTaskFragment().asTask(); + return mLaunchAdjacentFlagRootTask.getAdjacentTask(); } else { return mLaunchAdjacentFlagRootTask; } @@ -1095,10 +1095,8 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { for (int i = mLaunchRootTasks.size() - 1; i >= 0; --i) { if (mLaunchRootTasks.get(i).contains(windowingMode, activityType)) { final Task launchRootTask = mLaunchRootTasks.get(i).task; - final TaskFragment adjacentTaskFragment = launchRootTask != null - ? launchRootTask.getAdjacentTaskFragment() : null; - final Task adjacentRootTask = - adjacentTaskFragment != null ? adjacentTaskFragment.asTask() : null; + final Task adjacentRootTask = launchRootTask != null + ? launchRootTask.getAdjacentTask() : null; if (sourceTask != null && adjacentRootTask != null && (sourceTask == adjacentRootTask || sourceTask.isDescendantOf(adjacentRootTask))) { @@ -1116,16 +1114,14 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> { // A pinned task relaunching should be handled by its task organizer. Skip fallback // launch target of a pinned task from source task. || candidateTask.getWindowingMode() != WINDOWING_MODE_PINNED)) { - Task launchTarget = sourceTask.getCreatedByOrganizerTask(); - if (launchTarget != null && launchTarget.getAdjacentTaskFragment() != null) { - if (candidateTask != null) { - final Task candidateRoot = candidateTask.getCreatedByOrganizerTask(); - if (candidateRoot != null && candidateRoot != launchTarget - && launchTarget == candidateRoot.getAdjacentTaskFragment()) { - launchTarget = candidateRoot; - } + final Task adjacentTarget = sourceTask.getAdjacentTask(); + if (adjacentTarget != null) { + if (candidateTask != null + && (candidateTask == adjacentTarget + || candidateTask.isDescendantOf(adjacentTarget))) { + return adjacentTarget; } - return launchTarget; + return sourceTask.getCreatedByOrganizerTask(); } } diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java index 184293e11002..5626aa7f075f 100644 --- a/services/core/java/com/android/server/wm/TaskOrganizerController.java +++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java @@ -681,6 +681,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub { final StartingWindowRemovalInfo removalInfo = new StartingWindowRemovalInfo(); removalInfo.taskId = task.mTaskId; removalInfo.playRevealAnimation = prepareAnimation + && task.getDisplayContent() != null && task.getDisplayInfo().state == Display.STATE_ON; final boolean playShiftUpAnimation = !task.inMultiWindowMode(); final ActivityRecord topActivity = task.topActivityContainsStartingWindow(); diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index 969afe544b18..492252314356 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -848,6 +848,16 @@ public abstract class WindowManagerInternal { } /** + * Sets by the {@link com.android.server.inputmethod.InputMethodManagerService} to monitor + * the visibility change of the IME targeted windows. + * + * @see ImeTargetChangeListener#onImeTargetOverlayVisibilityChanged + * @see ImeTargetChangeListener#onImeInputTargetVisibilityChanged + */ + public abstract void setInputMethodTargetChangeListener( + @NonNull ImeTargetChangeListener listener); + + /** * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}. */ public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 99d0ea86e2f4..62b3c7cd1daf 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -723,6 +723,9 @@ public class WindowManagerService extends IWindowManager.Stub boolean mHardKeyboardAvailable; WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; + + @Nullable ImeTargetChangeListener mImeTargetChangeListener; + SettingsObserver mSettingsObserver; final EmbeddedWindowController mEmbeddedWindowController; final AnrController mAnrController; @@ -1807,6 +1810,10 @@ public class WindowManagerService extends IWindowManager.Stub if (imMayMove) { displayContent.computeImeTarget(true /* updateImeTarget */); + if (win.isImeOverlayLayeringTarget()) { + dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), + win.isVisibleRequestedOrAdding(), false /* removed */); + } } // Don't do layout here, the window must call @@ -2328,6 +2335,8 @@ public class WindowManagerService extends IWindowManager.Stub winAnimator.mSurfaceController.setSecure(win.isSecureLocked()); } + final boolean wasVisible = win.isVisible(); + win.mRelayoutCalled = true; win.mInRelayout = true; @@ -2336,7 +2345,6 @@ public class WindowManagerService extends IWindowManager.Stub "Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility, viewVisibility, new RuntimeException().fillInStackTrace()); - win.setDisplayLayoutNeeded(); win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; @@ -2501,6 +2509,18 @@ public class WindowManagerService extends IWindowManager.Stub } win.mInRelayout = false; + final boolean winVisibleChanged = win.isVisible() != wasVisible; + if (win.isImeOverlayLayeringTarget() && winVisibleChanged) { + dispatchImeTargetOverlayVisibilityChanged(client.asBinder(), + win.isVisible(), false /* removed */); + } + // Notify listeners about IME input target window visibility change. + final boolean isImeInputTarget = win.getDisplayContent().getImeInputTarget() == win; + if (isImeInputTarget && winVisibleChanged) { + dispatchImeInputTargetVisibilityChanged(win.mClient.asBinder(), + win.isVisible() /* visible */, false /* removed */); + } + if (outSyncIdBundle != null) { final int maybeSyncSeqId; if (USE_BLAST_SYNC && win.useBLASTSync() && viewVisibility == View.VISIBLE @@ -3325,6 +3345,30 @@ public class WindowManagerService extends IWindowManager.Stub }); } + void dispatchImeTargetOverlayVisibilityChanged(@NonNull IBinder token, boolean visible, + boolean removed) { + if (mImeTargetChangeListener != null) { + if (DEBUG_INPUT_METHOD) { + Slog.d(TAG, "onImeTargetOverlayVisibilityChanged, win=" + mWindowMap.get(token) + + "visible=" + visible + ", removed=" + removed); + } + mH.post(() -> mImeTargetChangeListener.onImeTargetOverlayVisibilityChanged(token, + visible, removed)); + } + } + + void dispatchImeInputTargetVisibilityChanged(@NonNull IBinder token, boolean visible, + boolean removed) { + if (mImeTargetChangeListener != null) { + if (DEBUG_INPUT_METHOD) { + Slog.d(TAG, "onImeInputTargetVisibilityChanged, win=" + mWindowMap.get(token) + + "visible=" + visible + ", removed=" + removed); + } + mH.post(() -> mImeTargetChangeListener.onImeInputTargetVisibilityChanged(token, + visible, removed)); + } + } + @Override public void setSwitchingUser(boolean switching) { if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL, @@ -8262,13 +8306,19 @@ public class WindowManagerService extends IWindowManager.Stub } return null; } + + @Override + public void setInputMethodTargetChangeListener(@NonNull ImeTargetChangeListener listener) { + synchronized (mGlobalLock) { + mImeTargetChangeListener = listener; + } + } } private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy { - // TODO(b/258048231): Track IME visibility change in bugreport when invocations. @Override - public boolean showImeScreenShot(@NonNull IBinder imeTarget, int displayId) { + public boolean showImeScreenshot(@NonNull IBinder imeTarget, int displayId) { synchronized (mGlobalLock) { final WindowState imeTargetWindow = mWindowMap.get(imeTarget); if (imeTargetWindow == null) { @@ -8284,24 +8334,18 @@ public class WindowManagerService extends IWindowManager.Stub return true; } } - - // TODO(b/258048231): Track IME visibility change in bugreport when invocations. @Override - public boolean updateImeParent(@NonNull IBinder imeTarget, int displayId) { + public boolean removeImeScreenshot(int displayId) { synchronized (mGlobalLock) { - final WindowState imeTargetWindow = mWindowMap.get(imeTarget); - if (imeTargetWindow == null) { - return false; - } final DisplayContent dc = mRoot.getDisplayContent(displayId); if (dc == null) { - Slog.w(TAG, "Invalid displayId:" + displayId + ", fail to update ime parent"); + Slog.w(TAG, "Invalid displayId:" + displayId + + ", fail to remove ime screenshot"); return false; } - - dc.updateImeParent(); - return true; + dc.removeImeSurfaceImmediately(); } + return true; } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index d1618e9a278b..a29959297dc7 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -166,6 +166,7 @@ import static com.android.server.wm.WindowStateProto.IS_ON_SCREEN; import static com.android.server.wm.WindowStateProto.IS_READY_FOR_DISPLAY; import static com.android.server.wm.WindowStateProto.IS_VISIBLE; import static com.android.server.wm.WindowStateProto.KEEP_CLEAR_AREAS; +import static com.android.server.wm.WindowStateProto.MERGED_LOCAL_INSETS_SOURCES; import static com.android.server.wm.WindowStateProto.PENDING_SEAMLESS_ROTATION; import static com.android.server.wm.WindowStateProto.REMOVED; import static com.android.server.wm.WindowStateProto.REMOVE_ON_EXIT; @@ -353,6 +354,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // overlay window is hidden because the owning app is suspended private boolean mHiddenWhileSuspended; private boolean mAppOpVisibility = true; + boolean mPermanentlyHidden; // the window should never be shown again // This is a non-system overlay window that is currently force hidden. private boolean mForceHideNonSystemOverlayWindow; @@ -2349,6 +2351,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } super.removeImmediately(); + if (isImeOverlayLayeringTarget()) { + mWmService.dispatchImeTargetOverlayVisibilityChanged(mClient.asBinder(), + false /* visible */, true /* removed */); + } final DisplayContent dc = getDisplayContent(); if (isImeLayeringTarget()) { // Remove the attached IME screenshot surface. @@ -2359,6 +2365,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP dc.computeImeTarget(true /* updateImeTarget */); } if (dc.getImeInputTarget() == this && !inRelaunchingActivity()) { + mWmService.dispatchImeInputTargetVisibilityChanged(mClient.asBinder(), + false /* visible */, true /* removed */); dc.updateImeInputAndControlTarget(null); } @@ -4027,6 +4035,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP for (Rect r : mUnrestrictedKeepClearAreas) { r.dumpDebug(proto, UNRESTRICTED_KEEP_CLEAR_AREAS); } + if (mMergedLocalInsetsSources != null) { + for (int i = 0; i < mMergedLocalInsetsSources.size(); ++i) { + mMergedLocalInsetsSources.valueAt(i).dumpDebug(proto, MERGED_LOCAL_INSETS_SOURCES); + } + } proto.end(token); } @@ -5493,6 +5506,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return getDisplayContent().getImeTarget(IME_TARGET_LAYERING) == this; } + /** + * Whether the window is non-focusable IME overlay layering target. + */ + boolean isImeOverlayLayeringTarget() { + return isImeLayeringTarget() + && (mAttrs.flags & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0; + } + WindowState getImeLayeringTarget() { final InsetsControlTarget target = getDisplayContent().getImeTarget(IME_TARGET_LAYERING); return target != null ? target.getWindow() : null; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java index ee73f8afabd2..82f9aadba9f4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BundlePolicySerializer.java @@ -17,50 +17,28 @@ package com.android.server.devicepolicy; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.admin.BundlePolicyValue; import android.app.admin.PackagePolicyKey; import android.app.admin.PolicyKey; import android.os.Bundle; -import android.os.Environment; import android.os.Parcelable; -import android.util.AtomicFile; -import android.util.Slog; -import android.util.Xml; +import android.util.Log; -import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; -import libcore.io.IoUtils; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Objects; -// TODO(b/266704763): clean this up and stop creating separate files for each value, the code here -// is copied from UserManagerService, however it doesn't currently handle setting different -// restrictions for the same package in different users, it also will not remove the files for -// outdated restrictions, this will all get fixed when we save it as part of the policies file -// rather than in its own files. final class BundlePolicySerializer extends PolicySerializer<Bundle> { private static final String TAG = "BundlePolicySerializer"; - private static final String ATTR_FILE_NAME = "file-name"; - - private static final String RESTRICTIONS_FILE_PREFIX = "AppRestrictions_"; - private static final String XML_SUFFIX = ".xml"; - - private static final String TAG_RESTRICTIONS = "restrictions"; private static final String TAG_ENTRY = "entry"; private static final String TAG_VALUE = "value"; private static final String ATTR_KEY = "key"; @@ -83,62 +61,26 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> { throw new IllegalArgumentException("policyKey is not of type " + "PackagePolicyKey"); } - String packageName = ((PackagePolicyKey) policyKey).getPackageName(); - String fileName = packageToRestrictionsFileName(packageName, value); - writeApplicationRestrictionsLAr(fileName, value); - serializer.attribute(/* namespace= */ null, ATTR_FILE_NAME, fileName); + writeBundle(value, serializer); } - @Nullable @Override BundlePolicyValue readFromXml(TypedXmlPullParser parser) { - String fileName = parser.getAttributeValue(/* namespace= */ null, ATTR_FILE_NAME); - - return new BundlePolicyValue(readApplicationRestrictions(fileName)); - } - - private static String packageToRestrictionsFileName(String packageName, Bundle restrictions) { - return RESTRICTIONS_FILE_PREFIX + packageName + Objects.hash(restrictions) + XML_SUFFIX; - } - - @GuardedBy("mAppRestrictionsLock") - private static Bundle readApplicationRestrictions(String fileName) { - AtomicFile restrictionsFile = - new AtomicFile(new File(Environment.getDataSystemDirectory(), fileName)); - return readApplicationRestrictions(restrictionsFile); - } - - @VisibleForTesting - @GuardedBy("mAppRestrictionsLock") - static Bundle readApplicationRestrictions(AtomicFile restrictionsFile) { - final Bundle restrictions = new Bundle(); - final ArrayList<String> values = new ArrayList<>(); - if (!restrictionsFile.getBaseFile().exists()) { - return restrictions; - } - - FileInputStream fis = null; + Bundle bundle = new Bundle(); + ArrayList<String> values = new ArrayList<>(); try { - fis = restrictionsFile.openRead(); - final TypedXmlPullParser parser = Xml.resolvePullParser(fis); - XmlUtils.nextElement(parser); - if (parser.getEventType() != XmlPullParser.START_TAG) { - Slog.e(TAG, "Unable to read restrictions file " - + restrictionsFile.getBaseFile()); - return restrictions; - } - while (parser.next() != XmlPullParser.END_DOCUMENT) { - readEntry(restrictions, values, parser); + final int outerDepth = parser.getDepth(); + while (XmlUtils.nextElementWithin(parser, outerDepth)) { + readBundle(bundle, values, parser); } - } catch (IOException | XmlPullParserException e) { - Slog.w(TAG, "Error parsing " + restrictionsFile.getBaseFile(), e); - } finally { - IoUtils.closeQuietly(fis); + } catch (XmlPullParserException | IOException e) { + Log.e(TAG, "Error parsing Bundle policy.", e); + return null; } - return restrictions; + return new BundlePolicyValue(bundle); } - private static void readEntry(Bundle restrictions, ArrayList<String> values, + private static void readBundle(Bundle restrictions, ArrayList<String> values, TypedXmlPullParser parser) throws XmlPullParserException, IOException { int type = parser.getEventType(); if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) { @@ -186,37 +128,11 @@ final class BundlePolicySerializer extends PolicySerializer<Bundle> { Bundle childBundle = new Bundle(); int outerDepth = parser.getDepth(); while (XmlUtils.nextElementWithin(parser, outerDepth)) { - readEntry(childBundle, values, parser); + readBundle(childBundle, values, parser); } return childBundle; } - private static void writeApplicationRestrictionsLAr(String fileName, Bundle restrictions) { - AtomicFile restrictionsFile = new AtomicFile( - new File(Environment.getDataSystemDirectory(), fileName)); - writeApplicationRestrictionsLAr(restrictions, restrictionsFile); - } - - static void writeApplicationRestrictionsLAr(Bundle restrictions, AtomicFile restrictionsFile) { - FileOutputStream fos = null; - try { - fos = restrictionsFile.startWrite(); - final TypedXmlSerializer serializer = Xml.resolveSerializer(fos); - serializer.startDocument(null, true); - serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - - serializer.startTag(null, TAG_RESTRICTIONS); - writeBundle(restrictions, serializer); - serializer.endTag(null, TAG_RESTRICTIONS); - - serializer.endDocument(); - restrictionsFile.finishWrite(fos); - } catch (Exception e) { - restrictionsFile.failWrite(fos); - Slog.e(TAG, "Error writing application restrictions list", e); - } - } - private static void writeBundle(Bundle restrictions, TypedXmlSerializer serializer) throws IOException { for (String key : restrictions.keySet()) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 18fcafa84c24..7e5d5aae06e4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -11053,7 +11053,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (!isPermissionCheckFlagEnabled() && !isPolicyEngineForFinanceFlagEnabled()) { - // TODO: Figure out if something like this needs to be restored for policy engine final ComponentName profileOwner = getProfileOwnerAsUser(userId); if (profileOwner == null) { return false; @@ -11640,7 +11639,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { caller.getUserId()); } setBackwardsCompatibleAppRestrictions( - packageName, restrictions, caller.getUserHandle()); + caller, packageName, restrictions, caller.getUserHandle()); } else { Preconditions.checkCallAuthorization((caller.hasAdminComponent() && (isProfileOwner(caller) || isDefaultDeviceOwner(caller))) @@ -11661,17 +11660,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** - * Set app restrictions in user manager to keep backwards compatibility for the old - * getApplicationRestrictions API. + * Set app restrictions in user manager for DPC callers only to keep backwards compatibility + * for the old getApplicationRestrictions API. */ private void setBackwardsCompatibleAppRestrictions( - String packageName, Bundle restrictions, UserHandle userHandle) { - Bundle restrictionsToApply = restrictions == null || restrictions.isEmpty() - ? getAppRestrictionsSetByAnyAdmin(packageName, userHandle) - : restrictions; - mInjector.binderWithCleanCallingIdentity(() -> { - mUserManager.setApplicationRestrictions(packageName, restrictionsToApply, userHandle); - }); + CallerIdentity caller, String packageName, Bundle restrictions, UserHandle userHandle) { + if ((caller.hasAdminComponent() && (isProfileOwner(caller) || isDefaultDeviceOwner(caller))) + || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_APP_RESTRICTIONS))) { + Bundle restrictionsToApply = restrictions == null || restrictions.isEmpty() + ? getAppRestrictionsSetByAnyAdmin(packageName, userHandle) + : restrictions; + mInjector.binderWithCleanCallingIdentity(() -> { + mUserManager.setApplicationRestrictions(packageName, restrictionsToApply, + userHandle); + }); + } else { + // Notify package of changes via an intent - only sent to explicitly registered + // receivers. Sending here because For DPCs, this is being sent in UMS. + final Intent changeIntent = new Intent(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED); + changeIntent.setPackage(packageName); + changeIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mContext.sendBroadcastAsUser(changeIntent, userHandle); + } } private Bundle getAppRestrictionsSetByAnyAdmin(String packageName, UserHandle userHandle) { diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java index 7d4f87d73507..a6ada4d77253 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/DefaultImeVisibilityApplierTest.java @@ -38,6 +38,7 @@ import static org.mockito.Mockito.verify; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.view.Display; import android.view.inputmethod.InputMethodManager; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -144,6 +145,26 @@ public class DefaultImeVisibilityApplierTest extends InputMethodManagerServiceTe } } + @Test + public void testShowImeScreenshot() { + synchronized (ImfLock.class) { + mVisibilityApplier.showImeScreenshot(mWindowToken, Display.DEFAULT_DISPLAY, + null /* statsToken */); + } + + verify(mMockImeTargetVisibilityPolicy).showImeScreenshot(eq(mWindowToken), + eq(Display.DEFAULT_DISPLAY)); + } + + @Test + public void testRemoveImeScreenshot() { + synchronized (ImfLock.class) { + mVisibilityApplier.removeImeScreenshot(Display.DEFAULT_DISPLAY); + } + + verify(mMockImeTargetVisibilityPolicy).removeImeScreenshot(eq(Display.DEFAULT_DISPLAY)); + } + private InputBindResult startInputOrWindowGainedFocus(IBinder windowToken, int softInputMode) { return mInputMethodManagerService.startInputOrWindowGainedFocus( StartInputReason.WINDOW_FOCUS_GAIN /* startInputReason */, diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java index 2a256f262980..3871e1dfd5b0 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ImeVisibilityStateComputerTest.java @@ -24,7 +24,15 @@ import static android.view.WindowManager.DISPLAY_IME_POLICY_HIDE; import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.internal.inputmethod.SoftInputShowHideReason.HIDE_WHEN_INPUT_TARGET_INVISIBLE; +import static com.android.internal.inputmethod.SoftInputShowHideReason.REMOVE_IME_SCREENSHOT_FROM_IMMS; +import static com.android.internal.inputmethod.SoftInputShowHideReason.SHOW_IME_SCREENSHOT_FROM_IMMS; import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeTargetWindowState; +import static com.android.server.inputmethod.ImeVisibilityStateComputer.ImeVisibilityResult; +import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME_EXPLICIT; +import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_REMOVE_IME_SNAPSHOT; +import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME_SNAPSHOT; import static com.android.server.inputmethod.InputMethodManagerService.FALLBACK_DISPLAY_ID; import static com.android.server.inputmethod.InputMethodManagerService.ImeDisplayValidator; @@ -37,11 +45,13 @@ import android.view.inputmethod.InputMethodManager; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.server.wm.ImeTargetChangeListener; import com.android.server.wm.WindowManagerInternal; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; /** * Test the behavior of {@link ImeVisibilityStateComputer} and {@link ImeVisibilityApplier} when @@ -53,6 +63,7 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTestBase { private ImeVisibilityStateComputer mComputer; + private ImeTargetChangeListener mListener; private int mImeDisplayPolicy = DISPLAY_IME_POLICY_LOCAL; @Before @@ -69,7 +80,11 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes return displayId -> mImeDisplayPolicy; } }; + ArgumentCaptor<ImeTargetChangeListener> captor = ArgumentCaptor.forClass( + ImeTargetChangeListener.class); + verify(mMockWindowManagerInternal).setInputMethodTargetChangeListener(captor.capture()); mComputer = new ImeVisibilityStateComputer(mInputMethodManagerService, injector); + mListener = captor.getValue(); } @Test @@ -196,6 +211,53 @@ public class ImeVisibilityStateComputerTest extends InputMethodManagerServiceTes lastState.isRequestedImeVisible()); } + @Test + public void testOnInteractiveChanged() { + mComputer.getOrCreateWindowState(mWindowToken); + // Precondition: ensure IME has shown before hiding request. + mComputer.requestImeVisibility(mWindowToken, true); + mComputer.setInputShown(true); + + // No need any visibility change When initially shows IME on the device was interactive. + ImeVisibilityStateComputer.ImeVisibilityResult result = mComputer.onInteractiveChanged( + mWindowToken, true /* interactive */); + assertThat(result).isNull(); + + // Show the IME screenshot to capture the last IME visible state when the device inactive. + result = mComputer.onInteractiveChanged(mWindowToken, false /* interactive */); + assertThat(result).isNotNull(); + assertThat(result.getState()).isEqualTo(STATE_SHOW_IME_SNAPSHOT); + assertThat(result.getReason()).isEqualTo(SHOW_IME_SCREENSHOT_FROM_IMMS); + + // Remove the IME screenshot when the device became interactive again. + result = mComputer.onInteractiveChanged(mWindowToken, true /* interactive */); + assertThat(result).isNotNull(); + assertThat(result.getState()).isEqualTo(STATE_REMOVE_IME_SNAPSHOT); + assertThat(result.getReason()).isEqualTo(REMOVE_IME_SCREENSHOT_FROM_IMMS); + } + + @Test + public void testOnApplyImeVisibilityFromComputer() { + final IBinder testImeTargetOverlay = new Binder(); + final IBinder testImeInputTarget = new Binder(); + + // Simulate a test IME layering target overlay fully occluded the IME input target. + mListener.onImeTargetOverlayVisibilityChanged(testImeTargetOverlay, true, false); + mListener.onImeInputTargetVisibilityChanged(testImeInputTarget, false, false); + final ArgumentCaptor<IBinder> targetCaptor = ArgumentCaptor.forClass(IBinder.class); + final ArgumentCaptor<ImeVisibilityResult> resultCaptor = ArgumentCaptor.forClass( + ImeVisibilityResult.class); + verify(mInputMethodManagerService).onApplyImeVisibilityFromComputer(targetCaptor.capture(), + resultCaptor.capture()); + final IBinder imeInputTarget = targetCaptor.getValue(); + final ImeVisibilityResult result = resultCaptor.getValue(); + + // Verify the computer will callback hiding IME state to IMMS. + assertThat(imeInputTarget).isEqualTo(testImeInputTarget); + assertThat(result.getState()).isEqualTo(STATE_HIDE_IME_EXPLICIT); + assertThat(result.getReason()).isEqualTo(HIDE_WHEN_INPUT_TARGET_INVISIBLE); + } + private ImeTargetWindowState initImeTargetWindowState(IBinder windowToken) { final ImeTargetWindowState state = new ImeTargetWindowState(SOFT_INPUT_STATE_UNCHANGED, 0, true, true, true); diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java index 90691a75aede..c80ecbf62142 100644 --- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java +++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java @@ -62,6 +62,7 @@ import com.android.server.SystemServerInitThreadPool; import com.android.server.SystemService; import com.android.server.input.InputManagerInternal; import com.android.server.pm.UserManagerInternal; +import com.android.server.wm.ImeTargetVisibilityPolicy; import com.android.server.wm.WindowManagerInternal; import org.junit.After; @@ -113,6 +114,7 @@ public class InputMethodManagerServiceTestBase { @Mock protected IInputMethod mMockInputMethod; @Mock protected IBinder mMockInputMethodBinder; @Mock protected IInputManager mMockIInputManager; + @Mock protected ImeTargetVisibilityPolicy mMockImeTargetVisibilityPolicy; protected Context mContext; protected MockitoSession mMockingSession; @@ -166,6 +168,8 @@ public class InputMethodManagerServiceTestBase { .when(() -> LocalServices.getService(DisplayManagerInternal.class)); doReturn(mMockUserManagerInternal) .when(() -> LocalServices.getService(UserManagerInternal.class)); + doReturn(mMockImeTargetVisibilityPolicy) + .when(() -> LocalServices.getService(ImeTargetVisibilityPolicy.class)); doReturn(mMockIInputMethodManager) .when(() -> ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE)); doReturn(mMockIPlatformCompat) @@ -218,6 +222,7 @@ public class InputMethodManagerServiceTestBase { false); mInputMethodManagerService = new InputMethodManagerService(mContext, mServiceThread, mMockInputMethodBindingController); + spyOn(mInputMethodManagerService); // Start a InputMethodManagerService.Lifecycle to publish and manage the lifecycle of // InputMethodManagerService, which is closer to the real situation. diff --git a/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java b/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java new file mode 100644 index 000000000000..d9fbba5b4274 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/display/HighBrightnessModeMetadataMapperTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.junit.Before; +import org.junit.Test; + +public class HighBrightnessModeMetadataMapperTest { + + private HighBrightnessModeMetadataMapper mHighBrightnessModeMetadataMapper; + + @Before + public void setUp() { + mHighBrightnessModeMetadataMapper = new HighBrightnessModeMetadataMapper(); + } + + @Test + public void testGetHighBrightnessModeMetadata() { + // Display device is null + final LogicalDisplay display = mock(LogicalDisplay.class); + when(display.getPrimaryDisplayDeviceLocked()).thenReturn(null); + assertNull(mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display)); + + // No HBM metadata stored for this display yet + final DisplayDevice device = mock(DisplayDevice.class); + when(display.getPrimaryDisplayDeviceLocked()).thenReturn(device); + HighBrightnessModeMetadata hbmMetadata = + mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display); + assertTrue(hbmMetadata.getHbmEventQueue().isEmpty()); + assertTrue(hbmMetadata.getRunningStartTimeMillis() < 0); + + // Modify the metadata + long startTimeMillis = 100; + long endTimeMillis = 200; + long setTime = 300; + hbmMetadata.addHbmEvent(new HbmEvent(startTimeMillis, endTimeMillis)); + hbmMetadata.setRunningStartTimeMillis(setTime); + hbmMetadata = + mHighBrightnessModeMetadataMapper.getHighBrightnessModeMetadataLocked(display); + assertEquals(1, hbmMetadata.getHbmEventQueue().size()); + assertEquals(startTimeMillis, + hbmMetadata.getHbmEventQueue().getFirst().getStartTimeMillis()); + assertEquals(endTimeMillis, hbmMetadata.getHbmEventQueue().getFirst().getEndTimeMillis()); + assertEquals(setTime, hbmMetadata.getRunningStartTimeMillis()); + } +} diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java index 90d148856fff..4406d831dd93 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java @@ -71,10 +71,10 @@ import android.service.notification.StatusBarNotification; import android.testing.TestableContext; import android.util.ArraySet; import android.util.Pair; -import com.android.modules.utils.TypedXmlPullParser; -import com.android.modules.utils.TypedXmlSerializer; import android.util.Xml; +import com.android.modules.utils.TypedXmlPullParser; +import com.android.modules.utils.TypedXmlSerializer; import com.android.server.UiServiceTestCase; import com.google.common.collect.ImmutableList; @@ -92,6 +92,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; public class NotificationListenersTest extends UiServiceTestCase { @@ -626,6 +627,58 @@ public class NotificationListenersTest extends UiServiceTestCase { .onNotificationChannelGroupModification(anyString(), any(), any(), anyInt()); } + @Test + public void testNotificationListenerFilter_threadSafety() throws Exception { + testThreadSafety(() -> { + mListeners.setNotificationListenerFilter( + new Pair<>(new ComponentName("pkg1", "cls1"), 0), + new NotificationListenerFilter()); + mListeners.setNotificationListenerFilter( + new Pair<>(new ComponentName("pkg2", "cls2"), 10), + new NotificationListenerFilter()); + mListeners.setNotificationListenerFilter( + new Pair<>(new ComponentName("pkg3", "cls3"), 11), + new NotificationListenerFilter()); + + mListeners.onUserRemoved(10); + mListeners.onPackagesChanged(true, new String[]{"pkg1", "pkg2"}, new int[]{0, 0}); + }, 20, 50); + } + + /** + * Helper method to test the thread safety of some operations. + * + * <p>Runs the supplied {@code operationToTest}, {@code nRunsPerThread} times, + * concurrently using {@code nThreads} threads, and waits for all of them to finish. + */ + private static void testThreadSafety(Runnable operationToTest, int nThreads, + int nRunsPerThread) throws InterruptedException { + final CountDownLatch startLatch = new CountDownLatch(1); + final CountDownLatch doneLatch = new CountDownLatch(nThreads); + + for (int i = 0; i < nThreads; i++) { + Runnable threadRunnable = () -> { + try { + startLatch.await(); + for (int j = 0; j < nRunsPerThread; j++) { + operationToTest.run(); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + doneLatch.countDown(); + } + }; + new Thread(threadRunnable, "Test Thread #" + i).start(); + } + + // Ready set go + startLatch.countDown(); + + // Wait for all test threads to be done. + doneLatch.await(); + } + private ManagedServices.ManagedServiceInfo getParcelingListener( final NotificationChannelGroup toParcel) throws RemoteException { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 9cfdaa7cad0c..dd9f3cb3d343 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -5447,6 +5447,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void testVisitUris_callStyle() { + Icon personIcon = Icon.createWithContentUri("content://media/person"); + Icon verificationIcon = Icon.createWithContentUri("content://media/verification"); + Person callingPerson = new Person.Builder().setName("Someone") + .setIcon(personIcon) + .build(); + PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(), + PendingIntent.FLAG_IMMUTABLE); + Notification n = new Notification.Builder(mContext, "a") + .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent) + .setVerificationIcon(verificationIcon)) + .setContentTitle("Calling...") + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .build(); + + Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); + n.visitUris(visitor); + + verify(visitor, times(1)).accept(eq(personIcon.getUri())); + verify(visitor, times(1)).accept(eq(verificationIcon.getUri())); + } + + @Test public void testVisitUris_audioContentsString() throws Exception { final Uri audioContents = Uri.parse("content://com.example/audio"); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index 4e001fe06fb8..37c4b3787835 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -28,6 +28,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMor import static com.google.common.truth.Truth.assertWithMessage; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; @@ -501,6 +502,12 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase { onActivityLaunched(mTrampolineActivity); mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent, mTrampolineActivity /* caller */, mTrampolineActivity.getUid()); + + // Simulate a corner case that the trampoline activity is removed by CLEAR_TASK. + // The 2 launch events can still be coalesced to one by matching the uid. + mTrampolineActivity.takeFromHistory(); + assertNull(mTrampolineActivity.getTask()); + notifyActivityLaunched(START_SUCCESS, mTopActivity); transitToDrawnAndVerifyOnLaunchFinished(mTopActivity); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 8f2b470908c4..0033e3e368c6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2399,7 +2399,10 @@ public class ActivityRecordTests extends WindowTestsBase { holder.addConnection(connection); assertTrue(holder.isActivityVisible()); final int[] count = new int[1]; - final Consumer<Object> c = conn -> count[0]++; + final Consumer<Object> c = conn -> { + count[0]++; + assertFalse(Thread.holdsLock(activity)); + }; holder.forEachConnection(c); assertEquals(1, count[0]); diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java index 17ae215c2930..6d7f2c13197c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java @@ -232,11 +232,36 @@ public class BackNavigationControllerTests extends WindowTestsBase { IOnBackInvokedCallback callback = createOnBackInvokedCallback(); window.setOnBackInvokedCallbackInfo( - new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT)); + new OnBackInvokedCallbackInfo( + callback, + OnBackInvokedDispatcher.PRIORITY_DEFAULT, + /* isAnimationCallback = */ false)); BackNavigationInfo backNavigationInfo = startBackNavigation(); assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull(); assertThat(backNavigationInfo.getType()).isEqualTo(BackNavigationInfo.TYPE_CALLBACK); + assertThat(backNavigationInfo.isAnimationCallback()).isEqualTo(false); + assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); + } + + @Test + public void backInfoWithAnimationCallback() { + WindowState window = createWindow(null, WindowManager.LayoutParams.TYPE_WALLPAPER, + "Wallpaper"); + addToWindowMap(window, true); + makeWindowVisibleAndDrawn(window); + + IOnBackInvokedCallback callback = createOnBackInvokedCallback(); + window.setOnBackInvokedCallbackInfo( + new OnBackInvokedCallbackInfo( + callback, + OnBackInvokedDispatcher.PRIORITY_DEFAULT, + /* isAnimationCallback = */ true)); + + BackNavigationInfo backNavigationInfo = startBackNavigation(); + assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull(); + assertThat(backNavigationInfo.getType()).isEqualTo(BackNavigationInfo.TYPE_CALLBACK); + assertThat(backNavigationInfo.isAnimationCallback()).isEqualTo(true); assertThat(backNavigationInfo.getOnBackInvokedCallback()).isEqualTo(callback); } @@ -364,7 +389,10 @@ public class BackNavigationControllerTests extends WindowTestsBase { IOnBackInvokedCallback callback = createOnBackInvokedCallback(); window.setOnBackInvokedCallbackInfo( - new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT)); + new OnBackInvokedCallbackInfo( + callback, + OnBackInvokedDispatcher.PRIORITY_DEFAULT, + /* isAnimationCallback = */ false)); BackNavigationInfo backNavigationInfo = startBackNavigation(); assertThat(backNavigationInfo).isNull(); @@ -450,14 +478,20 @@ public class BackNavigationControllerTests extends WindowTestsBase { private IOnBackInvokedCallback withSystemCallback(Task task) { IOnBackInvokedCallback callback = createOnBackInvokedCallback(); task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo( - new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_SYSTEM)); + new OnBackInvokedCallbackInfo( + callback, + OnBackInvokedDispatcher.PRIORITY_SYSTEM, + /* isAnimationCallback = */ false)); return callback; } private IOnBackInvokedCallback withAppCallback(Task task) { IOnBackInvokedCallback callback = createOnBackInvokedCallback(); task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo( - new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT)); + new OnBackInvokedCallbackInfo( + callback, + OnBackInvokedDispatcher.PRIORITY_DEFAULT, + /* isAnimationCallback = */ false)); return callback; } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index 206554019526..a8fc25fc4477 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -84,12 +84,14 @@ public class InsetsPolicyTest extends WindowTestsBase { } @Test - public void testControlsForDispatch_multiWindowTaskVisible() { + public void testControlsForDispatch_adjacentTasksVisible() { addStatusBar(); addNavigationBar(); - final WindowState win = createWindow(null, WINDOWING_MODE_MULTI_WINDOW, - ACTIVITY_TYPE_STANDARD, TYPE_APPLICATION, mDisplayContent, "app"); + final Task task1 = createTask(mDisplayContent); + final Task task2 = createTask(mDisplayContent); + task1.setAdjacentTaskFragment(task2); + final WindowState win = createAppWindow(task1, WINDOWING_MODE_MULTI_WINDOW, "app"); final InsetsSourceControl[] controls = addWindowAndGetControlsForDispatch(win); // The app must not control any system bars. diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 49d8da1b2880..9d597b11120d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -586,6 +586,15 @@ public class TaskFragmentTest extends WindowTestsBase { // Making the activity0 be the focused activity and ensure the focused app is updated. activity0.moveFocusableActivityToTop("test"); assertEquals(activity0, mDisplayContent.mFocusedApp); + + // Moving activity1 to top and make both the two activities resumed. + activity1.moveFocusableActivityToTop("test"); + activity0.setState(RESUMED, "test"); + activity1.setState(RESUMED, "test"); + + // Verifies that the focus app can be updated to an Activity in the adjacent TF + mAtm.setFocusedTask(task.mTaskId, activity0); + assertEquals(activity0, mDisplayContent.mFocusedApp); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 766e74c85dab..460a603d51a2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.InsetsSource.ID_IME; import static android.view.Surface.ROTATION_0; import static android.view.Surface.ROTATION_270; @@ -85,17 +86,25 @@ import android.content.res.Configuration; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; +import android.os.Bundle; import android.os.IBinder; import android.os.InputConfig; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.util.ArraySet; +import android.util.MergedConfiguration; import android.view.Gravity; +import android.view.IWindow; +import android.view.IWindowSessionCallback; import android.view.InputWindowHandle; import android.view.InsetsSource; +import android.view.InsetsSourceControl; import android.view.InsetsState; import android.view.SurfaceControl; +import android.view.View; +import android.view.WindowInsets; import android.view.WindowManager; +import android.window.ClientWindowFrames; import android.window.ITaskFragmentOrganizer; import android.window.TaskFragmentOrganizer; @@ -1280,4 +1289,118 @@ public class WindowStateTests extends WindowTestsBase { assertEquals(new ArraySet(Arrays.asList(expectedArea1, expectedArea2)), new ArraySet(unrestrictedKeepClearAreas)); } + + @Test + public void testImeTargetChangeListener_OnImeInputTargetVisibilityChanged() { + final TestImeTargetChangeListener listener = new TestImeTargetChangeListener(); + mWm.mImeTargetChangeListener = listener; + + final WindowState imeTarget = createWindow(null /* parent */, TYPE_BASE_APPLICATION, + createActivityRecord(mDisplayContent), "imeTarget"); + + imeTarget.mActivityRecord.setVisibleRequested(true); + makeWindowVisible(imeTarget); + mDisplayContent.setImeInputTarget(imeTarget); + waitHandlerIdle(mWm.mH); + + assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder()); + assertThat(listener.mIsRemoved).isFalse(); + assertThat(listener.mIsVisibleForImeInputTarget).isTrue(); + + imeTarget.mActivityRecord.setVisibleRequested(false); + waitHandlerIdle(mWm.mH); + + assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder()); + assertThat(listener.mIsRemoved).isFalse(); + assertThat(listener.mIsVisibleForImeInputTarget).isFalse(); + + imeTarget.removeImmediately(); + assertThat(listener.mImeTargetToken).isEqualTo(imeTarget.mClient.asBinder()); + assertThat(listener.mIsRemoved).isTrue(); + assertThat(listener.mIsVisibleForImeInputTarget).isFalse(); + } + + @SetupWindows(addWindows = {W_INPUT_METHOD}) + @Test + public void testImeTargetChangeListener_OnImeTargetOverlayVisibilityChanged() { + final TestImeTargetChangeListener listener = new TestImeTargetChangeListener(); + mWm.mImeTargetChangeListener = listener; + + // Scenario 1: test addWindow/relayoutWindow to add Ime layering overlay window as visible. + final WindowToken windowToken = createTestWindowToken(TYPE_APPLICATION_OVERLAY, + mDisplayContent); + final IWindow client = new TestIWindow(); + final Session session = new Session(mWm, new IWindowSessionCallback.Stub() { + @Override + public void onAnimatorScaleChanged(float v) throws RemoteException { + + } + }); + final ClientWindowFrames outFrames = new ClientWindowFrames(); + final MergedConfiguration outConfig = new MergedConfiguration(); + final SurfaceControl outSurfaceControl = new SurfaceControl(); + final InsetsState outInsetsState = new InsetsState(); + final InsetsSourceControl.Array outControls = new InsetsSourceControl.Array(); + final Bundle outBundle = new Bundle(); + final WindowManager.LayoutParams params = new WindowManager.LayoutParams( + TYPE_APPLICATION_OVERLAY); + params.setTitle("imeLayeringTargetOverlay"); + params.token = windowToken.token; + params.flags = FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM; + + mWm.addWindow(session, client, params, View.VISIBLE, DEFAULT_DISPLAY, + 0 /* userUd */, WindowInsets.Type.defaultVisible(), null, new InsetsState(), + new InsetsSourceControl.Array(), new Rect(), new float[1]); + mWm.relayoutWindow(session, client, params, 100, 200, View.VISIBLE, 0, 0, 0, + outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); + waitHandlerIdle(mWm.mH); + + final WindowState imeLayeringTargetOverlay = mDisplayContent.getWindow( + w -> w.mClient.asBinder() == client.asBinder()); + assertThat(imeLayeringTargetOverlay.isVisible()).isTrue(); + assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder()); + assertThat(listener.mIsRemoved).isFalse(); + assertThat(listener.mIsVisibleForImeTargetOverlay).isTrue(); + + // Scenario 2: test relayoutWindow to let the Ime layering target overlay window invisible. + mWm.relayoutWindow(session, client, params, 100, 200, View.GONE, 0, 0, 0, + outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle); + waitHandlerIdle(mWm.mH); + + assertThat(imeLayeringTargetOverlay.isVisible()).isFalse(); + assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder()); + assertThat(listener.mIsRemoved).isFalse(); + assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse(); + + // Scenario 3: test removeWindow to remove the Ime layering target overlay window. + mWm.removeWindow(session, client); + waitHandlerIdle(mWm.mH); + + assertThat(listener.mImeTargetToken).isEqualTo(client.asBinder()); + assertThat(listener.mIsRemoved).isTrue(); + assertThat(listener.mIsVisibleForImeTargetOverlay).isFalse(); + } + + private static class TestImeTargetChangeListener implements ImeTargetChangeListener { + private IBinder mImeTargetToken; + private boolean mIsRemoved; + private boolean mIsVisibleForImeTargetOverlay; + private boolean mIsVisibleForImeInputTarget; + + @Override + public void onImeTargetOverlayVisibilityChanged(IBinder overlayWindowToken, boolean visible, + boolean removed) { + mImeTargetToken = overlayWindowToken; + mIsVisibleForImeTargetOverlay = visible; + mIsRemoved = removed; + } + + @Override + public void onImeInputTargetVisibilityChanged(IBinder imeInputTarget, + boolean visibleRequested, boolean removed) { + mImeTargetToken = imeInputTarget; + mIsVisibleForImeInputTarget = visibleRequested; + mIsRemoved = removed; + } + } } diff --git a/telephony/OWNERS b/telephony/OWNERS index 025869dd2999..3158ad8fc58e 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -11,12 +11,6 @@ chinmayd@google.com amruthr@google.com sasindran@google.com -# Temporarily reduced the owner during refactoring -per-file SubscriptionManager.java=set noparent -per-file SubscriptionManager.java=jackyu@google.com,amruthr@google.com -per-file SubscriptionInfo.java=set noparent -per-file SubscriptionInfo.java=jackyu@google.com,amruthr@google.com - # Requiring TL ownership for new carrier config keys. per-file CarrierConfigManager.java=set noparent per-file CarrierConfigManager.java=amruthr@google.com,tgunn@google.com,rgreenwalt@google.com,satk@google.com diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 905a90c11957..caafce2f1a7e 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -331,8 +331,8 @@ public final class TelephonyPermissions { * Same as {@link #checkCallingOrSelfReadSubscriberIdentifiers(Context, int, String, String, * String)} except this allows an additional parameter reportFailure. Caller may not want to * report a failure when this is an internal/intermediate check, for example, - * SubscriptionController calls this with an INVALID_SUBID to check if caller has the required - * permissions to bypass carrier privilege checks. + * SubscriptionManagerService calls this with an INVALID_SUBID to check if caller has the + * required permissions to bypass carrier privilege checks. * @param reportFailure Indicates if failure should be reported. */ public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId, diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 559faf9b20de..64e43568e4d6 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -91,8 +91,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; /** - * SubscriptionManager is the application interface to SubscriptionController - * and provides information about the current Telephony Subscriptions. + * Subscription manager provides the mobile subscription information. */ @SystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION) @@ -119,13 +118,12 @@ public class SubscriptionManager { public static final int DEFAULT_SUBSCRIPTION_ID = Integer.MAX_VALUE; /** - * Indicates the caller wants the default phone id. - * Used in SubscriptionController and Phone but do we really need it??? + * Indicates the default phone id. * @hide */ public static final int DEFAULT_PHONE_INDEX = Integer.MAX_VALUE; - /** Indicates the caller wants the default slot id. NOT used remove? */ + /** Indicates the default slot index. */ /** @hide */ public static final int DEFAULT_SIM_SLOT_INDEX = Integer.MAX_VALUE; @@ -141,29 +139,10 @@ public class SubscriptionManager { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static final Uri CONTENT_URI = SimInfo.CONTENT_URI; - private static final String CACHE_KEY_DEFAULT_SUB_ID_PROPERTY = - "cache_key.telephony.get_default_sub_id"; - - private static final String CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY = - "cache_key.telephony.get_default_data_sub_id"; - - private static final String CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY = - "cache_key.telephony.get_default_sms_sub_id"; - - private static final String CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY = - "cache_key.telephony.get_active_data_sub_id"; - - private static final String CACHE_KEY_SLOT_INDEX_PROPERTY = - "cache_key.telephony.get_slot_index"; - /** The IPC cache key shared by all subscription manager service cacheable properties. */ private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY = "cache_key.telephony.subscription_manager_service"; - /** The temporarily cache key to indicate whether subscription manager service is enabled. */ - private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY = - "cache_key.telephony.subscription_manager_service_enabled"; - /** @hide */ public static final String GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME = "getSimSpecificSettings"; @@ -273,83 +252,41 @@ public class SubscriptionManager { } } - private static VoidPropertyInvalidatedCache<Integer> sDefaultSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId, - CACHE_KEY_DEFAULT_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSubIdCache = new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sDefaultDataSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId, - CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultDataSubIdCache = new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sDefaultSmsSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId, - CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSmsSubIdCache = new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sActiveDataSubIdCache = - new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId, - CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static VoidPropertyInvalidatedCache<Integer> sGetActiveDataSubscriptionIdCache = new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - private static IntegerPropertyInvalidatedCache<Integer> sSlotIndexCache = - new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex, - CACHE_KEY_SLOT_INDEX_PROPERTY, - INVALID_SIM_SLOT_INDEX); - private static IntegerPropertyInvalidatedCache<Integer> sGetSlotIndexCache = new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SIM_SLOT_INDEX); - private static IntegerPropertyInvalidatedCache<Integer> sSubIdCache = - new IntegerPropertyInvalidatedCache<>(ISub::getSubId, - CACHE_KEY_SLOT_INDEX_PROPERTY, - INVALID_SUBSCRIPTION_ID); - private static IntegerPropertyInvalidatedCache<Integer> sGetSubIdCache = new IntegerPropertyInvalidatedCache<>(ISub::getSubId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_SUBSCRIPTION_ID); - /** Cache depends on getDefaultSubId, so we use the defaultSubId cache key */ - private static IntegerPropertyInvalidatedCache<Integer> sPhoneIdCache = - new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId, - CACHE_KEY_DEFAULT_SUB_ID_PROPERTY, - INVALID_PHONE_INDEX); - private static IntegerPropertyInvalidatedCache<Integer> sGetPhoneIdCache = new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId, CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY, INVALID_PHONE_INDEX); - //TODO: Removed before U AOSP public release. - private static VoidPropertyInvalidatedCache<Boolean> sIsSubscriptionManagerServiceEnabled = - new VoidPropertyInvalidatedCache<>(ISub::isSubscriptionManagerServiceEnabled, - CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY, - false); - /** * Generates a content {@link Uri} used to receive updates on simInfo change * on the given subscriptionId @@ -1455,17 +1392,6 @@ public class SubscriptionManager { mContext = context; } - /** - * @return {@code true} if the new subscription manager service is used. This is temporary and - * will be removed before Android 14 release. - * - * @hide - */ - //TODO: Removed before U AOSP public release. - public static boolean isSubscriptionManagerServiceEnabled() { - return sIsSubscriptionManagerServiceEnabled.query(null); - } - private NetworkPolicyManager getNetworkPolicyManager() { return (NetworkPolicyManager) mContext .getSystemService(Context.NETWORK_POLICY_SERVICE); @@ -1520,7 +1446,7 @@ public class SubscriptionManager { + " listener=" + listener); } // We use the TelephonyRegistry as it runs in the system and thus is always - // available. Where as SubscriptionController could crash and not be available + // available. TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { @@ -1550,7 +1476,7 @@ public class SubscriptionManager { + " listener=" + listener); } // We use the TelephonyRegistry as it runs in the system and thus is always - // available where as SubscriptionController could crash and not be available + // available. TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { @@ -1608,7 +1534,7 @@ public class SubscriptionManager { } // We use the TelephonyRegistry as it runs in the system and thus is always - // available where as SubscriptionController could crash and not be available + // available. TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); if (telephonyRegistryManager != null) { @@ -2149,9 +2075,9 @@ public class SubscriptionManager { Log.e(LOG_TAG, "[removeSubscriptionInfoRecord]- ISub service is null"); return; } - int result = iSub.removeSubInfo(uniqueId, subscriptionType); - if (result < 0) { - Log.e(LOG_TAG, "Removal of subscription didn't succeed: error = " + result); + boolean result = iSub.removeSubInfo(uniqueId, subscriptionType); + if (!result) { + Log.e(LOG_TAG, "Removal of subscription didn't succeed"); } else { logd("successfully removed subscription"); } @@ -2236,8 +2162,7 @@ public class SubscriptionManager { * subscriptionId doesn't have an associated slot index. */ public static int getSlotIndex(int subscriptionId) { - if (isSubscriptionManagerServiceEnabled()) return sGetSlotIndexCache.query(subscriptionId); - return sSlotIndexCache.query(subscriptionId); + return sGetSlotIndexCache.query(subscriptionId); } /** @@ -2294,15 +2219,13 @@ public class SubscriptionManager { return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } - if (isSubscriptionManagerServiceEnabled()) return sGetSubIdCache.query(slotIndex); - return sSubIdCache.query(slotIndex); + return sGetSubIdCache.query(slotIndex); } /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public static int getPhoneId(int subId) { - if (isSubscriptionManagerServiceEnabled()) return sGetPhoneIdCache.query(subId); - return sPhoneIdCache.query(subId); + return sGetPhoneIdCache.query(subId); } private static void logd(String msg) { @@ -2323,8 +2246,7 @@ public class SubscriptionManager { * @return the "system" default subscription id. */ public static int getDefaultSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSubIdCache.query(null); - return sDefaultSubIdCache.query(null); + return sGetDefaultSubIdCache.query(null); } /** @@ -2412,8 +2334,7 @@ public class SubscriptionManager { * @return the default SMS subscription Id. */ public static int getDefaultSmsSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSmsSubIdCache.query(null); - return sDefaultSmsSubIdCache.query(null); + return sGetDefaultSmsSubIdCache.query(null); } /** @@ -2447,8 +2368,7 @@ public class SubscriptionManager { * @return the default data subscription Id. */ public static int getDefaultDataSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) return sGetDefaultDataSubIdCache.query(null); - return sDefaultDataSubIdCache.query(null); + return sGetDefaultDataSubIdCache.query(null); } /** @@ -3912,10 +3832,7 @@ public class SubscriptionManager { * @see TelephonyCallback.ActiveDataSubscriptionIdListener */ public static int getActiveDataSubscriptionId() { - if (isSubscriptionManagerServiceEnabled()) { - return sGetActiveDataSubscriptionIdCache.query(null); - } - return sActiveDataSubIdCache.query(null); + return sGetActiveDataSubscriptionIdCache.query(null); } /** @@ -3934,61 +3851,16 @@ public class SubscriptionManager { } /** @hide */ - public static void invalidateDefaultSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SUB_ID_PROPERTY); - } - - /** @hide */ - public static void invalidateDefaultDataSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY); - } - - /** @hide */ - public static void invalidateDefaultSmsSubIdCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY); - } - - /** @hide */ - public static void invalidateActiveDataSubIdCaches() { - if (isSubscriptionManagerServiceEnabled()) { - PropertyInvalidatedCache.invalidateCache( - CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY); - } else { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY); - } - } - - /** @hide */ - public static void invalidateSlotIndexCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SLOT_INDEX_PROPERTY); - } - - /** @hide */ public static void invalidateSubscriptionManagerServiceCaches() { PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY); } - /** @hide */ - //TODO: Removed before U AOSP public release. - public static void invalidateSubscriptionManagerServiceEnabledCaches() { - PropertyInvalidatedCache.invalidateCache( - CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_ENABLED_PROPERTY); - } - /** * Allows a test process to disable client-side caching operations. * * @hide */ public static void disableCaching() { - sDefaultSubIdCache.disableLocal(); - sDefaultDataSubIdCache.disableLocal(); - sActiveDataSubIdCache.disableLocal(); - sDefaultSmsSubIdCache.disableLocal(); - sSlotIndexCache.disableLocal(); - sSubIdCache.disableLocal(); - sPhoneIdCache.disableLocal(); - sGetDefaultSubIdCache.disableLocal(); sGetDefaultDataSubIdCache.disableLocal(); sGetActiveDataSubscriptionIdCache.disableLocal(); @@ -3996,8 +3868,6 @@ public class SubscriptionManager { sGetSlotIndexCache.disableLocal(); sGetSubIdCache.disableLocal(); sGetPhoneIdCache.disableLocal(); - - sIsSubscriptionManagerServiceEnabled.disableLocal(); } /** @@ -4005,14 +3875,6 @@ public class SubscriptionManager { * * @hide */ public static void clearCaches() { - sDefaultSubIdCache.clear(); - sDefaultDataSubIdCache.clear(); - sActiveDataSubIdCache.clear(); - sDefaultSmsSubIdCache.clear(); - sSlotIndexCache.clear(); - sSubIdCache.clear(); - sPhoneIdCache.clear(); - sGetDefaultSubIdCache.clear(); sGetDefaultDataSubIdCache.clear(); sGetActiveDataSubscriptionIdCache.clear(); @@ -4020,8 +3882,6 @@ public class SubscriptionManager { sGetSlotIndexCache.clear(); sGetSubIdCache.clear(); sGetPhoneIdCache.clear(); - - sIsSubscriptionManagerServiceEnabled.clear(); } /** diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 6a5380ddb36e..21a6b447d6a4 100644 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -129,9 +129,9 @@ interface ISub { * @param uniqueId This is the unique identifier for the subscription within the specific * subscription type. * @param subscriptionType the type of subscription to be removed - * @return 0 if success, < 0 on error. + * @return true if success, false on error. */ - int removeSubInfo(String uniqueId, int subscriptionType); + boolean removeSubInfo(String uniqueId, int subscriptionType); /** * Set SIM icon tint color by simInfo index @@ -260,7 +260,7 @@ interface ISub { int[] getActiveSubIdList(boolean visibleOnly); - int setSubscriptionProperty(int subId, String propKey, String propValue); + void setSubscriptionProperty(int subId, String propKey, String propValue); String getSubscriptionProperty(int subId, String propKey, String callingPackage, String callingFeatureId); @@ -353,13 +353,6 @@ interface ISub { */ List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(in UserHandle userHandle); - /** - * @return {@code true} if using SubscriptionManagerService instead of - * SubscriptionController. - */ - //TODO: Removed before U AOSP public release. - boolean isSubscriptionManagerServiceEnabled(); - /** * Called during setup wizard restore flow to attempt to restore the backed up sim-specific * configs to device for all existing SIMs in the subscription database diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt index 18e49fe1078f..ae9ca8007dc8 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenCameraOnDoubleClickPowerButton.kt @@ -102,7 +102,7 @@ class OpenCameraOnDoubleClickPowerButton(flicker: FlickerTest) : @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered() - @Postsubmit + @Ignore("Not applicable to this CUJ. App is full screen at the end") @Test override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd() @@ -127,11 +127,11 @@ class OpenCameraOnDoubleClickPowerButton(flicker: FlickerTest) : @Test override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible() - @Postsubmit + @Ignore("Not applicable to this CUJ. App is full screen at the end") @Test override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd() - @Postsubmit + @Ignore("Not applicable to this CUJ. App is full screen at the end") @Test override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible() @@ -145,7 +145,7 @@ class OpenCameraOnDoubleClickPowerButton(flicker: FlickerTest) : override fun visibleWindowsShownMoreThanOneConsecutiveEntry() = super.visibleWindowsShownMoreThanOneConsecutiveEntry() - @Postsubmit + @Ignore("Not applicable to this CUJ. App is full screen at the end") @Test override fun navBarWindowIsVisibleAtStartAndEnd() { super.navBarWindowIsVisibleAtStartAndEnd() |