Merge "Add preinstalled-packages-asl-files.xml config file" into udc-dev
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 63da0a2..d375760 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2916,6 +2916,14 @@
}
}
+ 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 74a69a6..307f306 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -12349,7 +12349,9 @@
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 @@
}
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/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 048289f..960d10a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2628,6 +2628,15 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2699,6 +2708,15 @@
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 3e1c5bb..8cc4cdb 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -316,6 +316,15 @@
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Parsed package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -368,19 +377,27 @@
return input.success(targetVers);
}
+ // If it's a pre-release SDK and the codename matches this platform, it
+ // definitely targets this SDK.
+ if (matchTargetCode(platformSdkCodenames, targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Parsed package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
try {
if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
} catch (IllegalArgumentException e) {
- // isAtMost() throws it when encountering an older SDK codename
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, e.getMessage());
- }
-
- // If it's a pre-release SDK and the codename matches this platform, it
- // definitely targets this SDK.
- if (matchTargetCode(platformSdkCodenames, targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
}
// Otherwise, we're looking at an incompatible pre-release SDK.
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index bc0e35d..511cb2d 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -43,7 +43,7 @@
* Creates an empty IntArray with the default initial capacity.
*/
public IntArray() {
- this(10);
+ this(0);
}
/**
diff --git a/core/java/android/util/LongArray.java b/core/java/android/util/LongArray.java
index 53dddeb..9f269ed 100644
--- a/core/java/android/util/LongArray.java
+++ b/core/java/android/util/LongArray.java
@@ -48,7 +48,7 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public LongArray() {
- this(10);
+ this(0);
}
/**
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
index e0ee683..e44f436 100644
--- a/core/java/android/window/BackNavigationInfo.java
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -94,26 +94,29 @@
@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 @@
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 @@
dest.writeTypedObject(mOnBackNavigationDone, flags);
dest.writeStrongInterface(mOnBackInvokedCallback);
dest.writeBoolean(mPrepareRemoteAnimation);
+ dest.writeBoolean(mAnimationCallback);
dest.writeTypedObject(mCustomAnimationInfo, flags);
}
@@ -159,7 +164,7 @@
}
/**
- * 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 @@
}
/**
+ * 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 @@
+ "mType=" + typeToString(mType) + " (" + mType + ")"
+ ", mOnBackNavigationDone=" + mOnBackNavigationDone
+ ", mOnBackInvokedCallback=" + mOnBackInvokedCallback
+ + ", mPrepareRemoteAnimation=" + mPrepareRemoteAnimation
+ + ", mAnimationCallback=" + mAnimationCallback
+ ", mCustomizeAnimationInfo=" + mCustomAnimationInfo
+ '}';
}
@@ -343,6 +358,7 @@
private IOnBackInvokedCallback mOnBackInvokedCallback = null;
private boolean mPrepareRemoteAnimation;
private CustomAnimationInfo mCustomAnimationInfo;
+ private boolean mAnimationCallback = false;
/**
* @see BackNavigationInfo#getType()
@@ -387,6 +403,7 @@
mCustomAnimationInfo.mWindowAnimations = windowAnimations;
return this;
}
+
/**
* Set resources ids for customize activity animation.
*/
@@ -402,12 +419,21 @@
}
/**
+ * @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 6480da3..bb5fe96 100644
--- a/core/java/android/window/OnBackInvokedCallbackInfo.java
+++ b/core/java/android/window/OnBackInvokedCallbackInfo.java
@@ -28,15 +28,20 @@
@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 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 @@
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 8066f50..51382a4 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -193,7 +193,10 @@
? ((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/config/sysui/SystemUiSystemPropertiesFlags.java b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
index 2b08a55..853fe2f 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiSystemPropertiesFlags.java
@@ -77,6 +77,10 @@
/** Gating the removal of sorting-notifications-by-interruptiveness. */
public static final Flag NO_SORT_BY_INTERRUPTIVENESS =
devFlag("persist.sysui.notification.no_sort_by_interruptiveness");
+
+ /** Gating the logging of DND state change events. */
+ public static final Flag LOG_DND_STATE_EVENTS =
+ devFlag("persist.sysui.notification.log_dnd_state_events");
}
//// == End of flags. Everything below this line is the implementation. == ////
diff --git a/core/java/com/android/internal/inputmethod/InputMethodDebug.java b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
index 1b4afd6..bb8bdf5 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodDebug.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodDebug.java
@@ -255,6 +255,12 @@
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 ec9184b..6e9cd44 100644
--- a/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
+++ b/core/java/com/android/internal/inputmethod/SoftInputShowHideReason.java
@@ -65,7 +65,10 @@
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 @@
*/
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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e62477f..f6c9fab 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1036,9 +1036,9 @@
android:protectionLevel="dangerous" />
<!-- @SystemApi @hide Allows an application to communicate over satellite.
- Only granted if the application is a system app. -->
+ Only granted if the application is a system app or privileged app. -->
<permission android:name="android.permission.SATELLITE_COMMUNICATION"
- android:protectionLevel="internal|role" />
+ android:protectionLevel="role|signature|privileged" />
<!-- ====================================================================== -->
<!-- Permissions for accessing external storage -->
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index c7395dd..a57a051 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 b0932d6..c6462f1 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5897,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
new file mode 100644
index 0000000..3754072
--- /dev/null
+++ b/core/tests/coretests/res/drawable-nodpi/test_too_big.png
Binary files differ
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index a53d57f..a102b3e 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -1127,6 +1127,31 @@
mActivityRule.runOnUiThread(() -> {});
}
+ @Test
+ public void restartValueAnimator() throws Throwable {
+ CountDownLatch latch = new CountDownLatch(1);
+ ValueAnimator.AnimatorUpdateListener listener = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ if (((float) animation.getAnimatedValue()) != A1_START_VALUE) {
+ latch.countDown();
+ }
+ }
+ };
+ a1.addUpdateListener(listener);
+
+ mActivityRule.runOnUiThread(() -> {
+ a1.start();
+ });
+
+ // wait for a change in the value
+ assertTrue(latch.await(2, TimeUnit.SECONDS));
+
+ mActivityRule.runOnUiThread(() -> {
+ a1.start();
+ assertEquals(A1_START_VALUE, a1.getAnimatedValue());
+ });
+ }
class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
boolean wasRunning = false;
long firstRunningFrameTime = -1;
diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java
index 75390a2..5d92296 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 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 @@
}
}
+ 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/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 8ece337..40cb7f2 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -518,6 +518,8 @@
<permission name="android.permission.LOG_FOREGROUND_RESOURCE_USE"/>
<!-- Permission required for CTS test - CtsVoiceInteractionTestCases -->
<permission name="android.permission.SOUND_TRIGGER_RUN_IN_BATTERY_SAVER"/>
+ <!-- Permission required for CTS test - SatelliteManagerTest -->
+ <permission name="android.permission.SATELLITE_COMMUNICATION"/>
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index a76d74e..708feeb 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -35,6 +35,7 @@
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 @@
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 @@
}
/**
+ * 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 @@
}
}
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 @@
}
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 dcce4698..ab64f9e 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/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 47d3a5c..dc27ceb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -20,6 +20,9 @@
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
@@ -37,7 +40,9 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.MathUtils;
import android.util.SparseArray;
import android.view.IRemoteAnimationRunner;
import android.view.InputDevice;
@@ -56,6 +61,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.view.AppearanceRegion;
+import com.android.wm.shell.animation.FlingAnimationUtils;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
@@ -80,6 +86,17 @@
public static boolean IS_U_ANIMATION_ENABLED =
SystemProperties.getInt("persist.wm.debug.predictive_back_anim",
SETTING_VALUE_ON) == SETTING_VALUE_ON;
+
+ public static final float FLING_MAX_LENGTH_SECONDS = 0.1f; // 100ms
+ public static final float FLING_SPEED_UP_FACTOR = 0.6f;
+
+ /**
+ * The maximum additional progress in case of fling gesture.
+ * The end animation starts after the user lifts the finger from the screen, we continue to
+ * fire {@link BackEvent}s until the velocity reaches 0.
+ */
+ private static final float MAX_FLING_PROGRESS = 0.3f; /* 30% of the screen */
+
/** Predictive back animation developer option */
private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
/**
@@ -96,6 +113,7 @@
private boolean mShouldStartOnNextMoveEvent = false;
/** @see #setTriggerBack(boolean) */
private boolean mTriggerBack;
+ private FlingAnimationUtils mFlingAnimationUtils;
@Nullable
private BackNavigationInfo mBackNavigationInfo;
@@ -174,6 +192,11 @@
mBgHandler = bgHandler;
shellInit.addInitCallback(this::onInit, this);
mAnimationBackground = backAnimationBackground;
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ mFlingAnimationUtils = new FlingAnimationUtils.Builder(displayMetrics)
+ .setMaxLengthSeconds(FLING_MAX_LENGTH_SECONDS)
+ .setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
+ .build();
}
@VisibleForTesting
@@ -465,6 +488,78 @@
}
}
+
+ /**
+ * Allows us to manage the fling gesture, it smoothly animates the current progress value to
+ * the final position, calculated based on the current velocity.
+ *
+ * @param callback the callback to be invoked when the animation ends.
+ */
+ private void dispatchOrAnimateOnBackInvoked(IOnBackInvokedCallback callback) {
+ if (callback == null) {
+ return;
+ }
+
+ boolean animationStarted = false;
+
+ if (mBackNavigationInfo != null && mBackNavigationInfo.isAnimationCallback()) {
+
+ final BackMotionEvent backMotionEvent = mTouchTracker.createProgressEvent();
+ if (backMotionEvent != null) {
+ // Constraints - absolute values
+ float minVelocity = mFlingAnimationUtils.getMinVelocityPxPerSecond();
+ float maxVelocity = mFlingAnimationUtils.getHighVelocityPxPerSecond();
+ float maxX = mTouchTracker.getMaxX(); // px
+ float maxFlingDistance = maxX * MAX_FLING_PROGRESS; // px
+
+ // Current state
+ float currentX = backMotionEvent.getTouchX();
+ float velocity = MathUtils.constrain(backMotionEvent.getVelocityX(),
+ -maxVelocity, maxVelocity);
+
+ // Target state
+ float animationFaction = velocity / maxVelocity; // value between -1 and 1
+ float flingDistance = animationFaction * maxFlingDistance; // px
+ float endX = MathUtils.constrain(currentX + flingDistance, 0f, maxX);
+
+ if (!Float.isNaN(endX)
+ && currentX != endX
+ && Math.abs(velocity) >= minVelocity) {
+ ValueAnimator animator = ValueAnimator.ofFloat(currentX, endX);
+
+ mFlingAnimationUtils.apply(
+ /* animator = */ animator,
+ /* currValue = */ currentX,
+ /* endValue = */ endX,
+ /* velocity = */ velocity,
+ /* maxDistance = */ maxFlingDistance
+ );
+
+ animator.addUpdateListener(animation -> {
+ Float animatedValue = (Float) animation.getAnimatedValue();
+ float progress = mTouchTracker.getProgress(animatedValue);
+ final BackMotionEvent backEvent = mTouchTracker
+ .createProgressEvent(progress);
+ dispatchOnBackProgressed(mActiveCallback, backEvent);
+ });
+
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ dispatchOnBackInvoked(callback);
+ }
+ });
+ animator.start();
+ animationStarted = true;
+ }
+ }
+ }
+
+ if (!animationStarted) {
+ dispatchOnBackInvoked(callback);
+ }
+ }
+
private void dispatchOnBackInvoked(IOnBackInvokedCallback callback) {
if (callback == null) {
return;
@@ -530,7 +625,7 @@
if (mBackNavigationInfo != null) {
final IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
if (mTriggerBack) {
- dispatchOnBackInvoked(callback);
+ dispatchOrAnimateOnBackInvoked(callback);
} else {
dispatchOnBackCancelled(callback);
}
@@ -605,7 +700,7 @@
// The next callback should be {@link #onBackAnimationFinished}.
if (mTriggerBack) {
- dispatchOnBackInvoked(mActiveCallback);
+ dispatchOrAnimateOnBackInvoked(mActiveCallback);
} else {
dispatchOnBackCancelled(mActiveCallback);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 904574b..7a00f5b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -16,7 +16,10 @@
package com.android.wm.shell.back;
+import android.annotation.FloatRange;
import android.os.SystemProperties;
+import android.util.MathUtils;
+import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.window.BackEvent;
import android.window.BackMotionEvent;
@@ -99,28 +102,42 @@
}
BackMotionEvent createProgressEvent() {
- float progressThreshold = PROGRESS_THRESHOLD >= 0
- ? PROGRESS_THRESHOLD : mProgressThreshold;
- progressThreshold = progressThreshold == 0 ? 1 : progressThreshold;
float progress = 0;
// Progress is always 0 when back is cancelled and not restarted.
if (!mCancelled) {
- // If back is committed, progress is the distance between the last and first touch
- // point, divided by the max drag distance. Otherwise, it's the distance between
- // the last touch point and the starting threshold, divided by max drag distance.
- // The starting threshold is initially the first touch location, and updated to
- // the location everytime back is restarted after being cancelled.
- float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
- float deltaX = Math.max(
- mSwipeEdge == BackEvent.EDGE_LEFT
- ? mLatestTouchX - startX
- : startX - mLatestTouchX,
- 0);
- progress = Math.min(Math.max(deltaX / progressThreshold, 0), 1);
+ progress = getProgress(mLatestTouchX);
}
return createProgressEvent(progress);
}
+ /**
+ * Progress value computed from the touch position.
+ *
+ * @param touchX the X touch position of the {@link MotionEvent}.
+ * @return progress value
+ */
+ @FloatRange(from = 0.0, to = 1.0)
+ float getProgress(float touchX) {
+ // If back is committed, progress is the distance between the last and first touch
+ // point, divided by the max drag distance. Otherwise, it's the distance between
+ // the last touch point and the starting threshold, divided by max drag distance.
+ // The starting threshold is initially the first touch location, and updated to
+ // the location everytime back is restarted after being cancelled.
+ float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
+ float deltaX = Math.abs(startX - touchX);
+ float maxX = getMaxX();
+ maxX = maxX == 0 ? 1 : maxX;
+ return MathUtils.constrain(deltaX / maxX, 0, 1);
+ }
+
+ /**
+ * Maximum X value (in pixels).
+ * Progress is considered to be completed (1f) when this limit is exceeded.
+ */
+ float getMaxX() {
+ return PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
+ }
+
BackMotionEvent createProgressEvent(float progress) {
return new BackMotionEvent(
/* touchX = */ mLatestTouchX,
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 713ace6..b6216b3 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 @@
* 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;
}
@@ -1532,6 +1532,9 @@
if (snapshotSurface != null) {
mSyncTransactionQueue.queue(wct);
mSyncTransactionQueue.runInSync(t -> {
+ // reset the pinch gesture
+ maybePerformFinishResizeCallback();
+
// Scale the snapshot from its pre-resize bounds to the post-resize bounds.
mSurfaceTransactionHelper.scale(t, snapshotSurface, preResizeBounds,
snapshotDest);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
index 222307f..5f6b3fe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipAction.java
@@ -31,6 +31,12 @@
abstract class TvPipAction {
+ /**
+ * Extras key for adding a boolean to the {@link Notification.Action} to differentiate custom
+ * from system actions, most importantly to identify custom close actions.
+ **/
+ public static final String EXTRA_IS_PIP_CUSTOM_ACTION = "EXTRA_IS_PIP_CUSTOM_ACTION";
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"ACTION_"}, value = {
ACTION_FULLSCREEN,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
index bca27a5..977aad4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipCustomAction.java
@@ -86,7 +86,7 @@
Bundle extras = new Bundle();
extras.putCharSequence(Notification.EXTRA_PICTURE_CONTENT_DESCRIPTION,
mRemoteAction.getContentDescription());
- extras.putBoolean(Notification.EXTRA_CONTAINS_CUSTOM_VIEW, true);
+ extras.putBoolean(TvPipAction.EXTRA_IS_PIP_CUSTOM_ACTION, true);
builder.addExtras(extras);
builder.setSemanticAction(isCloseAction()
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 6eef225..f86f987 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 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 @@
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 @@
.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.onCloseEduText();
+ mListener.onCloseEduTextAnimationStart();
+ }
+
+ public void onCloseEduTextAnimationEnd() {
+ setVisibility(GONE);
+ mListener.onCloseEduTextAnimationEnd();
}
/**
@@ -270,11 +296,8 @@
* 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 6eb719b..d076418 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 @@
* 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 @@
private final View mDimLayer;
private final TvPipMenuEduTextDrawer mEduTextDrawer;
+ private final ViewGroup mEduTextContainer;
private final int mPipMenuOuterSpace;
private final int mPipMenuBorderWidth;
@@ -139,9 +141,9 @@
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 @@
* 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 @@
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 @@
}
@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 @@
}
}
- interface Listener extends TvPipMenuEduTextDrawer.Listener {
+ interface Listener {
void onBackPress();
@@ -573,5 +588,11 @@
* 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 c9b3a1a..c4a0e9c 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 @@
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 a8b209f..b554872 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.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 @@
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 @@
mixer.setRecentsTransition(transition);
}
if (transition == null) {
- controller.cancel();
+ controller.cancel("startRecentsTransition");
return;
}
controller.setTransition(transition);
@@ -127,6 +131,7 @@
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 @@
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 @@
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 @@
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 @@
}
}
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 @@
}
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 @@
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 @@
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 @@
} 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 @@
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 @@
&& 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 @@
// 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 @@
+ " 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 @@
// 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 @@
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 @@
+ foundRecentsClosing);
if (foundRecentsClosing) {
mWillFinishToHome = false;
- cancel(false /* toHome */);
+ cancel(false /* toHome */, "didn't merge");
}
return;
}
@@ -549,6 +594,8 @@
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 @@
@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 @@
@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 @@
@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 @@
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 @@
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 @@
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 @@
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 @@
*/
@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/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index bdb7d44..08b0bf7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -429,6 +429,7 @@
&& (change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) {
t.setAlpha(leash, 0.f);
}
+ finishT.show(leash);
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
finishT.hide(leash);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index d95c7a4..3d8bd38 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -135,12 +135,15 @@
mShellExecutor.flushAll();
}
- private void createNavigationInfo(int backType, boolean enableAnimation) {
+ private void createNavigationInfo(int backType,
+ boolean enableAnimation,
+ boolean isAnimationCallback) {
BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder()
.setType(backType)
.setOnBackNavigationDone(new RemoteCallback((bundle) -> {}))
.setOnBackInvokedCallback(mAppCallback)
- .setPrepareRemoteAnimation(enableAnimation);
+ .setPrepareRemoteAnimation(enableAnimation)
+ .setAnimationCallback(isAnimationCallback);
createNavigationInfo(builder);
}
@@ -218,7 +221,9 @@
@Test
public void backToHome_dispatchesEvents() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
@@ -240,6 +245,32 @@
}
@Test
+ public void backToHomeWithAnimationCallback_dispatchesEvents() throws RemoteException {
+ registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ true);
+
+ doMotionEvent(MotionEvent.ACTION_DOWN, 0);
+
+ // Check that back start and progress is dispatched when first move.
+ doMotionEvent(MotionEvent.ACTION_MOVE, 100, 3000);
+
+ simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+
+ verify(mAnimatorCallback).onBackStarted(any(BackMotionEvent.class));
+ verify(mBackAnimationRunner).onAnimationStart(anyInt(), any(), any(), any(), any());
+ ArgumentCaptor<BackMotionEvent> backEventCaptor =
+ ArgumentCaptor.forClass(BackMotionEvent.class);
+ verify(mAnimatorCallback, atLeastOnce()).onBackProgressed(backEventCaptor.capture());
+
+ // Check that back invocation is dispatched.
+ mController.setTriggerBack(true); // Fake trigger back
+ doMotionEvent(MotionEvent.ACTION_UP, 0);
+ verify(mAnimatorCallback).onBackInvoked();
+ }
+
+ @Test
public void animationDisabledFromSettings() throws RemoteException {
// Toggle the setting off
Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0");
@@ -254,7 +285,9 @@
ArgumentCaptor<BackMotionEvent> backEventCaptor =
ArgumentCaptor.forClass(BackMotionEvent.class);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, false);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ false,
+ /* isAnimationCallback = */ false);
triggerBackGesture();
releaseBackGesture();
@@ -271,7 +304,9 @@
@Test
public void ignoresGesture_transitionInProgress() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
triggerBackGesture();
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
@@ -309,7 +344,9 @@
@Test
public void acceptsGesture_transitionTimeout() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
// In case it is still running in animation.
doNothing().when(mAnimatorCallback).onBackInvoked();
@@ -334,7 +371,9 @@
public void cancelBackInvokeWhenLostFocus() throws RemoteException {
registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
- createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, true);
+ createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
// Check that back start and progress is dispatched when first move.
@@ -454,7 +493,9 @@
mController.registerAnimation(type, animationRunner);
- createNavigationInfo(type, true);
+ createNavigationInfo(type,
+ /* enableAnimation = */ true,
+ /* isAnimationCallback = */ false);
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
@@ -473,11 +514,15 @@
}
private void doMotionEvent(int actionDown, int coordinate) {
+ doMotionEvent(actionDown, coordinate, 0);
+ }
+
+ private void doMotionEvent(int actionDown, int coordinate, float velocity) {
mController.onMotionEvent(
/* touchX */ coordinate,
/* touchY */ coordinate,
- /* velocityX = */ 0,
- /* velocityY = */ 0,
+ /* velocityX = */ velocity,
+ /* velocityY = */ velocity,
/* keyAction */ actionDown,
/* swipeEdge */ BackEvent.EDGE_LEFT);
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
index 4d2bb4c..8b74d76 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt
@@ -18,6 +18,7 @@
import android.app.Activity
import android.os.IBinder
+import android.text.TextUtils
import android.util.Log
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
@@ -67,9 +68,9 @@
var uiMetrics: UIMetrics = UIMetrics()
- init{
+ init {
uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_INIT,
- credManRepo.requestInfo?.appPackageName)
+ credManRepo.requestInfo?.appPackageName)
}
/**************************************************************************/
@@ -100,7 +101,7 @@
if (this.credManRepo.requestInfo?.token != credManRepo.requestInfo?.token) {
this.uiMetrics.resetInstanceId()
this.uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_NEW_REQUEST,
- credManRepo.requestInfo?.appPackageName)
+ credManRepo.requestInfo?.appPackageName)
}
}
@@ -174,7 +175,7 @@
private fun onInternalError() {
Log.w(Constants.LOG_TAG, "UI closed due to illegal internal state")
this.uiMetrics.logNormal(LifecycleEvent.CREDMAN_ACTIVITY_INTERNAL_ERROR,
- credManRepo.requestInfo?.appPackageName)
+ credManRepo.requestInfo?.appPackageName)
credManRepo.onParsingFailureCancel()
uiState = uiState.copy(dialogState = DialogState.COMPLETE)
}
@@ -314,10 +315,11 @@
uiState = uiState.copy(
createCredentialUiState = uiState.createCredentialUiState?.copy(
currentScreenState =
- if (activeEntry.activeProvider.id ==
- userConfigRepo.getDefaultProviderId())
+ if (activeEntry.activeProvider.id == userConfigRepo.getDefaultProviderId() ||
+ !TextUtils.isEmpty(uiState.createCredentialUiState?.requestDisplayInfo
+ ?.appPreferredDefaultProviderId))
CreateScreenState.CREATION_OPTION_SELECTION
- else CreateScreenState.MORE_OPTIONS_ROW_INTRO,
+ else CreateScreenState.DEFAULT_PROVIDER_CONFIRMATION,
activeEntry = activeEntry
)
)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 96010cc..9d871ed 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -139,12 +139,12 @@
onRemoteEntrySelected = viewModel::createFlowOnEntrySelected,
onLog = { viewModel.logUiEvent(it) },
)
- CreateScreenState.MORE_OPTIONS_ROW_INTRO -> {
+ CreateScreenState.DEFAULT_PROVIDER_CONFIRMATION -> {
if (createCredentialUiState.activeEntry == null) {
viewModel.onIllegalUiState("Expect active entry to be non-null" +
" upon default provider dialog.")
} else {
- MoreOptionsRowIntroCard(
+ DefaultProviderConfirmationCard(
selectedEntry = createCredentialUiState.activeEntry,
onIllegalScreenState = viewModel::onIllegalUiState,
onChangeDefaultSelected =
@@ -420,7 +420,7 @@
}
@Composable
-fun MoreOptionsRowIntroCard(
+fun DefaultProviderConfirmationCard(
selectedEntry: ActiveEntry,
onIllegalScreenState: (String) -> Unit,
onChangeDefaultSelected: () -> Unit,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 12bb629..225dbf2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -126,6 +126,6 @@
PROVIDER_SELECTION,
CREATION_OPTION_SELECTION,
MORE_OPTIONS_SELECTION,
- MORE_OPTIONS_ROW_INTRO,
+ DEFAULT_PROVIDER_CONFIRMATION,
EXTERNAL_ONLY_SELECTION,
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
index 96ea5b4..27aade5 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java
@@ -19,6 +19,7 @@
import android.Manifest;
import android.accessibilityservice.AccessibilityButtonController;
import android.accessibilityservice.AccessibilityService;
+import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -82,6 +83,9 @@
// TODO(b/136716947): Support multi-display once a11y framework side is ready.
private DisplayManager mDisplayManager;
+
+ private KeyguardManager mKeyguardManager;
+
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
int mRotation;
@@ -114,7 +118,7 @@
private final BroadcastReceiver mToggleMenuReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mA11yMenuLayout.toggleVisibility();
+ toggleVisibility();
}
};
@@ -159,10 +163,7 @@
*/
@Override
public void onClicked(AccessibilityButtonController controller) {
- if (SystemClock.uptimeMillis() - mLastTimeTouchedOutside
- > BUTTON_CLICK_TIMEOUT) {
- mA11yMenuLayout.toggleVisibility();
- }
+ toggleVisibility();
}
/**
@@ -209,6 +210,7 @@
mDisplayManager = getSystemService(DisplayManager.class);
mDisplayManager.registerDisplayListener(mDisplayListener, null);
mAudioManager = getSystemService(AudioManager.class);
+ mKeyguardManager = getSystemService(KeyguardManager.class);
sInitialized = true;
}
@@ -379,4 +381,12 @@
}
return false;
}
+
+ private void toggleVisibility() {
+ boolean locked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
+ if (!locked && SystemClock.uptimeMillis() - mLastTimeTouchedOutside
+ > BUTTON_CLICK_TIMEOUT) {
+ mA11yMenuLayout.toggleVisibility();
+ }
+ }
}
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
index 7277392..9d1af0e 100644
--- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
+++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java
@@ -33,6 +33,7 @@
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Instrumentation;
+import android.app.KeyguardManager;
import android.app.UiAutomation;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -44,6 +45,7 @@
import android.os.PowerManager;
import android.provider.Settings;
import android.util.Log;
+import android.view.Display;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -69,15 +71,19 @@
private static final int CLICK_ID = AccessibilityNodeInfo.ACTION_CLICK;
private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5;
- private static final int TIMEOUT_UI_CHANGE_S = 10;
+ private static final int TIMEOUT_UI_CHANGE_S = 5;
private static final int NO_GLOBAL_ACTION = -1;
private static final String INPUT_KEYEVENT_KEYCODE_BACK = "input keyevent KEYCODE_BACK";
+ private static final String TEST_PIN = "1234";
private static Instrumentation sInstrumentation;
private static UiAutomation sUiAutomation;
private static AtomicInteger sLastGlobalAction;
private static AccessibilityManager sAccessibilityManager;
+ private static PowerManager sPowerManager;
+ private static KeyguardManager sKeyguardManager;
+ private static DisplayManager sDisplayManager;
@BeforeClass
public static void classSetup() throws Throwable {
@@ -85,8 +91,14 @@
sInstrumentation = InstrumentationRegistry.getInstrumentation();
sUiAutomation = sInstrumentation.getUiAutomation(
UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+ sUiAutomation.adoptShellPermissionIdentity(
+ UiAutomation.ALL_PERMISSIONS.toArray(new String[0]));
+
final Context context = sInstrumentation.getTargetContext();
sAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ sPowerManager = context.getSystemService(PowerManager.class);
+ sKeyguardManager = context.getSystemService(KeyguardManager.class);
+ sDisplayManager = context.getSystemService(DisplayManager.class);
// Disable all a11yServices if any are active.
if (!sAccessibilityManager.getEnabledAccessibilityServiceList(
@@ -123,12 +135,16 @@
@AfterClass
public static void classTeardown() throws Throwable {
+ clearPin();
Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, "");
}
@Before
public void setup() throws Throwable {
+ clearPin();
+ wakeUpScreen();
+ sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU");
openMenu();
}
@@ -138,11 +154,43 @@
sLastGlobalAction.set(NO_GLOBAL_ACTION);
}
+ private static void clearPin() throws Throwable {
+ sUiAutomation.executeShellCommand("locksettings clear --old " + TEST_PIN);
+ TestUtils.waitUntil("Device did not register as unlocked & insecure.",
+ TIMEOUT_SERVICE_STATUS_CHANGE_S,
+ () -> !sKeyguardManager.isDeviceSecure());
+ }
+
+ private static void setPin() throws Throwable {
+ sUiAutomation.executeShellCommand("locksettings set-pin " + TEST_PIN);
+ TestUtils.waitUntil("Device did not recognize as locked & secure.",
+ TIMEOUT_SERVICE_STATUS_CHANGE_S,
+ () -> sKeyguardManager.isDeviceSecure());
+ }
+
private static boolean isMenuVisible() {
AccessibilityNodeInfo root = sUiAutomation.getRootInActiveWindow();
return root != null && root.getPackageName().toString().equals(PACKAGE_NAME);
}
+ private static void wakeUpScreen() throws Throwable {
+ sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
+ TestUtils.waitUntil("Screen did not wake up.",
+ TIMEOUT_UI_CHANGE_S,
+ () -> sPowerManager.isInteractive());
+ }
+
+ private static void closeScreen() throws Throwable {
+ Display display = sDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ setPin();
+ sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN);
+ TestUtils.waitUntil("Screen did not close.",
+ TIMEOUT_UI_CHANGE_S,
+ () -> !sPowerManager.isInteractive()
+ && display.getState() == Display.STATE_OFF
+ );
+ }
+
private static void openMenu() throws Throwable {
Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU);
sInstrumentation.getContext().sendBroadcast(intent);
@@ -381,23 +429,24 @@
@Test
public void testOnScreenLock_closesMenu() throws Throwable {
- openMenu();
- Context context = sInstrumentation.getTargetContext();
- PowerManager powerManager = context.getSystemService(PowerManager.class);
-
- assertThat(powerManager).isNotNull();
- assertThat(powerManager.isInteractive()).isTrue();
-
- sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN);
- TestUtils.waitUntil("Screen did not become locked",
- TIMEOUT_UI_CHANGE_S,
- () -> !powerManager.isInteractive());
-
- sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
- TestUtils.waitUntil("Screen did not wake up",
- TIMEOUT_UI_CHANGE_S,
- () -> powerManager.isInteractive());
+ closeScreen();
+ wakeUpScreen();
assertThat(isMenuVisible()).isFalse();
}
+
+ @Test
+ public void testOnScreenLock_cannotOpenMenu() throws Throwable {
+ closeScreen();
+ wakeUpScreen();
+
+ boolean timedOut = false;
+ try {
+ openMenu();
+ } catch (AssertionError e) {
+ // Expected
+ timedOut = true;
+ }
+ assertThat(timedOut).isTrue();
+ }
}
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 1786d13..91c0a5b 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 @@
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 b5b6037..7e56f4b 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 @@
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 ef5ad43..b899127 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 @@
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 @@
*
* 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/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 204bac8..450c616 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -316,9 +316,9 @@
),
CLOCK_VIBRANT(
CoreSpec(
- a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
- a2 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
- a3 = TonalSpec(HueAdd(60.0), ChromaBound(ChromaSource(), 30.0, Chroma.MAX_VALUE)),
+ a1 = TonalSpec(HueSource(), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
+ a2 = TonalSpec(HueAdd(20.0), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
+ a3 = TonalSpec(HueAdd(60.0), ChromaBound(ChromaSource(), 70.0, Chroma.MAX_VALUE)),
// Not Used
n1 = TonalSpec(HueSource(), ChromaConstant(0.0)),
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
index 5b0e290..461d390 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -41,10 +41,10 @@
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 @@
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 @@
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 @@
"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 b8c0ccb..f2685c5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFingerprintListenModel.kt
@@ -41,11 +41,11 @@
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 @@
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 @@
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 @@
"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 76e051e..693268d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -178,6 +178,7 @@
@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 ea04376..10c08bc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -297,7 +297,7 @@
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 @@
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 @@
|| (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 @@
!mSwitchingUser
&& !fingerprintDisabledForUser
&& (!mKeyguardGoingAway || !mDeviceInteractive)
- && mIsPrimaryUser
+ && mIsSystemUser
&& biometricEnabledForUser
&& !isUserInLockdown(user);
final boolean strongerAuthRequired = !isUnlockingWithFingerprintAllowed();
@@ -3021,11 +3021,11 @@
isKeyguardVisible(),
mKeyguardOccluded,
mOccludingAppRequestingFp,
- mIsPrimaryUser,
shouldListenSideFpsState,
shouldListenForFingerprintAssistant,
strongerAuthRequired,
mSwitchingUser,
+ mIsSystemUser,
isUdfps,
userDoesNotHaveTrust));
@@ -3070,7 +3070,7 @@
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 @@
|| mAlternateBouncerShowing)
&& !mSwitchingUser && !faceDisabledForUser && userNotTrustedOrDetectionIsNeeded
&& !mKeyguardGoingAway && biometricEnabledForUser
- && faceAuthAllowedOrDetectionIsNeeded && mIsPrimaryUser
+ && faceAuthAllowedOrDetectionIsNeeded && mIsSystemUser
&& (!mSecureCameraLaunched || mAlternateBouncerShowing)
&& faceAndFpNotAuthenticated
&& !mGoingToSleep
@@ -3108,10 +3108,10 @@
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 b6ee4cb..3349fe5 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.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 @@
@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 71c5f24..6e8275f 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 @@
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 98a3e4b..11ef749 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.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 @@
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/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e0af5ce..7a2013e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1957,11 +1957,12 @@
if (mShowing && mKeyguardStateController.isShowing()) {
if (mPM.isInteractive() && !mHiding) {
// It's already showing, and we're not trying to show it while the screen is off.
- // We can simply reset all of the views.
+ // We can simply reset all of the views, but don't hide the bouncer in case the user
+ // is currently interacting with it.
if (DEBUG) Log.d(TAG, "doKeyguard: not showing (instead, resetting) because it is "
+ "already showing, we're interactive, and we were not previously hiding. "
+ "It should be safe to short-circuit here.");
- resetStateLocked();
+ resetStateLocked(/* hideBouncer= */ false);
return;
} else {
// We are trying to show the keyguard while the screen is off or while we were in
@@ -2035,8 +2036,12 @@
* @see #handleReset
*/
private void resetStateLocked() {
+ resetStateLocked(/* hideBouncer= */ true);
+ }
+
+ private void resetStateLocked(boolean hideBouncer) {
if (DEBUG) Log.e(TAG, "resetStateLocked");
- Message msg = mHandler.obtainMessage(RESET);
+ Message msg = mHandler.obtainMessage(RESET, hideBouncer ? 1 : 0, 0);
mHandler.sendMessage(msg);
}
@@ -2226,7 +2231,7 @@
handleHide();
break;
case RESET:
- handleReset();
+ handleReset(msg.arg1 != 0);
break;
case VERIFY_UNLOCK:
Trace.beginSection("KeyguardViewMediator#handleMessage VERIFY_UNLOCK");
@@ -3008,10 +3013,10 @@
* Handle message sent by {@link #resetStateLocked}
* @see #RESET
*/
- private void handleReset() {
+ private void handleReset(boolean hideBouncer) {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleReset");
- mKeyguardViewControllerLazy.get().reset(true /* hideBouncerWhenShowing */);
+ mKeyguardViewControllerLazy.get().reset(hideBouncer);
}
scheduleNonStrongBiometricIdleTimeout();
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 05ab01b..5f2178df 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 @@
}
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 @@
"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 @@
logAndObserve(
combine(
keyguardInteractor.isSecureCameraActive,
- alternateBouncerInteractor.isVisible,
+ alternateBouncerInteractor.isVisible
) { a, b ->
!a || b
},
@@ -334,12 +341,12 @@
logAndObserve(isLockedOut.isFalse(), "isNotInLockOutState", faceAuthLog),
logAndObserve(
deviceEntryFingerprintAuthRepository.isLockedOut.isFalse(),
- "fpLockedOut",
+ "fpIsNotLockedOut",
faceAuthLog
),
logAndObserve(
trustRepository.isCurrentUserTrusted.isFalse(),
- "currentUserTrusted",
+ "currentUserIsNotTrusted",
faceAuthLog
),
logAndObserve(
@@ -347,11 +354,6 @@
"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 06ae11fe8..74ef7a5 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 @@
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 cad40aa..5005b6c 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 @@
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 20ebb71..6b515da 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 @@
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 5770f3e..ddce516 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 @@
duration = TO_LOCKSCREEN_DURATION,
onStep = { value -> -translatePx + value * translatePx },
interpolator = EMPHASIZED_DECELERATE,
+ onCancel = { 0f },
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 7edb378..077ee02 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -136,6 +136,14 @@
return factory.create("NotifRemoteInputLog", 50 /* maxSize */, false /* systrace */);
}
+ /** Provides a logging buffer for all logs related to unseen notifications. */
+ @Provides
+ @SysUISingleton
+ @UnseenNotificationLog
+ public static LogBuffer provideUnseenNotificationLogBuffer(LogBufferFactory factory) {
+ return factory.create("UnseenNotifLog", 20 /* maxSize */, false /* systrace */);
+ }
+
/** Provides a logging buffer for all logs related to the data layer of notifications. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
new file mode 100644
index 0000000..5c2321b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/UnseenNotificationLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.plugins.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for unseen notification related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface UnseenNotificationLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 9e204e4..11c8c50 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -2809,6 +2809,7 @@
@Override
public void setBouncerShowing(boolean bouncerShowing) {
mBouncerShowing = bouncerShowing;
+ mNotificationStackScrollLayoutController.updateShowEmptyShadeView();
updateVisibility();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 4cbbefe..2fa070c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -21,8 +21,10 @@
import android.os.UserHandle
import android.provider.Settings
import androidx.annotation.VisibleForTesting
+import com.android.systemui.Dumpable
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -42,8 +44,14 @@
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.headsUpEvents
+import com.android.systemui.util.asIndenting
+import com.android.systemui.util.indentIfPossible
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import java.io.PrintWriter
+import javax.inject.Inject
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -57,13 +65,11 @@
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
-import javax.inject.Inject
-import kotlin.time.Duration
-import kotlin.time.Duration.Companion.seconds
/**
* Filters low priority and privacy-sensitive notifications from the lockscreen, and hides section
@@ -74,17 +80,19 @@
@Inject
constructor(
@Background private val bgDispatcher: CoroutineDispatcher,
+ private val dumpManager: DumpManager,
private val headsUpManager: HeadsUpManager,
private val keyguardNotificationVisibilityProvider: KeyguardNotificationVisibilityProvider,
private val keyguardRepository: KeyguardRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val logger: KeyguardCoordinatorLogger,
private val notifPipelineFlags: NotifPipelineFlags,
@Application private val scope: CoroutineScope,
private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
private val secureSettings: SecureSettings,
private val seenNotifsProvider: SeenNotificationsProviderImpl,
private val statusBarStateController: StatusBarStateController,
-) : Coordinator {
+) : Coordinator, Dumpable {
private val unseenNotifications = mutableSetOf<NotificationEntry>()
private var unseenFilterEnabled = false
@@ -103,6 +111,7 @@
pipeline.addCollectionListener(collectionListener)
scope.launch { trackUnseenNotificationsWhileUnlocked() }
scope.launch { invalidateWhenUnseenSettingChanges() }
+ dumpManager.registerDumpable(this)
}
private suspend fun trackUnseenNotificationsWhileUnlocked() {
@@ -122,14 +131,16 @@
// If the screen is turning off, stop tracking, but if that transition is
// cancelled, then start again.
emitAll(
- keyguardTransitionRepository.transitions
- .map { step -> !step.isScreenTurningOff }
+ keyguardTransitionRepository.transitions.map { step ->
+ !step.isScreenTurningOff
+ }
)
}
}
// Prevent double emit of `false` caused by transition to AOD, followed by keyguard
// showing
.distinctUntilChanged()
+ .onEach { trackingUnseen -> logger.logTrackingUnseen(trackingUnseen) }
// Use collectLatest so that trackUnseenNotifications() is cancelled when the keyguard is
// showing again
@@ -140,9 +151,11 @@
// set when unlocked
awaitTimeSpentNotDozing(SEEN_TIMEOUT)
clearUnseenOnBeginTracking = true
+ logger.logSeenOnLockscreen()
} else {
if (clearUnseenOnBeginTracking) {
clearUnseenOnBeginTracking = false
+ logger.logAllMarkedSeenOnUnlock()
unseenNotifications.clear()
}
unseenNotifFilter.invalidateList("keyguard no longer showing")
@@ -166,6 +179,8 @@
.first()
}
+ // Track "unseen" notifications, marking them as seen when either shade is expanded or the
+ // notification becomes heads up.
private suspend fun trackUnseenNotifications() {
coroutineScope {
launch { clearUnseenNotificationsWhenShadeIsExpanded() }
@@ -179,6 +194,7 @@
// keyguard transition and not the user expanding the shade
yield()
if (isExpanded) {
+ logger.logShadeExpanded()
unseenNotifications.clear()
}
}
@@ -190,6 +206,7 @@
.forEach { unseenNotifications.remove(it) }
headsUpManager.headsUpEvents.collect { (entry, isHun) ->
if (isHun) {
+ logger.logUnseenHun(entry.key)
unseenNotifications.remove(entry)
}
}
@@ -231,6 +248,7 @@
if (
keyguardRepository.isKeyguardShowing() || !statusBarStateController.isExpanded
) {
+ logger.logUnseenAdded(entry.key)
unseenNotifications.add(entry)
}
}
@@ -239,12 +257,15 @@
if (
keyguardRepository.isKeyguardShowing() || !statusBarStateController.isExpanded
) {
+ logger.logUnseenUpdated(entry.key)
unseenNotifications.add(entry)
}
}
override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
- unseenNotifications.remove(entry)
+ if (unseenNotifications.remove(entry)) {
+ logger.logUnseenRemoved(entry.key)
+ }
}
}
@@ -272,6 +293,7 @@
}.also { hasFiltered -> hasFilteredAnyNotifs = hasFilteredAnyNotifs || hasFiltered }
override fun onCleanup() {
+ logger.logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs)
seenNotifsProvider.hasFilteredOutSeenNotifications = hasFilteredAnyNotifs
hasFilteredAnyNotifs = false
}
@@ -306,11 +328,25 @@
sectionHeaderVisibilityProvider.sectionHeadersVisible = showSections
}
+ override fun dump(pw: PrintWriter, args: Array<out String>) =
+ with(pw.asIndenting()) {
+ println(
+ "seenNotifsProvider.hasFilteredOutSeenNotifications=" +
+ seenNotifsProvider.hasFilteredOutSeenNotifications
+ )
+ println("unseen notifications:")
+ indentIfPossible {
+ for (notification in unseenNotifications) {
+ println(notification.key)
+ }
+ }
+ }
+
companion object {
private const val TAG = "KeyguardCoordinator"
private val SEEN_TIMEOUT = 5.seconds
}
}
-private val TransitionStep.isScreenTurningOff: Boolean get() =
- transitionState == TransitionState.STARTED && to != KeyguardState.GONE
\ No newline at end of file
+private val TransitionStep.isScreenTurningOff: Boolean
+ get() = transitionState == TransitionState.STARTED && to != KeyguardState.GONE
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
new file mode 100644
index 0000000..6503a64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorLogger.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.log.dagger.UnseenNotificationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel
+import javax.inject.Inject
+
+private const val TAG = "KeyguardCoordinator"
+
+class KeyguardCoordinatorLogger
+@Inject
+constructor(
+ @UnseenNotificationLog private val buffer: LogBuffer,
+) {
+ fun logSeenOnLockscreen() =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "Notifications on lockscreen will be marked as seen when unlocked."
+ )
+
+ fun logTrackingUnseen(trackingUnseen: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { bool1 = trackingUnseen },
+ messagePrinter = { "${if (bool1) "Start" else "Stop"} tracking unseen notifications." },
+ )
+
+ fun logAllMarkedSeenOnUnlock() =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "Notifications have been marked as seen now that device is unlocked."
+ )
+
+ fun logShadeExpanded() =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ "Notifications have been marked as seen due to shade expansion."
+ )
+
+ fun logUnseenAdded(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif added: $str1" },
+ )
+
+ fun logUnseenUpdated(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif updated: $str1" },
+ )
+
+ fun logUnseenRemoved(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif removed: $str1" },
+ )
+
+ fun logProviderHasFilteredOutSeenNotifs(hasFilteredAnyNotifs: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { bool1 = hasFilteredAnyNotifs },
+ messagePrinter = { "UI showing unseen filter treatment: $bool1" },
+ )
+
+ fun logUnseenHun(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ messageInitializer = { str1 = key },
+ messagePrinter = { "Unseen notif has become heads up: $str1" },
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index e2f93ce..4177263 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -1235,7 +1235,8 @@
// Hide empty shade view when in transition to Keyguard.
// That avoids "No Notifications" to blink when transitioning to AOD.
// For more details, see: b/228790482
- && !isInTransitionToKeyguard();
+ && !isInTransitionToKeyguard()
+ && !mCentralSurfaces.isBouncerShowing();
mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade());
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index ed40eed..2962c14 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 @@
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 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 @@
// Preconditions for sfps auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1503,7 +1503,7 @@
// GIVEN Preconditions for sfps auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1532,7 +1532,7 @@
// GIVEN Preconditions for sfps auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1684,7 +1684,7 @@
// Face auth should run when the following is true.
keyguardNotGoingAway();
occludingAppRequestsFaceAuth();
- currentUserIsPrimary();
+ currentUserIsSystem();
primaryAuthNotRequiredByStrongAuthTracker();
biometricsEnabledForCurrentUser();
currentUserDoesNotHaveTrust();
@@ -1705,7 +1705,7 @@
// Face auth should run when the following is true.
bouncerFullyVisibleAndNotGoingToSleep();
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
primaryAuthNotRequiredByStrongAuthTracker();
biometricsEnabledForCurrentUser();
currentUserDoesNotHaveTrust();
@@ -1728,7 +1728,7 @@
// Face auth should run when the following is true.
bouncerFullyVisibleAndNotGoingToSleep();
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
primaryAuthNotRequiredByStrongAuthTracker();
biometricsEnabledForCurrentUser();
currentUserDoesNotHaveTrust();
@@ -1749,7 +1749,7 @@
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 @@
// Face auth should run when the following is true.
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
biometricsEnabledForCurrentUser();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
@@ -1791,7 +1791,7 @@
throws RemoteException {
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1813,7 +1813,7 @@
// Face auth should run when the following is true.
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1833,7 +1833,7 @@
throws RemoteException {
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1854,7 +1854,7 @@
// Face auth should run when the following is true.
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1876,7 +1876,7 @@
throws RemoteException {
// Face auth should run when the following is true.
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1896,7 +1896,7 @@
throws RemoteException {
// Face auth should run when the following is true.
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1915,7 +1915,7 @@
public void testShouldListenForFace_whenKeyguardIsAwake_returnsTrue() throws RemoteException {
// Preconditions for face auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1940,7 +1940,7 @@
public void testShouldListenForFace_whenUdfpsFingerDown_returnsTrue() throws RemoteException {
// Preconditions for face auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1959,7 +1959,7 @@
throws RemoteException {
// Preconditions for face auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -1977,7 +1977,7 @@
throws RemoteException {
// Preconditions for face auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -2002,7 +2002,7 @@
throws RemoteException {
// Preconditions for face auth to run
keyguardNotGoingAway();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -2324,7 +2324,7 @@
throws RemoteException {
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -2455,7 +2455,7 @@
mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_CLOSED;
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -2479,7 +2479,7 @@
mKeyguardUpdateMonitor.mConfigFaceAuthSupportedPosture = DEVICE_POSTURE_UNKNOWN;
keyguardNotGoingAway();
bouncerFullyVisibleAndNotGoingToSleep();
- currentUserIsPrimary();
+ currentUserIsSystem();
currentUserDoesNotHaveTrust();
biometricsNotDisabledThroughDevicePolicyManager();
biometricsEnabledForCurrentUser();
@@ -2877,8 +2877,8 @@
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/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 0de9608..8f58140 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -502,7 +502,7 @@
TestableLooper.get(this).processAllMessages();
assertTrue(mViewMediator.isShowingAndNotOccluded());
- verify(mStatusBarKeyguardViewManager).reset(anyBoolean());
+ verify(mStatusBarKeyguardViewManager).reset(false);
}
@Test
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 a76d03b..fa40fc4 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 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 @@
}
@Test
- fun authenticateDoesNotRunWhenCurrentUserIsNotPrimary() =
- testScope.runTest {
- testGatingCheckForFaceAuth {
- launch { fakeUserRepository.setSelectedUserInfo(secondaryUser) }
- }
- }
-
- @Test
fun authenticateDoesNotRunWhenSecureCameraIsActive() =
testScope.runTest {
testGatingCheckForFaceAuth {
@@ -653,6 +644,58 @@
}
@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 3d1d2f4..5da1a84 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 @@
}
@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 0c4e845..efa5f0c 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 @@
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/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index 8f07f8d..c3f5123 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -24,6 +24,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.advanceTimeBy
+import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -380,10 +381,12 @@
val keyguardCoordinator =
KeyguardCoordinator(
testDispatcher,
+ mock<DumpManager>(),
headsUpManager,
keyguardNotifVisibilityProvider,
keyguardRepository,
keyguardTransitionRepository,
+ mock<KeyguardCoordinatorLogger>(),
notifPipelineFlags,
testScope.backgroundScope,
sectionHeaderVisibilityProvider,
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0bdb0c8..0d973d9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1443,17 +1443,19 @@
return;
}
if (!mVisibleBgUserIds.get(userId)) {
- Slogf.wtf(LOG_TAG, "Cannot change current user to %d as it's not visible "
- + "(mVisibleUsers=%s)", userId, mVisibleBgUserIds);
+ Slogf.wtf(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): cannot change "
+ + "current user to %d as it's not visible (mVisibleUsers=%s)",
+ userId, mVisibleBgUserIds);
return;
}
if (mCurrentUserId == userId) {
- Slogf.w(LOG_TAG, "NOT changing current user for test automation purposes as it is "
- + "already %d", mCurrentUserId);
+ Slogf.d(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): NOT changing "
+ + "current user for test automation purposes as it is already %d",
+ mCurrentUserId);
return;
}
- Slogf.i(LOG_TAG, "Changing current user from %d to %d for test automation purposes",
- mCurrentUserId, userId);
+ Slogf.i(LOG_TAG, "changeCurrentUserForTestAutomationIfNeededLocked(): changing current user"
+ + " from %d to %d for test automation purposes", mCurrentUserId, userId);
mRealCurrentUserId = mCurrentUserId;
switchUser(userId);
}
@@ -1466,7 +1468,13 @@
+ "because device doesn't support visible background users");
return;
}
- Slogf.i(LOG_TAG, "Restoring current user to %d after using %d for test automation purposes",
+ if (mRealCurrentUserId == UserHandle.USER_CURRENT) {
+ Slogf.d(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): ignoring "
+ + "because mRealCurrentUserId is already USER_CURRENT");
+ return;
+ }
+ Slogf.i(LOG_TAG, "restoreCurrentUserForTestAutomationIfNeededLocked(): restoring current "
+ + "user to %d after using %d for test automation purposes",
mRealCurrentUserId, mCurrentUserId);
int currentUserId = mRealCurrentUserId;
mRealCurrentUserId = UserHandle.USER_CURRENT;
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 b042c30..ff72476 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 @@
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 1656b6f..77990af 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 @@
// 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 81dc346..1f80aec 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 @@
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 @@
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 a3163e0..02c4770 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 @@
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 @@
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 @@
}
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 @@
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 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 @@
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 @@
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 85b4034..5d92c7f 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.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 @@
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 @@
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 @@
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 @@
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 @@
// 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 0000000..76702d3
--- /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 9eedc4e..f47c4b2 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 @@
@ServiceThreadOnly
private void launchDeviceDiscovery() {
assertRunOnServiceThread();
- clearDeviceInfoList();
DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
new DeviceDiscoveryCallback() {
@Override
@@ -691,13 +690,6 @@
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 805ff66..75fe63a 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 @@
// 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 @@
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 0ae1e80..a1b67e1 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 @@
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.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 @@
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 @@
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 f03e985..27f6a89 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 @@
// 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 61fe654..19d6fa0 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.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 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 @@
*/
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 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 @@
STATE_HIDE_IME_EXPLICIT,
STATE_HIDE_IME_NOT_ALWAYS,
STATE_SHOW_IME_IMPLICIT,
+ STATE_REMOVE_IME_SNAPSHOT,
})
@interface VisibilityState {}
@@ -172,6 +192,24 @@
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 @@
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 2433211..c70d555 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 @@
}
}
+ 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 @@
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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ebcbfed..07891f3 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 @@
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 @@
@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 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 @@
}
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 @@
@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);
+ 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);
+ 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);
+ 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 5015985..7198de2 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 @@
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/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 2d3928c..8f41608 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -2237,7 +2237,14 @@
}
clearAllResourcesAndClientMapping(getClientProfile(clientId));
mClientProfiles.remove(clientId);
- mListeners.remove(clientId);
+
+ // it may be called by unregisterClientProfileInternal under test
+ synchronized (mLock) {
+ ResourcesReclaimListenerRecord record = mListeners.remove(clientId);
+ if (record != null) {
+ record.getListener().asBinder().unlinkToDeath(record, 0);
+ }
+ }
}
private void clearFrontendAndClientMapping(ClientProfile profile) {
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a757d90..f71f3b1 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 @@
/** 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 2160ce1..c6a2e0e 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 @@
}
}
+ @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 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 @@
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 5f56af7..1208b6ef 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 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 c5e75fa..a27f3e4 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 @@
// 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 abf66bc..f93afe8 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 @@
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 597c8bf..805bff2 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 @@
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 11d84ff..0c196d7 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 @@
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 c2bc459..bad64d3 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 @@
*/
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 @@
@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 @@
}
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 @@
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 @@
*/
@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 339b6ec..747819e9 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 @@
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 @@
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 0000000..8bc445b
--- /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 71dd917..1d9f24c 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 @@
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 @@
* @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 300a894..cff86ad 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 @@
/** 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 9363eb5..5c33e64 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 @@
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 @@
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 b0a879e..e80cbb3 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 @@
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 @@
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 @@
// 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 184293e..5626aa7 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 @@
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 969afe5..4922523 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 @@
}
/**
+ * 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 99d0ea8..62b3c7c 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 @@
boolean mHardKeyboardAvailable;
WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
+
+ @Nullable ImeTargetChangeListener mImeTargetChangeListener;
+
SettingsObserver mSettingsObserver;
final EmbeddedWindowController mEmbeddedWindowController;
final AnrController mAnrController;
@@ -1807,6 +1810,10 @@
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 @@
winAnimator.mSurfaceController.setSecure(win.isSecureLocked());
}
+ final boolean wasVisible = win.isVisible();
+
win.mRelayoutCalled = true;
win.mInRelayout = true;
@@ -2336,7 +2345,6 @@
"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 @@
}
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 @@
});
}
+ 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 @@
}
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 @@
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 678d4c8..a299592 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -354,6 +354,7 @@
// 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;
@@ -2350,6 +2351,10 @@
}
super.removeImmediately();
+ if (isImeOverlayLayeringTarget()) {
+ mWmService.dispatchImeTargetOverlayVisibilityChanged(mClient.asBinder(),
+ false /* visible */, true /* removed */);
+ }
final DisplayContent dc = getDisplayContent();
if (isImeLayeringTarget()) {
// Remove the attached IME screenshot surface.
@@ -2360,6 +2365,8 @@
dc.computeImeTarget(true /* updateImeTarget */);
}
if (dc.getImeInputTarget() == this && !inRelaunchingActivity()) {
+ mWmService.dispatchImeInputTargetVisibilityChanged(mClient.asBinder(),
+ false /* visible */, true /* removed */);
dc.updateImeInputAndControlTarget(null);
}
@@ -5499,6 +5506,14 @@
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 ee73f8a..82f9aad 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 @@
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;
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ readBundle(bundle, values, parser);
}
- while (parser.next() != XmlPullParser.END_DOCUMENT) {
- readEntry(restrictions, 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 @@
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 18fcafa..7e5d5aa 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 @@
}
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 @@
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 @@
}
/**
- * 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 7d4f87d..a6ada4d 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 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 @@
}
}
+ @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 2a256f2..3871e1d 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_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 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 @@
@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 @@
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 @@
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 90691a7..c80ecbf 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.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 @@
@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 @@
.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 @@
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 0000000..d9fbba5
--- /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/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index aca96ad..aad373f 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -445,14 +445,14 @@
+ " <library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
- + " on-bootclasspath-before=\"Q\"\n"
+ + " on-bootclasspath-before=\"A\"\n"
+ " on-bootclasspath-since=\"W\"\n"
+ " />\n\n"
+ " </permissions>";
parseSharedLibraries(contents);
assertFooIsOnlySharedLibrary();
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
- assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
+ assertThat(entry.onBootclasspathBefore).isEqualTo("A");
assertThat(entry.onBootclasspathSince).isEqualTo("W");
}
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 90d1488..4406d83 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.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.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
public class NotificationListenersTest extends UiServiceTestCase {
@@ -626,6 +627,58 @@
.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 9cfdaa7..dd9f3cb 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 @@
}
@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 4e001fe..37c4b37 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.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 @@
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 8f2b470..0033e3e 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 @@
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 17ae215..6d7f2c1 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 @@
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 @@
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 @@
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 2065540..a8fc25f 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 @@
}
@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 49d8da1..9d597b1 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 @@
// 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 766e74c..460a603 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.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.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 @@
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 025869d..3158ad8 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -11,12 +11,6 @@
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 905a90c..caafce2 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -331,8 +331,8 @@
* 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 559faf9..64e4356 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -91,8 +91,7 @@
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 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 @@
@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 @@
}
}
- 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 @@
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 @@
+ " 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 @@
+ " 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 @@
}
// 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 @@
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 @@
* 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 @@
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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
}
/** @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 @@
sGetSlotIndexCache.disableLocal();
sGetSubIdCache.disableLocal();
sGetPhoneIdCache.disableLocal();
-
- sIsSubscriptionManagerServiceEnabled.disableLocal();
}
/**
@@ -4005,14 +3875,6 @@
*
* @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 @@
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 6a5380d..21a6b44 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -129,9 +129,9 @@
* @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 @@
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 @@
*/
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 18e49fe..ae9ca80 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 @@
@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 @@
@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 @@
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()
diff --git a/tools/validatekeymaps/Android.bp b/tools/validatekeymaps/Android.bp
index 25373f9..554f64e 100644
--- a/tools/validatekeymaps/Android.bp
+++ b/tools/validatekeymaps/Android.bp
@@ -15,7 +15,7 @@
cc_binary_host {
name: "validatekeymaps",
-
+ cpp_std: "c++20",
srcs: ["Main.cpp"],
cflags: [