summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt17
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/app/GameState.java48
-rw-r--r--core/java/android/app/KeyguardManager.java84
-rw-r--r--core/java/android/service/dreams/DreamOverlayService.java20
-rw-r--r--core/java/android/service/dreams/DreamService.java61
-rw-r--r--core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java4
-rw-r--r--core/java/android/util/DumpableContainer.java3
-rw-r--r--core/java/android/view/IWindowManager.aidl4
-rw-r--r--core/java/android/view/SurfaceControl.java4
-rw-r--r--core/java/android/view/SurfaceControlViewHost.java3
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java24
-rw-r--r--core/java/com/android/internal/policy/IKeyguardLockedStateListener.aidl21
-rw-r--r--core/res/AndroidManifest.xml11
-rw-r--r--core/res/res/values/dimens.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java40
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java138
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java26
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java3
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt15
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt22
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt13
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java2
-rw-r--r--packages/CompanionDeviceManager/Android.bp1
-rw-r--r--packages/CompanionDeviceManager/AndroidManifest.xml1
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java28
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java67
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java23
-rw-r--r--packages/Shell/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java115
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java124
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt27
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java16
-rw-r--r--services/core/java/com/android/server/app/GameManagerService.java57
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java2
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java22
-rw-r--r--services/core/java/com/android/server/dreams/DreamManagerService.java20
-rw-r--r--services/core/java/com/android/server/inputmethod/ImePlatformCompatUtils.java64
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java26
-rw-r--r--services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java112
-rw-r--r--services/core/java/com/android/server/locales/LocaleManagerService.java35
-rw-r--r--services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java49
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java34
-rw-r--r--services/core/java/com/android/server/pm/InstallPackageHelper.java28
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java11
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java7
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java9
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java7
-rw-r--r--services/core/java/com/android/server/wm/Transition.java12
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java51
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java7
-rw-r--r--services/java/com/android/server/SystemServer.java8
-rw-r--r--services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java9
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java6
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt1
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt21
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt11
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt2
78 files changed, 1302 insertions, 417 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index ec1e665dbdb1..78711086e2c8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -189,6 +189,7 @@ package android {
field public static final String START_VIEW_APP_FEATURES = "android.permission.START_VIEW_APP_FEATURES";
field public static final String START_VIEW_PERMISSION_USAGE = "android.permission.START_VIEW_PERMISSION_USAGE";
field public static final String STATUS_BAR = "android.permission.STATUS_BAR";
+ field public static final String SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE = "android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE";
field public static final String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
field public static final String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
field public static final String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
@@ -5559,11 +5560,11 @@ package android.app {
public final class GameState implements android.os.Parcelable {
ctor public GameState(boolean, int);
- ctor public GameState(boolean, int, @Nullable String, @NonNull android.os.Bundle);
+ ctor public GameState(boolean, int, int, int);
method public int describeContents();
- method @Nullable public String getDescription();
- method @NonNull public android.os.Bundle getMetadata();
+ method public int getLabel();
method public int getMode();
+ method public int getQuality();
method public boolean isLoading();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.GameState> CREATOR;
@@ -5677,6 +5678,7 @@ package android.app {
}
public class KeyguardManager {
+ method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addKeyguardLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method @Deprecated public boolean inKeyguardRestrictedInputMode();
@@ -5685,6 +5687,7 @@ package android.app {
method public boolean isKeyguardLocked();
method public boolean isKeyguardSecure();
method @Deprecated public android.app.KeyguardManager.KeyguardLock newKeyguardLock(String);
+ method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeKeyguardLockedStateListener(@NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
method public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback);
}
@@ -5700,6 +5703,10 @@ package android.app {
method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void reenableKeyguard();
}
+ @java.lang.FunctionalInterface public static interface KeyguardManager.KeyguardLockedStateListener {
+ method public void onKeyguardLockedStateChanged(boolean);
+ }
+
@Deprecated public static interface KeyguardManager.OnKeyguardExitResult {
method @Deprecated public void onKeyguardExitResult(boolean);
}
@@ -49292,7 +49299,7 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction setDataSpace(@NonNull android.view.SurfaceControl, int);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int);
method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, int);
- method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
+ method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int);
method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int);
method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean);
method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float);
@@ -53112,7 +53119,7 @@ package android.view.inputmethod {
field public static final int RESULT_SHOWN = 2; // 0x2
field public static final int RESULT_UNCHANGED_HIDDEN = 1; // 0x1
field public static final int RESULT_UNCHANGED_SHOWN = 0; // 0x0
- field public static final int SHOW_FORCED = 2; // 0x2
+ field @Deprecated public static final int SHOW_FORCED = 2; // 0x2
field public static final int SHOW_IMPLICIT = 1; // 0x1
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9757b2ff318f..e64392b3b0c2 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2347,6 +2347,8 @@ package android.service.dreams {
public abstract class DreamOverlayService extends android.app.Service {
ctor public DreamOverlayService();
+ method @Nullable public final CharSequence getDreamLabel();
+ method public final boolean isPreviewMode();
method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onStartDream(@NonNull android.view.WindowManager.LayoutParams);
method public final void requestExit();
@@ -3082,6 +3084,7 @@ package android.view.inputmethod {
method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
method public boolean hasActiveInputConnection(@Nullable android.view.View);
method public boolean isInputMethodPickerShown();
+ field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
}
}
diff --git a/core/java/android/app/GameState.java b/core/java/android/app/GameState.java
index 979dd34e8276..fe6e5543a662 100644
--- a/core/java/android/app/GameState.java
+++ b/core/java/android/app/GameState.java
@@ -18,8 +18,6 @@ package android.app;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -88,12 +86,11 @@ public final class GameState implements Parcelable {
// One of the states listed above.
private final @GameStateMode int mMode;
- // This is a game specific description. For example can be level or scene name.
- private final @Nullable String mDescription;
+ // A developer-supplied enum, e.g. to indicate level or scene.
+ private final int mLabel;
- // This contains any other game specific parameters not covered by the fields above. It can be
- // quality parameter data, settings, or game modes.
- private final @NonNull Bundle mMetaData;
+ // The developer-supplied enum, e.g. to indicate the current quality level.
+ private final int mQuality;
/**
* Create a GameState with the specified loading status.
@@ -101,29 +98,28 @@ public final class GameState implements Parcelable {
* @param mode The game state mode of type @GameStateMode.
*/
public GameState(boolean isLoading, @GameStateMode int mode) {
- this(isLoading, mode, null, new Bundle());
+ this(isLoading, mode, -1, -1);
}
/**
* Create a GameState with the given state variables.
* @param isLoading Whether the game is in the loading state.
- * @param mode The game state mode of type @GameStateMode.
- * @param description An optional description of the state.
- * @param metaData Optional metadata.
+ * @param mode The game state mode.
+ * @param label An optional developer-supplied enum e.g. for the current level.
+ * @param quality An optional developer-supplied enum, e.g. for the current quality level.
*/
- public GameState(boolean isLoading, @GameStateMode int mode, @Nullable String description,
- @NonNull Bundle metaData) {
+ public GameState(boolean isLoading, @GameStateMode int mode, int label, int quality) {
mIsLoading = isLoading;
mMode = mode;
- mDescription = description;
- mMetaData = metaData;
+ mLabel = label;
+ mQuality = quality;
}
private GameState(Parcel in) {
mIsLoading = in.readBoolean();
mMode = in.readInt();
- mDescription = in.readString();
- mMetaData = in.readBundle();
+ mLabel = in.readInt();
+ mQuality = in.readInt();
}
/**
@@ -141,17 +137,19 @@ public final class GameState implements Parcelable {
}
/**
- * @return The state description, or null if one is not set.
+ * @return The developer-supplied enum, e.g. to indicate level or scene. The default value (if
+ * not supplied) is -1.
*/
- public @Nullable String getDescription() {
- return mDescription;
+ public int getLabel() {
+ return mLabel;
}
/**
- * @return metadata associated with the state.
+ * @return The developer-supplied enum, e.g. to indicate the current quality level. The default
+ * value (if not suplied) is -1.
*/
- public @NonNull Bundle getMetadata() {
- return mMetaData;
+ public int getQuality() {
+ return mQuality;
}
@Override
@@ -163,8 +161,8 @@ public final class GameState implements Parcelable {
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeBoolean(mIsLoading);
parcel.writeInt(mMode);
- parcel.writeString(mDescription);
- parcel.writeBundle(mMetaData);
+ parcel.writeInt(mLabel);
+ parcel.writeInt(mQuality);
}
/**
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 99100003e5b3..87ba197d8052 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -52,6 +52,7 @@ import android.view.WindowManager.LayoutParams;
import android.view.WindowManagerGlobal;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.util.Preconditions;
import com.android.internal.widget.IWeakEscrowTokenActivatedListener;
import com.android.internal.widget.IWeakEscrowTokenRemovedListener;
@@ -183,6 +184,10 @@ public class KeyguardManager {
})
@interface LockTypes {}
+ // TODO(b/220379118): register only one binder listener and keep a map of listener to executor.
+ private final ArrayMap<KeyguardLockedStateListener, IKeyguardLockedStateListener>
+ mKeyguardLockedStateListeners = new ArrayMap<>();
+
/**
* Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
* if enrolled) for the current user of the device. The caller is expected to launch this
@@ -534,7 +539,7 @@ public class KeyguardManager {
/**
* Return whether the keyguard is currently locked.
*
- * @return true if keyguard is locked.
+ * @return {@code true} if the keyguard is locked.
*/
public boolean isKeyguardLocked() {
try {
@@ -550,7 +555,7 @@ public class KeyguardManager {
*
* <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
*
- * @return true if a PIN, pattern or password is set or a SIM card is locked.
+ * @return {@code true} if a PIN, pattern or password is set or a SIM card is locked.
*/
public boolean isKeyguardSecure() {
try {
@@ -565,7 +570,7 @@ public class KeyguardManager {
* keyguard password emergency screen). When in such mode, certain keys,
* such as the Home key and the right soft keys, don't work.
*
- * @return true if in keyguard restricted input mode.
+ * @return {@code true} if in keyguard restricted input mode.
* @deprecated Use {@link #isKeyguardLocked()} instead.
*/
public boolean inKeyguardRestrictedInputMode() {
@@ -576,7 +581,7 @@ public class KeyguardManager {
* Returns whether the device is currently locked and requires a PIN, pattern or
* password to unlock.
*
- * @return true if unlocking the device currently requires a PIN, pattern or
+ * @return {@code true} if unlocking the device currently requires a PIN, pattern or
* password.
*/
public boolean isDeviceLocked() {
@@ -603,7 +608,7 @@ public class KeyguardManager {
*
* <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
*
- * @return true if a PIN, pattern or password was set.
+ * @return {@code true} if a PIN, pattern or password was set.
*/
public boolean isDeviceSecure() {
return isDeviceSecure(mContext.getUserId());
@@ -762,7 +767,7 @@ public class KeyguardManager {
* as the output of String#getBytes
* @param complexity - complexity level imposed by the requester
* as defined in {@code DevicePolicyManager.PasswordComplexity}
- * @return true if the password is valid, false otherwise
+ * @return {@code true} if the password is valid, false otherwise
* @hide
*/
@RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
@@ -821,7 +826,7 @@ public class KeyguardManager {
* as the output of String#getBytes
* @param complexity - complexity level imposed by the requester
* as defined in {@code DevicePolicyManager.PasswordComplexity}
- * @return true if the lock is successfully set, false otherwise
+ * @return {@code true} if the lock is successfully set, false otherwise
* @hide
*/
@RequiresPermission(Manifest.permission.SET_INITIAL_LOCK)
@@ -903,8 +908,8 @@ public class KeyguardManager {
/**
* Remove a weak escrow token.
*
- * @return true if the given handle refers to a valid weak token previously returned from
- * {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise.
+ * @return {@code true} if the given handle refers to a valid weak token previously returned
+ * from {@link #addWeakEscrowToken}, whether it's active or not. return false otherwise.
* @hide
*/
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
@@ -944,7 +949,7 @@ public class KeyguardManager {
/**
* Register the given WeakEscrowTokenRemovedListener.
*
- * @return true if the listener is registered successfully, return false otherwise.
+ * @return {@code true} if the listener is registered successfully, return false otherwise.
* @hide
*/
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
@@ -982,7 +987,7 @@ public class KeyguardManager {
/**
* Unregister the given WeakEscrowTokenRemovedListener.
*
- * @return true if the listener is unregistered successfully, return false otherwise.
+ * @return {@code true} if the listener is unregistered successfully, return false otherwise.
* @hide
*/
@RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE)
@@ -1076,4 +1081,61 @@ public class KeyguardManager {
throw new IllegalArgumentException("Unknown lock type " + lockType);
}
}
+
+ /**
+ * Listener for keyguard locked state changes.
+ */
+ @FunctionalInterface
+ public interface KeyguardLockedStateListener {
+ /**
+ * Callback function that executes when the keyguard locked state changes.
+ */
+ void onKeyguardLockedStateChanged(boolean isKeyguardLocked);
+ }
+
+ /**
+ * Registers a listener to execute when the keyguard visibility changes.
+ *
+ * @param listener The listener to add to receive keyguard visibility changes.
+ */
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ public void addKeyguardLockedStateListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull KeyguardLockedStateListener listener) {
+ synchronized (mKeyguardLockedStateListeners) {
+ try {
+ final IKeyguardLockedStateListener innerListener =
+ new IKeyguardLockedStateListener.Stub() {
+ @Override
+ public void onKeyguardLockedStateChanged(boolean isKeyguardLocked) {
+ executor.execute(
+ () -> listener.onKeyguardLockedStateChanged(isKeyguardLocked));
+ }
+ };
+ mWM.addKeyguardLockedStateListener(innerListener);
+ mKeyguardLockedStateListeners.put(listener, innerListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Unregisters a listener that executes when the keyguard visibility changes.
+ */
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ public void removeKeyguardLockedStateListener(@NonNull KeyguardLockedStateListener listener) {
+ synchronized (mKeyguardLockedStateListeners) {
+ IKeyguardLockedStateListener innerListener = mKeyguardLockedStateListeners.get(
+ listener);
+ if (innerListener == null) {
+ return;
+ }
+ try {
+ mWM.removeKeyguardLockedStateListener(innerListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mKeyguardLockedStateListeners.remove(listener);
+ }
+ }
}
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 163d6ed4b18b..bfc3b8b39385 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -36,6 +36,9 @@ public abstract class DreamOverlayService extends Service {
private static final String TAG = "DreamOverlayService";
private static final boolean DEBUG = false;
private boolean mShowComplications;
+ private boolean mIsPreviewMode;
+ @Nullable
+ private CharSequence mDreamLabel;
private IDreamOverlay mDreamOverlay = new IDreamOverlay.Stub() {
@Override
@@ -56,6 +59,8 @@ public abstract class DreamOverlayService extends Service {
public final IBinder onBind(@NonNull Intent intent) {
mShowComplications = intent.getBooleanExtra(DreamService.EXTRA_SHOW_COMPLICATIONS,
DreamService.DEFAULT_SHOW_COMPLICATIONS);
+ mIsPreviewMode = intent.getBooleanExtra(DreamService.EXTRA_IS_PREVIEW, false);
+ mDreamLabel = intent.getCharSequenceExtra(DreamService.EXTRA_DREAM_LABEL);
return mDreamOverlay.asBinder();
}
@@ -84,4 +89,19 @@ public abstract class DreamOverlayService extends Service {
public final boolean shouldShowComplications() {
return mShowComplications;
}
+
+ /**
+ * Returns whether the dream is running in preview mode.
+ */
+ public final boolean isPreviewMode() {
+ return mIsPreviewMode;
+ }
+
+ /**
+ * Returns the user-facing label of the currently running dream.
+ */
+ @Nullable
+ public final CharSequence getDreamLabel() {
+ return mDreamLabel;
+ }
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 345917220b6b..db622d39b785 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -216,6 +216,18 @@ public class DreamService extends Service implements Window.Callback {
"android.service.dreams.SHOW_COMPLICATIONS";
/**
+ * Extra containing a boolean for whether we are showing this dream in preview mode.
+ * @hide
+ */
+ public static final String EXTRA_IS_PREVIEW = "android.service.dreams.IS_PREVIEW";
+
+ /**
+ * The user-facing label of the current dream service.
+ * @hide
+ */
+ public static final String EXTRA_DREAM_LABEL = "android.service.dreams.DREAM_LABEL";
+
+ /**
* The default value for whether to show complications on the overlay.
* @hide
*/
@@ -258,15 +270,19 @@ public class DreamService extends Service implements Window.Callback {
}
public void bind(Context context, @Nullable ComponentName overlayService,
- ComponentName dreamService) {
+ ComponentName dreamService, boolean isPreviewMode) {
if (overlayService == null) {
return;
}
+ final ServiceInfo serviceInfo = fetchServiceInfo(context, dreamService);
+
final Intent overlayIntent = new Intent();
overlayIntent.setComponent(overlayService);
overlayIntent.putExtra(EXTRA_SHOW_COMPLICATIONS,
- fetchShouldShowComplications(context, dreamService));
+ fetchShouldShowComplications(context, serviceInfo));
+ overlayIntent.putExtra(EXTRA_DREAM_LABEL, fetchDreamLabel(context, serviceInfo));
+ overlayIntent.putExtra(EXTRA_IS_PREVIEW, isPreviewMode);
context.bindService(overlayIntent,
this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
@@ -988,8 +1004,11 @@ public class DreamService extends Service implements Window.Callback {
// Connect to the overlay service if present.
if (!mWindowless) {
- mOverlayConnection.bind(this, intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
- new ComponentName(this, getClass()));
+ mOverlayConnection.bind(
+ /* context= */ this,
+ intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
+ new ComponentName(this, getClass()),
+ intent.getBooleanExtra(EXTRA_IS_PREVIEW, /* defaultValue= */ false));
}
return mDreamServiceWrapper;
@@ -1111,7 +1130,10 @@ public class DreamService extends Service implements Window.Callback {
* @hide
*/
@Nullable
- public static DreamMetadata getDreamMetadata(Context context, ServiceInfo serviceInfo) {
+ public static DreamMetadata getDreamMetadata(Context context,
+ @Nullable ServiceInfo serviceInfo) {
+ if (serviceInfo == null) return null;
+
final PackageManager pm = context.getPackageManager();
final TypedArray rawMetadata = readMetadata(pm, serviceInfo);
@@ -1350,22 +1372,33 @@ public class DreamService extends Service implements Window.Callback {
* {@link DreamService#DEFAULT_SHOW_COMPLICATIONS}.
*/
private static boolean fetchShouldShowComplications(Context context,
- ComponentName componentName) {
+ @Nullable ServiceInfo serviceInfo) {
+ final DreamMetadata metadata = getDreamMetadata(context, serviceInfo);
+ if (metadata != null) {
+ return metadata.showComplications;
+ }
+ return DEFAULT_SHOW_COMPLICATIONS;
+ }
+
+ @Nullable
+ private static CharSequence fetchDreamLabel(Context context,
+ @Nullable ServiceInfo serviceInfo) {
+ if (serviceInfo == null) return null;
+ final PackageManager pm = context.getPackageManager();
+ return serviceInfo.loadLabel(pm);
+ }
+
+ @Nullable
+ private static ServiceInfo fetchServiceInfo(Context context, ComponentName componentName) {
final PackageManager pm = context.getPackageManager();
try {
- final ServiceInfo si = pm.getServiceInfo(componentName,
+ return pm.getServiceInfo(componentName,
PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
- final DreamMetadata metadata = getDreamMetadata(context, si);
-
- if (metadata != null) {
- return metadata.showComplications;
- }
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) Log.w(TAG, "cannot find component " + componentName.flattenToShortString());
}
-
- return DEFAULT_SHOW_COMPLICATIONS;
+ return null;
}
@Override
diff --git a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
index 8fe6f71b598d..adc9251d89be 100644
--- a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
+++ b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
@@ -40,7 +40,7 @@ public class FloatingToolbarRoot extends LinearLayout {
private final IBinder mTargetInputToken;
private final SelectionToolbarRenderService.TransferTouchListener mTransferTouchListener;
- private Rect mContentRect;
+ private final Rect mContentRect = new Rect();
private int mLastDownX = -1;
private int mLastDownY = -1;
@@ -57,7 +57,7 @@ public class FloatingToolbarRoot extends LinearLayout {
* Sets the Rect that shows the selection toolbar content.
*/
public void setContentRect(Rect contentRect) {
- mContentRect = contentRect;
+ mContentRect.set(contentRect);
}
@Override
diff --git a/core/java/android/util/DumpableContainer.java b/core/java/android/util/DumpableContainer.java
index e7b2acd5b500..fef5acd42e4e 100644
--- a/core/java/android/util/DumpableContainer.java
+++ b/core/java/android/util/DumpableContainer.java
@@ -18,8 +18,7 @@ package android.util;
import android.annotation.NonNull;
/**
- * Objects that contains a list of {@link Dumpable}, which will be dumped when the object itself
- * is dumped.
+ * Represents a container that manages {@link Dumpable dumpables}.
*/
public interface DumpableContainer {
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index ce21086931da..53b842a0f3a2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -18,6 +18,7 @@ package android.view;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.policy.IShortcutService;
import android.app.IAssistDataReceiver;
@@ -199,6 +200,9 @@ interface IWindowManager
boolean isKeyguardSecure(int userId);
void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message);
+ void addKeyguardLockedStateListener(in IKeyguardLockedStateListener listener);
+ void removeKeyguardLockedStateListener(in IKeyguardLockedStateListener listener);
+
// Requires INTERACT_ACROSS_USERS_FULL permission
void setSwitchingUser(boolean switching);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 98cef95885bd..632af2315bcd 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -3094,6 +3094,10 @@ public final class SurfaceControl implements Parcelable {
* @param destFrame The destination rectangle in parent space. Or null for the source frame.
* @param orientation The buffer rotation
* @return This transaction object.
+ * @deprecated Use {@link #setCrop(SurfaceControl, Rect)},
+ * {@link #setBufferTransform(SurfaceControl, int)},
+ * {@link #setPosition(SurfaceControl, float, float)} and
+ * {@link #setScale(SurfaceControl, float, float)} instead.
*/
@NonNull
public Transaction setGeometry(@NonNull SurfaceControl sc, @Nullable Rect sourceCrop,
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index 2edfda5d065c..a13579d0acad 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -328,7 +328,8 @@ public class SurfaceControlViewHost {
*/
public @Nullable SurfacePackage getSurfacePackage() {
if (mSurfaceControl != null && mAccessibilityEmbeddedConnection != null) {
- return new SurfacePackage(mSurfaceControl, mAccessibilityEmbeddedConnection,
+ return new SurfacePackage(new SurfaceControl(mSurfaceControl, "getSurfacePackage"),
+ mAccessibilityEmbeddedConnection,
mWm.getFocusGrantToken(), mRemoteInterface);
} else {
return null;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 27174630bfa3..017b8aa3cf6c 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -46,6 +46,8 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
import android.app.ActivityThread;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -356,6 +358,21 @@ public final class InputMethodManager {
/** @hide */
public static final int SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES = 2;
+ /**
+ * Clear {@link #SHOW_FORCED} flag when the next IME focused application changed.
+ *
+ * <p>
+ * Note that when this flag enabled in server side, {@link #SHOW_FORCED} will no longer
+ * affect the next focused application to keep showing IME, in case of unexpected IME visible
+ * when the next focused app isn't be the IME requester. </p>
+ *
+ * @hide
+ */
+ @TestApi
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // This is a bug id.
+
@UnsupportedAppUsage
final IInputMethodManager mService;
final Looper mMainLooper;
@@ -1646,7 +1663,14 @@ public final class InputMethodManager {
* Flag for {@link #showSoftInput} to indicate that the user has forced
* the input method open (such as by long-pressing menu) so it should
* not be closed until they explicitly do so.
+ *
+ * @deprecated Use {@link #showSoftInput} without this flag instead. Using this flag can lead
+ * to the soft input remaining visible even when the calling application is closed. The
+ * use of this flag can make the soft input remains visible globally. Starting in
+ * {@link Build.VERSION_CODES#TIRAMISU Android T}, this flag only has an effect while the
+ * caller is currently focused.
*/
+ @Deprecated
public static final int SHOW_FORCED = 0x0002;
/**
diff --git a/core/java/com/android/internal/policy/IKeyguardLockedStateListener.aidl b/core/java/com/android/internal/policy/IKeyguardLockedStateListener.aidl
new file mode 100644
index 000000000000..ee5021918879
--- /dev/null
+++ b/core/java/com/android/internal/policy/IKeyguardLockedStateListener.aidl
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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.internal.policy;
+
+oneway interface IKeyguardLockedStateListener {
+ void onKeyguardLockedStateChanged(boolean isKeyguardLocked);
+} \ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d4c03e412fcb..58a3bb4818df 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4119,6 +4119,13 @@
<permission android:name="android.permission.MANAGE_HOTWORD_DETECTION"
android:protectionLevel="internal|preinstalled" />
+ <!-- Allows an application to subscribe to keyguard locked (i.e., showing) state.
+ <p>Protection level: internal|role
+ <p>Intended for use by ROLE_ASSISTANT only.
+ -->
+ <permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE"
+ android:protectionLevel="internal|role"/>
+
<!-- Must be required by a {@link android.service.autofill.AutofillService},
to ensure that only the system can bind to it.
<p>Protection level: signature
@@ -6912,6 +6919,10 @@
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
+ <service android:name="com.android.server.appsearch.contactsindexer.ContactsIndexerMaintenanceService"
+ android:permission="android.permission.BIND_JOB_SERVICE">
+ </service>
+
<service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader"
android:exported="false">
<intent-filter>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 744c3dab9510..adf8f8e99d35 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -606,6 +606,9 @@
<!-- The padding ratio of the Accessibility icon foreground drawable -->
<item name="accessibility_icon_foreground_padding_ratio" type="dimen">21.88%</item>
+ <!-- The minimum window size of the accessibility window magnifier -->
+ <dimen name="accessibility_window_magnifier_min_size">122dp</dimen>
+
<!-- Margin around the various security views -->
<dimen name="keyguard_muliuser_selector_margin">8dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d4513d0c4a3d..558e3c3a0222 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4399,6 +4399,7 @@
<java-symbol type="color" name="accessibility_focus_highlight_color" />
<!-- Width of the outline stroke used by the accessibility focus rectangle -->
<java-symbol type="dimen" name="accessibility_focus_highlight_stroke_width" />
+ <java-symbol type="dimen" name="accessibility_window_magnifier_min_size" />
<java-symbol type="bool" name="config_attachNavBarToAppDuringTransition" />
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index f7c92fed5522..8a482fbfa1c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -144,21 +144,42 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return Math.max(dividerInset, radius);
}
- /** Gets bounds of the primary split. */
+ /** Gets bounds of the primary split with screen based coordinate. */
public Rect getBounds1() {
return new Rect(mBounds1);
}
- /** Gets bounds of the secondary split. */
+ /** Gets bounds of the primary split with parent based coordinate. */
+ public Rect getRefBounds1() {
+ Rect outBounds = getBounds1();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
+ /** Gets bounds of the secondary split with screen based coordinate. */
public Rect getBounds2() {
return new Rect(mBounds2);
}
- /** Gets bounds of divider window. */
+ /** Gets bounds of the secondary split with parent based coordinate. */
+ public Rect getRefBounds2() {
+ final Rect outBounds = getBounds2();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
+ /** Gets bounds of divider window with screen based coordinate. */
public Rect getDividerBounds() {
return new Rect(mDividerBounds);
}
+ /** Gets bounds of divider window with parent based coordinate. */
+ public Rect getRefDividerBounds() {
+ final Rect outBounds = getDividerBounds();
+ outBounds.offset(-mRootBounds.left, -mRootBounds.top);
+ return outBounds;
+ }
+
/** Returns leash of the current divider bar. */
@Nullable
public SurfaceControl getDividerLeash() {
@@ -452,14 +473,17 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) {
final SurfaceControl dividerLeash = getDividerLeash();
if (dividerLeash != null) {
- t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top);
+ mTempRect.set(getRefDividerBounds());
+ t.setPosition(dividerLeash, mTempRect.left, mTempRect.top);
// Resets layer of divider bar to make sure it is always on top.
t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
}
- t.setPosition(leash1, mBounds1.left, mBounds1.top)
- .setWindowCrop(leash1, mBounds1.width(), mBounds1.height());
- t.setPosition(leash2, mBounds2.left, mBounds2.top)
- .setWindowCrop(leash2, mBounds2.width(), mBounds2.height());
+ mTempRect.set(getRefBounds1());
+ t.setPosition(leash1, mTempRect.left, mTempRect.top)
+ .setWindowCrop(leash1, mTempRect.width(), mTempRect.height());
+ mTempRect.set(getRefBounds2());
+ t.setPosition(leash2, mTempRect.left, mTempRect.top)
+ .setWindowCrop(leash2, mTempRect.width(), mTempRect.height());
if (mImePositionProcessor.adjustSurfaceLayoutForIme(
t, dividerLeash, leash1, leash2, dimLayer1, dimLayer2)) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
index 180e3fb48c9d..d7322ce7beda 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipSurfaceTransactionHelper.java
@@ -138,8 +138,8 @@ public class PipSurfaceTransactionHelper {
// destination are different.
final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
final Rect crop = mTmpDestinationRect;
- crop.set(0, 0, Transitions.ENABLE_SHELL_TRANSITIONS ? destH
- : destW, Transitions.ENABLE_SHELL_TRANSITIONS ? destW : destH);
+ crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH
+ : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH);
// Inverse scale for crop to fit in screen coordinates.
crop.scale(1 / scale);
crop.offset(insets.left, insets.top);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 60aac6806623..91615fe05417 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -97,7 +97,7 @@ public class PipTransition extends PipTransitionController {
* meaningful if {@link #mInFixedRotation} is true.
*/
@Surface.Rotation
- private int mFixedRotation;
+ private int mEndFixedRotation;
/** Whether the PIP window has fade out for fixed rotation. */
private boolean mHasFadeOut;
@@ -153,7 +153,7 @@ public class PipTransition extends PipTransitionController {
final TransitionInfo.Change currentPipChange = findCurrentPipChange(info);
final TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info);
mInFixedRotation = fixedRotationChange != null;
- mFixedRotation = mInFixedRotation
+ mEndFixedRotation = mInFixedRotation
? fixedRotationChange.getEndFixedRotation()
: ROTATION_UNDEFINED;
@@ -257,7 +257,7 @@ public class PipTransition extends PipTransitionController {
final ActivityManager.RunningTaskInfo taskInfo = mPipOrganizer.getTaskInfo();
if (taskInfo != null) {
startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
- new Rect(mExitDestinationBounds));
+ new Rect(mExitDestinationBounds), Surface.ROTATION_0);
}
mExitDestinationBounds.setEmpty();
mCurrentPipTaskToken = null;
@@ -332,30 +332,31 @@ public class PipTransition extends PipTransitionController {
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TransitionInfo.Change pipChange) {
- TransitionInfo.Change displayRotationChange = null;
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- if (change.getMode() == TRANSIT_CHANGE
- && (change.getFlags() & FLAG_IS_DISPLAY) != 0
- && change.getStartRotation() != change.getEndRotation()) {
- displayRotationChange = change;
- break;
- }
- }
-
- if (displayRotationChange != null) {
- // Exiting PIP to fullscreen with orientation change.
- startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
- finishCallback, displayRotationChange, pipChange);
- return;
- }
-
- // When there is no rotation, we can simply expand the PIP window.
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
finishCallback.onTransitionFinished(wct, wctCB);
};
+ // Check if it is Shell rotation.
+ if (Transitions.SHELL_TRANSITIONS_ROTATION) {
+ TransitionInfo.Change displayRotationChange = null;
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.getMode() == TRANSIT_CHANGE
+ && (change.getFlags() & FLAG_IS_DISPLAY) != 0
+ && change.getStartRotation() != change.getEndRotation()) {
+ displayRotationChange = change;
+ break;
+ }
+ }
+ if (displayRotationChange != null) {
+ // Exiting PIP to fullscreen with orientation change.
+ startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
+ displayRotationChange, pipChange);
+ return;
+ }
+ }
+
// Set the initial frame as scaling the end to the start.
final Rect destinationBounds = new Rect(pipChange.getEndAbsBounds());
final Point offset = pipChange.getEndRelOffset();
@@ -364,13 +365,41 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper.scale(startTransaction, pipChange.getLeash(),
destinationBounds, mPipBoundsState.getBounds());
startTransaction.apply();
- startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds);
+
+ // Check if it is fixed rotation.
+ final int rotationDelta;
+ if (mInFixedRotation) {
+ final int startRotation = pipChange.getStartRotation();
+ final int endRotation = mEndFixedRotation;
+ rotationDelta = deltaRotation(startRotation, endRotation);
+ final Rect endBounds = new Rect(destinationBounds);
+
+ // Set the end frame since the display won't rotate until fixed rotation is finished
+ // in the next display change transition.
+ rotateBounds(endBounds, destinationBounds, rotationDelta);
+ final int degree, x, y;
+ if (rotationDelta == ROTATION_90) {
+ degree = 90;
+ x = destinationBounds.right;
+ y = destinationBounds.top;
+ } else {
+ degree = -90;
+ x = destinationBounds.left;
+ y = destinationBounds.bottom;
+ }
+ mSurfaceTransactionHelper.rotateAndScaleWithCrop(finishTransaction,
+ pipChange.getLeash(), endBounds, endBounds, new Rect(), degree, x, y,
+ true /* isExpanding */, rotationDelta == ROTATION_270 /* clockwise */);
+ } else {
+ rotationDelta = Surface.ROTATION_0;
+ }
+ startExpandAnimation(pipChange.getTaskInfo(), pipChange.getLeash(), destinationBounds,
+ rotationDelta);
}
private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
- @NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull TransitionInfo.Change displayRotationChange,
@NonNull TransitionInfo.Change pipChange) {
final int rotateDelta = deltaRotation(displayRotationChange.getStartRotation(),
@@ -380,11 +409,6 @@ public class PipTransition extends PipTransitionController {
final CounterRotatorHelper rotator = new CounterRotatorHelper();
rotator.handleClosingChanges(info, startTransaction, displayRotationChange);
- mFinishCallback = (wct, wctCB) -> {
- mPipOrganizer.onExitPipFinished(pipChange.getTaskInfo());
- finishCallback.onTransitionFinished(wct, wctCB);
- };
-
// Get the start bounds in new orientation.
final Rect startBounds = new Rect(pipChange.getStartAbsBounds());
rotateBounds(startBounds, displayRotationChange.getStartAbsBounds(), rotateDelta);
@@ -425,12 +449,11 @@ public class PipTransition extends PipTransitionController {
}
private void startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
- final Rect destinationBounds) {
- PipAnimationController.PipTransitionAnimator animator =
+ final Rect destinationBounds, final int rotationDelta) {
+ final PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(),
mPipBoundsState.getBounds(), destinationBounds, null,
- TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, Surface.ROTATION_0);
-
+ TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, rotationDelta);
animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
@@ -526,7 +549,7 @@ public class PipTransition extends PipTransitionController {
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
mFinishCallback = finishCallback;
- final int endRotation = mInFixedRotation ? mFixedRotation : enterPip.getEndRotation();
+ final int endRotation = mInFixedRotation ? mEndFixedRotation : enterPip.getEndRotation();
return startEnterAnimation(enterPip.getTaskInfo(), enterPip.getLeash(),
startTransaction, finishTransaction, enterPip.getStartRotation(),
endRotation);
@@ -545,8 +568,8 @@ public class PipTransition extends PipTransitionController {
taskInfo.pictureInPictureParams, currentBounds);
if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
// Need to get the bounds of new rotation in old rotation for fixed rotation,
- sourceHintRect = computeRotatedBounds(rotationDelta, startRotation, endRotation,
- taskInfo, TRANSITION_DIRECTION_TO_PIP, destinationBounds, sourceHintRect);
+ computeEnterPipRotatedBounds(rotationDelta, startRotation, endRotation, taskInfo,
+ destinationBounds, sourceHintRect);
}
PipAnimationController.PipTransitionAnimator animator;
// Set corner radius for entering pip.
@@ -583,8 +606,6 @@ public class PipTransition extends PipTransitionController {
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- // Reverse the rotation for Shell transition animation.
- rotationDelta = deltaRotation(rotationDelta, 0);
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
0 /* startingAngle */, rotationDelta);
@@ -617,33 +638,22 @@ public class PipTransition extends PipTransitionController {
return true;
}
- /** Computes destination bounds in old rotation and returns source hint rect if available. */
- @Nullable
- private Rect computeRotatedBounds(int rotationDelta, int startRotation, int endRotation,
- TaskInfo taskInfo, int direction, Rect outDestinationBounds,
- @Nullable Rect sourceHintRect) {
- if (direction == TRANSITION_DIRECTION_TO_PIP) {
- mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
- final Rect displayBounds = mPipBoundsState.getDisplayBounds();
- outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
- // Transform the destination bounds to current display coordinates.
- rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
- // When entering PiP (from button navigation mode), adjust the source rect hint by
- // display cutout if applicable.
- if (sourceHintRect != null && taskInfo.displayCutoutInsets != null) {
- if (rotationDelta == Surface.ROTATION_270) {
- sourceHintRect.offset(taskInfo.displayCutoutInsets.left,
- taskInfo.displayCutoutInsets.top);
- }
+ /** Computes destination bounds in old rotation and updates source hint rect if available. */
+ private void computeEnterPipRotatedBounds(int rotationDelta, int startRotation, int endRotation,
+ TaskInfo taskInfo, Rect outDestinationBounds, @Nullable Rect outSourceHintRect) {
+ mPipBoundsState.getDisplayLayout().rotateTo(mContext.getResources(), endRotation);
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
+ // Transform the destination bounds to current display coordinates.
+ rotateBounds(outDestinationBounds, displayBounds, endRotation, startRotation);
+ // When entering PiP (from button navigation mode), adjust the source rect hint by
+ // display cutout if applicable.
+ if (outSourceHintRect != null && taskInfo.displayCutoutInsets != null) {
+ if (rotationDelta == Surface.ROTATION_270) {
+ outSourceHintRect.offset(taskInfo.displayCutoutInsets.left,
+ taskInfo.displayCutoutInsets.top);
}
- } else if (direction == TRANSITION_DIRECTION_LEAVE_PIP) {
- final Rect rotatedDestinationBounds = new Rect(outDestinationBounds);
- rotateBounds(rotatedDestinationBounds, mPipBoundsState.getDisplayBounds(),
- rotationDelta);
- return PipBoundsAlgorithm.getValidSourceHintRect(taskInfo.pictureInPictureParams,
- rotatedDestinationBounds);
- }
- return sourceHintRect;
+ }
}
private void startExitToSplitAnimation(TransitionInfo info,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 69d6c9e0c3bd..32ebe2d6aecf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -33,6 +33,7 @@ import android.os.RemoteException;
import android.util.Log;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.WindowManagerGlobal;
import androidx.annotation.Nullable;
@@ -143,7 +144,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
mSystemWindows.addView(mPipMenuView,
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
0, SHELL_ROOT_LAYER_PIP);
- mPipMenuView.setFocusGrantToken(mSystemWindows.getFocusGrantToken(mPipMenuView));
}
@Override
@@ -164,6 +164,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
t.setPosition(menuSurfaceControl, menuBounds.left, menuBounds.top);
t.apply();
}
+ grantPipMenuFocus(true);
mPipMenuView.show(mInMoveMode, mDelegate.getPipGravity());
}
}
@@ -194,8 +195,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
if (DEBUG) Log.d(TAG, "hideMenu()");
}
- mPipMenuView.hide(mInMoveMode);
+ mPipMenuView.hide();
if (!mInMoveMode) {
+ grantPipMenuFocus(false);
mDelegate.closeMenu();
}
}
@@ -453,4 +455,15 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
void closePip();
}
+
+ private void grantPipMenuFocus(boolean grantFocus) {
+ if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
+
+ try {
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ mSystemWindows.getFocusGrantToken(mPipMenuView), grantFocus);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to update focus", e);
+ }
+ }
}
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 773e9bfa8977..3090139f6db9 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
@@ -30,7 +30,6 @@ import android.app.RemoteAction;
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
-import android.os.IBinder;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
@@ -39,7 +38,6 @@ import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
-import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -72,7 +70,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
private final ImageView mArrowRight;
private final ImageView mArrowDown;
private final ImageView mArrowLeft;
- private IBinder mFocusGrantToken = null;
private final ViewGroup mScrollView;
private final ViewGroup mHorizontalScrollView;
@@ -152,10 +149,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
mListener = listener;
}
- void setFocusGrantToken(IBinder token) {
- mFocusGrantToken = token;
- }
-
void setExpandedModeEnabled(boolean enabled) {
mExpandButton.setVisibility(enabled ? VISIBLE : GONE);
}
@@ -170,8 +163,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
void show(boolean inMoveMode, int gravity) {
if (DEBUG) Log.d(TAG, "show(), inMoveMode: " + inMoveMode);
- grantWindowFocus(true);
-
if (inMoveMode) {
showMovementHints(gravity);
} else {
@@ -180,15 +171,11 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
animateAlphaTo(1, mMenuFrameView);
}
- void hide(boolean isInMoveMode) {
+ void hide() {
if (DEBUG) Log.d(TAG, "hide()");
animateAlphaTo(0, mActionButtonsContainer);
animateAlphaTo(0, mMenuFrameView);
hideMovementHints();
-
- if (!isInMoveMode) {
- grantWindowFocus(false);
- }
}
private void animateAlphaTo(float alpha, View view) {
@@ -217,17 +204,6 @@ public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
|| mArrowLeft.getAlpha() != 0f;
}
- private void grantWindowFocus(boolean grantFocus) {
- if (DEBUG) Log.d(TAG, "grantWindowFocus(" + grantFocus + ")");
-
- try {
- WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
- mFocusGrantToken, grantFocus);
- } catch (Exception e) {
- Log.e(TAG, "Unable to update focus", e);
- }
- }
-
void setAdditionalActions(List<RemoteAction> actions, Handler mainHandler) {
if (DEBUG) Log.d(TAG, "setAdditionalActions()");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 81dacdb753a7..76641f0e6c21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -979,7 +979,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
t.setAlpha(dividerLeash, 1);
t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER);
t.setPosition(dividerLeash,
- mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top);
+ mSplitLayout.getRefDividerBounds().left,
+ mSplitLayout.getRefDividerBounds().top);
} else {
t.hide(dividerLeash);
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
index 65eb9aa991c2..57bcbc093a62 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/apppairs/AppPairsTestSupportPairNonResizeableApps.kt
@@ -17,6 +17,7 @@
package com.android.wm.shell.flicker.apppairs
import android.platform.test.annotations.Presubmit
+import android.view.Display
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -24,6 +25,7 @@ import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.wm.shell.flicker.appPairsDividerIsVisibleAtEnd
import com.android.wm.shell.flicker.helpers.AppPairsHelper
import com.android.wm.shell.flicker.helpers.MultiWindowHelper.Companion.resetMultiWindowConfig
@@ -60,7 +62,18 @@ class AppPairsTestSupportPairNonResizeableApps(
// TODO pair apps through normal UX flow
executeShellCommand(
composePairsCommand(primaryTaskId, nonResizeableTaskId, pair = true))
- nonResizeableApp?.run { wmHelper.waitForFullScreenApp(nonResizeableApp.component) }
+ val waitConditions = mutableListOf(
+ WindowManagerConditionsFactory.isWindowVisible(primaryApp.component),
+ WindowManagerConditionsFactory.isLayerVisible(primaryApp.component),
+ WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY))
+
+ nonResizeableApp?.let {
+ waitConditions.add(
+ WindowManagerConditionsFactory.isWindowVisible(nonResizeableApp.component))
+ waitConditions.add(
+ WindowManagerConditionsFactory.isLayerVisible(nonResizeableApp.component))
+ }
+ wmHelper.waitFor(*waitConditions.toTypedArray())
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
index 0f00edea136f..cc5b9f9eb26d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -62,7 +62,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
if (wmHelper == null) {
device.waitForIdle()
} else {
- require(wmHelper.waitImeShown()) { "IME did not appear" }
+ wmHelper.waitImeShown()
}
}
@@ -79,7 +79,7 @@ open class ImeAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
if (wmHelper == null) {
uiDevice.waitForIdle()
} else {
- require(wmHelper.waitImeGone()) { "IME did did not close" }
+ wmHelper.waitImeGone()
}
} else {
// While pressing the back button should close the IME on TV as well, it may also lead
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 7e232ea32181..e9d438a569d5 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -58,17 +58,27 @@ class PipAppHelper(instrumentation: Instrumentation) : BaseAppHelper(
}
}
- /** {@inheritDoc} */
- override fun launchViaIntent(
+ /**
+ * Launches the app through an intent instead of interacting with the launcher and waits
+ * until the app window is in PIP mode
+ */
+ @JvmOverloads
+ fun launchViaIntentAndWaitForPip(
wmHelper: WindowManagerStateHelper,
- expectedWindowName: String,
- action: String?,
+ expectedWindowName: String = "",
+ action: String? = null,
stringExtras: Map<String, String>
) {
- super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras)
- wmHelper.waitPipShown()
+ launchViaIntentAndWaitShown(wmHelper, expectedWindowName, action, stringExtras,
+ waitConditions = arrayOf(WindowManagerStateHelper.pipShownCondition))
}
+ /**
+ * Expand the PIP window back to full screen via intent and wait until the app is visible
+ */
+ fun exitPipToFullScreenViaIntent(wmHelper: WindowManagerStateHelper) =
+ launchViaIntentAndWaitShown(wmHelper)
+
private fun focusOnObject(selector: BySelector): Boolean {
// We expect all the focusable UI elements to be arranged in a way so that it is possible
// to "cycle" over all them by clicking the D-Pad DOWN button, going back up to "the top"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index f2c50935a3e9..274d34ba3c5b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -64,7 +64,18 @@ class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
* Defines the transition used to run the test
*/
override val transition: FlickerBuilder.() -> Unit
- get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
+ get() = {
+ setupAndTeardown(this)
+ setup {
+ eachRun {
+ pipApp.launchViaIntent(wmHelper)
+ }
+ }
+ teardown {
+ eachRun {
+ pipApp.exit(wmHelper)
+ }
+ }
transitions {
pipApp.clickEnterPipButton(wmHelper)
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 4f98b70e222a..e2d08346efb6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -74,7 +74,7 @@ class ExitPipViaExpandButtonClickTest(
// This will bring PipApp to fullscreen
pipApp.expandPipWindowToApp(wmHelper)
// Wait until the other app is no longer visible
- wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+ wmHelper.waitForSurfaceAppeared(testApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index e00d7491839f..3fe6f02eccf7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -72,9 +72,9 @@ class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransit
}
transitions {
// This will bring PipApp to fullscreen
- pipApp.launchViaIntent(wmHelper)
+ pipApp.exitPipToFullScreenViaIntent(wmHelper)
// Wait until the other app is no longer visible
- wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+ wmHelper.waitForWindowSurfaceDisappeared(testApp.component)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index bb66f7bbc01f..654fa4ec9446 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -122,15 +122,14 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
setup {
test {
- removeAllTasksButHome()
if (!eachRun) {
- pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
+ pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
wmHelper.waitPipShown()
}
}
eachRun {
if (eachRun) {
- pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
+ pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
wmHelper.waitPipShown()
}
}
@@ -145,7 +144,6 @@ abstract class PipTransition(protected val testSpec: FlickerTestParameter) {
if (!eachRun) {
pipApp.exit(wmHelper)
}
- removeAllTasksButHome()
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index dda1a8295e51..85527c81ad9e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
+
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -51,6 +52,7 @@ public class SplitTestUtils {
final SurfaceControl leash = createMockSurface();
SplitLayout out = mock(SplitLayout.class);
doReturn(dividerBounds).when(out).getDividerBounds();
+ doReturn(dividerBounds).when(out).getRefDividerBounds();
doReturn(leash).when(out).getDividerLeash();
return out;
}
diff --git a/packages/CompanionDeviceManager/Android.bp b/packages/CompanionDeviceManager/Android.bp
index 6ded16371e8a..9f5bfd40e7e3 100644
--- a/packages/CompanionDeviceManager/Android.bp
+++ b/packages/CompanionDeviceManager/Android.bp
@@ -34,6 +34,7 @@ license {
android_app {
name: "CompanionDeviceManager",
defaults: ["platform_app_defaults"],
+ certificate: "platform",
srcs: ["src/**/*.java"],
static_libs: [
diff --git a/packages/CompanionDeviceManager/AndroidManifest.xml b/packages/CompanionDeviceManager/AndroidManifest.xml
index 06f2d9d0f0c8..8b5d214f7a10 100644
--- a/packages/CompanionDeviceManager/AndroidManifest.xml
+++ b/packages/CompanionDeviceManager/AndroidManifest.xml
@@ -31,6 +31,7 @@
<uses-permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
<application
android:allowClearUserData="true"
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index b51d3103caec..a6a8fcf9af62 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -37,6 +37,7 @@ import android.companion.AssociationRequest;
import android.companion.CompanionDeviceManager;
import android.companion.IAssociationRequestCallback;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.net.MacAddress;
import android.os.Bundle;
import android.os.Handler;
@@ -71,6 +72,9 @@ public class CompanionDeviceActivity extends AppCompatActivity {
private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
+ // Activity result: Internal Error.
+ private static final int RESULT_INTERNAL_ERROR = 2;
+
// AssociationRequestsProcessor -> UI
private static final int RESULT_CODE_ASSOCIATION_CREATED = 0;
private static final String EXTRA_ASSOCIATION = "association";
@@ -191,6 +195,20 @@ public class CompanionDeviceActivity extends AppCompatActivity {
private void initUI() {
if (DEBUG) Log.d(TAG, "initUI(), request=" + mRequest);
+ final String packageName = mRequest.getPackageName();
+ final int userId = mRequest.getUserId();
+ final CharSequence appLabel;
+
+ try {
+ appLabel = getApplicationLabel(this, packageName, userId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Package u" + userId + "/" + packageName + " not found.");
+
+ CompanionDeviceDiscoveryService.stop(this);
+ setResultAndFinish(null, RESULT_INTERNAL_ERROR);
+ return;
+ }
+
setContentView(R.layout.activity_confirmation);
mTitle = findViewById(R.id.title);
@@ -203,8 +221,6 @@ public class CompanionDeviceActivity extends AppCompatActivity {
mButtonAllow.setOnClickListener(this::onPositiveButtonClick);
findViewById(R.id.btn_negative).setOnClickListener(this::onNegativeButtonClick);
- final CharSequence appLabel = getApplicationLabel(this, mRequest.getPackageName());
-
if (mRequest.isSelfManaged()) {
initUiForSelfManagedAssociation(appLabel);
} else if (mRequest.isSingleDevice()) {
@@ -257,7 +273,7 @@ public class CompanionDeviceActivity extends AppCompatActivity {
if (DEBUG) Log.i(TAG, "onAssociationCreated(), association=" + association);
// Don't need to notify the app, CdmService has already done that. Just finish.
- setResultAndFinish(association);
+ setResultAndFinish(association, RESULT_OK);
}
private void cancel(boolean discoveryTimeout) {
@@ -284,10 +300,10 @@ public class CompanionDeviceActivity extends AppCompatActivity {
}
// ... then set result and finish ("sending" onActivityResult()).
- setResultAndFinish(null);
+ setResultAndFinish(null, RESULT_CANCELED);
}
- private void setResultAndFinish(@Nullable AssociationInfo association) {
+ private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) {
if (DEBUG) Log.i(TAG, "setResultAndFinish(), association=" + association);
final Intent data = new Intent();
@@ -297,7 +313,7 @@ public class CompanionDeviceActivity extends AppCompatActivity {
data.putExtra(CompanionDeviceManager.EXTRA_DEVICE, mSelectedDevice.getDevice());
}
}
- setResult(association != null ? RESULT_OK : RESULT_CANCELED, data);
+ setResult(resultCode, data);
finish();
}
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
index eab421e48446..e3e563d56e8a 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
@@ -50,14 +50,13 @@ class Utils {
}
static @NonNull CharSequence getApplicationLabel(
- @NonNull Context context, @NonNull String packageName) {
+ @NonNull Context context, @NonNull String packageName, int userId)
+ throws PackageManager.NameNotFoundException {
final PackageManager packageManager = context.getPackageManager();
- final ApplicationInfo appInfo;
- try {
- appInfo = packageManager.getApplicationInfo(packageName, 0);
- } catch (PackageManager.NameNotFoundException e) {
- throw new RuntimeException(e);
- }
+
+ final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
+ packageName, PackageManager.ApplicationInfoFlags.of(0), userId);
+
return packageManager.getApplicationLabel(appInfo);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
index 961fab32fc2c..4ed7e19f341d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
@@ -22,6 +22,7 @@ import static android.provider.Settings.Secure.DEVICE_STATE_ROTATION_LOCK_UNLOCK
import android.content.ContentResolver;
import android.content.Context;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.Looper;
@@ -34,7 +35,10 @@ import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
/**
@@ -48,13 +52,14 @@ public final class DeviceStateRotationLockSettingsManager {
private static DeviceStateRotationLockSettingsManager sSingleton;
- private final String[] mDeviceStateRotationLockDefaults;
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private final Set<DeviceStateRotationLockSettingsListener> mListeners = new HashSet<>();
private final SecureSettings mSecureSettings;
+ private String[] mDeviceStateRotationLockDefaults;
private SparseIntArray mDeviceStateRotationLockSettings;
private SparseIntArray mDeviceStateRotationLockFallbackSettings;
private String mLastSettingValue;
+ private List<SettableDeviceState> mSettableDeviceStates;
@VisibleForTesting
DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) {
@@ -79,6 +84,12 @@ public final class DeviceStateRotationLockSettingsManager {
return sSingleton;
}
+ /** Resets the singleton instance of this class. Only used for testing. */
+ @VisibleForTesting
+ public static synchronized void resetInstance() {
+ sSingleton = null;
+ }
+
/** Returns true if device-state based rotation lock settings are enabled. */
public static boolean isDeviceStateRotationLockEnabled(Context context) {
return context.getResources()
@@ -186,6 +197,12 @@ public final class DeviceStateRotationLockSettingsManager {
return true;
}
+ /** Returns a list of device states and their respective auto-rotation setting availability. */
+ public List<SettableDeviceState> getSettableDeviceStates() {
+ // Returning a copy to make sure that nothing outside can mutate our internal list.
+ return new ArrayList<>(mSettableDeviceStates);
+ }
+
private void initializeInMemoryMap() {
String serializedSetting =
mSecureSettings.getStringForUser(
@@ -220,6 +237,17 @@ public final class DeviceStateRotationLockSettingsManager {
}
}
+ /**
+ * Resets the state of the class and saved settings back to the default values provided by the
+ * resources config.
+ */
+ @VisibleForTesting
+ public void resetStateForTesting(Resources resources) {
+ mDeviceStateRotationLockDefaults =
+ resources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
+ fallbackOnDefaults();
+ }
+
private void fallbackOnDefaults() {
loadDefaults();
persistSettings();
@@ -259,6 +287,7 @@ public final class DeviceStateRotationLockSettingsManager {
}
private void loadDefaults() {
+ mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockSettings = new SparseIntArray(
mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
@@ -279,6 +308,8 @@ public final class DeviceStateRotationLockSettingsManager {
+ values.length);
}
}
+ boolean isSettable = rotationLockSetting != DEVICE_STATE_ROTATION_LOCK_IGNORED;
+ mSettableDeviceStates.add(new SettableDeviceState(deviceState, isSettable));
mDeviceStateRotationLockSettings.put(deviceState, rotationLockSetting);
} catch (NumberFormatException e) {
Log.wtf(TAG, "Error parsing settings entry. Entry was: " + entry, e);
@@ -308,4 +339,38 @@ public final class DeviceStateRotationLockSettingsManager {
/** Called whenever the settings have changed. */
void onSettingsChanged();
}
+
+ /** Represents a device state and whether it has an auto-rotation setting. */
+ public static class SettableDeviceState {
+ private final int mDeviceState;
+ private final boolean mIsSettable;
+
+ SettableDeviceState(int deviceState, boolean isSettable) {
+ mDeviceState = deviceState;
+ mIsSettable = isSettable;
+ }
+
+ /** Returns the device state associated with this object. */
+ public int getDeviceState() {
+ return mDeviceState;
+ }
+
+ /** Returns whether there is an auto-rotation setting for this device state. */
+ public boolean isSettable() {
+ return mIsSettable;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SettableDeviceState)) return false;
+ SettableDeviceState that = (SettableDeviceState) o;
+ return mDeviceState == that.mDeviceState && mIsSettable == that.mIsSettable;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceState, mIsSettable);
+ }
+ }
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
index 1a45384bc768..81006dd6b011 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -30,12 +30,17 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.R;
+import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class DeviceStateRotationLockSettingsManagerTest {
@@ -94,4 +99,22 @@ public class DeviceStateRotationLockSettingsManagerTest {
assertThat(mNumSettingsChanges).isEqualTo(3);
}
+
+ @Test
+ public void getSettableDeviceStates_returnsExpectedValuesInOriginalOrder() {
+ when(mMockResources.getStringArray(
+ R.array.config_perDeviceStateRotationLockDefaults)).thenReturn(
+ new String[]{"2:2", "4:0", "1:1", "0:0"});
+
+ List<SettableDeviceState> settableDeviceStates =
+ DeviceStateRotationLockSettingsManager.getInstance(
+ mMockContext).getSettableDeviceStates();
+
+ assertThat(settableDeviceStates).containsExactly(
+ new SettableDeviceState(/* deviceState= */ 2, /* isSettable= */ true),
+ new SettableDeviceState(/* deviceState= */ 4, /* isSettable= */ false),
+ new SettableDeviceState(/* deviceState= */ 1, /* isSettable= */ true),
+ new SettableDeviceState(/* deviceState= */ 0, /* isSettable= */ false)
+ ).inOrder();
+ }
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f0b180e5cab6..121f9e58a62a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -588,6 +588,9 @@
<uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
<uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
+ <!-- Permission required for CTS test - KeyguardLockedStateApiTest -->
+ <uses-permission android:name="android.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE" />
+
<uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
<!-- Permission required for CTS test - ResourceObserverNativeTest -->
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 0d20403b08f2..de03993a6f17 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -43,6 +43,7 @@ import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.util.Range;
+import android.util.Size;
import android.view.Choreographer;
import android.view.Display;
import android.view.Gravity;
@@ -62,6 +63,8 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.view.accessibility.IRemoteMagnificationAnimationCallback;
+import androidx.core.math.MathUtils;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
@@ -166,6 +169,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private final Rect mMagnificationFrameBoundary = new Rect();
// The top Y of the system gesture rect at the bottom. Set to -1 if it is invalid.
private int mSystemGestureTop = -1;
+ private int mMinWindowSize;
private final WindowMagnificationAnimationController mAnimationController;
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
@@ -208,8 +212,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mBounceEffectDuration = mResources.getInteger(
com.android.internal.R.integer.config_shortAnimTime);
updateDimensions();
- setMagnificationFrameWith(mWindowBounds, mWindowBounds.width() / 2,
- mWindowBounds.height() / 2);
+
+ final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds);
+ setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(),
+ mWindowBounds.width() / 2, mWindowBounds.height() / 2);
computeBounceAnimationScale();
mMirrorWindowControl = mirrorWindowControl;
@@ -281,6 +287,8 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
R.dimen.magnification_drag_view_size);
mOuterBorderSize = mResources.getDimensionPixelSize(
R.dimen.magnification_outer_border_margin);
+ mMinWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
}
private void computeBounceAnimationScale() {
@@ -414,9 +422,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
return false;
}
mWindowBounds.set(currentWindowBounds);
+ final Size windowSize = getDefaultWindowSizeWithWindowBounds(mWindowBounds);
final float newCenterX = (getCenterX()) * mWindowBounds.width() / oldWindowBounds.width();
final float newCenterY = (getCenterY()) * mWindowBounds.height() / oldWindowBounds.height();
- setMagnificationFrameWith(mWindowBounds, (int) newCenterX, (int) newCenterY);
+
+ setMagnificationFrame(windowSize.getWidth(), windowSize.getHeight(), (int) newCenterX,
+ (int) newCenterY);
calculateMagnificationFrameBoundary();
return true;
}
@@ -454,11 +465,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mWindowBounds.set(currentWindowBounds);
- calculateMagnificationFrameBoundary();
-
- if (!isWindowVisible()) {
- return;
- }
// Keep MirrorWindow position on the screen unchanged when device rotates 90°
// clockwise or anti-clockwise.
@@ -469,14 +475,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
} else if (rotationDegree == 270) {
matrix.postTranslate(0, mWindowBounds.height());
}
- // The rect of MirrorView is going to be transformed.
- LayoutParams params =
- (LayoutParams) mMirrorView.getLayoutParams();
- mTmpRect.set(params.x, params.y, params.x + params.width, params.y + params.height);
- final RectF transformedRect = new RectF(mTmpRect);
+
+ final RectF transformedRect = new RectF(mMagnificationFrame);
+ // The window frame is going to be transformed by the rotation matrix.
+ transformedRect.inset(-mMirrorSurfaceMargin, -mMirrorSurfaceMargin);
matrix.mapRect(transformedRect);
- moveWindowMagnifier(transformedRect.left - mTmpRect.left,
- transformedRect.top - mTmpRect.top);
+ setWindowSizeAndCenter((int) transformedRect.width(), (int) transformedRect.height(),
+ (int) transformedRect.centerX(), (int) transformedRect.centerY());
}
/** Returns the rotation degree change of two {@link Surface.Rotation} */
@@ -573,16 +578,52 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
}
- private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) {
+ /**
+ * Sets the window size with given width and height in pixels without changing the
+ * window center. The width or the height will be clamped in the range
+ * [{@link #mMinWindowSize}, screen width or height].
+ *
+ * @param width the window width in pixels
+ * @param height the window height in pixels.
+ */
+ public void setWindowSize(int width, int height) {
+ setWindowSizeAndCenter(width, height, Float.NaN, Float.NaN);
+ }
+
+ void setWindowSizeAndCenter(int width, int height, float centerX, float centerY) {
+ width = MathUtils.clamp(width, mMinWindowSize, mWindowBounds.width());
+ height = MathUtils.clamp(height, mMinWindowSize, mWindowBounds.height());
+
+ if (Float.isNaN(centerX)) {
+ centerX = mMagnificationFrame.centerX();
+ }
+ if (Float.isNaN(centerX)) {
+ centerY = mMagnificationFrame.centerY();
+ }
+
+ final int frameWidth = width - 2 * mMirrorSurfaceMargin;
+ final int frameHeight = height - 2 * mMirrorSurfaceMargin;
+ setMagnificationFrame(frameWidth, frameHeight, (int) centerX, (int) centerY);
+ calculateMagnificationFrameBoundary();
+ // Correct the frame position to ensure it is inside the boundary.
+ updateMagnificationFramePosition(0, 0);
+ modifyWindowMagnification(true);
+ }
+
+ private void setMagnificationFrame(int width, int height, int centerX, int centerY) {
// Sets the initial frame area for the mirror and place it to the given center on the
// display.
+ final int initX = centerX - width / 2;
+ final int initY = centerY - height / 2;
+ mMagnificationFrame.set(initX, initY, initX + width, initY + height);
+ }
+
+ private Size getDefaultWindowSizeWithWindowBounds(Rect windowBounds) {
int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2;
initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size),
initSize);
initSize += 2 * mMirrorSurfaceMargin;
- final int initX = centerX - initSize / 2;
- final int initY = centerY - initSize / 2;
- mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
+ return new Size(initSize, initSize);
}
/**
@@ -596,8 +637,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
mTransaction.show(mMirrorSurface)
.reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
-
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
private void addDragTouchListeners() {
@@ -615,18 +655,25 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
}
/**
- * Modifies the placement of the mirrored content when the position of mMirrorView is updated.
+ * Modifies the placement of the mirrored content when the position or size of mMirrorView is
+ * updated.
+ *
+ * @param computeWindowSize set to {@code true} to compute window size with
+ * {@link #mMagnificationFrame}.
*/
- private void modifyWindowMagnification(SurfaceControl.Transaction t) {
+ private void modifyWindowMagnification(boolean computeWindowSize) {
mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
- updateMirrorViewLayout();
+ updateMirrorViewLayout(computeWindowSize);
}
/**
- * Updates the layout params of MirrorView and translates MirrorView position when the view is
- * moved close to the screen edges.
+ * Updates the layout params of MirrorView based on the size of {@link #mMagnificationFrame}
+ * and translates MirrorView position when the view is moved close to the screen edges;
+ *
+ * @param computeWindowSize set to {@code true} to compute window size with
+ * {@link #mMagnificationFrame}.
*/
- private void updateMirrorViewLayout() {
+ private void updateMirrorViewLayout(boolean computeWindowSize) {
if (!isWindowVisible()) {
return;
}
@@ -637,6 +684,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
(LayoutParams) mMirrorView.getLayoutParams();
params.x = mMagnificationFrame.left - mMirrorSurfaceMargin;
params.y = mMagnificationFrame.top - mMirrorSurfaceMargin;
+ if (computeWindowSize) {
+ params.width = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin;
+ params.height = mMagnificationFrame.height() + 2 * mMirrorSurfaceMargin;
+ }
// Translates MirrorView position to make MirrorSurfaceView that is inside MirrorView
// able to move close to the screen edges.
@@ -899,7 +950,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
createMirrorWindow();
showControls();
} else {
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
}
@@ -930,7 +981,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
return;
}
if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) {
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
}
@@ -1014,9 +1065,15 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
pw.println(" mOverlapWithGestureInsets:" + mOverlapWithGestureInsets);
pw.println(" mScale:" + mScale);
pw.println(" mMirrorViewBounds:" + (isWindowVisible() ? mMirrorViewBounds : "empty"));
+ pw.println(" mMagnificationFrameBoundary:"
+ + (isWindowVisible() ? mMagnificationFrameBoundary : "empty"));
+ pw.println(" mMagnificationFrame:"
+ + (isWindowVisible() ? mMagnificationFrame : "empty"));
pw.println(" mSourceBounds:"
+ (isWindowVisible() ? mSourceBounds : "empty"));
pw.println(" mSystemGestureTop:" + mSystemGestureTop);
+ pw.println(" mMagnificationFrameOffsetX:" + mMagnificationFrameOffsetX);
+ pw.println(" mMagnificationFrameOffsetY:" + mMagnificationFrameOffsetY);
}
private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index a262b8ad2e28..217210a5dafc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -165,6 +165,7 @@ internal class FooterActionsController @Inject constructor(
powerMenuLite.visibility = View.GONE
}
settingsButton.setOnClickListener(onClickListener)
+ multiUserSetting.isListening = true
if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
val securityFooter = securityFooterController.view as DualHeightHorizontalLinearLayout
securityFootersContainer?.addView(securityFooter)
@@ -215,6 +216,7 @@ internal class FooterActionsController @Inject constructor(
override fun onViewDetached() {
setListening(false)
+ multiUserSetting.isListening = false
}
fun setListening(listening: Boolean) {
@@ -222,7 +224,6 @@ internal class FooterActionsController @Inject constructor(
return
}
this.listening = listening
- multiUserSetting.isListening = listening
if (this.listening) {
userInfoController.addCallback(onUserInfoChangedListener)
updateView()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 1dd5e227a909..6e5926db519d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -88,6 +88,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
@LargeTest
@TestableLooper.RunWithLooper
@@ -345,15 +346,17 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
@Test
public void onOrientationChanged_disabled_updateDisplayRotation() {
- final Display display = Mockito.spy(mContext.getDisplay());
- when(display.getRotation()).thenReturn(Surface.ROTATION_90);
- when(mContext.getDisplay()).thenReturn(display);
+ final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
+ // Rotate the window clockwise 90 degree.
+ windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
+ windowBounds.right);
+ mWindowManager.setWindowBounds(windowBounds);
+ final int newRotation = simulateRotateTheDevice();
- mInstrumentation.runOnMainSync(() -> {
- mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
- });
+ mInstrumentation.runOnMainSync(() -> mWindowMagnificationController.onConfigurationChanged(
+ ActivityInfo.CONFIG_ORIENTATION));
- assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
+ assertEquals(newRotation, mWindowMagnificationController.mRotation);
}
@Test
@@ -603,6 +606,113 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
ReferenceTestUtils.waitForCondition(() -> hasMagnificationOverlapFlag());
}
+ @Test
+ public void setMinimumWindowSize_enabled_expectedWindowSize() {
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int expectedWindowHeight = minimumWindowSize;
+ final int expectedWindowWidth = minimumWindowSize;
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+
+ });
+
+ assertEquals(expectedWindowHeight, actualWindowHeight.get());
+ assertEquals(expectedWindowWidth, actualWindowWidth.get());
+ }
+
+ @Test
+ public void setMinimumWindowSizeThenEnable_expectedWindowSize() {
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final int expectedWindowHeight = minimumWindowSize;
+ final int expectedWindowWidth = minimumWindowSize;
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(expectedWindowWidth, expectedWindowHeight);
+ mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ assertEquals(expectedWindowHeight, actualWindowHeight.get());
+ assertEquals(expectedWindowWidth, actualWindowWidth.get());
+ }
+
+ @Test
+ public void setWindowSizeLessThanMin_enabled_minimumWindowSize() {
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(minimumWindowSize - 10,
+ minimumWindowSize - 10);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ assertEquals(minimumWindowSize, actualWindowHeight.get());
+ assertEquals(minimumWindowSize, actualWindowWidth.get());
+ }
+
+ @Test
+ public void setWindowSizeLargerThanScreenSize_enabled_windowSizeIsScreenSize() {
+ final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger actualWindowHeight = new AtomicInteger();
+ final AtomicInteger actualWindowWidth = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSize(bounds.width() + 10, bounds.height() + 10);
+ actualWindowHeight.set(mWindowManager.getLayoutParamsFromAttachedView().height);
+ actualWindowWidth.set(mWindowManager.getLayoutParamsFromAttachedView().width);
+ });
+
+ assertEquals(bounds.height(), actualWindowHeight.get());
+ assertEquals(bounds.width(), actualWindowWidth.get());
+ }
+
+ @Test
+ public void setWindowCenterOutOfScreen_enabled_magnificationCenterIsInsideTheScreen() {
+
+ final int minimumWindowSize = mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.accessibility_window_magnifier_min_size);
+ final Rect bounds = mWindowManager.getCurrentWindowMetrics().getBounds();
+ mInstrumentation.runOnMainSync(
+ () -> mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN,
+ Float.NaN, Float.NaN));
+
+ final AtomicInteger magnificationCenterX = new AtomicInteger();
+ final AtomicInteger magnificationCenterY = new AtomicInteger();
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.setWindowSizeAndCenter(minimumWindowSize,
+ minimumWindowSize, bounds.right, bounds.bottom);
+ magnificationCenterX.set((int) mWindowMagnificationController.getCenterX());
+ magnificationCenterY.set((int) mWindowMagnificationController.getCenterY());
+ });
+
+ assertTrue(magnificationCenterX.get() < bounds.right);
+ assertTrue(magnificationCenterY.get() < bounds.bottom);
+ }
+
private CharSequence getAccessibilityWindowTitle() {
final View mirrorView = mWindowManager.getAttachedView();
if (mirrorView == null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index 58ffbfa76328..15aaf5fa8e42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -163,6 +163,31 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
}
@Test
+ public void testPreviewModeFalseByDefault() {
+ mService.onBind(new Intent());
+
+ assertThat(mService.isPreviewMode()).isFalse();
+ }
+
+ @Test
+ public void testPreviewModeSetByIntentExtra() {
+ final Intent intent = new Intent();
+ intent.putExtra(DreamService.EXTRA_IS_PREVIEW, true);
+ mService.onBind(intent);
+
+ assertThat(mService.isPreviewMode()).isTrue();
+ }
+
+ @Test
+ public void testDreamLabel() {
+ final Intent intent = new Intent();
+ intent.putExtra(DreamService.EXTRA_DREAM_LABEL, "TestDream");
+ mService.onBind(intent);
+
+ assertThat(mService.getDreamLabel()).isEqualTo("TestDream");
+ }
+
+ @Test
public void testDestroy() {
mService.onDestroy();
mMainExecutor.runAllReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index 8ce50a680e50..f736f26e5c46 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -100,7 +100,9 @@ class FooterActionsControllerTest : LeakCheckedTest() {
@After
fun tearDown() {
- ViewUtils.detachView(view)
+ if (view.isAttachedToWindow) {
+ ViewUtils.detachView(view)
+ }
}
@Test
@@ -139,8 +141,7 @@ class FooterActionsControllerTest : LeakCheckedTest() {
@Test
fun testMultiUserSwitchUpdatedWhenSettingChanged() {
- // When expanded, listening is true
- controller.setListening(true)
+ // Always listening to setting while View is attached
testableLooper.processAllMessages()
val multiUserSwitch = view.requireViewById<View>(R.id.multi_user_switch)
@@ -156,4 +157,24 @@ class FooterActionsControllerTest : LeakCheckedTest() {
assertThat(multiUserSwitch.visibility).isEqualTo(View.VISIBLE)
}
+
+ @Test
+ fun testMultiUserSettingNotListenedAfterDetach() {
+ testableLooper.processAllMessages()
+
+ val multiUserSwitch = view.requireViewById<View>(R.id.multi_user_switch)
+ assertThat(multiUserSwitch.visibility).isNotEqualTo(View.VISIBLE)
+
+ ViewUtils.detachView(view)
+
+ // The setting is only used as an indicator for whether the view should refresh. The actual
+ // value of the setting is ignored; isMultiUserEnabled is the source of truth
+ whenever(multiUserSwitchController.isMultiUserEnabled).thenReturn(true)
+
+ // Changing the value of USER_SWITCHER_ENABLED should cause the view to update
+ fakeSettings.putIntForUser(Settings.Global.USER_SWITCHER_ENABLED, 1, userTracker.userId)
+ testableLooper.processAllMessages()
+
+ assertThat(multiUserSwitch.visibility).isNotEqualTo(View.VISIBLE)
+ }
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6813f3f83135..1c10304f7223 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -15623,24 +15623,20 @@ public class ActivityManagerService extends IActivityManager.Stub
}
for (int i = 0, size = processes.size(); i < size; i++) {
ProcessRecord app = processes.get(i);
- pw.println(String.format("------ DUMP RESOURCES %s (%s) ------",
+ pw.println(String.format("Resources History for %s (%s)",
app.processName,
app.info.packageName));
pw.flush();
try {
- TransferPipe tp = new TransferPipe();
+ TransferPipe tp = new TransferPipe(" ");
try {
IApplicationThread thread = app.getThread();
if (thread != null) {
app.getThread().dumpResources(tp.getWriteFd(), null);
tp.go(fd.getFileDescriptor(), 2000);
- pw.println(String.format("------ END DUMP RESOURCES %s (%s) ------",
- app.processName,
- app.info.packageName));
- pw.flush();
} else {
pw.println(String.format(
- "------ DUMP RESOURCES %s (%s) failed, no thread ------",
+ " Resources history for %s (%s) failed, no thread",
app.processName,
app.info.packageName));
}
@@ -15648,11 +15644,7 @@ public class ActivityManagerService extends IActivityManager.Stub
tp.kill();
}
} catch (IOException e) {
- pw.println(String.format(
- "------ EXCEPTION DUMPING RESOURCES for %s (%s): %s ------",
- app.processName,
- app.info.packageName,
- e.getMessage()));
+ pw.println(" " + e.getMessage());
pw.flush();
}
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index b813bc48118a..0edbea0dbd28 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -90,6 +90,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.CompatibilityOverrideConfig;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
@@ -268,16 +269,34 @@ public final class GameManagerService extends IGameManagerService.Stub {
break;
}
case SET_GAME_STATE: {
- if (mPowerManagerInternal == null) {
- final Bundle data = msg.getData();
- Slog.d(TAG, "Error setting loading mode for package "
- + data.getString(PACKAGE_NAME_MSG_KEY)
- + " and userId " + data.getInt(USER_ID_MSG_KEY));
- break;
- }
final GameState gameState = (GameState) msg.obj;
final boolean isLoading = gameState.isLoading();
- mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, isLoading);
+ final Bundle data = msg.getData();
+ final String packageName = data.getString(PACKAGE_NAME_MSG_KEY);
+ final int userId = data.getInt(USER_ID_MSG_KEY);
+
+ // Restrict to games only. Requires performance mode to be enabled.
+ final boolean boostEnabled =
+ getGameMode(packageName, userId) == GameManager.GAME_MODE_PERFORMANCE;
+ int uid;
+ try {
+ uid = mPackageManager.getPackageUidAsUser(packageName, userId);
+ } catch (NameNotFoundException e) {
+ Slog.v(TAG, "Failed to get package metadata");
+ uid = -1;
+ }
+ FrameworkStatsLog.write(FrameworkStatsLog.GAME_STATE_CHANGED, packageName, uid,
+ boostEnabled, gameStateModeToStatsdGameState(gameState.getMode()),
+ isLoading, gameState.getLabel(), gameState.getQuality());
+
+ if (boostEnabled) {
+ if (mPowerManagerInternal == null) {
+ Slog.d(TAG, "Error setting loading mode for package " + packageName
+ + " and userId " + userId);
+ break;
+ }
+ mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, isLoading);
+ }
break;
}
}
@@ -387,12 +406,6 @@ public final class GameManagerService extends IGameManagerService.Stub {
// Restrict to games only.
return;
}
-
- if (getGameMode(packageName, userId) != GameManager.GAME_MODE_PERFORMANCE) {
- // Requires performance mode to be enabled.
- return;
- }
-
final Message msg = mHandler.obtainMessage(SET_GAME_STATE);
final Bundle data = new Bundle();
data.putString(PACKAGE_NAME_MSG_KEY, packageName);
@@ -1543,6 +1556,22 @@ public final class GameManagerService extends IGameManagerService.Stub {
return out.toString();
}
+ private static int gameStateModeToStatsdGameState(int mode) {
+ switch (mode) {
+ case GameState.MODE_NONE:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_NONE;
+ case GameState.MODE_GAMEPLAY_INTERRUPTIBLE:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_GAMEPLAY_INTERRUPTIBLE;
+ case GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_GAMEPLAY_UNINTERRUPTIBLE;
+ case GameState.MODE_CONTENT:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_CONTENT;
+ case GameState.MODE_UNKNOWN:
+ default:
+ return FrameworkStatsLog.GAME_STATE_CHANGED__STATE__MODE_UNKNOWN;
+ }
+ }
+
private static ServiceThread createServiceThread() {
ServiceThread handlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 3491cd59ebb7..49a935ebadc9 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -479,6 +479,8 @@ public class BtHelper {
}
if (profile == BluetoothProfile.A2DP) {
mA2dp = (BluetoothA2dp) proxy;
+ } else if (profile == BluetoothProfile.HEARING_AID) {
+ mHearingAid = (BluetoothHearingAid) proxy;
} else if (profile == BluetoothProfile.LE_AUDIO) {
mLeAudio = (BluetoothLeAudio) proxy;
}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 76754d3e95d5..4a1a950c6a07 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -104,7 +104,7 @@ final class DreamController {
pw.println(" mCurrentDream:");
pw.println(" mToken=" + mCurrentDream.mToken);
pw.println(" mName=" + mCurrentDream.mName);
- pw.println(" mIsTest=" + mCurrentDream.mIsTest);
+ pw.println(" mIsPreviewMode=" + mCurrentDream.mIsPreviewMode);
pw.println(" mCanDoze=" + mCurrentDream.mCanDoze);
pw.println(" mUserId=" + mCurrentDream.mUserId);
pw.println(" mBound=" + mCurrentDream.mBound);
@@ -117,7 +117,7 @@ final class DreamController {
}
public void startDream(Binder token, ComponentName name,
- boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
+ boolean isPreviewMode, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
ComponentName overlayComponentName) {
stopDream(true /*immediate*/, "starting new dream");
@@ -127,10 +127,10 @@ final class DreamController {
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
Slog.i(TAG, "Starting dream: name=" + name
- + ", isTest=" + isTest + ", canDoze=" + canDoze
+ + ", isPreviewMode=" + isPreviewMode + ", canDoze=" + canDoze
+ ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId, wakeLock);
+ mCurrentDream = new DreamRecord(token, name, isPreviewMode, canDoze, userId, wakeLock);
mDreamStartTime = SystemClock.elapsedRealtime();
MetricsLogger.visible(mContext,
@@ -140,6 +140,7 @@ final class DreamController {
intent.setComponent(name);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.putExtra(DreamService.EXTRA_DREAM_OVERLAY_COMPONENT, overlayComponentName);
+ intent.putExtra(DreamService.EXTRA_IS_PREVIEW, isPreviewMode);
try {
if (!mContext.bindServiceAsUser(intent, mCurrentDream,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
@@ -190,7 +191,8 @@ final class DreamController {
final DreamRecord oldDream = mCurrentDream;
mCurrentDream = null;
Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
- + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ + ", isPreviewMode=" + oldDream.mIsPreviewMode
+ + ", canDoze=" + oldDream.mCanDoze
+ ", userId=" + oldDream.mUserId
+ ", reason='" + reason + "'"
+ (mSavedStopReason == null ? "" : "(from '" + mSavedStopReason + "')"));
@@ -247,7 +249,7 @@ final class DreamController {
mCurrentDream.mService = service;
- if (!mCurrentDream.mIsTest) {
+ if (!mCurrentDream.mIsPreviewMode) {
mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL);
mCurrentDream.mSentStartBroadcast = true;
}
@@ -263,7 +265,7 @@ final class DreamController {
private final class DreamRecord implements DeathRecipient, ServiceConnection {
public final Binder mToken;
public final ComponentName mName;
- public final boolean mIsTest;
+ public final boolean mIsPreviewMode;
public final boolean mCanDoze;
public final int mUserId;
@@ -275,11 +277,11 @@ final class DreamController {
public boolean mWakingGently;
- public DreamRecord(Binder token, ComponentName name,
- boolean isTest, boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
+ DreamRecord(Binder token, ComponentName name, boolean isPreviewMode,
+ boolean canDoze, int userId, PowerManager.WakeLock wakeLock) {
mToken = token;
mName = name;
- mIsTest = isTest;
+ mIsPreviewMode = isPreviewMode;
mCanDoze = canDoze;
mUserId = userId;
mWakeLock = wakeLock;
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index f0a6af3c8834..22d32a665611 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -87,7 +87,7 @@ public final class DreamManagerService extends SystemService {
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
private int mCurrentDreamUserId;
- private boolean mCurrentDreamIsTest;
+ private boolean mCurrentDreamIsPreview;
private boolean mCurrentDreamCanDoze;
private boolean mCurrentDreamIsDozing;
private boolean mCurrentDreamIsWaking;
@@ -169,7 +169,7 @@ public final class DreamManagerService extends SystemService {
pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
pw.println("mCurrentDreamName=" + mCurrentDreamName);
pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
- pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+ pw.println("mCurrentDreamIsPreview=" + mCurrentDreamIsPreview);
pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
pw.println("mCurrentDreamIsWaking=" + mCurrentDreamIsWaking);
@@ -190,7 +190,7 @@ public final class DreamManagerService extends SystemService {
private boolean isDreamingInternal() {
synchronized (mLock) {
- return mCurrentDreamToken != null && !mCurrentDreamIsTest
+ return mCurrentDreamToken != null && !mCurrentDreamIsPreview
&& !mCurrentDreamIsWaking;
}
}
@@ -235,7 +235,7 @@ public final class DreamManagerService extends SystemService {
private void testDreamInternal(ComponentName dream, int userId) {
synchronized (mLock) {
- startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
+ startDreamLocked(dream, true /*isPreviewMode*/, false /*canDoze*/, userId);
}
}
@@ -244,7 +244,7 @@ public final class DreamManagerService extends SystemService {
final ComponentName dream = chooseDreamForUser(doze, userId);
if (dream != null) {
synchronized (mLock) {
- startDreamLocked(dream, false /*isTest*/, doze, userId);
+ startDreamLocked(dream, false /*isPreviewMode*/, doze, userId);
}
}
}
@@ -395,10 +395,10 @@ public final class DreamManagerService extends SystemService {
}
private void startDreamLocked(final ComponentName name,
- final boolean isTest, final boolean canDoze, final int userId) {
+ final boolean isPreviewMode, final boolean canDoze, final int userId) {
if (!mCurrentDreamIsWaking
&& Objects.equals(mCurrentDreamName, name)
- && mCurrentDreamIsTest == isTest
+ && mCurrentDreamIsPreview == isPreviewMode
&& mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
Slog.i(TAG, "Already in target dream.");
@@ -412,7 +412,7 @@ public final class DreamManagerService extends SystemService {
final Binder newToken = new Binder();
mCurrentDreamToken = newToken;
mCurrentDreamName = name;
- mCurrentDreamIsTest = isTest;
+ mCurrentDreamIsPreview = isPreviewMode;
mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
@@ -424,7 +424,7 @@ public final class DreamManagerService extends SystemService {
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
mHandler.post(wakeLock.wrap(() -> {
mAtmInternal.notifyDreamStateChanged(true);
- mController.startDream(newToken, name, isTest, canDoze, userId, wakeLock,
+ mController.startDream(newToken, name, isPreviewMode, canDoze, userId, wakeLock,
mDreamOverlayServiceName);
}));
}
@@ -457,7 +457,7 @@ public final class DreamManagerService extends SystemService {
}
mCurrentDreamToken = null;
mCurrentDreamName = null;
- mCurrentDreamIsTest = false;
+ mCurrentDreamIsPreview = false;
mCurrentDreamCanDoze = false;
mCurrentDreamUserId = 0;
mCurrentDreamIsWaking = false;
diff --git a/services/core/java/com/android/server/inputmethod/ImePlatformCompatUtils.java b/services/core/java/com/android/server/inputmethod/ImePlatformCompatUtils.java
new file mode 100644
index 000000000000..83ca16d72c9b
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/ImePlatformCompatUtils.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 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.inputmethod;
+
+import static android.inputmethodservice.InputMethodService.FINISH_INPUT_NO_FALLBACK_CONNECTION;
+import static android.view.inputmethod.InputMethodManager.CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.compat.IPlatformCompat;
+
+/**
+ * A utility class used by {@link InputMethodManagerService} to manage the platform
+ * compatibility changes on IMF (Input Method Framework) side.
+ */
+final class ImePlatformCompatUtils {
+ private final IPlatformCompat mPlatformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
+ /**
+ * Whether to finish the {@link android.view.inputmethod.InputConnection} when the device
+ * becomes {@link android.os.PowerManager#isInteractive non-interactive}.
+ *
+ * @param imeUid The uid of the IME application
+ */
+ public boolean shouldFinishInputWithReportToIme(int imeUid) {
+ return isChangeEnabledByUid(FINISH_INPUT_NO_FALLBACK_CONNECTION, imeUid);
+ }
+
+ /**
+ * Whether to clear {@link android.view.inputmethod.InputMethodManager#SHOW_FORCED} flag
+ * when the next IME focused application changed.
+ *
+ * @param clientUid The uid of the app
+ */
+ public boolean shouldClearShowForcedFlag(int clientUid) {
+ return isChangeEnabledByUid(CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING, clientUid);
+ }
+
+ private boolean isChangeEnabledByUid(long changeFlag, int uid) {
+ boolean result = false;
+ try {
+ result = mPlatformCompat.isChangeEnabledByUid(changeFlag, uid);
+ } catch (RemoteException e) {
+ }
+ return result;
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0b7e39136feb..eb1de2a9bf91 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,7 +15,6 @@
package com.android.server.inputmethod;
-import static android.inputmethodservice.InputMethodService.FINISH_INPUT_NO_FALLBACK_CONNECTION;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import static android.os.IServiceManager.DUMP_FLAG_PROTO;
@@ -148,7 +147,6 @@ import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.inputmethod.DirectBootAwareness;
@@ -279,6 +277,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
+ final ImePlatformCompatUtils mImePlatformCompatUtils;
final boolean mHasFeature;
private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
new ArrayMap<>();
@@ -691,8 +690,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
*/
boolean mIsInteractive = true;
- private final IPlatformCompat mPlatformCompat;
-
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
/**
@@ -1627,6 +1624,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
+ mImePlatformCompatUtils = new ImePlatformCompatUtils();
mImeDisplayValidator = mWindowManagerInternal::getDisplayImePolicy;
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
@@ -1634,8 +1632,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mAccessibilityManager = AccessibilityManager.getInstance(context);
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
- mPlatformCompat = IPlatformCompat.Stub.asInterface(
- ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
Bundle extras = new Bundle();
@@ -3620,6 +3617,14 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return InputBindResult.INVALID_USER;
}
+ final boolean shouldClearFlag = mImePlatformCompatUtils.shouldClearShowForcedFlag(cs.uid);
+ // In case mShowForced flag affects the next client to keep IME visible, when the current
+ // client is leaving due to the next focused client, we clear mShowForced flag when the
+ // next client's targetSdkVersion is T or higher.
+ if (mCurFocusedWindow != windowToken && mShowForced && shouldClearFlag) {
+ mShowForced = false;
+ }
+
// cross-profile access is always allowed here to allow profile-switching.
if (!mSettings.isCurrentProfile(userId)) {
Slog.w(TAG, "A background user is requesting window. Hiding IME.");
@@ -4728,14 +4733,9 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// Inform the current client of the change in active status
if (mCurClient != null && mCurClient.client != null) {
- boolean reportToImeController = false;
- try {
- reportToImeController = mPlatformCompat.isChangeEnabledByUid(
- FINISH_INPUT_NO_FALLBACK_CONNECTION, getCurMethodUidLocked());
- } catch (RemoteException e) {
- }
scheduleSetActiveToClient(mCurClient, mIsInteractive, mInFullscreenMode,
- reportToImeController);
+ mImePlatformCompatUtils.shouldFinishInputWithReportToIme(
+ getCurMethodUidLocked()));
}
}
}
diff --git a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
index 01aee7bc1942..db81393a9ad6 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerBackupHelper.java
@@ -34,7 +34,6 @@ import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.LocaleList;
-import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -45,7 +44,6 @@ import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.content.PackageMonitor;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -89,32 +87,24 @@ class LocaleManagerBackupHelper {
// SparseArray because it is more memory-efficient than a HashMap.
private final SparseArray<StagedData> mStagedData;
- private final PackageMonitor mPackageMonitor;
private final BroadcastReceiver mUserMonitor;
LocaleManagerBackupHelper(LocaleManagerService localeManagerService,
- PackageManagerInternal pmInternal) {
+ PackageManagerInternal pmInternal, HandlerThread broadcastHandlerThread) {
this(localeManagerService.mContext, localeManagerService, pmInternal, Clock.systemUTC(),
- new SparseArray<>());
+ new SparseArray<>(), broadcastHandlerThread);
}
@VisibleForTesting LocaleManagerBackupHelper(Context context,
LocaleManagerService localeManagerService,
- PackageManagerInternal pmInternal, Clock clock, SparseArray<StagedData> stagedData) {
+ PackageManagerInternal pmInternal, Clock clock, SparseArray<StagedData> stagedData,
+ HandlerThread broadcastHandlerThread) {
mContext = context;
mLocaleManagerService = localeManagerService;
mPackageManagerInternal = pmInternal;
mClock = clock;
mStagedData = stagedData;
- HandlerThread broadcastHandlerThread = new HandlerThread(TAG,
- Process.THREAD_PRIORITY_BACKGROUND);
- broadcastHandlerThread.start();
-
- mPackageMonitor = new PackageMonitorImpl();
- mPackageMonitor.register(context, broadcastHandlerThread.getLooper(),
- UserHandle.ALL,
- true);
mUserMonitor = new UserMonitor();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_REMOVED);
@@ -127,11 +117,6 @@ class LocaleManagerBackupHelper {
return mUserMonitor;
}
- @VisibleForTesting
- PackageMonitor getPackageMonitor() {
- return mPackageMonitor;
- }
-
/**
* @see LocaleManagerInternal#getBackupPayload(int userId)
*/
@@ -267,6 +252,53 @@ class LocaleManagerBackupHelper {
BackupManager.dataChanged(SYSTEM_BACKUP_PACKAGE_KEY);
}
+ /**
+ * <p><b>Note:</b> This is invoked by service's common monitor
+ * {@link LocaleManagerServicePackageMonitor#onPackageAdded} when a new package is
+ * added on device.
+ */
+ void onPackageAdded(String packageName, int uid) {
+ try {
+ synchronized (mStagedDataLock) {
+ cleanStagedDataForOldEntriesLocked();
+
+ int userId = UserHandle.getUserId(uid);
+ if (mStagedData.contains(userId)) {
+ // Perform lazy restore only if the staged data exists.
+ doLazyRestoreLocked(packageName, userId);
+ }
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception in onPackageAdded.", e);
+ }
+ }
+
+ /**
+ * <p><b>Note:</b> This is invoked by service's common monitor
+ * {@link LocaleManagerServicePackageMonitor#onPackageDataCleared} when a package's data
+ * is cleared.
+ */
+ void onPackageDataCleared() {
+ try {
+ notifyBackupManager();
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception in onPackageDataCleared.", e);
+ }
+ }
+
+ /**
+ * <p><b>Note:</b> This is invoked by service's common monitor
+ * {@link LocaleManagerServicePackageMonitor#onPackageRemoved} when a package is removed
+ * from device.
+ */
+ void onPackageRemoved() {
+ try {
+ notifyBackupManager();
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception in onPackageRemoved.", e);
+ }
+ }
+
private boolean isPackageInstalledForUser(String packageName, int userId) {
PackageInfo pkgInfo = null;
try {
@@ -395,48 +427,6 @@ class LocaleManagerBackupHelper {
}
/**
- * Helper to monitor package states.
- *
- * <p>We're interested in package added, package data cleared and package removed events.
- */
- private final class PackageMonitorImpl extends PackageMonitor {
- @Override
- public void onPackageAdded(String packageName, int uid) {
- try {
- synchronized (mStagedDataLock) {
- cleanStagedDataForOldEntriesLocked();
-
- int userId = UserHandle.getUserId(uid);
- if (mStagedData.contains(userId)) {
- // Perform lazy restore only if the staged data exists.
- doLazyRestoreLocked(packageName, userId);
- }
- }
- } catch (Exception e) {
- Slog.e(TAG, "Exception in onPackageAdded.", e);
- }
- }
-
- @Override
- public void onPackageDataCleared(String packageName, int uid) {
- try {
- notifyBackupManager();
- } catch (Exception e) {
- Slog.e(TAG, "Exception in onPackageDataCleared.", e);
- }
- }
-
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- try {
- notifyBackupManager();
- } catch (Exception e) {
- Slog.e(TAG, "Exception in onPackageRemoved.", e);
- }
- }
- }
-
- /**
* Performs lazy restore from the staged data.
*
* <p>This is invoked by the package monitor on the package added callback.
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index d459f8df99b6..c42770555bab 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -29,6 +29,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
+import android.os.HandlerThread;
import android.os.LocaleList;
import android.os.Process;
import android.os.RemoteException;
@@ -38,14 +39,13 @@ import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityTaskManagerInternal;
import java.io.FileDescriptor;
-import java.io.PrintWriter;
/**
* The implementation of ILocaleManager.aidl.
@@ -62,6 +62,8 @@ public class LocaleManagerService extends SystemService {
private LocaleManagerBackupHelper mBackupHelper;
+ private final PackageMonitor mPackageMonitor;
+
public static final boolean DEBUG = false;
public LocaleManagerService(Context context) {
@@ -71,15 +73,26 @@ public class LocaleManagerService extends SystemService {
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+
+ HandlerThread broadcastHandlerThread = new HandlerThread(TAG,
+ Process.THREAD_PRIORITY_BACKGROUND);
+ broadcastHandlerThread.start();
+
mBackupHelper = new LocaleManagerBackupHelper(this,
- mPackageManagerInternal);
+ mPackageManagerInternal, broadcastHandlerThread);
+
+ mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper);
+ mPackageMonitor.register(context, broadcastHandlerThread.getLooper(),
+ UserHandle.ALL,
+ true);
}
@VisibleForTesting
LocaleManagerService(Context context, ActivityTaskManagerInternal activityTaskManagerInternal,
ActivityManagerInternal activityManagerInternal,
PackageManagerInternal packageManagerInternal,
- LocaleManagerBackupHelper localeManagerBackupHelper) {
+ LocaleManagerBackupHelper localeManagerBackupHelper,
+ PackageMonitor packageMonitor) {
super(context);
mContext = context;
mBinderService = new LocaleManagerBinderService();
@@ -87,6 +100,7 @@ public class LocaleManagerService extends SystemService {
mActivityManagerInternal = activityManagerInternal;
mPackageManagerInternal = packageManagerInternal;
mBackupHelper = localeManagerBackupHelper;
+ mPackageMonitor = packageMonitor;
}
@Override
@@ -130,11 +144,6 @@ public class LocaleManagerService extends SystemService {
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- LocaleManagerService.this.dump(fd, pw, args);
- }
-
- @Override
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
@@ -407,14 +416,6 @@ public class LocaleManagerService extends SystemService {
return null;
}
- /**
- * Dumps useful info related to service.
- */
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- // TODO(b/201766221): Implement when there is state.
- }
-
private void logMetric(@NonNull AppLocaleChangedAtomRecord atomRecordForMetrics) {
FrameworkStatsLog.write(FrameworkStatsLog.APPLICATION_LOCALES_CHANGED,
atomRecordForMetrics.mCallingUid,
diff --git a/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java b/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java
new file mode 100644
index 000000000000..b459be768b9f
--- /dev/null
+++ b/services/core/java/com/android/server/locales/LocaleManagerServicePackageMonitor.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 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.locales;
+
+import com.android.internal.content.PackageMonitor;
+
+/**
+ * Helper to monitor package states inside {@link LocaleManagerService}.
+ *
+ * <p> These listeners forward the call to different aspects of locale service that
+ * handle the business logic.
+ * <p> We're interested in package added, package data cleared and package removed events.
+ */
+final class LocaleManagerServicePackageMonitor extends PackageMonitor {
+ private LocaleManagerBackupHelper mBackupHelper;
+
+ LocaleManagerServicePackageMonitor(LocaleManagerBackupHelper localeManagerBackupHelper) {
+ mBackupHelper = localeManagerBackupHelper;
+ }
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ mBackupHelper.onPackageAdded(packageName, uid);
+ }
+
+ @Override
+ public void onPackageDataCleared(String packageName, int uid) {
+ mBackupHelper.onPackageDataCleared();
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ mBackupHelper.onPackageRemoved();
+ }
+}
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index d42e2c63e80d..0b8f94c574c6 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1607,6 +1607,8 @@ public class LocationProviderManager extends
public @Nullable Location getLastLocation(LastLocationRequest request,
CallerIdentity identity, @PermissionLevel int permissionLevel) {
+ request = calculateLastLocationRequest(request);
+
if (!isActive(request.isBypass(), identity)) {
return null;
}
@@ -1634,6 +1636,38 @@ public class LocationProviderManager extends
return location;
}
+ private LastLocationRequest calculateLastLocationRequest(LastLocationRequest baseRequest) {
+ LastLocationRequest.Builder builder = new LastLocationRequest.Builder(baseRequest);
+
+ boolean locationSettingsIgnored = baseRequest.isLocationSettingsIgnored();
+ if (locationSettingsIgnored) {
+ // if we are not currently allowed use location settings ignored, disable it
+ if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
+ getIdentity().getPackageName(), getIdentity().getAttributionTag())
+ && !mLocationManagerInternal.isProvider(null, getIdentity())) {
+ locationSettingsIgnored = false;
+ }
+
+ builder.setLocationSettingsIgnored(locationSettingsIgnored);
+ }
+
+ boolean adasGnssBypass = baseRequest.isAdasGnssBypass();
+ if (adasGnssBypass) {
+ // if we are not currently allowed use adas gnss bypass, disable it
+ if (!GPS_PROVIDER.equals(mName)) {
+ Log.e(TAG, "adas gnss bypass request received in non-gps provider");
+ adasGnssBypass = false;
+ } else if (!mLocationSettings.getUserSettings(
+ getIdentity().getUserId()).isAdasGnssLocationEnabled()) {
+ adasGnssBypass = false;
+ }
+
+ builder.setAdasGnssBypass(adasGnssBypass);
+ }
+
+ return builder.build();
+ }
+
/**
* This function does not perform any permissions or safety checks, by calling it you are
* committing to performing all applicable checks yourself. This always returns a "fine"
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c09c904ff931..db0b0c58b046 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -183,7 +183,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -1596,18 +1595,16 @@ final class InstallPackageHelper {
parsedPackage.setRestrictUpdateHash(oldPackage.getRestrictUpdateHash());
}
- // Check for shared user id changes
- if (!Objects.equals(oldPackage.getSharedUserId(),
- parsedPackage.getSharedUserId())
- // Don't mark as invalid if the app is trying to
- // leave a sharedUserId
- && parsedPackage.getSharedUserId() != null) {
+ // APK should not change its sharedUserId declarations
+ final var oldSharedUid = oldPackage.getSharedUserId() != null
+ ? oldPackage.getSharedUserId() : "<nothing>";
+ final var newSharedUid = parsedPackage.getSharedUserId() != null
+ ? parsedPackage.getSharedUserId() : "<nothing>";
+ if (!oldSharedUid.equals(newSharedUid)) {
throw new PrepareFailure(INSTALL_FAILED_UID_CHANGED,
"Package " + parsedPackage.getPackageName()
+ " shared user changed from "
- + (oldPackage.getSharedUserId() != null
- ? oldPackage.getSharedUserId() : "<nothing>")
- + " to " + parsedPackage.getSharedUserId());
+ + oldSharedUid + " to " + newSharedUid);
}
// In case of rollback, remember per-user/profile install state
@@ -3696,10 +3693,13 @@ final class InstallPackageHelper {
}
disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr(
parsedPackage.getPackageName());
- sharedUserSetting = (parsedPackage.getSharedUserId() != null)
- ? mPm.mSettings.getSharedUserLPw(parsedPackage.getSharedUserId(),
- 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true)
- : null;
+ if (parsedPackage.getSharedUserId() != null && !parsedPackage.isLeavingSharedUid()) {
+ sharedUserSetting = mPm.mSettings.getSharedUserLPw(
+ parsedPackage.getSharedUserId(),
+ 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
+ } else {
+ sharedUserSetting = null;
+ }
if (DEBUG_PACKAGE_SCANNING
&& (parseFlags & ParsingPackageUtils.PARSE_CHATTY) != 0
&& sharedUserSetting != null) {
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index cdc2b1245b1e..f6f9faf98c40 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -290,6 +290,9 @@ public interface ParsingPackage extends ParsingPackageRead {
/** @see R#styleable.AndroidManifest_inheritKeyStoreKeys */
ParsingPackage setInheritKeyStoreKeys(boolean inheritKeyStoreKeys);
+ /** @see R#styleable.AndroidManifest_sharedUserMaxSdkVersion */
+ ParsingPackage setLeavingSharedUid(boolean leavingSharedUid);
+
ParsingPackage setLabelRes(int labelRes);
ParsingPackage setLargestWidthLimitDp(int largestWidthLimitDp);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index 177eaca8e06f..67670272ef8b 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -549,6 +549,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
private static final long SDK_LIBRARY = 1L << 49;
private static final long INHERIT_KEYSTORE_KEYS = 1L << 50;
private static final long ENABLE_ON_BACK_INVOKED_CALLBACK = 1L << 51;
+ private static final long LEAVING_SHARED_UID = 1L << 52;
}
private ParsingPackageImpl setBoolean(@Booleans.Values long flag, boolean value) {
@@ -2403,6 +2404,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
+ public boolean isLeavingSharedUid() {
+ return getBoolean(Booleans.LEAVING_SHARED_UID);
+ }
+
+ @Override
public ParsingPackageImpl setBaseRevisionCode(int value) {
baseRevisionCode = value;
return this;
@@ -2551,6 +2557,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
}
@Override
+ public ParsingPackageImpl setLeavingSharedUid(boolean value) {
+ return setBoolean(Booleans.LEAVING_SHARED_UID, value);
+ }
+
+ @Override
public ParsingPackageImpl setLabelRes(int value) {
labelRes = value;
return this;
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index 428374fa21a8..50033f652bfd 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -360,4 +360,11 @@ public interface ParsingPackageRead extends PkgWithoutStateAppInfo, PkgWithoutSt
* @see R.styleable.AndroidManifestApplication_enableOnBackInvokedCallback
*/
boolean isOnBackInvokedCallbackEnabled();
+
+ /**
+ * Returns true if R.styleable#AndroidManifest_sharedUserMaxSdkVersion is set to a value
+ * smaller than the current SDK version.
+ * @see R.styleable#AndroidManifest_sharedUserMaxSdkVersion
+ */
+ boolean isLeavingSharedUid();
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index f30daa930e6c..ed1ab01e1d12 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -1032,11 +1032,6 @@ public class ParsingPackageUtils {
private static ParseResult<ParsingPackage> parseSharedUser(ParseInput input,
ParsingPackage pkg, TypedArray sa) {
- int maxSdkVersion = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
- if ((maxSdkVersion != 0) && maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT) {
- return input.success(pkg);
- }
-
String str = nonConfigString(0, R.styleable.AndroidManifest_sharedUserId, sa);
if (TextUtils.isEmpty(str)) {
return input.success(pkg);
@@ -1052,7 +1047,11 @@ public class ParsingPackageUtils {
}
}
+ int maxSdkVersion = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa);
+ boolean leaving = (maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT);
+
return input.success(pkg
+ .setLeavingSharedUid(leaving)
.setSharedUserId(str.intern())
.setSharedUserLabel(resId(R.styleable.AndroidManifest_sharedUserLabel, sa)));
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4c5c7054e9a0..fd24565798fb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -5499,7 +5499,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* display, which set unrestricted keep-clear areas.
*
* For context on restricted vs unrestricted keep-clear areas, see
- * {@link android.Manifest.permission.USE_UNRESTRICTED_KEEP_CLEAR_AREAS}.
+ * {@link android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS}.
*/
void getKeepClearAreas(List<Rect> outRestricted, List<Rect> outUnrestricted) {
final Matrix tmpMatrix = new Matrix();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ffa1a601d41b..98c74f8ad81d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5149,10 +5149,13 @@ class Task extends TaskFragment {
// Ensure that we do not trigger entering PiP an activity on the root pinned task
return false;
}
+ final boolean isTransient = opts != null && opts.getTransientLaunch();
final Task targetRootTask = toFrontTask != null
? toFrontTask.getRootTask() : toFrontActivity.getRootTask();
- if (targetRootTask != null && targetRootTask.isActivityTypeAssistant()) {
- // Ensure the task/activity being brought forward is not the assistant
+ if (targetRootTask != null && (targetRootTask.isActivityTypeAssistant() || isTransient)) {
+ // Ensure the task/activity being brought forward is not the assistant and is not
+ // transient. In the case of transient-launch, we want to wait until the end of the
+ // transition and only allow switch if the transient launch was committed.
return false;
}
return true;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 0b965c37a2ba..3a3103e752ad 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -459,9 +459,19 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
// activity in a bad state.
if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
boolean commitVisibility = true;
- if (ar.getDeferHidingClient() && ar.getTask() != null) {
+ if (ar.isVisible() && ar.getTask() != null) {
if (ar.pictureInPictureArgs != null
&& ar.pictureInPictureArgs.isAutoEnterEnabled()) {
+ if (mTransientLaunches != null) {
+ for (int j = 0; j < mTransientLaunches.size(); ++j) {
+ if (mTransientLaunches.valueAt(j).isVisibleRequested()) {
+ // force enable pip-on-task-switch now that we've committed
+ // to actually launching to the transient activity.
+ ar.supportsEnterPipOnTaskSwitch = true;
+ break;
+ }
+ }
+ }
mController.mAtm.enterPictureInPictureMode(ar, ar.pictureInPictureArgs);
// Avoid commit visibility to false here, or else we will get a sudden
// "flash" / surface going invisible for a split second.
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index c267cbacdf24..c13ae95217b5 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -30,6 +30,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.IApplicationThread;
+import android.app.WindowConfiguration;
import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.RemoteException;
@@ -296,6 +297,17 @@ class TransitionController {
return ci.mVisible;
}
+ @WindowConfiguration.WindowingMode
+ int getWindowingModeAtStart(@NonNull WindowContainer wc) {
+ if (mCollectingTransition == null) return wc.getWindowingMode();
+ final Transition.ChangeInfo ci = mCollectingTransition.mChanges.get(wc);
+ if (ci == null) {
+ // not part of transition, so use current state.
+ return wc.getWindowingMode();
+ }
+ return ci.mWindowingMode;
+ }
+
@WindowManager.TransitionType
int getCollectingTransitionType() {
return mCollectingTransition != null ? mCollectingTransition.mType : TRANSIT_NONE;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5b1021eefc0a..709f885db776 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -200,6 +200,7 @@ import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteCallback;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -288,6 +289,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
+import com.android.internal.policy.IKeyguardLockedStateListener;
import com.android.internal.policy.IShortcutService;
import com.android.internal.policy.KeyInterceptionInfo;
import com.android.internal.protolog.ProtoLogImpl;
@@ -460,6 +462,10 @@ public class WindowManagerService extends IWindowManager.Stub
final private KeyguardDisableHandler mKeyguardDisableHandler;
+ private final RemoteCallbackList<IKeyguardLockedStateListener> mKeyguardLockedStateListeners =
+ new RemoteCallbackList<>();
+ private boolean mDispatchedKeyguardLockedState = false;
+
// VR Vr2d Display Id.
int mVr2dDisplayId = INVALID_DISPLAY;
boolean mVrModeEnabled = false;
@@ -3029,6 +3035,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void onKeyguardShowingAndNotOccludedChanged() {
mH.sendEmptyMessage(H.RECOMPUTE_FOCUS);
+ dispatchKeyguardLockedStateState();
}
@Override
@@ -3218,6 +3225,50 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @Override
+ public void addKeyguardLockedStateListener(IKeyguardLockedStateListener listener) {
+ enforceSubscribeToKeyguardLockedStatePermission();
+ boolean registered = mKeyguardLockedStateListeners.register(listener);
+ if (!registered) {
+ Slog.w(TAG, "Failed to register listener: " + listener);
+ }
+ }
+
+ @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE)
+ @Override
+ public void removeKeyguardLockedStateListener(IKeyguardLockedStateListener listener) {
+ enforceSubscribeToKeyguardLockedStatePermission();
+ mKeyguardLockedStateListeners.unregister(listener);
+ }
+
+ private void enforceSubscribeToKeyguardLockedStatePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE,
+ Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE
+ + " permission required to read keyguard visibility");
+ }
+
+ private void dispatchKeyguardLockedStateState() {
+ mH.post(() -> {
+ final boolean isKeyguardLocked = mPolicy.isKeyguardShowing();
+ if (mDispatchedKeyguardLockedState == isKeyguardLocked) {
+ return;
+ }
+ final int n = mKeyguardLockedStateListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mKeyguardLockedStateListeners.getBroadcastItem(i).onKeyguardLockedStateChanged(
+ isKeyguardLocked);
+ } catch (RemoteException e) {
+ // Handled by the RemoteCallbackList.
+ }
+ }
+ mKeyguardLockedStateListeners.finishBroadcast();
+ mDispatchedKeyguardLockedState = isKeyguardLocked;
+ });
+ }
+
@Override
public void setSwitchingUser(boolean switching) {
if (!checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index ccaa03ae8fd0..a2e8813c998a 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
@@ -645,8 +646,10 @@ class WindowToken extends WindowContainer<WindowState> {
final ActivityRecord r = asActivityRecord();
if (r != null) {
final Task rootTask = r.getRootTask();
- // Don't transform the activity in PiP because the PiP task organizer will handle it.
- if (rootTask != null && rootTask.inPinnedWindowingMode()) {
+ // Don't transform the activity exiting PiP because the PiP task organizer will handle
+ // it.
+ if (rootTask != null && mTransitionController.getWindowingModeAtStart(rootTask)
+ == WINDOWING_MODE_PINNED) {
return;
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e895d377f607..5098abe4bb55 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -386,8 +386,8 @@ public final class SystemServer implements Dumpable {
"com.android.server.DeviceIdleController";
private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
"com.android.server.blob.BlobStoreManagerService";
- private static final String APP_SEARCH_MANAGER_SERVICE_CLASS =
- "com.android.server.appsearch.AppSearchManagerService";
+ private static final String APPSEARCH_MODULE_LIFECYCLE_CLASS =
+ "com.android.server.appsearch.AppSearchModule$Lifecycle";
private static final String ISOLATED_COMPILATION_SERVICE_CLASS =
"com.android.server.compos.IsolatedCompilationService";
private static final String ROLLBACK_MANAGER_SERVICE_CLASS =
@@ -2764,8 +2764,8 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(SAFETY_CENTER_SERVICE_CLASS);
t.traceEnd();
- t.traceBegin("AppSearchManagerService");
- mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
+ t.traceBegin("AppSearchModule");
+ mSystemServiceManager.startService(APPSEARCH_MODULE_LIFECYCLE_CLASS);
t.traceEnd();
if (SystemProperties.getBoolean("ro.config.isolated_compilation_enabled", false)) {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index cd2d0fce6691..83ccabf03935 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -238,6 +238,7 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::isVendor,
AndroidPackage::isVisibleToInstantApps,
AndroidPackage::isVmSafeMode,
+ AndroidPackage::isLeavingSharedUid,
AndroidPackage::isResetEnabledSettingsOnAppDataCleared,
AndroidPackage::getMaxAspectRatio,
AndroidPackage::getMinAspectRatio,
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index d2358a08624d..023608c68ee3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -1167,7 +1167,14 @@ public class GameManagerServiceTests {
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(
mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- GameState gameState = new GameState(isLoading, GameState.MODE_NONE);
+ int testMode = GameState.MODE_NONE;
+ int testLabel = 99;
+ int testQuality = 123;
+ GameState gameState = new GameState(isLoading, testMode, testLabel, testQuality);
+ assertEquals(isLoading, gameState.isLoading());
+ assertEquals(testMode, gameState.getMode());
+ assertEquals(testLabel, gameState.getLabel());
+ assertEquals(testQuality, gameState.getQuality());
gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
mTestLooper.dispatchAll();
verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, isLoading);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 890a5495ef16..4e4854c6688d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -333,6 +333,10 @@ public class LocationProviderManagerTest {
@Test
public void testGetLastLocation_Bypass() {
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().add(
+ IDENTITY.getPackageName()).build());
+
assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
PERMISSION_FINE)).isNull();
assertThat(mManager.getLastLocation(
@@ -381,6 +385,14 @@ public class LocationProviderManagerTest {
new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
IDENTITY, PERMISSION_FINE)).isEqualTo(
loc);
+
+ mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
+ new PackageTagsList.Builder().build());
+ mProvider.setProviderAllowed(false);
+
+ assertThat(mManager.getLastLocation(
+ new LastLocationRequest.Builder().setLocationSettingsIgnored(true).build(),
+ IDENTITY, PERMISSION_FINE)).isNull();
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
index c77100045118..0287510041be 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
@@ -41,7 +41,9 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
+import android.os.HandlerThread;
import android.os.LocaleList;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SimpleClock;
import android.util.SparseArray;
@@ -78,6 +80,7 @@ import java.util.Map;
*/
@RunWith(AndroidJUnit4.class)
public class LocaleManagerBackupRestoreTest {
+ private static final String TAG = "LocaleManagerBackupRestoreTest";
private static final String DEFAULT_PACKAGE_NAME = "com.android.myapp";
private static final String DEFAULT_LOCALE_TAGS = "en-XC,ar-XB";
private static final String TEST_LOCALES_XML_TAG = "locales";
@@ -131,12 +134,17 @@ public class LocaleManagerBackupRestoreTest {
doReturn(mMockPackageManager).when(mMockContext).getPackageManager();
+ HandlerThread broadcastHandlerThread = new HandlerThread(TAG,
+ Process.THREAD_PRIORITY_BACKGROUND);
+ broadcastHandlerThread.start();
+
mBackupHelper = spy(new ShadowLocaleManagerBackupHelper(mMockContext,
- mMockLocaleManagerService, mMockPackageManagerInternal, mClock, STAGE_DATA));
+ mMockLocaleManagerService, mMockPackageManagerInternal, mClock, STAGE_DATA,
+ broadcastHandlerThread));
doNothing().when(mBackupHelper).notifyBackupManager();
mUserMonitor = mBackupHelper.getUserMonitor();
- mPackageMonitor = mBackupHelper.getPackageMonitor();
+ mPackageMonitor = new LocaleManagerServicePackageMonitor(mBackupHelper);
setCurrentTimeMillis(DEFAULT_CREATION_TIME_MILLIS);
}
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
index ca5b0cb1112f..0b3ef4542cbf 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
@@ -46,6 +46,7 @@ import android.os.LocaleList;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.internal.content.PackageMonitor;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.PackageConfig;
@@ -86,6 +87,8 @@ public class LocaleManagerServiceTest {
private ActivityTaskManagerInternal mMockActivityTaskManager;
@Mock
private ActivityManagerInternal mMockActivityManager;
+ @Mock
+ PackageMonitor mMockPackageMonitor;
@Before
public void setUp() throws Exception {
@@ -93,6 +96,7 @@ public class LocaleManagerServiceTest {
mMockActivityTaskManager = mock(ActivityTaskManagerInternal.class);
mMockActivityManager = mock(ActivityManagerInternal.class);
mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+ mMockPackageMonitor = mock(PackageMonitor.class);
// For unit tests, set the default installer info
PackageManager mockPackageManager = mock(PackageManager.class);
@@ -113,7 +117,8 @@ public class LocaleManagerServiceTest {
mMockBackupHelper = mock(ShadowLocaleManagerBackupHelper.class);
mLocaleManagerService = new LocaleManagerService(mMockContext, mMockActivityTaskManager,
- mMockActivityManager, mMockPackageManagerInternal, mMockBackupHelper);
+ mMockActivityManager, mMockPackageManagerInternal,
+ mMockBackupHelper, mMockPackageMonitor);
}
@Test(expected = SecurityException.class)
diff --git a/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java b/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java
index b0fc6363b701..ad9be0d5fe8d 100644
--- a/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java
+++ b/services/tests/servicestests/src/com/android/server/locales/ShadowLocaleManagerBackupHelper.java
@@ -18,6 +18,7 @@ package com.android.server.locales;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
+import android.os.HandlerThread;
import android.util.SparseArray;
import java.time.Clock;
@@ -31,7 +32,8 @@ public class ShadowLocaleManagerBackupHelper extends LocaleManagerBackupHelper {
ShadowLocaleManagerBackupHelper(Context context,
LocaleManagerService localeManagerService,
PackageManagerInternal pmInternal, Clock clock,
- SparseArray<LocaleManagerBackupHelper.StagedData> stagedData) {
- super(context, localeManagerService, pmInternal, clock, stagedData);
+ SparseArray<LocaleManagerBackupHelper.StagedData> stagedData,
+ HandlerThread broadcastHandlerThread) {
+ super(context, localeManagerService, pmInternal, clock, stagedData, broadcastHandlerThread);
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 8d60466eff95..4cddd8506df7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -60,7 +60,7 @@ abstract class CloseAppTransition(protected val testSpec: FlickerTestParameter)
}
teardown {
test {
- testApp.exit()
+ testApp.exit(wmHelper)
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index 7ee6451b2797..5bd365c7eefd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -64,7 +64,6 @@ open class ImeAppHelper @JvmOverloads constructor(
device.waitForIdle()
} else {
wmHelper.waitImeShown()
- wmHelper.waitForAppTransitionIdle()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index b66c45c7c9f0..a135e0af067b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -53,8 +53,8 @@ class TwoActivitiesAppHelper @JvmOverloads constructor(
button.click()
device.wait(Until.gone(launchActivityButton), FIND_TIMEOUT)
- wmHelper.waitForFullScreenApp(secondActivityComponent)
wmHelper.waitFor(
+ WindowManagerStateHelper.isAppFullScreen(secondActivityComponent),
WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY),
WindowManagerConditionsFactory.hasLayersAnimating().negate()
)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index ba5698cafa15..a9564fdd2332 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -88,7 +88,7 @@ class ReOpenImeWindowTest(private val testSpec: FlickerTestParameter) {
}
transitions {
device.reopenAppFromOverview(wmHelper)
- require(wmHelper.waitImeShown()) { "IME didn't show in time" }
+ wmHelper.waitImeShown()
}
teardown {
test {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 19e2c92304d4..7e3ed8252f4c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -18,6 +18,7 @@ package com.android.server.wm.flicker.ime
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import android.view.Display
import android.view.Surface
import android.view.WindowManagerPolicyConstants
import androidx.test.filters.RequiresDevice
@@ -35,6 +36,8 @@ import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarWindowIsVisible
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -64,12 +67,22 @@ class SwitchImeWindowsFromGestureNavTest(private val testSpec: FlickerTestParame
eachRun {
this.setRotation(testSpec.startRotation)
testApp.launchViaIntent(wmHelper)
- wmHelper.waitForFullScreenApp(testApp.component)
- wmHelper.waitForAppTransitionIdle()
+ val testAppVisible = wmHelper.waitFor(
+ WindowManagerStateHelper.isAppFullScreen(testApp.component),
+ WindowManagerConditionsFactory.isAppTransitionIdle(
+ Display.DEFAULT_DISPLAY))
+ require(testAppVisible) {
+ "Expected ${testApp.component.toWindowName()} to be visible"
+ }
imeTestApp.launchViaIntent(wmHelper)
- wmHelper.waitForFullScreenApp(testApp.component)
- wmHelper.waitForAppTransitionIdle()
+ val imeAppVisible = wmHelper.waitFor(
+ WindowManagerStateHelper.isAppFullScreen(imeTestApp.component),
+ WindowManagerConditionsFactory.isAppTransitionIdle(
+ Display.DEFAULT_DISPLAY))
+ require(imeAppVisible) {
+ "Expected ${imeTestApp.component.toWindowName()} to be visible"
+ }
imeTestApp.openIME(device, wmHelper)
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index b5e13be7dca0..cc808a0ce871 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -18,6 +18,7 @@ package com.android.server.wm.flicker.launch
import android.app.Instrumentation
import android.platform.test.annotations.Presubmit
+import android.view.Display
import androidx.test.filters.RequiresDevice
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.wm.flicker.entireScreenCovered
@@ -30,7 +31,9 @@ import com.android.server.wm.flicker.annotation.Group4
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.server.wm.traces.parser.toFlickerComponent
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -77,14 +80,16 @@ class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
}
teardown {
test {
- testApp.exit()
+ testApp.exit(wmHelper)
}
}
transitions {
testApp.openSecondActivity(device, wmHelper)
device.pressBack()
- wmHelper.waitForAppTransitionIdle()
- wmHelper.waitForFullScreenApp(testApp.component)
+ val firstActivityVisible = wmHelper.waitFor(
+ WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY),
+ WindowManagerStateHelper.isAppFullScreen(testApp.component))
+ require(firstActivityVisible) { "Expected ${testApp.component} to be visible" }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 53560cc14c44..4313b8dbc883 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -56,7 +56,7 @@ abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
}
teardown {
test {
- testApp.exit()
+ testApp.exit(wmHelper)
}
}
}