Merge "Adjustments to expanded view size and position" into tm-dev
diff --git a/Android.bp b/Android.bp
index 8afea34..933d1af 100644
--- a/Android.bp
+++ b/Android.bp
@@ -591,7 +591,7 @@
libs: [
"art.module.public.api",
"sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-tiramisu",
+ "sdk_module-lib_current_framework-connectivity-t",
"sdk_public_current_framework-bluetooth",
// There are a few classes from modules used by the core that
// need to be resolved by metalava. We use a prebuilt stub of the
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 726ab2a..94f4374 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -258,7 +258,7 @@
srcs: [":module-lib-api-stubs-docs-non-updatable"],
libs: [
"sdk_module-lib_current_framework-tethering",
- "sdk_module-lib_current_framework-connectivity-tiramisu",
+ "sdk_module-lib_current_framework-connectivity-t",
"sdk_public_current_framework-bluetooth",
// NOTE: The below can be removed once the prebuilt stub contains bluetooth.
"sdk_system_current_android",
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index b843dca..cae6cdc 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -25,6 +25,7 @@
import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
import static android.app.usage.UsageStatsManager.REASON_SUB_DEFAULT_APP_UPDATE;
import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
+import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_USER_FLAG_INTERACTION;
import static android.app.usage.UsageStatsManager.REASON_SUB_MASK;
import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
@@ -1581,7 +1582,11 @@
// Only user force can bypass the delay restriction. If the user forced the
// app into the RESTRICTED bucket, then a toast confirming the action
// shouldn't be surprising.
- if (Build.IS_DEBUGGABLE) {
+ // Exclude REASON_SUB_FORCED_USER_FLAG_INTERACTION since the RESTRICTED bucket
+ // isn't directly visible in that flow.
+ if (Build.IS_DEBUGGABLE
+ && (reason & REASON_SUB_MASK)
+ != REASON_SUB_FORCED_USER_FLAG_INTERACTION) {
Toast.makeText(mContext,
// Since AppStandbyController sits low in the lock hierarchy,
// make sure not to call out with the lock held.
diff --git a/api/Android.bp b/api/Android.bp
index 66c7823..40472b7 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -93,7 +93,6 @@
// Silence reflection warnings. See b/168689341
metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED "
metalava_cmd += " --quiet --no-banner --format=v2 "
-metalava_cmd += " --hide ChangedThrows "
genrule {
name: "current-api-xml",
@@ -113,7 +112,7 @@
"framework-appsearch",
"framework-bluetooth",
"framework-connectivity",
- "framework-connectivity-tiramisu",
+ "framework-connectivity-t",
"framework-graphics",
"framework-media",
"framework-mediaprovider",
diff --git a/core/api/current.txt b/core/api/current.txt
index ddfb14b..77efa4d3 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -189,6 +189,7 @@
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 @@
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 @@
}
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 @@
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 @@
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);
}
@@ -14390,6 +14397,8 @@
method @NonNull @Size(min=3) public abstract float[] fromXyz(@NonNull @Size(min=3) float[]);
method @NonNull public static android.graphics.ColorSpace get(@NonNull android.graphics.ColorSpace.Named);
method @IntRange(from=1, to=4) public int getComponentCount();
+ method public int getDataSpace();
+ method @Nullable public static android.graphics.ColorSpace getFromDataSpace(int);
method @IntRange(from=android.graphics.ColorSpace.MIN_ID, to=android.graphics.ColorSpace.MAX_ID) public int getId();
method public abstract float getMaxValue(@IntRange(from=0, to=3) int);
method public abstract float getMinValue(@IntRange(from=0, to=3) int);
@@ -31789,7 +31798,7 @@
method public android.os.PowerManager.WakeLock newWakeLock(int, String);
method @RequiresPermission(android.Manifest.permission.REBOOT) public void reboot(@Nullable String);
method public void removeThermalStatusListener(@NonNull android.os.PowerManager.OnThermalStatusChangedListener);
- field public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
+ field @Deprecated public static final int ACQUIRE_CAUSES_WAKEUP = 268435456; // 0x10000000
field public static final String ACTION_DEVICE_IDLE_MODE_CHANGED = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
field public static final String ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED = "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED";
field public static final String ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED = "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED";
@@ -49290,7 +49299,7 @@
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);
@@ -53110,7 +53119,7 @@
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 9757b2f..e64392b 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2347,6 +2347,8 @@
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 @@
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 979dd34..fe6e554 100644
--- a/core/java/android/app/GameState.java
+++ b/core/java/android/app/GameState.java
@@ -18,8 +18,6 @@
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 @@
// 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 @@
* @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 @@
}
/**
- * @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 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/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 7c48a57..fe0edfe 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -510,7 +510,6 @@
void noteAlarmFinish(in IIntentSender sender, in WorkSource workSource, int sourceUid, in String tag);
@UnsupportedAppUsage
int getPackageProcessState(in String packageName, in String callingPackage);
- void updateDeviceOwner(in String packageName);
// Start of N transactions
// Start Binder transaction tracking for all applications.
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 9910000..87ba197 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -52,6 +52,7 @@
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 @@
})
@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 @@
/**
* 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 @@
*
* <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 @@
* 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 @@
* 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 @@
*
* <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 @@
* 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 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
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/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 2fd79cf..c38a847 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -1079,16 +1079,24 @@
}
/**
- * Gets the key code produced by the specified location on a US keyboard layout.
- * Key code as defined in {@link android.view.KeyEvent}.
- * This API is only functional for devices with {@link InputDevice#SOURCE_KEYBOARD} available
- * which can alter their key mapping using country specific keyboard layouts.
+ * Gets the {@link android.view.KeyEvent key code} produced by the given location on a reference
+ * QWERTY keyboard layout.
+ * <p>
+ * This API is useful for querying the physical location of keys that change the character
+ * produced based on the current locale and keyboard layout.
+ * <p>
+ * @see InputDevice#getKeyCodeForKeyLocation(int) for examples.
*
- * @param deviceId The input device id.
- * @param locationKeyCode The location of a key on a US keyboard layout.
- * @return The key code produced when pressing the key at the specified location, given the
- * active keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the requested
- * mapping could not be determined, or if an error occurred.
+ * @param locationKeyCode The location of a key specified as a key code on the QWERTY layout.
+ * This provides a consistent way of referring to the physical location of a key independently
+ * of the current keyboard layout. Also see the
+ * <a href="https://www.w3.org/TR/2017/CR-uievents-code-20170601/#key-alphanumeric-writing-system">
+ * hypothetical keyboard</a> provided by the W3C, which may be helpful for identifying the
+ * physical location of a key.
+ * @return The key code produced by the key at the specified location, given the current
+ * keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the device does not specify
+ * {@link InputDevice#SOURCE_KEYBOARD} or the requested mapping cannot be determined.
+ *
* @hide
*/
public int getKeyCodeForKeyLocation(int deviceId, int locationKeyCode) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 315eef7..e3be4d3 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -183,25 +183,29 @@
/**
* Wake lock flag: Turn the screen on when the wake lock is acquired.
* <p>
- * Normally wake locks don't actually wake the device, they just cause
- * the screen to remain on once it's already on. Think of the video player
- * application as the normal behavior. Notifications that pop up and want
- * the device to be on are the exception; use this flag to be like them.
+ * Normally wake locks don't actually wake the device, they just cause the screen to remain on
+ * once it's already on. This flag will cause the device to wake up when the wake lock is
+ * acquired.
* </p><p>
* Android TV playback devices attempt to turn on the HDMI-connected TV via HDMI-CEC on any
* wake-up, including wake-ups triggered by wake locks.
* </p><p>
* Cannot be used with {@link #PARTIAL_WAKE_LOCK}.
* </p>
+ *
+ * @deprecated Most applications should use {@link android.R.attr#turnScreenOn} or
+ * {@link android.app.Activity#setTurnScreenOn(boolean)} instead, as this prevents the previous
+ * foreground app from being resumed first when the screen turns on. Note that this flag may
+ * require a permission in the future.
*/
+ @Deprecated
public static final int ACQUIRE_CAUSES_WAKEUP = 0x10000000;
/**
* Wake lock flag: When this wake lock is released, poke the user activity timer
* so the screen stays on for a little longer.
* <p>
- * Will not turn the screen on if it is not already on.
- * See {@link #ACQUIRE_CAUSES_WAKEUP} if you want that.
+ * This will not turn the screen on if it is not already on.
* </p><p>
* Cannot be used with {@link #PARTIAL_WAKE_LOCK}.
* </p>
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 163d6ed..bfc3b8b 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -36,6 +36,9 @@
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 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 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 3459172..db622d3 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -216,6 +216,18 @@
"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 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 @@
// 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 @@
* @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 @@
* {@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 8fe6f71..adc9251 100644
--- a/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
+++ b/core/java/android/service/selectiontoolbar/FloatingToolbarRoot.java
@@ -40,7 +40,7 @@
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 @@
* 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 e7b2acd..fef5acd 100644
--- a/core/java/android/util/DumpableContainer.java
+++ b/core/java/android/util/DumpableContainer.java
@@ -18,8 +18,7 @@
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 ce21086..53b842a 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -18,6 +18,7 @@
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 @@
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/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 3fc9f6b..b48b525 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -54,13 +54,11 @@
@NonNull
private InputMethodManagerDelegate getImmDelegate() {
- InputMethodManagerDelegate delegate = mDelegate;
- if (delegate != null) {
- return delegate;
+ if (mDelegate == null) {
+ mDelegate = mViewRootImpl.mContext.getSystemService(
+ InputMethodManager.class).getDelegate();
}
- delegate = mViewRootImpl.mContext.getSystemService(InputMethodManager.class).getDelegate();
- mDelegate = delegate;
- return delegate;
+ return mDelegate;
}
/** Called when the view root is moved to a different display. */
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 188d745..7d56039 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -737,15 +737,47 @@
}
/**
- * Gets the key code produced by the specified location on a US keyboard layout.
- * Key code as defined in {@link android.view.KeyEvent}.
- * This API is only functional for devices with {@link InputDevice#SOURCE_KEYBOARD} available
- * which can alter their key mapping using country specific keyboard layouts.
+ * Gets the {@link android.view.KeyEvent key code} produced by the given location on a reference
+ * QWERTY keyboard layout.
+ * <p>
+ * This API is useful for querying the physical location of keys that change the character
+ * produced based on the current locale and keyboard layout.
+ * <p>
+ * The following table provides a non-exhaustive list of examples:
+ * <table border="2" width="85%" align="center" cellpadding="5">
+ * <thead>
+ * <tr><th>Active Keyboard Layout</th> <th>Input Parameter</th>
+ * <th>Return Value</th></tr>
+ * </thead>
*
- * @param locationKeyCode The location of a key on a US keyboard layout.
- * @return The key code produced when pressing the key at the specified location, given the
- * active keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the requested
- * mapping could not be determined, or if an error occurred.
+ * <tbody>
+ * <tr>
+ * <td>French AZERTY</td>
+ * <td><code>{@link KeyEvent#KEYCODE_Q}</code></td>
+ * <td><code>{@link KeyEvent#KEYCODE_A}</code></td>
+ * </tr>
+ * <tr>
+ * <td>German QWERTZ</td>
+ * <td><code>{@link KeyEvent#KEYCODE_Y}</code></td>
+ * <td><code>{@link KeyEvent#KEYCODE_Z}</code></td>
+ * </tr>
+ * <tr>
+ * <td>US QWERTY</td>
+ * <td><code>{@link KeyEvent#KEYCODE_B}</code></td>
+ * <td><code>{@link KeyEvent#KEYCODE_B}</code></td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * @param locationKeyCode The location of a key specified as a key code on the QWERTY layout.
+ * This provides a consistent way of referring to the physical location of a key independently
+ * of the current keyboard layout. Also see the
+ * <a href="https://www.w3.org/TR/2017/CR-uievents-code-20170601/#key-alphanumeric-writing-system">
+ * hypothetical keyboard</a> provided by the W3C, which may be helpful for identifying the
+ * physical location of a key.
+ * @return The key code produced by the key at the specified location, given the current
+ * keyboard layout. Returns {@link KeyEvent#KEYCODE_UNKNOWN} if the device does not specify
+ * {@link InputDevice#SOURCE_KEYBOARD} or the requested mapping cannot be determined.
*/
public int getKeyCodeForKeyLocation(int locationKeyCode) {
return InputManager.getInstance().getKeyCodeForKeyLocation(mId, locationKeyCode);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 98cef958..632af23 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -3094,6 +3094,10 @@
* @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 2edfda5..a13579d 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -328,7 +328,8 @@
*/
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/View.java b/core/java/android/view/View.java
index 286b502..34a1386 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14173,7 +14173,7 @@
&& isAccessibilityPane()) {
// If the pane isn't visible, content changed events are sufficient unless we're
// reporting that the view just disappeared
- if ((getVisibility() == VISIBLE)
+ if ((isAggregatedVisible())
|| (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) {
final AccessibilityEvent event = AccessibilityEvent.obtain();
onInitializeAccessibilityEvent(event);
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2717463..017b8aa 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -46,6 +46,8 @@
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 @@
/** @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 @@
* 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/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3dfb4a5..c207af5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12774,7 +12774,9 @@
/**
* Called when a context menu option for the text view is selected. Currently
* this will be one of {@link android.R.id#selectAll}, {@link android.R.id#cut},
- * {@link android.R.id#copy}, {@link android.R.id#paste} or {@link android.R.id#shareText}.
+ * {@link android.R.id#copy}, {@link android.R.id#paste},
+ * {@link android.R.id#pasteAsPlainText} (starting at API level 23) or
+ * {@link android.R.id#shareText}.
*
* @return true if the context menu item action was performed.
*/
@@ -12965,6 +12967,7 @@
* method. The default actions can also be removed from the menu using
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
* {@link android.R.id#cut}, {@link android.R.id#copy}, {@link android.R.id#paste},
+ * {@link android.R.id#pasteAsPlainText} (starting at API level 23),
* {@link android.R.id#replaceText} or {@link android.R.id#shareText} ids as parameters.
*
* <p>Returning false from
@@ -13003,7 +13006,8 @@
* {@link android.view.ActionMode.Callback#onPrepareActionMode(android.view.ActionMode,
* android.view.Menu)} method. The default actions can also be removed from the menu using
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
- * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.</p>
+ * {@link android.R.id#paste}, {@link android.R.id#pasteAsPlainText} (starting at API
+ * level 23) or {@link android.R.id#replaceText} ids as parameters.</p>
*
* <p>Returning false from
* {@link android.view.ActionMode.Callback#onCreateActionMode(android.view.ActionMode,
diff --git a/core/java/com/android/internal/app/MediaRouteChooserDialog.java b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
index 7108d14..23d966fd 100644
--- a/core/java/com/android/internal/app/MediaRouteChooserDialog.java
+++ b/core/java/com/android/internal/app/MediaRouteChooserDialog.java
@@ -16,25 +16,26 @@
package com.android.internal.app;
-import com.android.internal.R;
-
-import android.app.Dialog;
+import android.app.AlertDialog;
import android.content.Context;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.TypedValue;
+import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
+import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
+import com.android.internal.R;
+
import java.util.Comparator;
/**
@@ -48,9 +49,10 @@
*
* TODO: Move this back into the API, as in the support library media router.
*/
-public class MediaRouteChooserDialog extends Dialog {
+public class MediaRouteChooserDialog extends AlertDialog {
private final MediaRouter mRouter;
private final MediaRouterCallback mCallback;
+ private final boolean mShowProgressBarWhenEmpty;
private int mRouteTypes;
private View.OnClickListener mExtendedSettingsClickListener;
@@ -60,10 +62,15 @@
private boolean mAttachedToWindow;
public MediaRouteChooserDialog(Context context, int theme) {
+ this(context, theme, true);
+ }
+
+ public MediaRouteChooserDialog(Context context, int theme, boolean showProgressBarWhenEmpty) {
super(context, theme);
mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mCallback = new MediaRouterCallback();
+ mShowProgressBarWhenEmpty = showProgressBarWhenEmpty;
}
/**
@@ -120,28 +127,38 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ // Note: setView must be called before super.onCreate().
+ setView(LayoutInflater.from(getContext()).inflate(R.layout.media_route_chooser_dialog,
+ null));
- getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
-
- setContentView(R.layout.media_route_chooser_dialog);
setTitle(mRouteTypes == MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY
? R.string.media_route_chooser_title_for_remote_display
: R.string.media_route_chooser_title);
- // Must be called after setContentView.
- getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
- isLightTheme(getContext()) ? R.drawable.ic_media_route_off_holo_light
- : R.drawable.ic_media_route_off_holo_dark);
+ setIcon(isLightTheme(getContext()) ? R.drawable.ic_media_route_off_holo_light
+ : R.drawable.ic_media_route_off_holo_dark);
+ super.onCreate(savedInstanceState);
+
+ View emptyView = findViewById(android.R.id.empty);
mAdapter = new RouteAdapter(getContext());
- mListView = (ListView)findViewById(R.id.media_route_list);
+ mListView = (ListView) findViewById(R.id.media_route_list);
mListView.setAdapter(mAdapter);
mListView.setOnItemClickListener(mAdapter);
- mListView.setEmptyView(findViewById(android.R.id.empty));
+ mListView.setEmptyView(emptyView);
- mExtendedSettingsButton = (Button)findViewById(R.id.media_route_extended_settings_button);
+ mExtendedSettingsButton = (Button) findViewById(R.id.media_route_extended_settings_button);
updateExtendedSettingsButton();
+
+ if (!mShowProgressBarWhenEmpty) {
+ findViewById(R.id.media_route_progress_bar).setVisibility(View.GONE);
+
+ // Center the empty view when the progress bar is not shown.
+ LinearLayout.LayoutParams params =
+ (LinearLayout.LayoutParams) emptyView.getLayoutParams();
+ params.gravity = Gravity.CENTER;
+ emptyView.setLayoutParams(params);
+ }
}
private void updateExtendedSettingsButton() {
diff --git a/core/java/com/android/internal/app/MediaRouteDialogPresenter.java b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
index bb2d7fa..5628b7e 100644
--- a/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
+++ b/core/java/com/android/internal/app/MediaRouteDialogPresenter.java
@@ -66,24 +66,37 @@
}
}
+ /** Create a media route dialog as appropriate. */
public static Dialog createDialog(Context context,
int routeTypes, View.OnClickListener extendedSettingsClickListener) {
- final MediaRouter router = (MediaRouter)context.getSystemService(
- Context.MEDIA_ROUTER_SERVICE);
-
int theme = MediaRouteChooserDialog.isLightTheme(context)
? android.R.style.Theme_DeviceDefault_Light_Dialog
: android.R.style.Theme_DeviceDefault_Dialog;
+ return createDialog(context, routeTypes, extendedSettingsClickListener, theme);
+ }
+
+ /** Create a media route dialog as appropriate. */
+ public static Dialog createDialog(Context context,
+ int routeTypes, View.OnClickListener extendedSettingsClickListener, int theme) {
+ return createDialog(context, routeTypes, extendedSettingsClickListener, theme,
+ true /* showProgressBarWhenEmpty */);
+ }
+
+ /** Create a media route dialog as appropriate. */
+ public static Dialog createDialog(Context context, int routeTypes,
+ View.OnClickListener extendedSettingsClickListener, int theme,
+ boolean showProgressBarWhenEmpty) {
+ final MediaRouter router = context.getSystemService(MediaRouter.class);
MediaRouter.RouteInfo route = router.getSelectedRoute();
if (route.isDefault() || !route.matchesTypes(routeTypes)) {
- final MediaRouteChooserDialog d = new MediaRouteChooserDialog(context, theme);
+ final MediaRouteChooserDialog d = new MediaRouteChooserDialog(context, theme,
+ showProgressBarWhenEmpty);
d.setRouteTypes(routeTypes);
d.setExtendedSettingsClickListener(extendedSettingsClickListener);
return d;
} else {
- MediaRouteControllerDialog d = new MediaRouteControllerDialog(context, theme);
- return d;
+ return new MediaRouteControllerDialog(context, theme);
}
}
}
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 0000000..ee50219
--- /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/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c33b7c9..e8f7b93 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -382,6 +382,7 @@
optional bool in_size_compat_mode = 32;
optional float min_aspect_ratio = 33;
optional bool provides_max_bounds = 34;
+ optional bool enable_recents_screenshot = 35;
}
/* represents WindowToken */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d4c03e4..58a3bb4 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/layout/media_route_chooser_dialog.xml b/core/res/res/layout/media_route_chooser_dialog.xml
index cd1c74f..bf73f4b 100644
--- a/core/res/res/layout/media_route_chooser_dialog.xml
+++ b/core/res/res/layout/media_route_chooser_dialog.xml
@@ -28,20 +28,21 @@
<!-- Content to show when list is empty. -->
<LinearLayout android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="64dp"
- android:orientation="horizontal"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:visibility="gone">
- <ProgressBar android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center" />
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:visibility="gone">
+ <ProgressBar android:id="@+id/media_route_progress_bar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center" />
<TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:paddingStart="16dp"
- android:text="@string/media_route_chooser_searching" />
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:paddingStart="16dp"
+ android:text="@string/media_route_chooser_searching" />
</LinearLayout>
<!-- Settings button. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 744c3dab..adf8f8e 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 e7eeecc..558e3c3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1676,6 +1676,7 @@
<java-symbol type="id" name="media_route_volume_slider" />
<java-symbol type="id" name="media_route_control_frame" />
<java-symbol type="id" name="media_route_extended_settings_button" />
+ <java-symbol type="id" name="media_route_progress_bar" />
<java-symbol type="string" name="media_route_chooser_title" />
<java-symbol type="string" name="media_route_chooser_title_for_remote_display" />
<java-symbol type="string" name="media_route_controller_disconnect" />
@@ -4398,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/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 2f978fc..582488f 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -22,6 +22,10 @@
import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.SuppressAutoDoc;
+import android.annotation.SuppressLint;
+import android.hardware.DataSpace;
+import android.hardware.DataSpace.NamedDataSpace;
+import android.util.SparseIntArray;
import libcore.util.NativeAllocationRegistry;
@@ -207,6 +211,7 @@
// See static initialization block next to #get(Named)
private static final ColorSpace[] sNamedColorSpaces = new ColorSpace[Named.values().length];
+ private static final SparseIntArray sDataToColorSpaces = new SparseIntArray();
@NonNull private final String mName;
@NonNull private final Model mModel;
@@ -1389,6 +1394,47 @@
}
/**
+ * Create a {@link ColorSpace} object using a {@link android.hardware.DataSpace DataSpace}
+ * value.
+ *
+ * <p>This function maps from a dataspace to a {@link Named} ColorSpace.
+ * If no {@link Named} ColorSpace object matching the {@code dataSpace} value can be created,
+ * {@code null} will return.</p>
+ *
+ * @param dataSpace The dataspace value
+ * @return the ColorSpace object or {@code null} if no matching colorspace can be found.
+ */
+ @SuppressLint("MethodNameUnits")
+ @Nullable
+ public static ColorSpace getFromDataSpace(@NamedDataSpace int dataSpace) {
+ int index = sDataToColorSpaces.get(dataSpace, -1);
+ if (index != -1) {
+ return ColorSpace.get(index);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the {@link android.hardware.DataSpace DataSpace} value from a {@link ColorSpace}
+ * object.
+ *
+ * <p>If this {@link ColorSpace} object has no matching {@code dataSpace} value,
+ * {@link android.hardware.DataSpace#DATASPACE_UNKNOWN DATASPACE_UNKNOWN} will return.</p>
+ *
+ * @return the dataspace value.
+ */
+ @SuppressLint("MethodNameUnits")
+ public @NamedDataSpace int getDataSpace() {
+ int index = sDataToColorSpaces.indexOfValue(getId());
+ if (index != -1) {
+ return sDataToColorSpaces.keyAt(index);
+ } else {
+ return DataSpace.DATASPACE_UNKNOWN;
+ }
+ }
+
+ /**
* <p>Returns an instance of {@link ColorSpace} identified by the specified
* name. The list of names provided in the {@link Named} enum gives access
* to a variety of common RGB color spaces.</p>
@@ -1445,6 +1491,7 @@
SRGB_TRANSFER_PARAMETERS,
Named.SRGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB, Named.SRGB.ordinal());
sNamedColorSpaces[Named.LINEAR_SRGB.ordinal()] = new ColorSpace.Rgb(
"sRGB IEC61966-2.1 (Linear)",
SRGB_PRIMARIES,
@@ -1453,6 +1500,7 @@
0.0f, 1.0f,
Named.LINEAR_SRGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_SRGB_LINEAR, Named.LINEAR_SRGB.ordinal());
sNamedColorSpaces[Named.EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
"scRGB-nl IEC 61966-2-2:2003",
SRGB_PRIMARIES,
@@ -1464,6 +1512,7 @@
SRGB_TRANSFER_PARAMETERS,
Named.EXTENDED_SRGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_SCRGB, Named.EXTENDED_SRGB.ordinal());
sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
"scRGB IEC 61966-2-2:2003",
SRGB_PRIMARIES,
@@ -1472,6 +1521,8 @@
-0.5f, 7.499f,
Named.LINEAR_EXTENDED_SRGB.ordinal()
);
+ sDataToColorSpaces.put(
+ DataSpace.DATASPACE_SCRGB_LINEAR, Named.LINEAR_EXTENDED_SRGB.ordinal());
sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb(
"Rec. ITU-R BT.709-5",
new float[] { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f },
@@ -1480,6 +1531,7 @@
new Rgb.TransferParameters(1 / 1.099, 0.099 / 1.099, 1 / 4.5, 0.081, 1 / 0.45),
Named.BT709.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_BT709, Named.BT709.ordinal());
sNamedColorSpaces[Named.BT2020.ordinal()] = new ColorSpace.Rgb(
"Rec. ITU-R BT.2020-1",
new float[] { 0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f },
@@ -1488,6 +1540,7 @@
new Rgb.TransferParameters(1 / 1.0993, 0.0993 / 1.0993, 1 / 4.5, 0.08145, 1 / 0.45),
Named.BT2020.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_BT2020, Named.BT2020.ordinal());
sNamedColorSpaces[Named.DCI_P3.ordinal()] = new ColorSpace.Rgb(
"SMPTE RP 431-2-2007 DCI (P3)",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
@@ -1496,6 +1549,7 @@
0.0f, 1.0f,
Named.DCI_P3.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_DCI_P3, Named.DCI_P3.ordinal());
sNamedColorSpaces[Named.DISPLAY_P3.ordinal()] = new ColorSpace.Rgb(
"Display P3",
new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
@@ -1504,6 +1558,7 @@
SRGB_TRANSFER_PARAMETERS,
Named.DISPLAY_P3.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_DISPLAY_P3, Named.DISPLAY_P3.ordinal());
sNamedColorSpaces[Named.NTSC_1953.ordinal()] = new ColorSpace.Rgb(
"NTSC (1953)",
NTSC_1953_PRIMARIES,
@@ -1528,6 +1583,7 @@
0.0f, 1.0f,
Named.ADOBE_RGB.ordinal()
);
+ sDataToColorSpaces.put(DataSpace.DATASPACE_ADOBE_RGB, Named.ADOBE_RGB.ordinal());
sNamedColorSpaces[Named.PRO_PHOTO_RGB.ordinal()] = new ColorSpace.Rgb(
"ROMM RGB ISO 22028-2:2013",
new float[] { 0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f },
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 f7c92fe..8a482fb 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 @@
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 @@
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 180e3fb..d7322ce 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 @@
// 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 60aac68..91615fe 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 @@
* 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 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 69d6c9e..32ebe2d 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.util.Log;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.WindowManagerGlobal;
import androidx.annotation.Nullable;
@@ -143,7 +144,6 @@
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 @@
t.setPosition(menuSurfaceControl, menuBounds.left, menuBounds.top);
t.apply();
}
+ grantPipMenuFocus(true);
mPipMenuView.show(mInMoveMode, mDelegate.getPipGravity());
}
}
@@ -194,8 +195,9 @@
if (DEBUG) Log.d(TAG, "hideMenu()");
}
- mPipMenuView.hide(mInMoveMode);
+ mPipMenuView.hide();
if (!mInMoveMode) {
+ grantPipMenuFocus(false);
mDelegate.closeMenu();
}
}
@@ -453,4 +455,15 @@
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 773e9bf..3090139 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.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.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 @@
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 @@
mListener = listener;
}
- void setFocusGrantToken(IBinder token) {
- mFocusGrantToken = token;
- }
-
void setExpandedModeEnabled(boolean enabled) {
mExpandButton.setVisibility(enabled ? VISIBLE : GONE);
}
@@ -170,8 +163,6 @@
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 @@
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 @@
|| 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 81dacdb..76641f0 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 @@
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 65eb9aa..57bcbc0 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.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 @@
// 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 0f00ede..cc5b9f9 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 @@
if (wmHelper == null) {
device.waitForIdle()
} else {
- require(wmHelper.waitImeShown()) { "IME did not appear" }
+ wmHelper.waitImeShown()
}
}
@@ -79,7 +79,7 @@
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 7e232ea..e9d438a 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 @@
}
}
- /** {@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 f2c5093..274d34b 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 @@
* 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 4f98b70..e2d0834 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 @@
// 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 e00d749..3fe6f02 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 @@
}
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 bb66f7b..654fa4e 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 @@
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 @@
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 dda1a82..85527c8 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 @@
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 @@
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/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index e0f04a1..9f52bf1 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -108,7 +108,6 @@
private long mUsage = HardwareBuffer.USAGE_CPU_WRITE_OFTEN;
private @HardwareBuffer.Format int mHardwareBufferFormat;
private @NamedDataSpace int mDataSpace;
- private boolean mUseLegacyImageFormat;
// Field below is used by native code, do not access or modify.
private int mWriterFormat;
@@ -257,7 +256,6 @@
+ ", maxImages: " + maxImages);
}
- mUseLegacyImageFormat = useLegacyImageFormat;
// Note that the underlying BufferQueue is working in synchronous mode
// to avoid dropping any buffers.
mNativeContext = nativeInit(new WeakReference<>(this), surface, maxImages, width, height,
@@ -334,12 +332,21 @@
int hardwareBufferFormat, int dataSpace, int width, int height, long usage) {
mMaxImages = maxImages;
mUsage = usage;
- mHardwareBufferFormat = hardwareBufferFormat;
- mDataSpace = dataSpace;
- int publicFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
+ int imageFormat;
+ // if useSurfaceImageFormatInfo is true, imageFormat will be set to UNKNOWN
+ // and retrieve corresponding hardwareBufferFormat and dataSpace here.
+ if (useSurfaceImageFormatInfo) {
+ imageFormat = ImageFormat.UNKNOWN;
+ mHardwareBufferFormat = PublicFormatUtils.getHalFormat(imageFormat);
+ mDataSpace = PublicFormatUtils.getHalDataspace(imageFormat);
+ } else {
+ imageFormat = PublicFormatUtils.getPublicFormat(hardwareBufferFormat, dataSpace);
+ mHardwareBufferFormat = hardwareBufferFormat;
+ mDataSpace = dataSpace;
+ }
initializeImageWriter(surface, maxImages, useSurfaceImageFormatInfo, false,
- publicFormat, hardwareBufferFormat, dataSpace, width, height, usage);
+ imageFormat, hardwareBufferFormat, dataSpace, width, height, usage);
}
/**
@@ -884,27 +891,17 @@
private @HardwareBuffer.Format int mHardwareBufferFormat = HardwareBuffer.RGBA_8888;
private @NamedDataSpace int mDataSpace = DataSpace.DATASPACE_UNKNOWN;
private boolean mUseSurfaceImageFormatInfo = true;
- // set this as true temporarily now as a workaround to get correct format
- // when using surface format by default without overriding the image format
- // in the builder pattern
- private boolean mUseLegacyImageFormat = true;
+ private boolean mUseLegacyImageFormat = false;
/**
* Constructs a new builder for {@link ImageWriter}.
*
- * <p>Uses {@code surface} input parameter to retrieve image format, hal format
- * and hal dataspace value for default. </p>
- *
* @param surface The destination Surface this writer produces Image data into.
*
* @throws IllegalArgumentException if the surface is already abandoned.
*/
public Builder(@NonNull Surface surface) {
mSurface = surface;
- // retrieve format from surface
- mImageFormat = SurfaceUtils.getSurfaceFormat(surface);
- mDataSpace = SurfaceUtils.getSurfaceDataspace(surface);
- mHardwareBufferFormat = PublicFormatUtils.getHalFormat(mImageFormat);
}
/**
@@ -1058,11 +1055,6 @@
mWidth = writer.mWidth;
mHeight = writer.mHeight;
mDataSpace = writer.mDataSpace;
-
- if (!mOwner.mUseLegacyImageFormat) {
- mFormat = PublicFormatUtils.getPublicFormat(
- mOwner.mHardwareBufferFormat, mDataSpace);
- }
}
@Override
@@ -1083,7 +1075,7 @@
public int getFormat() {
throwISEIfImageIsInvalid();
- if (mOwner.mUseLegacyImageFormat && mFormat == -1) {
+ if (mFormat == -1) {
mFormat = nativeGetFormat(mDataSpace);
}
return mFormat;
diff --git a/packages/CompanionDeviceManager/Android.bp b/packages/CompanionDeviceManager/Android.bp
index 6ded1637..9f5bfd4 100644
--- a/packages/CompanionDeviceManager/Android.bp
+++ b/packages/CompanionDeviceManager/Android.bp
@@ -34,6 +34,7 @@
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 06f2d9d..8b5d214 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 b51d310..a6a8fcf 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.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 @@
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 @@
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 @@
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 @@
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 @@
}
// ... 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 @@
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 eab421e..e3e563d 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java
@@ -50,14 +50,13 @@
}
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/AndroidSecureSettings.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java
new file mode 100644
index 0000000..8aee576
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/AndroidSecureSettings.java
@@ -0,0 +1,54 @@
+/*
+ * 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.settingslib.devicestate;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.provider.Settings;
+
+/**
+ * Implementation of {@link SecureSettings} that uses Android's {@link Settings.Secure}
+ * implementation.
+ */
+class AndroidSecureSettings implements SecureSettings {
+
+ private final ContentResolver mContentResolver;
+
+ AndroidSecureSettings(ContentResolver contentResolver) {
+ mContentResolver = contentResolver;
+ }
+
+ @Override
+ public void putStringForUser(String name, String value, int userHandle) {
+ Settings.Secure.putStringForUser(mContentResolver, name, value, userHandle);
+ }
+
+ @Override
+ public String getStringForUser(String name, int userHandle) {
+ return Settings.Secure.getStringForUser(mContentResolver, name, userHandle);
+ }
+
+ @Override
+ public void registerContentObserver(String name, boolean notifyForDescendants,
+ ContentObserver observer, int userHandle) {
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(name),
+ notifyForDescendants,
+ observer,
+ userHandle);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
index afd3626..4ed7e19 100644
--- a/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManager.java
@@ -22,8 +22,10 @@
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;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -33,7 +35,10 @@
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;
/**
@@ -47,32 +52,44 @@
private static DeviceStateRotationLockSettingsManager sSingleton;
- private final ContentResolver mContentResolver;
- private final String[] mDeviceStateRotationLockDefaults;
- private final Handler mMainHandler = Handler.getMain();
+ 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;
- private DeviceStateRotationLockSettingsManager(Context context) {
- mContentResolver = context.getContentResolver();
+ @VisibleForTesting
+ DeviceStateRotationLockSettingsManager(Context context, SecureSettings secureSettings) {
+ this.mSecureSettings = secureSettings;
mDeviceStateRotationLockDefaults =
context.getResources()
.getStringArray(R.array.config_perDeviceStateRotationLockDefaults);
loadDefaults();
initializeInMemoryMap();
- listenForSettingsChange(context);
+ listenForSettingsChange();
}
/** Returns a singleton instance of this class */
public static synchronized DeviceStateRotationLockSettingsManager getInstance(Context context) {
if (sSingleton == null) {
+ Context applicationContext = context.getApplicationContext();
+ ContentResolver contentResolver = applicationContext.getContentResolver();
+ SecureSettings secureSettings = new AndroidSecureSettings(contentResolver);
sSingleton =
- new DeviceStateRotationLockSettingsManager(context.getApplicationContext());
+ new DeviceStateRotationLockSettingsManager(applicationContext, secureSettings);
}
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()
@@ -81,11 +98,11 @@
> 0;
}
- private void listenForSettingsChange(Context context) {
- context.getContentResolver()
+ private void listenForSettingsChange() {
+ mSecureSettings
.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.DEVICE_STATE_ROTATION_LOCK),
- /* notifyForDescendents= */ false, //NOTYPO
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* notifyForDescendants= */ false,
new ContentObserver(mMainHandler) {
@Override
public void onChange(boolean selfChange) {
@@ -180,10 +197,15 @@
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 =
- Settings.Secure.getStringForUser(
- mContentResolver,
+ mSecureSettings.getStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
UserHandle.USER_CURRENT);
if (TextUtils.isEmpty(serializedSetting)) {
@@ -215,6 +237,17 @@
}
}
+ /**
+ * 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();
@@ -222,11 +255,7 @@
private void persistSettings() {
if (mDeviceStateRotationLockSettings.size() == 0) {
- Settings.Secure.putStringForUser(
- mContentResolver,
- Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
- /* value= */ "",
- UserHandle.USER_CURRENT);
+ persistSettingIfChanged(/* newSettingValue= */ "");
return;
}
@@ -243,14 +272,22 @@
.append(SEPARATOR_REGEX)
.append(mDeviceStateRotationLockSettings.valueAt(i));
}
- Settings.Secure.putStringForUser(
- mContentResolver,
+ persistSettingIfChanged(stringBuilder.toString());
+ }
+
+ private void persistSettingIfChanged(String newSettingValue) {
+ if (TextUtils.equals(mLastSettingValue, newSettingValue)) {
+ return;
+ }
+ mLastSettingValue = newSettingValue;
+ mSecureSettings.putStringForUser(
Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
- stringBuilder.toString(),
+ /* value= */ newSettingValue,
UserHandle.USER_CURRENT);
}
private void loadDefaults() {
+ mSettableDeviceStates = new ArrayList<>(mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockSettings = new SparseIntArray(
mDeviceStateRotationLockDefaults.length);
mDeviceStateRotationLockFallbackSettings = new SparseIntArray(1);
@@ -271,6 +308,8 @@
+ 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);
@@ -300,4 +339,38 @@
/** 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/src/com/android/settingslib/devicestate/SecureSettings.java b/packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java
new file mode 100644
index 0000000..1052873
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/devicestate/SecureSettings.java
@@ -0,0 +1,30 @@
+/*
+ * 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.settingslib.devicestate;
+
+import android.database.ContentObserver;
+
+/** Minimal wrapper interface around {@link android.provider.Settings.Secure} for easier testing. */
+interface SecureSettings {
+
+ void putStringForUser(String name, String value, int userHandle);
+
+ String getStringForUser(String name, int userHandle);
+
+ void registerContentObserver(String name, boolean notifyForDescendants,
+ ContentObserver settingsObserver, int userHandle);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index 93be66a..1e1dfae 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -81,6 +81,7 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ setTheme(R.style.SudThemeGlifV3_DayNight);
ThemeHelper.trySetDynamicColor(this);
setContentView(R.layout.avatar_picker);
setUpButtons();
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
new file mode 100644
index 0000000..81006dd
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/DeviceStateRotationLockSettingsManagerTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.settingslib.devicestate;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+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 {
+
+ @Mock private Context mMockContext;
+ @Mock private Resources mMockResources;
+
+ private DeviceStateRotationLockSettingsManager mManager;
+ private int mNumSettingsChanges = 0;
+ private final ContentObserver mContentObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ mNumSettingsChanges++;
+ }
+ };
+ private final FakeSecureSettings mFakeSecureSettings = new FakeSecureSettings();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = InstrumentationRegistry.getTargetContext();
+ when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getContentResolver()).thenReturn(context.getContentResolver());
+ mFakeSecureSettings.registerContentObserver(
+ Settings.Secure.DEVICE_STATE_ROTATION_LOCK,
+ /* notifyForDescendents= */ false, //NOTYPO
+ mContentObserver,
+ UserHandle.USER_CURRENT);
+ mManager = new DeviceStateRotationLockSettingsManager(context, mFakeSecureSettings);
+ }
+
+ @Test
+ public void initialization_settingsAreChangedOnce() {
+ assertThat(mNumSettingsChanges).isEqualTo(1);
+ }
+
+ @Test
+ public void updateSetting_multipleTimes_sameValue_settingsAreChangedOnlyOnce() {
+ mNumSettingsChanges = 0;
+
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+
+ assertThat(mNumSettingsChanges).isEqualTo(1);
+ }
+
+ @Test
+ public void updateSetting_multipleTimes_differentValues_settingsAreChangedMultipleTimes() {
+ mNumSettingsChanges = 0;
+
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ false);
+ mManager.updateSetting(/* deviceState= */ 1, /* rotationLocked= */ true);
+
+ 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/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/FakeSecureSettings.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/FakeSecureSettings.java
new file mode 100644
index 0000000..91baa68
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/FakeSecureSettings.java
@@ -0,0 +1,60 @@
+/*
+ * 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.settingslib.devicestate;
+
+import android.database.ContentObserver;
+import android.util.Pair;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** Fake implementation of {@link SecureSettings} that stores everything in memory. */
+class FakeSecureSettings implements SecureSettings {
+
+ private final Map<SettingsKey, String> mValues = new HashMap<>();
+ private final Multimap<SettingsKey, ContentObserver> mContentObservers = HashMultimap.create();
+
+ @Override
+ public void putStringForUser(String name, String value, int userHandle) {
+ SettingsKey settingsKey = new SettingsKey(userHandle, name);
+ mValues.put(settingsKey, value);
+ for (ContentObserver observer : mContentObservers.get(settingsKey)) {
+ observer.onChange(/* selfChange= */ false);
+ }
+ }
+
+ @Override
+ public String getStringForUser(String name, int userHandle) {
+ return mValues.getOrDefault(new SettingsKey(userHandle, name), "");
+ }
+
+ @Override
+ public void registerContentObserver(String name, boolean notifyForDescendants,
+ ContentObserver settingsObserver, int userHandle) {
+ mContentObservers.put(new SettingsKey(userHandle, name), settingsObserver);
+ }
+
+ private static class SettingsKey extends Pair<Integer, String> {
+
+ SettingsKey(Integer userHandle, String settingName) {
+ super(userHandle, settingName);
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS
new file mode 100644
index 0000000..98f4123
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/devicestate/OWNERS
@@ -0,0 +1,3 @@
+# Default reviewers for this and subdirectories.
+alexflo@google.com
+chrisgollner@google.com
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index f0b180e..121f9e5 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/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index c3f6a5d..0da60f0 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -298,6 +298,9 @@
*
* Important: The view must be attached to a [ViewGroup] when calling this function and
* during the animation. For safety, this method will return null when it is not.
+ *
+ * Note: The background of [view] should be a (rounded) rectangle so that it can be
+ * properly animated.
*/
@JvmStatic
fun fromView(view: View, cujType: Int? = null): Controller? {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index a3c5649..50178f4 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -79,6 +79,9 @@
* If [animateBackgroundBoundsChange] is true, then the background of the dialog will be
* animated when the dialog bounds change.
*
+ * Note: The background of [view] should be a (rounded) rectangle so that it can be properly
+ * animated.
+ *
* Caveats: When calling this function and [dialog] is not a fullscreen dialog, then it will be
* made fullscreen and 2 views will be inserted between the dialog DecorView and its children.
*/
@@ -153,6 +156,9 @@
* activity started, when the dialog to app animation is done (or when it is cancelled). If this
* method returns null, then the dialog won't be dismissed.
*
+ * Note: The background of [view] should be a (rounded) rectangle so that it can be properly
+ * animated.
+ *
* @param view any view inside the dialog to animate.
*/
@JvmOverloads
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index dad4c19..b98f413 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -123,6 +123,7 @@
<dimen name="bouncer_user_switcher_icon_size">190dp</dimen>
<dimen name="bouncer_user_switcher_icon_size_plus_margin">222dp</dimen>
+ <dimen name="user_switcher_fullscreen_horizontal_gap">64dp</dimen>
<dimen name="user_switcher_icon_selected_width">8dp</dimen>
<dimen name="user_switcher_fullscreen_button_text_size">14sp</dimen>
<dimen name="user_switcher_fullscreen_button_padding">12dp</dimen>
diff --git a/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml b/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml
new file mode 100644
index 0000000..0544b871
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_dialog_btn_filled_large.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape android:shape="rectangle">
+ <solid android:color="@android:color/white"/>
+ <corners android:radius="18dp"/>
+ </shape>
+ </item>
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="18dp"/>
+ <solid android:color="?androidprv:attr/colorAccentPrimary"/>
+ </shape>
+ </item>
+</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
index d057f5f..31a8c3b 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
@@ -19,13 +19,17 @@
<ripple
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
- <shape android:shape="oval">
+ <!-- We make this shape a rounded rectangle instead of a oval so that it can animate -->
+ <!-- properly into an app/dialog. -->
+ <shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
- <shape android:shape="oval">
+ <shape android:shape="rectangle">
<solid android:color="?attr/offStateColor"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
index 944061c..021a85f 100644
--- a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
@@ -19,13 +19,17 @@
<ripple
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
- <shape android:shape="oval">
+ <!-- We make this shape a rounded rectangle instead of a oval so that it can animate -->
+ <!-- properly into an app/dialog. -->
+ <shape android:shape="rectangle">
<solid android:color="@android:color/white"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
<item>
- <shape android:shape="oval">
+ <shape android:shape="rectangle">
<solid android:color="?android:attr/colorAccent"/>
+ <corners android:radius="@dimen/qs_footer_action_corner_radius"/>
</shape>
</item>
diff --git a/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
index a3e289a..e06bfdc 100644
--- a/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
+++ b/packages/SystemUI/res/layout/alert_dialog_button_bar_systemui.xml
@@ -22,10 +22,6 @@
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollIndicators="top|bottom"
android:fillViewport="true"
- android:paddingTop="@dimen/dialog_button_bar_top_padding"
- android:paddingStart="@dimen/dialog_side_padding"
- android:paddingEnd="@dimen/dialog_side_padding"
- android:paddingBottom="@dimen/dialog_bottom_padding"
style="?android:attr/buttonBarStyle">
<com.android.internal.widget.ButtonBarLayout
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/alert_dialog_systemui.xml b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
index f280cbd..ca8fadd 100644
--- a/packages/SystemUI/res/layout/alert_dialog_systemui.xml
+++ b/packages/SystemUI/res/layout/alert_dialog_systemui.xml
@@ -83,9 +83,15 @@
android:layout_height="wrap_content" />
</FrameLayout>
- <include
+ <FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- layout="@layout/alert_dialog_button_bar_systemui" />
+ android:paddingStart="@dimen/dialog_side_padding"
+ android:paddingEnd="@dimen/dialog_side_padding">
+ <include
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ layout="@layout/alert_dialog_button_bar_systemui" />
+ </FrameLayout>
</com.android.internal.widget.AlertDialogLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_container.xml b/packages/SystemUI/res/layout/dream_overlay_container.xml
index 330f515..8e83b4a 100644
--- a/packages/SystemUI/res/layout/dream_overlay_container.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_container.xml
@@ -34,34 +34,5 @@
app:layout_constraintBottom_toBottomOf="parent"
/>
- <com.android.systemui.dreams.DreamOverlayStatusBarView
- android:id="@+id/dream_overlay_status_bar"
- android:layout_width="match_parent"
- android:layout_height="@dimen/dream_overlay_status_bar_height"
- android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
- android:paddingStart="@dimen/dream_overlay_status_bar_margin"
- app:layout_constraintTop_toTopOf="parent">
-
- <androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/dream_overlay_system_status"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- app:layout_constraintEnd_toEndOf="parent">
-
- <com.android.systemui.statusbar.AlphaOptimizedImageView
- android:id="@+id/dream_overlay_wifi_status"
- android:layout_width="@dimen/status_bar_wifi_signal_size"
- android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
- android:visibility="gone"
- app:layout_constraintEnd_toStartOf="@id/dream_overlay_battery" />
-
- <com.android.systemui.battery.BatteryMeterView
- android:id="@+id/dream_overlay_battery"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- app:layout_constraintEnd_toEndOf="parent" />
-
- </androidx.constraintlayout.widget.ConstraintLayout>
- </com.android.systemui.dreams.DreamOverlayStatusBarView>
+ <include layout="@layout/dream_overlay_status_bar_view" />
</com.android.systemui.dreams.DreamOverlayContainerView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
new file mode 100644
index 0000000..813787e
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_status_bar_view.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<com.android.systemui.dreams.DreamOverlayStatusBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/dream_overlay_status_bar"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dream_overlay_status_bar_height"
+ android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
+ android:paddingStart="@dimen/dream_overlay_status_bar_margin"
+ app:layout_constraintTop_toTopOf="parent">
+
+ <com.android.systemui.dreams.DreamOverlayDotImageView
+ android:id="@+id/dream_overlay_notification_indicator"
+ android:layout_width="@dimen/dream_overlay_notification_indicator_size"
+ android:layout_height="@dimen/dream_overlay_notification_indicator_size"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_notification_indicator"
+ app:dotColor="@android:color/white"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent" />
+
+ <LinearLayout
+ android:id="@+id/dream_overlay_system_status"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_assistant_guest_mode_enabled"
+ android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+ android:src="@drawable/ic_account_circle"
+ android:tint="@android:color/white"
+ android:visibility="gone"
+ android:contentDescription=
+ "@string/dream_overlay_status_bar_assistant_guest_mode_enabled" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_alarm_set"
+ android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+ android:src="@drawable/ic_alarm"
+ android:tint="@android:color/white"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_alarm_set" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_priority_mode"
+ android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+ android:src="@drawable/ic_remove_circle"
+ android:tint="@android:color/white"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_priority_mode" />
+
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
+ android:id="@+id/dream_overlay_wifi_status"
+ android:layout_width="@dimen/dream_overlay_status_bar_icon_size"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+ android:src="@drawable/ic_signal_wifi_off"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_wifi_off" />
+
+ <com.android.systemui.dreams.DreamOverlayDotImageView
+ android:id="@+id/dream_overlay_camera_mic_off"
+ android:layout_width="@dimen/dream_overlay_camera_mic_off_indicator_size"
+ android:layout_height="@dimen/dream_overlay_camera_mic_off_indicator_size"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="@dimen/dream_overlay_status_icon_margin"
+ android:visibility="gone"
+ android:contentDescription="@string/dream_overlay_status_bar_camera_mic_off"
+ app:dotColor="@color/dream_overlay_camera_mic_off_dot_color" />
+
+ </LinearLayout>
+</com.android.systemui.dreams.DreamOverlayStatusBarView>
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
index 2d883bc..6bb6c2d 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
@@ -21,9 +21,8 @@
android:id="@+id/user_switcher_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginBottom="40dp"
- android:layout_marginEnd="60dp"
- android:layout_marginStart="60dp">
+ android:layout_marginVertical="40dp"
+ android:layout_marginHorizontal="60dp">
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/flow"
@@ -36,7 +35,7 @@
app:flow_horizontalBias="0.5"
app:flow_verticalAlign="center"
app:flow_wrapMode="chain"
- app:flow_horizontalGap="64dp"
+ app:flow_horizontalGap="@dimen/user_switcher_fullscreen_horizontal_gap"
app:flow_verticalGap="44dp"
app:flow_horizontalStyle="packed"/>
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml
index 3319442..a3d9a69 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen_item.xml
@@ -21,8 +21,8 @@
<ImageView
android:id="@+id/user_switcher_icon"
android:layout_gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_width="@dimen/bouncer_user_switcher_icon_size_plus_margin"
+ android:layout_height="@dimen/bouncer_user_switcher_icon_size_plus_margin" />
<TextView
style="@style/Bouncer.UserSwitcher.Spinner.Item"
android:id="@+id/user_switcher_text"
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index c37c804..8a4516a 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -42,4 +42,8 @@
the shade (in alpha) -->
<dimen name="lockscreen_shade_scrim_transition_distance">200dp</dimen>
+ <!-- Distance that the full shade transition takes in order for media to fully transition to
+ the shade -->
+ <dimen name="lockscreen_shade_media_transition_distance">200dp</dimen>
+
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 2992859..c5e005c 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -199,5 +199,9 @@
</declare-styleable>
<attr name="overlayButtonTextColor" format="color" />
+
+ <declare-styleable name="DreamOverlayDotImageView">
+ <attr name="dotColor" format="color" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f4e7cf3..dc74700 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -225,4 +225,6 @@
<color name="settingslib_track_off_color">@color/settingslib_track_off</color>
<color name="connected_network_primary_color">#191C18</color>
<color name="connected_network_secondary_color">#41493D</color>
+
+ <color name="dream_overlay_camera_mic_off_dot_color">#FCBE03</color>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3704134..fcf60bf 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1332,12 +1332,16 @@
<dimen name="fgs_manager_min_width_minor">100%</dimen>
<!-- Dream overlay related dimensions -->
- <dimen name="dream_overlay_status_bar_height">80dp</dimen>
+ <dimen name="dream_overlay_status_bar_height">60dp</dimen>
<dimen name="dream_overlay_status_bar_margin">40dp</dimen>
<dimen name="dream_overlay_status_icon_margin">8dp</dimen>
+ <dimen name="dream_overlay_status_bar_icon_size">
+ @*android:dimen/status_bar_system_icon_size</dimen>
<!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
shade. -->
<dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
+ <dimen name="dream_overlay_camera_mic_off_indicator_size">8dp</dimen>
+ <dimen name="dream_overlay_notification_indicator_size">6dp</dimen>
<!-- Dream overlay complications related dimensions -->
<dimen name="dream_overlay_complication_clock_time_text_size">72sp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 23b2529..df16b0d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2410,4 +2410,17 @@
<!-- Toast shown when a notification does not support dragging to split [CHAR LIMIT=NONE] -->
<string name="drag_split_not_supported">This notification does not support dragging to Splitscreen.</string>
+
+ <!-- Content description for the Wi-Fi off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_wifi_off">Wi\u2011Fi unavailable</string>
+ <!-- Content description for the priority mode icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_priority_mode">Priority mode</string>
+ <!-- Content description for the alarm set icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_alarm_set">Alarm set</string>
+ <!-- Content description for the assistant guest mode enabled icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_assistant_guest_mode_enabled">Assistant guest mode enabled</string>
+ <!-- Content description for the camera and mic off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_camera_mic_off">Camera and mic are off</string>
+ <!-- Content description for the camera and mic off icon in the dream overlay status bar [CHAR LIMIT=NONE] -->
+ <string name="dream_overlay_status_bar_notification_indicator">There are notifications</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9d65c38..f2eaa75 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -381,12 +381,19 @@
<item name="android:buttonBarNeutralButtonStyle">@style/Widget.Dialog.Button.BorderButton</item>
<item name="android:colorBackground">?androidprv:attr/colorSurface</item>
<item name="android:alertDialogStyle">@style/AlertDialogStyle</item>
+ <item name="android:buttonBarStyle">@style/ButtonBarStyle</item>
+ <item name="android:buttonBarButtonStyle">@style/Widget.Dialog.Button.Large</item>
</style>
<style name="AlertDialogStyle" parent="@androidprv:style/AlertDialog.DeviceDefault">
<item name="android:layout">@layout/alert_dialog_systemui</item>
</style>
+ <style name="ButtonBarStyle" parent="@androidprv:style/DeviceDefault.ButtonBar.AlertDialog">
+ <item name="android:paddingTop">@dimen/dialog_button_bar_top_padding</item>
+ <item name="android:paddingBottom">@dimen/dialog_bottom_padding</item>
+ </style>
+
<style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
<style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
@@ -962,6 +969,11 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <style name="Widget.Dialog.Button.Large">
+ <item name="android:background">@drawable/qs_dialog_btn_filled_large</item>
+ <item name="android:minHeight">56dp</item>
+ </style>
+
<style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault">
<item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 08b4d3f..2b1c47f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -103,8 +103,8 @@
// enabled (since it's used to navigate back within the bubbled app, or to collapse the bubble
// stack.
public static final int SYSUI_STATE_BUBBLES_EXPANDED = 1 << 14;
- // The global actions dialog is showing
- public static final int SYSUI_STATE_GLOBAL_ACTIONS_SHOWING = 1 << 15;
+ // A SysUI dialog is showing.
+ public static final int SYSUI_STATE_DIALOG_SHOWING = 1 << 15;
// The one-handed mode is active
public static final int SYSUI_STATE_ONE_HANDED_ACTIVE = 1 << 16;
// Allow system gesture no matter the system bar(s) is visible or not
@@ -140,7 +140,7 @@
SYSUI_STATE_TRACING_ENABLED,
SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
SYSUI_STATE_BUBBLES_EXPANDED,
- SYSUI_STATE_GLOBAL_ACTIONS_SHOWING,
+ SYSUI_STATE_DIALOG_SHOWING,
SYSUI_STATE_ONE_HANDED_ACTIVE,
SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
SYSUI_STATE_IME_SHOWING,
@@ -166,7 +166,7 @@
str.add((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED) != 0
? "keygrd_occluded" : "");
str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : "");
- str.add((flags & SYSUI_STATE_GLOBAL_ACTIONS_SHOWING) != 0 ? "global_actions" : "");
+ str.add((flags & SYSUI_STATE_DIALOG_SHOWING) != 0 ? "dialog_showing" : "");
str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : "");
str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : "");
str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
@@ -256,7 +256,7 @@
public static boolean isBackGestureDisabled(int sysuiStateFlags) {
// Always allow when the bouncer/global actions is showing (even on top of the keyguard)
if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0
- || (sysuiStateFlags & SYSUI_STATE_GLOBAL_ACTIONS_SHOWING) != 0) {
+ || (sysuiStateFlags & SYSUI_STATE_DIALOG_SHOWING) != 0) {
return false;
}
if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index b32c2b6..84b6ace 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -38,6 +38,7 @@
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.appops.AppOpsController;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -107,6 +108,7 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -372,6 +374,8 @@
@Inject Lazy<AmbientState> mAmbientStateLazy;
@Inject Lazy<GroupMembershipManager> mGroupMembershipManagerLazy;
@Inject Lazy<GroupExpansionManager> mGroupExpansionManagerLazy;
+ @Inject Lazy<SystemUIDialogManager> mSystemUIDialogManagerLazy;
+ @Inject Lazy<DialogLaunchAnimator> mDialogLaunchAnimatorLazy;
@Inject
public Dependency() {
@@ -592,6 +596,8 @@
mProviders.put(AmbientState.class, mAmbientStateLazy::get);
mProviders.put(GroupMembershipManager.class, mGroupMembershipManagerLazy::get);
mProviders.put(GroupExpansionManager.class, mGroupExpansionManagerLazy::get);
+ mProviders.put(SystemUIDialogManager.class, mSystemUIDialogManagerLazy::get);
+ mProviders.put(DialogLaunchAnimator.class, mDialogLaunchAnimatorLazy::get);
Dependency.setInstance(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 0d20403..de03993 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.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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
}
}
- 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 @@
}
mTransaction.show(mMirrorSurface)
.reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());
-
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
private void addDragTouchListeners() {
@@ -615,18 +655,25 @@
}
/**
- * 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 @@
(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 @@
createMirrorWindow();
showControls();
} else {
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
}
@@ -930,7 +981,7 @@
return;
}
if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) {
- modifyWindowMagnification(mTransaction);
+ modifyWindowMagnification(false);
}
}
@@ -1014,9 +1065,15 @@
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/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index be76e8f..7450103 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -18,12 +18,9 @@
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import android.graphics.Rect;
-import android.graphics.Region;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
@@ -62,43 +59,6 @@
// Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates).
private final Handler mHandler;
- // A hook into the internal inset calculation where we declare the overlays as the only
- // touchable regions.
- private final ViewTreeObserver.OnComputeInternalInsetsListener
- mOnComputeInternalInsetsListener =
- new ViewTreeObserver.OnComputeInternalInsetsListener() {
- @Override
- public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
- inoutInfo.setTouchableInsets(
- ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- final Region region = new Region();
- final Rect rect = new Rect();
- final int childCount = mDreamOverlayContentView.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mDreamOverlayContentView.getChildAt(i);
-
- if (mComplicationHostViewController.getView() == child) {
- region.op(mComplicationHostViewController.getTouchRegions(),
- Region.Op.UNION);
- continue;
- }
-
- if (child.getGlobalVisibleRect(rect)) {
- region.op(rect, Region.Op.UNION);
- }
- }
-
- // Add the notifications drag area to the tap region (otherwise the
- // notifications shade can't be dragged down).
- if (mDreamOverlayContentView.getGlobalVisibleRect(rect)) {
- rect.bottom = rect.top + mDreamOverlayNotificationsDragAreaHeight;
- region.op(rect, Region.Op.UNION);
- }
-
- inoutInfo.touchableRegion.set(region);
- }
- };
-
@Inject
public DreamOverlayContainerViewController(
DreamOverlayContainerView containerView,
@@ -136,16 +96,12 @@
@Override
protected void onViewAttached() {
- mView.getViewTreeObserver()
- .addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
}
@Override
protected void onViewDetached() {
mHandler.removeCallbacks(this::updateBurnInOffsets);
- mView.getViewTreeObserver()
- .removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
View getContainerView() {
@@ -162,6 +118,7 @@
// so no translation occurs when the values don't change.
mView.setTranslationX(getBurnInOffset(mMaxBurnInOffset * 2, true)
- mMaxBurnInOffset);
+
mView.setTranslationY(getBurnInOffset(mMaxBurnInOffset * 2, false)
- mMaxBurnInOffset);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java
new file mode 100644
index 0000000..02a8b39a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayDotImageView.java
@@ -0,0 +1,128 @@
+/*
+ * 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.systemui.dreams;
+
+import android.annotation.ColorInt;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
+
+/**
+ * An {@link AlphaOptimizedImageView} that is responsible for rendering a dot. Used by
+ * {@link DreamOverlayStatusBarView}.
+ */
+public class DreamOverlayDotImageView extends AlphaOptimizedImageView {
+ private final @ColorInt int mDotColor;
+
+ public DreamOverlayDotImageView(Context context) {
+ this(context, null);
+ }
+
+ public DreamOverlayDotImageView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DreamOverlayDotImageView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public DreamOverlayDotImageView(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
+ R.styleable.DreamOverlayDotImageView, 0, 0);
+
+ try {
+ mDotColor = a.getColor(R.styleable.DreamOverlayDotImageView_dotColor, Color.WHITE);
+ } finally {
+ a.recycle();
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setImageDrawable(new DotDrawable(mDotColor));
+ }
+
+ private static class DotDrawable extends Drawable {
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private Bitmap mDotBitmap;
+ private final Rect mBounds = new Rect();
+ private final @ColorInt int mDotColor;
+
+ DotDrawable(@ColorInt int color) {
+ mDotColor = color;
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ if (mBounds.isEmpty()) {
+ return;
+ }
+
+ if (mDotBitmap == null) {
+ mDotBitmap = createBitmap(mBounds.width(), mBounds.height());
+ }
+
+ canvas.drawBitmap(mDotBitmap, null, mBounds, mPaint);
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mBounds.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ // Make sure to regenerate the dot bitmap when the bounds change.
+ mDotBitmap = null;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+
+ private Bitmap createBitmap(int width, int height) {
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setColor(mDotColor);
+ canvas.drawCircle(width / 2.f, height / 2.f, Math.min(width, height) / 2.f, paint);
+ return bitmap;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
index 9847ef6..2d96920 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarView.java
@@ -25,17 +25,13 @@
import com.android.internal.util.Preconditions;
import com.android.systemui.R;
-import com.android.systemui.battery.BatteryMeterView;
-import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
/**
* {@link DreamOverlayStatusBarView} is the view responsible for displaying the status bar in a
- * dream. The status bar includes status icons such as battery and wifi.
+ * dream. The status bar displays conditional status icons such as "priority mode" and "no wifi".
*/
-public class DreamOverlayStatusBarView extends ConstraintLayout implements
- BatteryStateChangeCallback {
+public class DreamOverlayStatusBarView extends ConstraintLayout {
- private BatteryMeterView mBatteryView;
private ImageView mWifiStatusView;
public DreamOverlayStatusBarView(Context context) {
@@ -59,20 +55,8 @@
protected void onFinishInflate() {
super.onFinishInflate();
- mBatteryView = Preconditions.checkNotNull(findViewById(R.id.dream_overlay_battery),
- "R.id.dream_overlay_battery must not be null");
mWifiStatusView = Preconditions.checkNotNull(findViewById(R.id.dream_overlay_wifi_status),
"R.id.dream_overlay_wifi_status must not be null");
-
- mWifiStatusView.setImageDrawable(getContext().getDrawable(R.drawable.ic_signal_wifi_off));
- }
-
- /**
- * Whether to show the battery percent text next to the battery status icons.
- * @param show True if the battery percent text should be shown.
- */
- void showBatteryPercentText(boolean show) {
- mBatteryView.setForceShowPercent(show);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
index 5674b9f..32b2309 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStatusBarViewController.java
@@ -17,24 +17,20 @@
package com.android.systemui.dreams;
import android.annotation.IntDef;
-import android.content.Context;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
-import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
-import com.android.systemui.dreams.dagger.DreamOverlayModule;
-import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.touch.TouchInsetManager;
import com.android.systemui.util.ViewController;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Inject;
-import javax.inject.Named;
/**
* View controller for {@link DreamOverlayStatusBarView}.
@@ -52,21 +48,8 @@
private static final int WIFI_STATUS_UNAVAILABLE = 1;
private static final int WIFI_STATUS_AVAILABLE = 2;
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "BATTERY_STATUS_" }, value = {
- BATTERY_STATUS_UNKNOWN,
- BATTERY_STATUS_NOT_CHARGING,
- BATTERY_STATUS_CHARGING
- })
- private @interface BatteryStatus {}
- private static final int BATTERY_STATUS_UNKNOWN = 0;
- private static final int BATTERY_STATUS_NOT_CHARGING = 1;
- private static final int BATTERY_STATUS_CHARGING = 2;
-
- private final BatteryController mBatteryController;
- private final BatteryMeterViewController mBatteryMeterViewController;
private final ConnectivityManager mConnectivityManager;
- private final boolean mShowPercentAvailable;
+ private final TouchInsetManager.TouchInsetSession mTouchInsetSession;
private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
.clearCapabilities()
@@ -91,43 +74,20 @@
}
};
- private final BatteryController.BatteryStateChangeCallback mBatteryStateChangeCallback =
- new BatteryController.BatteryStateChangeCallback() {
- @Override
- public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
- DreamOverlayStatusBarViewController.this.onBatteryLevelChanged(charging);
- }
- };
-
private @WifiStatus int mWifiStatus = WIFI_STATUS_UNKNOWN;
- private @BatteryStatus int mBatteryStatus = BATTERY_STATUS_UNKNOWN;
@Inject
public DreamOverlayStatusBarViewController(
- Context context,
DreamOverlayStatusBarView view,
- BatteryController batteryController,
- @Named(DreamOverlayModule.DREAM_OVERLAY_BATTERY_CONTROLLER)
- BatteryMeterViewController batteryMeterViewController,
- ConnectivityManager connectivityManager) {
+ ConnectivityManager connectivityManager,
+ TouchInsetManager.TouchInsetSession touchInsetSession) {
super(view);
- mBatteryController = batteryController;
- mBatteryMeterViewController = batteryMeterViewController;
mConnectivityManager = connectivityManager;
-
- mShowPercentAvailable = context.getResources().getBoolean(
- com.android.internal.R.bool.config_battery_percentage_setting_available);
- }
-
- @Override
- protected void onInit() {
- super.onInit();
- mBatteryMeterViewController.init();
+ mTouchInsetSession = touchInsetSession;
}
@Override
protected void onViewAttached() {
- mBatteryController.addCallback(mBatteryStateChangeCallback);
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback);
NetworkCapabilities capabilities =
@@ -136,12 +96,13 @@
onWifiAvailabilityChanged(
capabilities != null
&& capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI));
+ mTouchInsetSession.addViewToTracking(mView);
}
@Override
protected void onViewDetached() {
- mBatteryController.removeCallback(mBatteryStateChangeCallback);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+ mTouchInsetSession.clear();
}
/**
@@ -155,18 +116,4 @@
mView.showWifiStatus(mWifiStatus == WIFI_STATUS_UNAVAILABLE);
}
}
-
- /**
- * The battery level has changed. Update the battery status icon as appropriate.
- * @param charging Whether the battery is currently charging.
- */
- private void onBatteryLevelChanged(boolean charging) {
- final int newBatteryStatus =
- charging ? BATTERY_STATUS_CHARGING : BATTERY_STATUS_NOT_CHARGING;
- if (mBatteryStatus != newBatteryStatus) {
- mBatteryStatus = newBatteryStatus;
- mView.showBatteryPercentText(
- mBatteryStatus == BATTERY_STATUS_CHARGING && mShowPercentAvailable);
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
index 0b80d8a..437e799 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
@@ -27,6 +27,7 @@
import androidx.constraintlayout.widget.Constraints;
import com.android.systemui.R;
+import com.android.systemui.touch.TouchInsetManager;
import java.util.ArrayList;
import java.util.Collections;
@@ -52,6 +53,7 @@
private static class ViewEntry implements Comparable<ViewEntry> {
private final View mView;
private final ComplicationLayoutParams mLayoutParams;
+ private final TouchInsetManager.TouchInsetSession mTouchInsetSession;
private final Parent mParent;
@Complication.Category
private final int mCategory;
@@ -61,7 +63,8 @@
* Default constructor. {@link Parent} allows for the {@link ViewEntry}'s surrounding
* view hierarchy to be accessed without traversing the entire view tree.
*/
- ViewEntry(View view, ComplicationLayoutParams layoutParams, int category, Parent parent,
+ ViewEntry(View view, ComplicationLayoutParams layoutParams,
+ TouchInsetManager.TouchInsetSession touchSession, int category, Parent parent,
int margin) {
mView = view;
// Views that are generated programmatically do not have a unique id assigned to them
@@ -70,9 +73,12 @@
// {@link Complication.ViewHolder} should not reference the root container by id.
mView.setId(View.generateViewId());
mLayoutParams = layoutParams;
+ mTouchInsetSession = touchSession;
mCategory = category;
mParent = parent;
mMargin = margin;
+
+ touchSession.addViewToTracking(mView);
}
/**
@@ -217,6 +223,7 @@
mParent.removeEntry(this);
((ViewGroup) mView.getParent()).removeView(mView);
+ mTouchInsetSession.removeViewFromTracking(mView);
}
@Override
@@ -242,15 +249,18 @@
*/
private static class Builder {
private final View mView;
+ private final TouchInsetManager.TouchInsetSession mTouchSession;
private final ComplicationLayoutParams mLayoutParams;
private final int mCategory;
private Parent mParent;
private int mMargin;
- Builder(View view, ComplicationLayoutParams lp, @Complication.Category int category) {
+ Builder(View view, TouchInsetManager.TouchInsetSession touchSession,
+ ComplicationLayoutParams lp, @Complication.Category int category) {
mView = view;
mLayoutParams = lp;
mCategory = category;
+ mTouchSession = touchSession;
}
/**
@@ -291,7 +301,8 @@
* Builds and returns the resulting {@link ViewEntry}.
*/
ViewEntry build() {
- return new ViewEntry(mView, mLayoutParams, mCategory, mParent, mMargin);
+ return new ViewEntry(mView, mLayoutParams, mTouchSession, mCategory, mParent,
+ mMargin);
}
}
@@ -442,13 +453,16 @@
private final int mMargin;
private final HashMap<ComplicationId, ViewEntry> mEntries = new HashMap<>();
private final HashMap<Integer, PositionGroup> mPositions = new HashMap<>();
+ private final TouchInsetManager.TouchInsetSession mSession;
/** */
@Inject
public ComplicationLayoutEngine(@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout layout,
- @Named(COMPLICATION_MARGIN) int margin) {
+ @Named(COMPLICATION_MARGIN) int margin,
+ TouchInsetManager.TouchInsetSession session) {
mLayout = layout;
mMargin = margin;
+ mSession = session;
}
/**
@@ -468,7 +482,7 @@
removeComplication(id);
}
- final ViewEntry.Builder entryBuilder = new ViewEntry.Builder(view, lp, category)
+ final ViewEntry.Builder entryBuilder = new ViewEntry.Builder(view, mSession, lp, category)
.setMargin(mMargin);
// Add position group if doesn't already exist
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index 4eb5cb9..63676d6 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -16,9 +16,7 @@
package com.android.systemui.dreams.dagger;
-import android.content.ContentResolver;
import android.content.res.Resources;
-import android.os.Handler;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -28,15 +26,12 @@
import com.android.internal.util.Preconditions;
import com.android.systemui.R;
-import com.android.systemui.battery.BatteryMeterView;
-import com.android.systemui.battery.BatteryMeterViewController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.DreamOverlayContainerView;
import com.android.systemui.dreams.DreamOverlayStatusBarView;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.tuner.TunerService;
+import com.android.systemui.touch.TouchInsetManager;
+
+import java.util.concurrent.Executor;
import javax.inject.Named;
@@ -47,9 +42,6 @@
/** Dagger module for {@link DreamOverlayComponent}. */
@Module
public abstract class DreamOverlayModule {
- private static final String DREAM_OVERLAY_BATTERY_VIEW = "dream_overlay_battery_view";
- public static final String DREAM_OVERLAY_BATTERY_CONTROLLER =
- "dream_overlay_battery_controller";
public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
public static final String MAX_BURN_IN_OFFSET = "max_burn_in_offset";
public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
@@ -76,6 +68,21 @@
/** */
@Provides
+ public static TouchInsetManager.TouchInsetSession providesTouchInsetSession(
+ TouchInsetManager manager) {
+ return manager.createSession();
+ }
+
+ /** */
+ @Provides
+ @DreamOverlayComponent.DreamOverlayScope
+ public static TouchInsetManager providesTouchInsetManager(@Main Executor executor,
+ DreamOverlayContainerView view) {
+ return new TouchInsetManager(executor, view);
+ }
+
+ /** */
+ @Provides
@DreamOverlayComponent.DreamOverlayScope
public static DreamOverlayStatusBarView providesDreamOverlayStatusBarView(
DreamOverlayContainerView view) {
@@ -86,37 +93,6 @@
/** */
@Provides
@DreamOverlayComponent.DreamOverlayScope
- @Named(DREAM_OVERLAY_BATTERY_VIEW)
- static BatteryMeterView providesBatteryMeterView(DreamOverlayContainerView view) {
- return Preconditions.checkNotNull(view.findViewById(R.id.dream_overlay_battery),
- "R.id.battery must not be null");
- }
-
- /** */
- @Provides
- @DreamOverlayComponent.DreamOverlayScope
- @Named(DREAM_OVERLAY_BATTERY_CONTROLLER)
- static BatteryMeterViewController providesBatteryMeterViewController(
- @Named(DREAM_OVERLAY_BATTERY_VIEW) BatteryMeterView batteryMeterView,
- ConfigurationController configurationController,
- TunerService tunerService,
- BroadcastDispatcher broadcastDispatcher,
- @Main Handler mainHandler,
- ContentResolver contentResolver,
- BatteryController batteryController) {
- return new BatteryMeterViewController(
- batteryMeterView,
- configurationController,
- tunerService,
- broadcastDispatcher,
- mainHandler,
- contentResolver,
- batteryController);
- }
-
- /** */
- @Provides
- @DreamOverlayComponent.DreamOverlayScope
@Named(MAX_BURN_IN_OFFSET)
static int providesMaxBurnInOffset(@Main Resources resources) {
return resources.getDimensionPixelSize(R.dimen.default_burn_in_prevention_offset);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 84fa6a6..e3886cd 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -27,7 +27,6 @@
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -117,7 +116,6 @@
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.scrim.ScrimDrawable;
@@ -125,7 +123,6 @@
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -200,7 +197,6 @@
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
private final UiEventLogger mUiEventLogger;
- private final SysUiState mSysUiState;
// Used for RingerModeTracker
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
@@ -241,7 +237,6 @@
protected Handler mMainHandler;
private int mSmallestScreenWidthDp;
private final Optional<StatusBar> mStatusBarOptional;
- private final SystemUIDialogManager mDialogManager;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final DialogLaunchAnimator mDialogLaunchAnimator;
@@ -347,13 +342,11 @@
@Background Executor backgroundExecutor,
UiEventLogger uiEventLogger,
RingerModeTracker ringerModeTracker,
- SysUiState sysUiState,
@Main Handler handler,
PackageManager packageManager,
Optional<StatusBar> statusBarOptional,
KeyguardUpdateMonitor keyguardUpdateMonitor,
- DialogLaunchAnimator dialogLaunchAnimator,
- SystemUIDialogManager dialogManager) {
+ DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mWindowManagerFuncs = windowManagerFuncs;
mAudioManager = audioManager;
@@ -379,13 +372,11 @@
mIWindowManager = iWindowManager;
mBackgroundExecutor = backgroundExecutor;
mRingerModeTracker = ringerModeTracker;
- mSysUiState = sysUiState;
mMainHandler = handler;
mSmallestScreenWidthDp = resources.getConfiguration().smallestScreenWidthDp;
mStatusBarOptional = statusBarOptional;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mDialogLaunchAnimator = dialogLaunchAnimator;
- mDialogManager = dialogManager;
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -682,11 +673,10 @@
ActionsDialogLite dialog = new ActionsDialogLite(mContext,
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActionsLite,
- mAdapter, mOverflowAdapter, mSysuiColorExtractor,
- mStatusBarService, mNotificationShadeWindowController,
- mSysUiState, this::onRefresh, mKeyguardShowing, mPowerAdapter, mUiEventLogger,
- mStatusBarOptional, mKeyguardUpdateMonitor, mLockPatternUtils,
- mDialogManager);
+ mAdapter, mOverflowAdapter, mSysuiColorExtractor, mStatusBarService,
+ mNotificationShadeWindowController, this::onRefresh, mKeyguardShowing,
+ mPowerAdapter, mUiEventLogger, mStatusBarOptional, mKeyguardUpdateMonitor,
+ mLockPatternUtils);
dialog.setOnDismissListener(this);
dialog.setOnShowListener(this);
@@ -2165,7 +2155,6 @@
private boolean mKeyguardShowing;
protected float mScrimAlpha;
protected final NotificationShadeWindowController mNotificationShadeWindowController;
- protected final SysUiState mSysUiState;
private ListPopupWindow mOverflowPopup;
private Dialog mPowerOptionsDialog;
protected final Runnable mOnRefreshCallback;
@@ -2226,15 +2215,13 @@
MyOverflowAdapter overflowAdapter,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
- SysUiState sysuiState, Runnable onRefreshCallback, boolean keyguardShowing,
+ Runnable onRefreshCallback, boolean keyguardShowing,
MyPowerOptionsAdapter powerAdapter, UiEventLogger uiEventLogger,
- Optional<StatusBar> statusBarOptional,
- KeyguardUpdateMonitor keyguardUpdateMonitor, LockPatternUtils lockPatternUtils,
- SystemUIDialogManager systemUiDialogManager) {
+ Optional<StatusBar> statusBarOptional, KeyguardUpdateMonitor keyguardUpdateMonitor,
+ LockPatternUtils lockPatternUtils) {
// We set dismissOnDeviceLock to false because we have a custom broadcast receiver to
// dismiss this dialog when the device is locked.
- super(context, themeRes, false /* dismissOnDeviceLock */,
- systemUiDialogManager);
+ super(context, themeRes, false /* dismissOnDeviceLock */);
mContext = context;
mAdapter = adapter;
mOverflowAdapter = overflowAdapter;
@@ -2242,7 +2229,6 @@
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
- mSysUiState = sysuiState;
mOnRefreshCallback = onRefreshCallback;
mKeyguardShowing = keyguardShowing;
mUiEventLogger = uiEventLogger;
@@ -2463,8 +2449,6 @@
public void show() {
super.show();
mNotificationShadeWindowController.setRequestTopUi(true, TAG);
- mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, true)
- .commitUpdate(mContext.getDisplayId());
// By default this dialog windowAnimationStyle is null, and therefore windowAnimations
// should be equal to 0 which means we need to animate the dialog in-window. If it's not
@@ -2563,9 +2547,6 @@
dismissPowerOptions();
mNotificationShadeWindowController.setRequestTopUi(false, TAG);
- mSysUiState.setFlag(SYSUI_STATE_GLOBAL_ACTIONS_SHOWING, false)
- .commitUpdate(mContext.getDisplayId());
-
super.dismiss();
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index eee3955..f4b6fbd 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -795,6 +795,9 @@
@TransformationType
fun calculateTransformationType(): Int {
if (isTransitioningToFullShade) {
+ if (inSplitShade) {
+ return TRANSFORMATION_TYPE_TRANSITION
+ }
return TRANSFORMATION_TYPE_FADE
}
if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS ||
@@ -961,6 +964,7 @@
(qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
!hasActiveMedia -> LOCATION_QS
+ onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
onLockscreen && allowedOnLockscreen -> LOCATION_LOCKSCREEN
else -> LOCATION_QQS
@@ -986,6 +990,10 @@
return location
}
+ private fun isSplitShadeExpanding(): Boolean {
+ return inSplitShade && isTransitioningToFullShade
+ }
+
/**
* Are we currently transforming to the full shade and already in QQS
*/
@@ -993,6 +1001,10 @@
if (!isTransitioningToFullShade) {
return false
}
+ if (inSplitShade) {
+ // Split shade doesn't use QQS.
+ return false
+ }
return fullShadeTransitionProgress > 0.5f
}
@@ -1000,6 +1012,10 @@
* Is the current transformationType fading
*/
private fun isCurrentlyFading(): Boolean {
+ if (isSplitShadeExpanding()) {
+ // Split shade always uses transition instead of fade.
+ return false
+ }
if (isTransitioningToFullShade) {
return true
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 7bb5454..04a324b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -56,7 +56,6 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Base dialog for media output UI
@@ -99,9 +98,8 @@
}
};
- public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController,
- SystemUIDialogManager dialogManager) {
- super(context, R.style.Theme_SystemUI_Dialog_Media, dialogManager);
+ public MediaOutputBaseDialog(Context context, MediaOutputController mediaOutputController) {
+ super(context, R.style.Theme_SystemUI_Dialog_Media);
// Save the context that is wrapped with our theme.
mContext = getContext();
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 7bc0f52..e929b5e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -66,7 +66,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import java.util.ArrayList;
import java.util.Collection;
@@ -91,7 +90,6 @@
private final ShadeController mShadeController;
private final ActivityStarter mActivityStarter;
private final DialogLaunchAnimator mDialogLaunchAnimator;
- private final SystemUIDialogManager mDialogManager;
private final List<MediaDevice> mGroupMediaDevices = new CopyOnWriteArrayList<>();
private final boolean mAboveStatusbar;
private final boolean mVolumeAdjustmentForRemoteGroupSessions;
@@ -119,7 +117,7 @@
boolean aboveStatusbar, MediaSessionManager mediaSessionManager, LocalBluetoothManager
lbm, ShadeController shadeController, ActivityStarter starter,
CommonNotifCollection notifCollection, UiEventLogger uiEventLogger,
- DialogLaunchAnimator dialogLaunchAnimator, SystemUIDialogManager dialogManager) {
+ DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mPackageName = packageName;
mMediaSessionManager = mediaSessionManager;
@@ -135,7 +133,6 @@
mDialogLaunchAnimator = dialogLaunchAnimator;
mVolumeAdjustmentForRemoteGroupSessions = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_volumeAdjustmentForRemoteGroupSessions);
- mDialogManager = dialogManager;
mColorActiveItem = Utils.getColorStateListDefaultColor(mContext,
R.color.media_dialog_active_item_main_content);
mColorInactiveItem = Utils.getColorStateListDefaultColor(mContext,
@@ -610,10 +607,9 @@
// We show the output group dialog from the output dialog.
MediaOutputController controller = new MediaOutputController(mContext, mPackageName,
mAboveStatusbar, mMediaSessionManager, mLocalBluetoothManager, mShadeController,
- mActivityStarter, mNotifCollection, mUiEventLogger, mDialogLaunchAnimator,
- mDialogManager);
+ mActivityStarter, mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
MediaOutputGroupDialog dialog = new MediaOutputGroupDialog(mContext, mAboveStatusbar,
- controller, mDialogManager);
+ controller);
mDialogLaunchAnimator.showFromView(dialog, mediaOutputDialog);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index 4e9da55..7696a1f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -29,7 +29,6 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Dialog for media output transferring.
@@ -39,9 +38,8 @@
final UiEventLogger mUiEventLogger;
MediaOutputDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController, UiEventLogger uiEventLogger,
- SystemUIDialogManager dialogManager) {
- super(context, mediaOutputController, dialogManager);
+ mediaOutputController, UiEventLogger uiEventLogger) {
+ super(context, mediaOutputController);
mUiEventLogger = uiEventLogger;
mAdapter = new MediaOutputAdapter(mMediaOutputController, this);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
index e1e7fa3..9e252ea 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -25,7 +25,6 @@
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
import com.android.systemui.statusbar.phone.ShadeController
-import com.android.systemui.statusbar.phone.SystemUIDialogManager
import javax.inject.Inject
/**
@@ -39,8 +38,7 @@
private val starter: ActivityStarter,
private val notifCollection: CommonNotifCollection,
private val uiEventLogger: UiEventLogger,
- private val dialogLaunchAnimator: DialogLaunchAnimator,
- private val dialogManager: SystemUIDialogManager
+ private val dialogLaunchAnimator: DialogLaunchAnimator
) {
companion object {
var mediaOutputDialog: MediaOutputDialog? = null
@@ -53,9 +51,8 @@
val controller = MediaOutputController(context, packageName, aboveStatusBar,
mediaSessionManager, lbm, shadeController, starter, notifCollection,
- uiEventLogger, dialogLaunchAnimator, dialogManager)
- val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger,
- dialogManager)
+ uiEventLogger, dialogLaunchAnimator)
+ val dialog = MediaOutputDialog(context, aboveStatusBar, controller, uiEventLogger)
mediaOutputDialog = dialog
// Show the dialog.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
index 9f752b9..f1c6601 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputGroupDialog.java
@@ -25,7 +25,6 @@
import androidx.core.graphics.drawable.IconCompat;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
/**
* Dialog for media output group.
@@ -34,8 +33,8 @@
public class MediaOutputGroupDialog extends MediaOutputBaseDialog {
MediaOutputGroupDialog(Context context, boolean aboveStatusbar, MediaOutputController
- mediaOutputController, SystemUIDialogManager dialogManager) {
- super(context, mediaOutputController, dialogManager);
+ mediaOutputController) {
+ super(context, mediaOutputController);
mMediaOutputController.resetGroupMediaDevices();
mAdapter = new MediaOutputGroupAdapter(mMediaOutputController);
if (!aboveStatusbar) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index a262b8a..217210a 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 @@
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 @@
override fun onViewDetached() {
setListening(false)
+ multiUserSetting.isListening = false
}
fun setListening(listening: Boolean) {
@@ -222,7 +224,6 @@
return
}
this.listening = listening
- multiUserSetting.isListening = listening
if (this.listening) {
userInfoController.addCallback(onUserInfoChangedListener)
updateView()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 3c7933f..3ef7220 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -513,7 +513,8 @@
mContainer.setExpansion(expansion);
final float translationScaleY = (mInSplitShade
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
- boolean onKeyguardAndExpanded = isKeyguardState() && !mShowCollapsedOnKeyguard;
+ boolean onKeyguard = isKeyguardState();
+ boolean onKeyguardAndExpanded = onKeyguard && !mShowCollapsedOnKeyguard;
if (!mHeaderAnimating && !headerWillBeAnimating()) {
getView().setTranslationY(
onKeyguardAndExpanded
@@ -547,6 +548,7 @@
mHeader.updateResources();
}
}
+ mQSPanelController.setIsOnKeyguard(onKeyguard);
mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
mQSPanelController.setRevealExpansion(expansion);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5126fcb..b04d752 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -110,6 +110,8 @@
private final ArrayMap<View, Integer> mChildrenLayoutTop = new ArrayMap<>();
private final Rect mClippingRect = new Rect();
private boolean mUseNewFooter = false;
+ private ViewGroup mMediaHostView;
+ private boolean mShouldMoveMediaOnExpansion = true;
public QSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -289,9 +291,15 @@
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (move) {
+ int topOffset;
+ if (child == mMediaHostView && !mShouldMoveMediaOnExpansion) {
+ topOffset = 0;
+ } else {
+ topOffset = tileHeightOffset;
+ }
int top = Objects.requireNonNull(mChildrenLayoutTop.get(child));
- child.setLeftTopRightBottom(child.getLeft(), top + tileHeightOffset,
- child.getRight(), top + tileHeightOffset + child.getHeight());
+ child.setLeftTopRightBottom(child.getLeft(), top + topOffset,
+ child.getRight(), top + topOffset + child.getHeight());
}
if (child == mTileLayout) {
move = true;
@@ -463,6 +471,7 @@
if (!mUsingMediaPlayer) {
return;
}
+ mMediaHostView = hostView;
ViewGroup newParent = horizontal ? mHorizontalLinearLayout : this;
ViewGroup currentParent = (ViewGroup) hostView.getParent();
if (currentParent != newParent) {
@@ -656,6 +665,19 @@
updatePadding();
}
+ /**
+ * Sets whether the media container should move during the expansion of the QS Panel.
+ *
+ * As the QS Panel expands and the QS unsquish, the views below the QS tiles move to adapt to
+ * the new height of the QS tiles.
+ *
+ * In some cases this might not be wanted for media. One example is when there is a transition
+ * animation of the media container happening on split shade lock screen.
+ */
+ public void setShouldMoveMediaOnExpansion(boolean shouldMoveMediaOnExpansion) {
+ mShouldMoveMediaOnExpansion = shouldMoveMediaOnExpansion;
+ }
+
private class H extends Handler {
private static final int ANNOUNCE_FOR_ACCESSIBILITY = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 3172aa9..6572daa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -419,6 +419,16 @@
return mView.getBrightnessView();
}
+ /** Sets whether we are currently on lock screen. */
+ public void setIsOnKeyguard(boolean isOnKeyguard) {
+ boolean isOnSplitShadeLockscreen = mShouldUseSplitNotificationShade && isOnKeyguard;
+ // When the split shade is expanding on lockscreen, the media container transitions from the
+ // lockscreen to QS.
+ // We have to prevent the media container position from moving during the transition to have
+ // a smooth translation animation without stuttering.
+ mView.setShouldMoveMediaOnExpansion(!isOnSplitShadeLockscreen);
+ }
+
/** */
public static final class TileRecord {
public TileRecord(QSTile tile, com.android.systemui.plugins.qs.QSTileView tileView) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index e088f54..5d6bbae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -202,11 +202,12 @@
mActivityStarter
.postStartActivityDismissingKeyguard(getLongClickIntent(), 0,
controller);
- });
+ }, R.style.Theme_SystemUI_Dialog, false /* showProgressBarWhenEmpty */);
holder.init(dialog);
SystemUIDialog.setShowForAllUsers(dialog, true);
SystemUIDialog.registerDismissListener(dialog);
SystemUIDialog.setWindowOnTop(dialog, mKeyguard.isShowing());
+ SystemUIDialog.setDialogSize(dialog);
mUiHandler.post(() -> {
if (view != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 8366bdd..8a9d6dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -342,9 +342,7 @@
qS.setTransitionToFullShadeAmount(field, qSDragProgress)
notificationPanelController.setTransitionToFullShadeAmount(field,
false /* animate */, 0 /* delay */)
- // TODO: appear media also in split shade
- val mediaAmount = if (useSplitShade) 0f else field
- mediaHierarchyManager.setTransitionToFullShadeAmount(mediaAmount)
+ mediaHierarchyManager.setTransitionToFullShadeAmount(field)
transitionToShadeAmountCommon(field)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
index 9f9e7d9..5caf4f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImpl.java
@@ -26,6 +26,7 @@
import android.app.IActivityManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Region;
import android.os.Binder;
@@ -117,6 +118,7 @@
* @see #batchApplyWindowLayoutParams(Runnable)
*/
private int mDeferWindowLayoutParams;
+ private boolean mLastKeyguardRotationAllowed;
@Inject
public NotificationShadeWindowControllerImpl(Context context, WindowManager windowManager,
@@ -143,7 +145,7 @@
mScreenOffAnimationController = screenOffAnimationController;
dumpManager.registerDumpable(getClass().getName(), this);
mAuthController = authController;
-
+ mLastKeyguardRotationAllowed = mKeyguardStateController.isKeyguardScreenRotationAllowed();
mLockScreenDisplayTimeout = context.getResources()
.getInteger(R.integer.config_lockScreenDisplayTimeout);
((SysuiStatusBarStateController) statusBarStateController)
@@ -779,6 +781,17 @@
setKeyguardDark(useDarkText);
}
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ final boolean newScreenRotationAllowed = mKeyguardStateController
+ .isKeyguardScreenRotationAllowed();
+
+ if (mLastKeyguardRotationAllowed != newScreenRotationAllowed) {
+ apply(mCurrentState);
+ mLastKeyguardRotationAllowed = newScreenRotationAllowed;
+ }
+ }
+
/**
* When keyguard will be dismissed but didn't start animation yet.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 9722528..79d646c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -42,7 +42,10 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.shared.system.QuickStepContract;
import java.util.ArrayList;
import java.util.List;
@@ -64,7 +67,8 @@
private final Context mContext;
@Nullable private final DismissReceiver mDismissReceiver;
private final Handler mHandler = new Handler();
- @Nullable private final SystemUIDialogManager mDialogManager;
+ private final SystemUIDialogManager mDialogManager;
+ private final SysUiState mSysUiState;
private int mLastWidth = Integer.MIN_VALUE;
private int mLastHeight = Integer.MIN_VALUE;
@@ -77,24 +81,11 @@
this(context, R.style.Theme_SystemUI_Dialog);
}
- public SystemUIDialog(Context context, SystemUIDialogManager dialogManager) {
- this(context, R.style.Theme_SystemUI_Dialog, true, dialogManager);
- }
-
public SystemUIDialog(Context context, int theme) {
this(context, theme, true /* dismissOnDeviceLock */);
}
- public SystemUIDialog(Context context, int theme, SystemUIDialogManager dialogManager) {
- this(context, theme, true /* dismissOnDeviceLock */, dialogManager);
- }
-
public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock) {
- this(context, theme, dismissOnDeviceLock, null);
- }
-
- public SystemUIDialog(Context context, int theme, boolean dismissOnDeviceLock,
- @Nullable SystemUIDialogManager dialogManager) {
super(context, theme);
mContext = context;
@@ -104,7 +95,12 @@
getWindow().setAttributes(attrs);
mDismissReceiver = dismissOnDeviceLock ? new DismissReceiver(this) : null;
- mDialogManager = dialogManager;
+
+ // TODO(b/219008720): Remove those calls to Dependency.get by introducing a
+ // SystemUIDialogFactory and make all other dialogs create a SystemUIDialog to which we set
+ // the content and attach listeners.
+ mDialogManager = Dependency.get(SystemUIDialogManager.class);
+ mSysUiState = Dependency.get(SysUiState.class);
}
@Override
@@ -174,13 +170,11 @@
mDismissReceiver.register();
}
- if (mDialogManager != null) {
- mDialogManager.setShowing(this, true);
- }
-
// Listen for configuration changes to resize this dialog window. This is mostly necessary
// for foldables that often go from large <=> small screen when folding/unfolding.
ViewRootImpl.addConfigCallback(this);
+ mDialogManager.setShowing(this, true);
+ mSysUiState.setFlag(QuickStepContract.SYSUI_STATE_DIALOG_SHOWING, true);
}
@Override
@@ -191,11 +185,9 @@
mDismissReceiver.unregister();
}
- if (mDialogManager != null) {
- mDialogManager.setShowing(this, false);
- }
-
ViewRootImpl.removeConfigCallback(this);
+ mDialogManager.setShowing(this, false);
+ mSysUiState.setFlag(QuickStepContract.SYSUI_STATE_DIALOG_SHOWING, false);
}
public void setShowForAllUsers(boolean show) {
@@ -401,10 +393,13 @@
private final Dialog mDialog;
private boolean mRegistered;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final DialogLaunchAnimator mDialogLaunchAnimator;
DismissReceiver(Dialog dialog) {
mDialog = dialog;
+ // TODO(b/219008720): Remove those calls to Dependency.get.
mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
+ mDialogLaunchAnimator = Dependency.get(DialogLaunchAnimator.class);
}
void register() {
@@ -421,6 +416,10 @@
@Override
public void onReceive(Context context, Intent intent) {
+ // These broadcast are usually received when locking the device, swiping up to home
+ // (which collapses the shade), etc. In those cases, we usually don't want to animate
+ // back into the view.
+ mDialogLaunchAnimator.disableAllCurrentDialogsExitAnimations();
mDialog.dismiss();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
new file mode 100644
index 0000000..de4e1e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/touch/TouchInsetManager.java
@@ -0,0 +1,181 @@
+/*
+ * 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.systemui.touch;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.view.View;
+import android.view.ViewRootImpl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+/**
+ * {@link TouchInsetManager} handles setting the touchable inset regions for a given View. This
+ * is useful for passing through touch events for all but select areas.
+ */
+public class TouchInsetManager {
+ /**
+ * {@link TouchInsetSession} provides an individualized session with the
+ * {@link TouchInsetManager}, linking any action to the client.
+ */
+ public static class TouchInsetSession {
+ private final TouchInsetManager mManager;
+
+ private final HashSet<View> mTrackedViews;
+ private final Executor mExecutor;
+
+ private final View.OnLayoutChangeListener mOnLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
+ -> updateTouchRegion();
+
+ /**
+ * Default constructor
+ * @param manager The parent {@link TouchInsetManager} which will be affected by actions on
+ * this session.
+ * @param rootView The parent of views that will be tracked.
+ * @param executor An executor for marshalling operations.
+ */
+ TouchInsetSession(TouchInsetManager manager, Executor executor) {
+ mManager = manager;
+ mTrackedViews = new HashSet<>();
+ mExecutor = executor;
+ }
+
+ /**
+ * Adds a descendant of the root view to be tracked.
+ * @param view {@link View} to be tracked.
+ */
+ public void addViewToTracking(View view) {
+ mExecutor.execute(() -> {
+ mTrackedViews.add(view);
+ view.addOnLayoutChangeListener(mOnLayoutChangeListener);
+ updateTouchRegion();
+ });
+ }
+
+ /**
+ * Removes a view from further tracking
+ * @param view {@link View} to be removed.
+ */
+ public void removeViewFromTracking(View view) {
+ mExecutor.execute(() -> {
+ mTrackedViews.remove(view);
+ view.removeOnLayoutChangeListener(mOnLayoutChangeListener);
+ updateTouchRegion();
+ });
+ }
+
+ private void updateTouchRegion() {
+ final Region cumulativeRegion = Region.obtain();
+
+ mTrackedViews.stream().forEach(view -> {
+ final Rect boundaries = new Rect();
+ view.getBoundsOnScreen(boundaries);
+ cumulativeRegion.op(boundaries, Region.Op.UNION);
+ });
+
+ mManager.setTouchRegion(this, cumulativeRegion);
+
+ cumulativeRegion.recycle();
+ }
+
+ /**
+ * Removes all tracked views and updates insets accordingly.
+ */
+ public void clear() {
+ mExecutor.execute(() -> {
+ mManager.clearRegion(this);
+ mTrackedViews.clear();
+ });
+ }
+ }
+
+ private final HashMap<TouchInsetSession, Region> mDefinedRegions = new HashMap<>();
+ private final Executor mExecutor;
+ private final View mRootView;
+
+ private final View.OnAttachStateChangeListener mAttachListener =
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ updateTouchInset();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ }
+ };
+
+ /**
+ * Default constructor.
+ * @param executor An {@link Executor} to marshal all operations on.
+ * @param rootView The root {@link View} for all views in sessions.
+ */
+ public TouchInsetManager(Executor executor, View rootView) {
+ mExecutor = executor;
+ mRootView = rootView;
+ mRootView.addOnAttachStateChangeListener(mAttachListener);
+
+ }
+
+ /**
+ * Creates a new associated session.
+ */
+ public TouchInsetSession createSession() {
+ return new TouchInsetSession(this, mExecutor);
+ }
+
+ private void updateTouchInset() {
+ final ViewRootImpl viewRootImpl = mRootView.getViewRootImpl();
+
+ if (viewRootImpl == null) {
+ return;
+ }
+
+ final Region aggregateRegion = Region.obtain();
+
+ for (Region region : mDefinedRegions.values()) {
+ aggregateRegion.op(region, Region.Op.UNION);
+ }
+
+ viewRootImpl.setTouchableRegion(aggregateRegion);
+
+ aggregateRegion.recycle();
+ }
+
+ protected void setTouchRegion(TouchInsetSession session, Region region) {
+ final Region introducedRegion = Region.obtain(region);
+ mExecutor.execute(() -> {
+ mDefinedRegions.put(session, introducedRegion);
+ updateTouchInset();
+ });
+ }
+
+ private void clearRegion(TouchInsetSession session) {
+ mExecutor.execute(() -> {
+ final Region storedRegion = mDefinedRegions.remove(session);
+
+ if (storedRegion != null) {
+ storedRegion.recycle();
+ }
+
+ updateTouchInset();
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index 14585fb..c0d7925 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -35,9 +35,8 @@
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.TextView
-
import androidx.constraintlayout.helper.widget.Flow
-
+import com.android.internal.annotations.VisibleForTesting
import com.android.internal.util.UserIcons
import com.android.settingslib.Utils
import com.android.systemui.R
@@ -47,12 +46,12 @@
import com.android.systemui.statusbar.phone.ShadeController
import com.android.systemui.statusbar.policy.UserSwitcherController
import com.android.systemui.statusbar.policy.UserSwitcherController.BaseUserAdapter
-import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord
import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA
import com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA
+import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord
import com.android.systemui.util.LifecycleActivity
-
import javax.inject.Inject
+import kotlin.math.ceil
private const val USER_VIEW = "user_view"
@@ -137,6 +136,18 @@
return UserIcons.getDefaultUserIcon(resources, item.info.id, false)
}
+ fun getTotalUserViews(): Int {
+ return users.count { item ->
+ !doNotRenderUserView(item)
+ }
+ }
+
+ fun doNotRenderUserView(item: UserRecord): Boolean {
+ return item.isAddUser ||
+ item.isAddSupervisedUser ||
+ item.isGuest && item.info == null
+ }
+
private fun getDrawable(item: UserRecord): Drawable {
var drawable = if (item.isCurrent && item.isGuest) {
getDrawable(R.drawable.ic_avatar_guest_user)
@@ -211,7 +222,8 @@
userSwitcherController.init(parent)
initBroadcastReceiver()
- buildUserViews()
+
+ parent.post { buildUserViews() }
}
private fun showPopupMenu() {
@@ -272,16 +284,32 @@
}
parent.removeViews(start, count)
addUserRecords.clear()
-
val flow = requireViewById<Flow>(R.id.flow)
+ val totalWidth = parent.width
+ val userViewCount = adapter.getTotalUserViews()
+ val maxColumns = getMaxColumns(userViewCount)
+ val horizontalGap = resources
+ .getDimensionPixelSize(R.dimen.user_switcher_fullscreen_horizontal_gap)
+ val totalWidthOfHorizontalGap = (maxColumns - 1) * horizontalGap
+ val maxWidgetDiameter = (totalWidth - totalWidthOfHorizontalGap) / maxColumns
+
+ flow.setMaxElementsWrap(maxColumns)
+
for (i in 0 until adapter.getCount()) {
val item = adapter.getItem(i)
- if (item.isAddUser ||
- item.isAddSupervisedUser ||
- item.isGuest && item.info == null) {
+ if (adapter.doNotRenderUserView(item)) {
addUserRecords.add(item)
} else {
val userView = adapter.getView(i, null, parent)
+ userView.requireViewById<ImageView>(R.id.user_switcher_icon).apply {
+ val lp = layoutParams
+ if (maxWidgetDiameter < lp.width) {
+ lp.width = maxWidgetDiameter
+ lp.height = maxWidgetDiameter
+ layoutParams = lp
+ }
+ }
+
userView.setId(View.generateViewId())
parent.addView(userView)
@@ -333,6 +361,11 @@
broadcastDispatcher.registerReceiver(broadcastReceiver, filter)
}
+ @VisibleForTesting
+ fun getMaxColumns(userCount: Int): Int {
+ return if (userCount < 5) 4 else ceil(userCount / 2.0).toInt()
+ }
+
private class ItemAdapter(
val parentContext: Context,
val resource: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index 6fefce2..b2a79b0 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -21,7 +21,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_GLOBAL_ACTIONS_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
@@ -97,7 +97,7 @@
implements CommandQueue.Callbacks, ProtoTraceable<SystemUiTraceProto> {
private static final String TAG = WMShell.class.getName();
private static final int INVALID_SYSUI_STATE_MASK =
- SYSUI_STATE_GLOBAL_ACTIONS_SHOWING
+ SYSUI_STATE_DIALOG_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
| SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
| SYSUI_STATE_BOUNCER_SHOWING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 40632a8..7a0db1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -42,6 +42,7 @@
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.AfterClass;
@@ -112,6 +113,11 @@
// KeyguardUpdateMonitor to be created (injected).
// TODO(b/1531701009) Clean up NotificationContentView creation to prevent this
mDependency.injectMockDependency(SmartReplyController.class);
+
+ // Make sure that all tests on any SystemUIDialog does not crash because this dependency
+ // is missing (constructing the actual one would throw).
+ // TODO(b/219008720): Remove this.
+ mDependency.injectMockDependency(SystemUIDialogManager.class);
}
@After
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 1dd5e22..6e5926d 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.MockitoAnnotations;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
@LargeTest
@TestableLooper.RunWithLooper
@@ -345,15 +346,17 @@
@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 @@
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/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index 7af039b..8ce10b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.dreams;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
@@ -118,31 +117,6 @@
}
@Test
- public void testOnViewAttachedRegistersComputeInsetsListener() {
- mController.onViewAttached();
- verify(mViewTreeObserver).addOnComputeInternalInsetsListener(any());
- }
-
- @Test
- public void testOnViewDetachedUnregistersComputeInsetsListener() {
- mController.onViewDetached();
- verify(mViewTreeObserver).removeOnComputeInternalInsetsListener(any());
- }
-
- @Test
- public void testComputeInsetsListenerReturnsRegion() {
- final ArgumentCaptor<ViewTreeObserver.OnComputeInternalInsetsListener>
- computeInsetsListenerCapture =
- ArgumentCaptor.forClass(ViewTreeObserver.OnComputeInternalInsetsListener.class);
- mController.onViewAttached();
- verify(mViewTreeObserver).addOnComputeInternalInsetsListener(
- computeInsetsListenerCapture.capture());
- final ViewTreeObserver.InternalInsetsInfo info = new ViewTreeObserver.InternalInsetsInfo();
- computeInsetsListenerCapture.getValue().onComputeInternalInsets(info);
- assertNotNull(info.touchableRegion);
- }
-
- @Test
public void testBurnInProtectionStartsWhenContentViewAttached() {
mController.onViewAttached();
verify(mHandler).postDelayed(any(Runnable.class), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
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 58ffbfa..15aaf5f 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 @@
}
@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/dreams/DreamOverlayStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
index 7f72dda..ad8d44d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayStatusBarViewControllerTest.java
@@ -29,8 +29,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.battery.BatteryMeterViewController;
-import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.touch.TouchInsetManager;
import org.junit.Before;
import org.junit.Test;
@@ -46,37 +45,21 @@
@Mock
DreamOverlayStatusBarView mView;
@Mock
- BatteryController mBatteryController;
- @Mock
- BatteryMeterViewController mBatteryMeterViewController;
- @Mock
ConnectivityManager mConnectivityManager;
@Mock
NetworkCapabilities mNetworkCapabilities;
@Mock
Network mNetwork;
+ @Mock
+ TouchInsetManager.TouchInsetSession mTouchSession;
DreamOverlayStatusBarViewController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mController = new DreamOverlayStatusBarViewController(
- mContext, mView, mBatteryController, mBatteryMeterViewController,
- mConnectivityManager);
- }
-
- @Test
- public void testOnInitInitializesControllers() {
- mController.onInit();
- verify(mBatteryMeterViewController).init();
- }
-
- @Test
- public void testOnViewAttachedAddsBatteryControllerCallback() {
- mController.onViewAttached();
- verify(mBatteryController)
- .addCallback(any(BatteryController.BatteryStateChangeCallback.class));
+ mController = new DreamOverlayStatusBarViewController(mView, mConnectivityManager,
+ mTouchSession);
}
@Test
@@ -113,13 +96,6 @@
}
@Test
- public void testOnViewDetachedRemovesBatteryControllerCallback() {
- mController.onViewDetached();
- verify(mBatteryController)
- .removeCallback(any(BatteryController.BatteryStateChangeCallback.class));
- }
-
- @Test
public void testOnViewDetachedUnregistersNetworkCallback() {
mController.onViewDetached();
verify(mConnectivityManager)
@@ -127,26 +103,6 @@
}
@Test
- public void testBatteryPercentTextShownWhenBatteryLevelChangesWhileCharging() {
- final ArgumentCaptor<BatteryController.BatteryStateChangeCallback> callbackCapture =
- ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class);
- mController.onViewAttached();
- verify(mBatteryController).addCallback(callbackCapture.capture());
- callbackCapture.getValue().onBatteryLevelChanged(1, true, true);
- verify(mView).showBatteryPercentText(true);
- }
-
- @Test
- public void testBatteryPercentTextHiddenWhenBatteryLevelChangesWhileNotCharging() {
- final ArgumentCaptor<BatteryController.BatteryStateChangeCallback> callbackCapture =
- ArgumentCaptor.forClass(BatteryController.BatteryStateChangeCallback.class);
- mController.onViewAttached();
- verify(mBatteryController).addCallback(callbackCapture.capture());
- callbackCapture.getValue().onBatteryLevelChanged(1, true, false);
- verify(mView).showBatteryPercentText(false);
- }
-
- @Test
public void testWifiStatusHiddenWhenWifiBecomesAvailable() {
// Make sure wifi starts out unavailable when onViewAttached is called.
when(mNetworkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
index 64b267d..51dcf2e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
@@ -29,6 +29,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.touch.TouchInsetManager;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +47,9 @@
@Mock
ConstraintLayout mLayout;
+ @Mock
+ TouchInsetManager.TouchInsetSession mTouchSession;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -112,7 +116,8 @@
Complication.CATEGORY_STANDARD,
mLayout);
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
addComplication(engine, firstViewInfo);
// Ensure the view is added to the top end corner
@@ -139,7 +144,8 @@
Complication.CATEGORY_STANDARD,
mLayout);
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
addComplication(engine, firstViewInfo);
// Ensure the view is added to the top end corner
@@ -155,7 +161,8 @@
*/
@Test
public void testDirectionLayout() {
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -203,7 +210,8 @@
*/
@Test
public void testPositionLayout() {
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -290,7 +298,8 @@
@Test
public void testMargin() {
final int margin = 5;
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, margin);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, margin, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
@@ -364,7 +373,8 @@
*/
@Test
public void testRemoval() {
- final ComplicationLayoutEngine engine = new ComplicationLayoutEngine(mLayout, 0);
+ final ComplicationLayoutEngine engine =
+ new ComplicationLayoutEngine(mLayout, 0, mTouchSession);
final ViewInfo firstViewInfo = new ViewInfo(
new ComplicationLayoutParams(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index 71fc8ee..953be7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -19,7 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -57,13 +56,11 @@
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.settings.UserContextProvider;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -112,7 +109,6 @@
@Mock private UiEventLogger mUiEventLogger;
@Mock private RingerModeTracker mRingerModeTracker;
@Mock private RingerModeLiveData mRingerModeLiveData;
- @Mock private SysUiState mSysUiState;
@Mock private PackageManager mPackageManager;
@Mock private Handler mHandler;
@Mock private UserContextProvider mUserContextProvider;
@@ -120,7 +116,6 @@
@Mock private StatusBar mStatusBar;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock private DialogLaunchAnimator mDialogLaunchAnimator;
- @Mock private SystemUIDialogManager mDialogManager;
private TestableLooper mTestableLooper;
@@ -161,19 +156,16 @@
mBackgroundExecutor,
mUiEventLogger,
mRingerModeTracker,
- mSysUiState,
mHandler,
mPackageManager,
Optional.of(mStatusBar),
mKeyguardUpdateMonitor,
- mDialogLaunchAnimator,
- mDialogManager);
+ mDialogLaunchAnimator);
mGlobalActionsDialogLite.setZeroDialogPressDelayForTesting();
ColorExtractor.GradientColors backdropColors = new ColorExtractor.GradientColors();
backdropColors.setMainColor(Color.BLACK);
when(mColorExtractor.getNeutralColors()).thenReturn(backdropColors);
- when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index e606be1..b359ae5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -33,10 +33,11 @@
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
import com.android.systemui.statusbar.phone.KeyguardBypassController
-import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.UniqueObjectHostView
-import junit.framework.Assert
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertNotNull
import org.junit.Before
import org.junit.Rule
@@ -44,16 +45,16 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
-import org.mockito.Mockito.any
-import org.mockito.Mockito.anyBoolean
-import org.mockito.Mockito.anyLong
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -83,8 +84,6 @@
@Mock
private lateinit var keyguardViewController: KeyguardViewController
@Mock
- private lateinit var configurationController: ConfigurationController
- @Mock
private lateinit var uniqueObjectHostView: UniqueObjectHostView
@Mock
private lateinit var dreamOverlayStateController: DreamOverlayStateController
@@ -97,6 +96,7 @@
val mockito = MockitoJUnit.rule()
private lateinit var mediaHiearchyManager: MediaHierarchyManager
private lateinit var mediaFrame: ViewGroup
+ private val configurationController = FakeConfigurationController()
@Before
fun setup() {
@@ -176,12 +176,7 @@
@Test
fun testGoingToFullShade() {
- // Let's set it onto Lock screen
- `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
- true)
- statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
- clearInvocations(mediaCarouselController)
+ goToLockscreen()
// Let's transition all the way to full shade
mediaHiearchyManager.setTransitionToFullShadeAmount(100000f)
@@ -204,41 +199,48 @@
// Let's make sure alpha is set
mediaHiearchyManager.setTransitionToFullShadeAmount(2.0f)
- Assert.assertTrue("alpha should not be 1.0f when cross fading", mediaFrame.alpha != 1.0f)
+ assertThat(mediaFrame.alpha).isNotEqualTo(1.0f)
}
@Test
fun testTransformationOnLockScreenIsFading() {
- // Let's set it onto Lock screen
- `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
- true)
- statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
- clearInvocations(mediaCarouselController)
+ goToLockscreen()
+ expandQS()
- // Let's transition from lockscreen to qs
- mediaHiearchyManager.qsExpansion = 1.0f
val transformType = mediaHiearchyManager.calculateTransformationType()
- Assert.assertTrue("media isn't transforming to qs with a fade",
- transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ }
+
+ @Test
+ fun calculateTransformationType_onLockShade_inSplitShade_goingToFullShade_returnsTransition() {
+ enableSplitShade()
+ goToLockscreen()
+ expandQS()
+ mediaHiearchyManager.setTransitionToFullShadeAmount(10000f)
+
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION)
+ }
+
+ @Test
+ fun calculateTransformationType_onLockShade_inSplitShade_notExpanding_returnsFade() {
+ enableSplitShade()
+ goToLockscreen()
+ goToLockedShade()
+ expandQS()
+ mediaHiearchyManager.setTransitionToFullShadeAmount(0f)
+
+ val transformType = mediaHiearchyManager.calculateTransformationType()
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@Test
fun testTransformationOnLockScreenToQQSisFading() {
- // Let's set it onto Lock screen
- `when`(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
- `when`(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
- true)
- statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
- clearInvocations(mediaCarouselController)
+ goToLockscreen()
+ goToLockedShade()
- // Let's transition from lockscreen to qs
- `when`(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
- statusBarCallback.value.onStatePreChange(StatusBarState.KEYGUARD,
- StatusBarState.SHADE_LOCKED)
val transformType = mediaHiearchyManager.calculateTransformationType()
- Assert.assertTrue("media isn't transforming to qqswith a fade",
- transformType == MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
+ assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
}
@Test
@@ -254,4 +256,32 @@
verify(mediaCarouselController).closeGuts()
}
-}
\ No newline at end of file
+
+ private fun enableSplitShade() {
+ context.getOrCreateTestableResources().addOverride(
+ R.bool.config_use_split_notification_shade, true
+ )
+ configurationController.notifyConfigurationChanged()
+ }
+
+ private fun goToLockscreen() {
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+ whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(
+ true
+ )
+ statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+ clearInvocations(mediaCarouselController)
+ }
+
+ private fun goToLockedShade() {
+ whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
+ statusBarCallback.value.onStatePreChange(
+ StatusBarState.KEYGUARD,
+ StatusBarState.SHADE_LOCKED
+ )
+ }
+
+ private fun expandQS() {
+ mediaHiearchyManager.qsExpansion = 1.0f
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index c5c4d79..2be30b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -45,7 +45,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.Before;
import org.junit.Test;
@@ -68,7 +67,6 @@
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputBaseDialogImpl mMediaOutputBaseDialogImpl;
private MediaOutputController mMediaOutputController;
@@ -82,7 +80,7 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputBaseDialogImpl = new MediaOutputBaseDialogImpl(mContext,
mMediaOutputController);
mMediaOutputBaseDialogImpl.onCreate(new Bundle());
@@ -175,7 +173,7 @@
class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
- super(context, mediaOutputController, mDialogManager);
+ super(context, mediaOutputController);
mAdapter = mMediaOutputBaseAdapter;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
index bdc3117..789822e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputControllerTest.java
@@ -55,7 +55,6 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.Before;
import org.junit.Test;
@@ -94,7 +93,6 @@
private CommonNotifCollection mNotifCollection = mock(CommonNotifCollection.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
@@ -117,7 +115,7 @@
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
@@ -161,7 +159,7 @@
public void start_withoutPackageName_verifyMediaControllerInit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.start(mCb);
@@ -182,7 +180,7 @@
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.start(mCb);
@@ -453,7 +451,7 @@
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotifCollection, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotifCollection, mUiEventLogger, mDialogLaunchAnimator);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index ada8d35..8a3ea56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -40,7 +40,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.Before;
@@ -68,7 +67,6 @@
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputDialog mMediaOutputDialog;
private MediaOutputController mMediaOutputController;
@@ -78,10 +76,10 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputDialog = new MediaOutputDialog(mContext, false,
- mMediaOutputController, mUiEventLogger, mDialogManager);
+ mMediaOutputController, mUiEventLogger);
mMediaOutputDialog.show();
when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
@@ -127,7 +125,7 @@
// and verify if the calling times increases.
public void onCreate_ShouldLogVisibility() {
MediaOutputDialog testDialog = new MediaOutputDialog(mContext, false,
- mMediaOutputController, mUiEventLogger, mDialogManager);
+ mMediaOutputController, mUiEventLogger);
testDialog.show();
testDialog.dismissDialog();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
index b114452..e8cd6c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputGroupDialogTest.java
@@ -38,7 +38,6 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.SystemUIDialogManager;
import org.junit.After;
import org.junit.Before;
@@ -67,7 +66,6 @@
mock(NotificationEntryManager.class);
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private final DialogLaunchAnimator mDialogLaunchAnimator = mock(DialogLaunchAnimator.class);
- private final SystemUIDialogManager mDialogManager = mock(SystemUIDialogManager.class);
private MediaOutputGroupDialog mMediaOutputGroupDialog;
private MediaOutputController mMediaOutputController;
@@ -77,10 +75,10 @@
public void setUp() {
mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
- mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator, mDialogManager);
+ mNotificationEntryManager, mUiEventLogger, mDialogLaunchAnimator);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
mMediaOutputGroupDialog = new MediaOutputGroupDialog(mContext, false,
- mMediaOutputController, mDialogManager);
+ mMediaOutputController);
mMediaOutputGroupDialog.show();
when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mMediaDevices);
}
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 8ce50a6..f736f26 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 @@
@After
fun tearDown() {
- ViewUtils.detachView(view)
+ if (view.isAttachedToWindow) {
+ ViewUtils.detachView(view)
+ }
}
@Test
@@ -139,8 +141,7 @@
@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 @@
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/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 9076e16..75ccd8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -23,7 +23,7 @@
import com.android.systemui.statusbar.phone.NotificationPanelViewController
import com.android.systemui.statusbar.phone.ScrimController
import com.android.systemui.statusbar.phone.StatusBar
-import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.FakeConfigurationController
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotNull
@@ -66,7 +66,6 @@
@Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle
@Mock lateinit var mediaHierarchyManager: MediaHierarchyManager
@Mock lateinit var scrimController: ScrimController
- @Mock lateinit var configurationController: ConfigurationController
@Mock lateinit var falsingManager: FalsingManager
@Mock lateinit var notificationPanelController: NotificationPanelViewController
@Mock lateinit var nsslController: NotificationStackScrollLayoutController
@@ -77,6 +76,8 @@
@Mock lateinit var qS: QS
@JvmField @Rule val mockito = MockitoJUnit.rule()
+ private val configurationController = FakeConfigurationController()
+
@Before
fun setup() {
val helper = NotificationTestHelper(
@@ -244,4 +245,27 @@
verify(qS).setTransitionToFullShadeAmount(anyFloat(), anyFloat())
verify(depthController).transitionToFullShadeProgress = anyFloat()
}
+
+ @Test
+ fun setDragDownAmount_setsValueOnMediaHierarchyManager() {
+ transitionController.dragDownAmount = 10f
+
+ verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f)
+ }
+
+ @Test
+ fun setDragDownAmount_inSplitShade_setsValueOnMediaHierarchyManager() {
+ enableSplitShade()
+
+ transitionController.dragDownAmount = 10f
+
+ verify(mediaHierarchyManager).setTransitionToFullShadeAmount(10f)
+ }
+
+ private fun enableSplitShade() {
+ context.getOrCreateTestableResources().addOverride(
+ R.bool.config_use_split_notification_shade, true
+ )
+ configurationController.notifyConfigurationChanged()
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
index 671ab59..c797bc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowControllerImplTest.java
@@ -32,6 +32,8 @@
import static org.mockito.Mockito.when;
import android.app.IActivityManager;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
@@ -228,6 +230,36 @@
}
@Test
+ public void rotationBecameAllowed_layoutParamsUpdated() {
+ mNotificationShadeWindowController.setKeyguardShowing(true);
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+ clearInvocations(mWindowManager);
+
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat(mLayoutParameters.getValue().screenOrientation)
+ .isEqualTo(ActivityInfo.SCREEN_ORIENTATION_USER);
+ }
+
+ @Test
+ public void rotationBecameNotAllowed_layoutParamsUpdated() {
+ mNotificationShadeWindowController.setKeyguardShowing(true);
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(true);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+ clearInvocations(mWindowManager);
+
+ when(mKeyguardStateController.isKeyguardScreenRotationAllowed()).thenReturn(false);
+ mNotificationShadeWindowController.onConfigChanged(new Configuration());
+
+ verify(mWindowManager).updateViewLayout(any(), mLayoutParameters.capture());
+ assertThat(mLayoutParameters.getValue().screenOrientation)
+ .isEqualTo(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+ }
+
+ @Test
public void batchApplyWindowLayoutParams_doesNotDispatchEvents() {
mNotificationShadeWindowController.setForceDozeBrightness(true);
verify(mWindowManager).updateViewLayout(any(), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
new file mode 100644
index 0000000..3a5d9ee
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
@@ -0,0 +1,31 @@
+package com.android.systemui.statusbar.policy
+
+import android.content.res.Configuration
+
+/** Fake implementation of [ConfigurationController] for tests. */
+class FakeConfigurationController : ConfigurationController {
+
+ private var listener: ConfigurationController.ConfigurationListener? = null
+
+ override fun addCallback(listener: ConfigurationController.ConfigurationListener) {
+ this.listener = listener
+ }
+
+ override fun removeCallback(listener: ConfigurationController.ConfigurationListener) {
+ this.listener = null
+ }
+
+ override fun onConfigurationChanged(newConfiguration: Configuration?) {
+ listener?.onConfigChanged(newConfiguration)
+ }
+
+ override fun notifyThemeChanged() {
+ listener?.onThemeChanged()
+ }
+
+ fun notifyConfigurationChanged() {
+ onConfigurationChanged(newConfiguration = null)
+ }
+
+ override fun isLayoutRtl(): Boolean = false
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java
new file mode 100644
index 0000000..14b9bfb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/touch/TouchInsetManagerTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.systemui.touch;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.view.ViewRootImpl;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class TouchInsetManagerTest extends SysuiTestCase {
+ @Mock
+ private View mRootView;
+
+ @Mock
+ private ViewRootImpl mRootViewImpl;
+
+ private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mRootView.getViewRootImpl()).thenReturn(mRootViewImpl);
+ }
+
+ @Test
+ public void testRootViewOnAttachedHandling() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ final ArgumentCaptor<View.OnAttachStateChangeListener> listener =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+ // Ensure manager has registered to listen to attached state of root view.
+ verify(mRootView).addOnAttachStateChangeListener(listener.capture());
+
+ // Trigger attachment and verify touchable region is set.
+ listener.getValue().onViewAttachedToWindow(mRootView);
+ verify(mRootViewImpl).setTouchableRegion(any());
+ }
+
+ @Test
+ public void testInsetRegionPropagation() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ // Create session
+ final TouchInsetManager.TouchInsetSession session = insetManager.createSession();
+
+ // Add a view to the session.
+ final Rect rect = new Rect(0, 0, 2, 2);
+
+ session.addViewToTracking(createView(rect));
+ mFakeExecutor.runAllReady();
+
+ // Check to see if view was properly accounted for.
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(rect, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+
+ @Test
+ public void testMultipleRegions() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ // Create session
+ final TouchInsetManager.TouchInsetSession session = insetManager.createSession();
+
+ // Add a view to the session.
+ final Rect firstBounds = new Rect(0, 0, 2, 2);
+ session.addViewToTracking(createView(firstBounds));
+
+ mFakeExecutor.runAllReady();
+ clearInvocations(mRootViewImpl);
+
+ // Create second session
+ final TouchInsetManager.TouchInsetSession secondSession = insetManager.createSession();
+
+ // Add a view to the second session.
+ final Rect secondBounds = new Rect(4, 4, 8, 10);
+ secondSession.addViewToTracking(createView(secondBounds));
+
+ mFakeExecutor.runAllReady();
+
+ // Check to see if all views and sessions was properly accounted for.
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstBounds, Region.Op.UNION);
+ expectedRegion.op(secondBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+
+
+ clearInvocations(mRootViewImpl);
+
+ // clear first session, ensure second session is still reflected.
+ session.clear();
+ mFakeExecutor.runAllReady();
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+ }
+
+ @Test
+ public void testMultipleViews() {
+ // Create inset manager
+ final TouchInsetManager insetManager = new TouchInsetManager(mFakeExecutor,
+ mRootView);
+
+ // Create session
+ final TouchInsetManager.TouchInsetSession session = insetManager.createSession();
+
+ // Add a view to the session.
+ final Rect firstViewBounds = new Rect(0, 0, 2, 2);
+ session.addViewToTracking(createView(firstViewBounds));
+
+ // only capture second invocation.
+ mFakeExecutor.runAllReady();
+ clearInvocations(mRootViewImpl);
+
+ // Add a second view to the session
+ final Rect secondViewBounds = new Rect(4, 4, 9, 10);
+ final View secondView = createView(secondViewBounds);
+ session.addViewToTracking(secondView);
+
+ mFakeExecutor.runAllReady();
+
+ // Check to see if all views and sessions was properly accounted for.
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstViewBounds, Region.Op.UNION);
+ expectedRegion.op(secondViewBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+
+ // Remove second view.
+ session.removeViewFromTracking(secondView);
+
+ clearInvocations(mRootViewImpl);
+ mFakeExecutor.runAllReady();
+
+ // Ensure first view still reflected in touch region.
+ {
+ final Region expectedRegion = Region.obtain();
+ expectedRegion.op(firstViewBounds, Region.Op.UNION);
+ verify(mRootViewImpl).setTouchableRegion(eq(expectedRegion));
+ }
+ }
+
+ private View createView(Rect bounds) {
+ final Rect rect = new Rect(bounds);
+ final View view = Mockito.mock(View.class);
+ doAnswer(invocation -> {
+ ((Rect) invocation.getArgument(0)).set(rect);
+ return null;
+ }).when(view).getBoundsOnScreen(any());
+
+ return view;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
new file mode 100644
index 0000000..d4be881
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.systemui.user
+
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.LayoutInflater
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.ShadeController
+import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
+class UserSwitcherActivityTest : SysuiTestCase() {
+ @Mock
+ private lateinit var activity: UserSwitcherActivity
+ @Mock
+ private lateinit var userSwitcherController: UserSwitcherController
+ @Mock
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock
+ private lateinit var layoutInflater: LayoutInflater
+ @Mock
+ private lateinit var falsingManager: FalsingManager
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock
+ private lateinit var shadeController: ShadeController
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ activity = UserSwitcherActivity(
+ userSwitcherController,
+ broadcastDispatcher,
+ layoutInflater,
+ falsingManager,
+ userManager,
+ shadeController
+ )
+ }
+
+ @Test
+ fun testMaxColumns() {
+ assertThat(activity.getMaxColumns(3)).isEqualTo(4)
+ assertThat(activity.getMaxColumns(4)).isEqualTo(4)
+ assertThat(activity.getMaxColumns(5)).isEqualTo(3)
+ assertThat(activity.getMaxColumns(6)).isEqualTo(3)
+ assertThat(activity.getMaxColumns(7)).isEqualTo(4)
+ assertThat(activity.getMaxColumns(9)).isEqualTo(5)
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6813f3f8..bdb3e80 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -694,12 +694,6 @@
return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}
- /**
- * The package name of the DeviceOwner. This package is not permitted to have its data cleared.
- * <p>Not actually used</p>
- */
- private volatile String mDeviceOwnerName;
-
private volatile int mDeviceOwnerUid = INVALID_UID;
/**
@@ -6238,17 +6232,6 @@
}
@Override
- public void updateDeviceOwner(String packageName) {
- final int callingUid = Binder.getCallingUid();
- if (callingUid != 0 && callingUid != SYSTEM_UID) {
- throw new SecurityException("updateDeviceOwner called from non-system process");
- }
- synchronized (this) {
- mDeviceOwnerName = packageName;
- }
- }
-
- @Override
public void updateLockTaskPackages(int userId, String[] packages) {
mActivityTaskManager.updateLockTaskPackages(userId, packages);
}
@@ -15623,24 +15606,20 @@
}
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 +15627,7 @@
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 b813bc4..0edbea0 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.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 @@
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 @@
// 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 @@
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 3491cd5..49a935e 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 @@
}
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 76754d3..4a1a950 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 @@
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 @@
}
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 @@
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 @@
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 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 @@
mCurrentDream.mService = service;
- if (!mCurrentDream.mIsTest) {
+ if (!mCurrentDream.mIsPreviewMode) {
mContext.sendBroadcastAsUser(mDreamingStartedIntent, UserHandle.ALL);
mCurrentDream.mSentStartBroadcast = true;
}
@@ -263,7 +265,7 @@
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 @@
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 f0a6af3..22d32a6 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 @@
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 @@
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 @@
private boolean isDreamingInternal() {
synchronized (mLock) {
- return mCurrentDreamToken != null && !mCurrentDreamIsTest
+ return mCurrentDreamToken != null && !mCurrentDreamIsPreview
&& !mCurrentDreamIsWaking;
}
}
@@ -235,7 +235,7 @@
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 @@
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 @@
}
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 @@
final Binder newToken = new Binder();
mCurrentDreamToken = newToken;
mCurrentDreamName = name;
- mCurrentDreamIsTest = isTest;
+ mCurrentDreamIsPreview = isPreviewMode;
mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
@@ -424,7 +424,7 @@
.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 @@
}
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 0000000..83ca16d
--- /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/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index b2f500a..d2d80ff 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -408,6 +408,11 @@
@GuardedBy("ImfLock.class")
@NonNull
InputBindResult bindCurrentMethod() {
+ if (mSelectedMethodId == null) {
+ Slog.e(TAG, "mSelectedMethodId is null!");
+ return InputBindResult.NO_IME;
+ }
+
InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
if (info == null) {
throw new IllegalArgumentException("Unknown id: " + mSelectedMethodId);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 0b7e391..eb1de2a 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.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 @@
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 @@
*/
boolean mIsInteractive = true;
- private final IPlatformCompat mPlatformCompat;
-
int mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
/**
@@ -1627,6 +1624,7 @@
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 @@
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 @@
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 @@
// 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 01aee7b..db81393 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.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.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 @@
// 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 @@
return mUserMonitor;
}
- @VisibleForTesting
- PackageMonitor getPackageMonitor() {
- return mPackageMonitor;
- }
-
/**
* @see LocaleManagerInternal#getBackupPayload(int userId)
*/
@@ -267,6 +252,53 @@
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 @@
}
/**
- * 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 d459f8d..c427705 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.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.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 @@
private LocaleManagerBackupHelper mBackupHelper;
+ private final PackageMonitor mPackageMonitor;
+
public static final boolean DEBUG = false;
public LocaleManagerService(Context context) {
@@ -71,15 +73,26 @@
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 @@
mActivityManagerInternal = activityManagerInternal;
mPackageManagerInternal = packageManagerInternal;
mBackupHelper = localeManagerBackupHelper;
+ mPackageMonitor = packageMonitor;
}
@Override
@@ -130,11 +144,6 @@
}
@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 @@
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 0000000..b459be7
--- /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/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index 8fdde24..e9bf90f 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -16,8 +16,6 @@
package com.android.server.location.contexthub;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import android.Manifest;
import android.content.Context;
import android.hardware.contexthub.V1_0.AsyncEventType;
@@ -297,19 +295,14 @@
}
/**
- * Checks for location hardware permissions.
+ * Checks for ACCESS_CONTEXT_HUB permissions.
*
* @param context the context of the service
*/
/* package */
static void checkPermissions(Context context) {
- boolean hasAccessContextHubPermission = (context.checkCallingPermission(
- CONTEXT_HUB_PERMISSION) == PERMISSION_GRANTED);
-
- if (!hasAccessContextHubPermission) {
- throw new SecurityException(
- "ACCESS_CONTEXT_HUB permission required to use Context Hub");
- }
+ context.enforceCallingOrSelfPermission(CONTEXT_HUB_PERMISSION,
+ "ACCESS_CONTEXT_HUB permission required to use Context Hub");
}
/**
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 d42e2c6..0b8f94c 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 @Nullable Location getLastLocation(LastLocationRequest request,
CallerIdentity identity, @PermissionLevel int permissionLevel) {
+ request = calculateLastLocationRequest(request);
+
if (!isActive(request.isBypass(), identity)) {
return null;
}
@@ -1634,6 +1636,38 @@
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/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 96391ac..074d891 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -647,18 +647,17 @@
if (mDestroyed) {
return;
}
- toSend = new ArrayList<>();
- if (mQueue != null) {
- toSend.ensureCapacity(mQueue.size());
- toSend.addAll(mQueue);
- }
+ toSend = mQueue == null ? null : new ArrayList<>(mQueue);
}
Collection<ISessionControllerCallbackHolder> deadCallbackHolders = null;
for (ISessionControllerCallbackHolder holder : mControllerCallbackHolders) {
- ParceledListSlice<QueueItem> parcelableQueue = new ParceledListSlice<>(toSend);
- // Limit the size of initial Parcel to prevent binder buffer overflow
- // as onQueueChanged is an async binder call.
- parcelableQueue.setInlineCountLimit(1);
+ ParceledListSlice<QueueItem> parcelableQueue = null;
+ if (toSend != null) {
+ parcelableQueue = new ParceledListSlice<>(toSend);
+ // Limit the size of initial Parcel to prevent binder buffer overflow
+ // as onQueueChanged is an async binder call.
+ parcelableQueue.setInlineCountLimit(1);
+ }
try {
holder.mCallback.onQueueChanged(parcelableQueue);
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index c09c904..db0b0c58 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.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 @@
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 @@
}
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 cdc2b12..f6f9faf 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 @@
/** @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 177eaca..6767027 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 @@
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 @@
}
@Override
+ public boolean isLeavingSharedUid() {
+ return getBoolean(Booleans.LEAVING_SHARED_UID);
+ }
+
+ @Override
public ParsingPackageImpl setBaseRevisionCode(int value) {
baseRevisionCode = value;
return this;
@@ -2551,6 +2557,11 @@
}
@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 428374f..50033f6 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 @@
* @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 f30daa9..ed1ab01 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 @@
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 @@
}
}
+ 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/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b0efa5b..d772586 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -148,6 +148,7 @@
import static com.android.server.wm.ActivityRecordProto.APP_STOPPED;
import static com.android.server.wm.ActivityRecordProto.CLIENT_VISIBLE;
import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT;
+import static com.android.server.wm.ActivityRecordProto.ENABLE_RECENTS_SCREENSHOT;
import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT;
import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK;
import static com.android.server.wm.ActivityRecordProto.IN_SIZE_COMPAT_MODE;
@@ -771,7 +772,7 @@
// Last visibility state we reported to the app token.
boolean reportedVisible;
- boolean mEnablePreviewScreenshots = true;
+ boolean mEnableRecentsScreenshot = true;
// Information about an application starting window if displayed.
// Note: these are de-referenced before the starting window animates away.
@@ -5151,7 +5152,7 @@
* See {@link Activity#setRecentsScreenshotEnabled}.
*/
void setRecentsScreenshotEnabled(boolean enabled) {
- mEnablePreviewScreenshots = enabled;
+ mEnableRecentsScreenshot = enabled;
}
/**
@@ -5163,7 +5164,7 @@
* screenshot.
*/
boolean shouldUseAppThemeSnapshot() {
- return !mEnablePreviewScreenshots || forAllWindows(WindowState::isSecureLocked,
+ return !mEnableRecentsScreenshot || forAllWindows(WindowState::isSecureLocked,
true /* topToBottom */);
}
@@ -9184,6 +9185,7 @@
// Only record if max bounds sandboxing is applied, if the caller has the necessary
// permission to access the device configs.
proto.write(PROVIDES_MAX_BOUNDS, providesMaxBounds());
+ proto.write(ENABLE_RECENTS_SCREENSHOT, mEnableRecentsScreenshot);
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4c5c705..fd24565 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 @@
* 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 ffa1a60..98c74f8 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 @@
// 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 0b965c3..3a3103e 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 @@
// 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 c267cba..c13ae95 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.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 @@
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/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 24493e2..14737d4 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -196,8 +196,11 @@
"Win " + w + ": token animating, looking behind.");
}
mFindResults.setIsWallpaperTargetForLetterbox(w.hasWallpaperForLetterboxBackground());
- // Found a target! End search.
- return true;
+ // While the keyguard is going away, both notification shade and a normal activity such
+ // as a launcher can satisfy criteria for a wallpaper target. In this case, we should
+ // chose the normal activity, otherwise wallpaper becomes invisible when a new animation
+ // starts before the keyguard going away animation finishes.
+ return w.mActivityRecord != null;
}
return false;
};
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5b1021e..709f885 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.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.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 @@
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 @@
@Override
public void onKeyguardShowingAndNotOccludedChanged() {
mH.sendEmptyMessage(H.RECOMPUTE_FOCUS);
+ dispatchKeyguardLockedStateState();
}
@Override
@@ -3218,6 +3225,50 @@
}
}
+ @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 ccaa03a..a2e8813 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 @@
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/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index a9c6b8d..11714dc 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -50,6 +50,7 @@
#include "android_runtime/Log.h"
#include "gnss/AGnss.h"
#include "gnss/AGnssRil.h"
+#include "gnss/Gnss.h"
#include "gnss/GnssAntennaInfo.h"
#include "gnss/GnssAntennaInfoCallback.h"
#include "gnss/GnssBatching.h"
@@ -68,18 +69,7 @@
static jclass class_gnssPowerStats;
-static jmethodID method_reportLocation;
-static jmethodID method_reportStatus;
-static jmethodID method_reportSvStatus;
-static jmethodID method_reportNmea;
-static jmethodID method_setTopHalCapabilities;
-static jmethodID method_setGnssYearOfHardware;
-static jmethodID method_setGnssHardwareModelName;
-static jmethodID method_psdsDownloadRequest;
static jmethodID method_reportNiNotification;
-static jmethodID method_requestLocation;
-static jmethodID method_requestUtcTime;
-static jmethodID method_reportGnssServiceDied;
static jmethodID method_reportGnssPowerStats;
static jmethodID method_reportNfwNotification;
static jmethodID method_isInEmergencySession;
@@ -92,7 +82,6 @@
using android::String16;
using android::wp;
using android::binder::Status;
-using android::gnss::GnssConfigurationInterface;
using android::hardware::Return;
using android::hardware::Void;
@@ -128,12 +117,8 @@
using android::hardware::gnss::GnssPowerStats;
using android::hardware::gnss::IGnssPowerIndication;
using android::hardware::gnss::IGnssPowerIndicationCallback;
-using android::hardware::gnss::PsdsType;
-using IAGnssAidl = android::hardware::gnss::IAGnss;
-using IAGnssRilAidl = android::hardware::gnss::IAGnssRil;
using IGnssAidl = android::hardware::gnss::IGnss;
-using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
using IGnssBatchingAidl = android::hardware::gnss::IGnssBatching;
using IGnssDebugAidl = android::hardware::gnss::IGnssDebug;
using IGnssPsdsAidl = android::hardware::gnss::IGnssPsds;
@@ -142,575 +127,30 @@
using GnssLocationAidl = android::hardware::gnss::GnssLocation;
using IGnssAntennaInfoAidl = android::hardware::gnss::IGnssAntennaInfo;
-struct GnssDeathRecipient : virtual public hidl_death_recipient
-{
- // hidl_death_recipient interface
- virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override {
- ALOGE("IGNSS hidl service failed, trying to recover...");
-
- JNIEnv* env = android::AndroidRuntime::getJNIEnv();
- env->CallVoidMethod(android::mCallbacksObj, method_reportGnssServiceDied);
- }
-};
-
-// Must match the value from GnssMeasurement.java
-static const uint32_t SVID_FLAGS_HAS_BASEBAND_CN0 = (1<<4);
-
-sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
-sp<IGnss_V1_0> gnssHal = nullptr;
-sp<IGnss_V1_1> gnssHal_V1_1 = nullptr;
-sp<IGnss_V2_0> gnssHal_V2_0 = nullptr;
-sp<IGnss_V2_1> gnssHal_V2_1 = nullptr;
-sp<IGnssAidl> gnssHalAidl = nullptr;
-sp<IGnssBatchingAidl> gnssBatchingAidlIface = nullptr;
-sp<IGnssPsdsAidl> gnssPsdsAidlIface = nullptr;
-sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IGnssNi> gnssNiIface = nullptr;
sp<IGnssPowerIndication> gnssPowerIndicationIface = nullptr;
-std::unique_ptr<GnssConfigurationInterface> gnssConfigurationIface = nullptr;
+std::unique_ptr<android::gnss::GnssHal> gnssHal = nullptr;
+std::unique_ptr<android::gnss::AGnssInterface> agnssIface = nullptr;
+std::unique_ptr<android::gnss::AGnssRilInterface> agnssRilIface = nullptr;
+std::unique_ptr<android::gnss::GnssAntennaInfoInterface> gnssAntennaInfoIface = nullptr;
+std::unique_ptr<android::gnss::GnssConfigurationInterface> gnssConfigurationIface = nullptr;
std::unique_ptr<android::gnss::GnssMeasurementInterface> gnssMeasurementIface = nullptr;
std::unique_ptr<android::gnss::GnssNavigationMessageInterface> gnssNavigationMessageIface = nullptr;
std::unique_ptr<android::gnss::GnssBatchingInterface> gnssBatchingIface = nullptr;
-std::unique_ptr<android::gnss::GnssGeofenceInterface> gnssGeofencingIface = nullptr;
-std::unique_ptr<android::gnss::AGnssInterface> agnssIface = nullptr;
std::unique_ptr<android::gnss::GnssDebugInterface> gnssDebugIface = nullptr;
-std::unique_ptr<android::gnss::AGnssRilInterface> agnssRilIface = nullptr;
+std::unique_ptr<android::gnss::GnssGeofenceInterface> gnssGeofencingIface = nullptr;
+std::unique_ptr<android::gnss::GnssPsdsInterface> gnssPsdsIface = nullptr;
std::unique_ptr<android::gnss::GnssVisibilityControlInterface> gnssVisibilityControlIface = nullptr;
-std::unique_ptr<android::gnss::GnssAntennaInfoInterface> gnssAntennaInfoIface = nullptr;
std::unique_ptr<android::gnss::MeasurementCorrectionsInterface> gnssMeasurementCorrectionsIface =
nullptr;
-#define WAKE_LOCK_NAME "GPS"
-
namespace android {
namespace {
-// Returns true if location has lat/long information.
-bool hasLatLong(const GnssLocationAidl& location) {
- return (location.gnssLocationFlags & GnssLocationAidl::HAS_LAT_LONG) != 0;
-}
-
-// Returns true if location has lat/long information.
-bool hasLatLong(const GnssLocation_V1_0& location) {
- return (static_cast<uint32_t>(location.gnssLocationFlags) &
- GnssLocationFlags::HAS_LAT_LONG) != 0;
-}
-
-// Returns true if location has lat/long information.
-bool hasLatLong(const GnssLocation_V2_0& location) {
- return hasLatLong(location.v1_0);
-}
-
-bool isSvStatusRegistered = false;
-bool isNmeaRegistered = false;
-
} // namespace
-static inline jboolean boolToJbool(bool value) {
- return value ? JNI_TRUE : JNI_FALSE;
-}
-
-static GnssLocationAidl createGnssLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
- jdouble longitudeDegrees, jdouble altitudeMeters,
- jfloat speedMetersPerSec, jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters,
- jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond,
- jfloat bearingAccuracyDegrees, jlong timestamp,
- jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
- jdouble elapsedRealtimeUncertaintyNanos) {
- GnssLocationAidl location;
- location.gnssLocationFlags = static_cast<int>(gnssLocationFlags);
- location.latitudeDegrees = static_cast<double>(latitudeDegrees);
- location.longitudeDegrees = static_cast<double>(longitudeDegrees);
- location.altitudeMeters = static_cast<double>(altitudeMeters);
- location.speedMetersPerSec = static_cast<double>(speedMetersPerSec);
- location.bearingDegrees = static_cast<double>(bearingDegrees);
- location.horizontalAccuracyMeters = static_cast<double>(horizontalAccuracyMeters);
- location.verticalAccuracyMeters = static_cast<double>(verticalAccuracyMeters);
- location.speedAccuracyMetersPerSecond = static_cast<double>(speedAccuracyMetersPerSecond);
- location.bearingAccuracyDegrees = static_cast<double>(bearingAccuracyDegrees);
- location.timestampMillis = static_cast<uint64_t>(timestamp);
-
- location.elapsedRealtime.flags = static_cast<int>(elapsedRealtimeFlags);
- location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
- location.elapsedRealtime.timeUncertaintyNs =
- static_cast<double>(elapsedRealtimeUncertaintyNanos);
-
- return location;
-}
-
-static GnssLocation_V1_0 createGnssLocation_V1_0(
- jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
- jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
- jlong timestamp) {
- GnssLocation_V1_0 location;
- location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags);
- location.latitudeDegrees = static_cast<double>(latitudeDegrees);
- location.longitudeDegrees = static_cast<double>(longitudeDegrees);
- location.altitudeMeters = static_cast<double>(altitudeMeters);
- location.speedMetersPerSec = static_cast<float>(speedMetersPerSec);
- location.bearingDegrees = static_cast<float>(bearingDegrees);
- location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters);
- location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters);
- location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond);
- location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees);
- location.timestamp = static_cast<uint64_t>(timestamp);
-
- return location;
-}
-
-static GnssLocation_V2_0 createGnssLocation_V2_0(
- jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
- jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
- jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
- jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
- jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
- jdouble elapsedRealtimeUncertaintyNanos) {
- GnssLocation_V2_0 location;
- location.v1_0 = createGnssLocation_V1_0(
- gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters,
- speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
- verticalAccuracyMeters, speedAccuracyMetersPerSecond,
- bearingAccuracyDegrees, timestamp);
-
- location.elapsedRealtime.flags = static_cast<uint16_t>(elapsedRealtimeFlags);
- location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
- location.elapsedRealtime.timeUncertaintyNs = static_cast<uint64_t>(elapsedRealtimeUncertaintyNanos);
-
- return location;
-}
-
-/*
- * GnssCallback class implements the callback methods for IGnss interface.
- */
-struct GnssCallback : public IGnssCallback_V2_1 {
- Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
- Return<void> gnssStatusCb(const IGnssCallback_V1_0::GnssStatusValue status) override;
- Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
- return gnssSvStatusCbImpl<IGnssCallback_V1_0::GnssSvStatus, IGnssCallback_V1_0::GnssSvInfo>(
- svStatus);
- }
- Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
- Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
- Return<void> gnssAcquireWakelockCb() override;
- Return<void> gnssReleaseWakelockCb() override;
- Return<void> gnssRequestTimeCb() override;
- Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;
-
- Return<void> gnssSetSystemInfoCb(const IGnssCallback_V1_0::GnssSystemInfo& info) override;
-
- // New in 1.1
- Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
-
- // New in 2.0
- Return<void> gnssRequestLocationCb_2_0(const bool independentFromGnss, const bool isUserEmergency)
- override;
- Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
- Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
- Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) override {
- return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_0::GnssSvInfo>,
- IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
- }
-
- // New in 2.1
- Return<void> gnssSvStatusCb_2_1(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) override {
- return gnssSvStatusCbImpl<hidl_vec<IGnssCallback_V2_1::GnssSvInfo>,
- IGnssCallback_V1_0::GnssSvInfo>(svInfoList);
- }
- Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
-
- // TODO: Reconsider allocation cost vs threadsafety on these statics
- static const char* sNmeaString;
- static size_t sNmeaStringLength;
-
- template <class T>
- static Return<void> gnssLocationCbImpl(const T& location);
-
- template <class T_list, class T_sv_info>
- static Return<void> gnssSvStatusCbImpl(const T_list& svStatus);
-
-private:
- template <class T>
- static uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
- return 0;
- }
-
- template <class T>
- static double getBasebandCn0DbHz(const T& svStatus, size_t i) {
- return 0.0;
- }
-
- template <class T>
- static uint32_t getGnssSvInfoListSize(const T& svInfoList) {
- return svInfoList.size();
- }
-
- static const IGnssCallbackAidl::GnssSvInfo& getGnssSvInfoOfIndex(
- const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i];
- }
-
- static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
- const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
- return svStatus.gnssSvList.data()[i];
- }
-
- static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
- const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i].v1_0;
- }
-
- static const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
- const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i].v2_0.v1_0;
- }
-
- template <class T>
- static uint32_t getConstellationType(const T& svInfoList, size_t i) {
- return static_cast<uint32_t>(svInfoList[i].constellation);
- }
-};
-
-Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
- ALOGD("%s: name=%s\n", __func__, name.c_str());
-
- JNIEnv* env = getJniEnv();
- jstring jstringName = env->NewStringUTF(name.c_str());
- env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
- if (jstringName) {
- env->DeleteLocalRef(jstringName);
- }
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
-
- return Void();
-}
-
-const char* GnssCallback::sNmeaString = nullptr;
-size_t GnssCallback::sNmeaStringLength = 0;
-
-template<class T>
-Return<void> GnssCallback::gnssLocationCbImpl(const T& location) {
- JNIEnv* env = getJniEnv();
-
- jobject jLocation = translateGnssLocation(env, location);
-
- env->CallVoidMethod(mCallbacksObj,
- method_reportLocation,
- boolToJbool(hasLatLong(location)),
- jLocation);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- env->DeleteLocalRef(jLocation);
- return Void();
-}
-
-Return<void> GnssCallback::gnssLocationCb(const GnssLocation_V1_0& location) {
- return gnssLocationCbImpl<GnssLocation_V1_0>(location);
-}
-
-Return<void>
-GnssCallback::gnssLocationCb_2_0(const GnssLocation_V2_0& location) {
- return gnssLocationCbImpl<GnssLocation_V2_0>(location);
-}
-
-Return<void> GnssCallback::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValue status) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-template<>
-uint32_t GnssCallback::getHasBasebandCn0DbHzFlag(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>&
- svStatus) {
- return SVID_FLAGS_HAS_BASEBAND_CN0;
-}
-
-template <>
-uint32_t GnssCallback::getHasBasebandCn0DbHzFlag(
- const std::vector<IGnssCallbackAidl::GnssSvInfo>& svStatus) {
- return SVID_FLAGS_HAS_BASEBAND_CN0;
-}
-
-template <>
-double GnssCallback::getBasebandCn0DbHz(
- const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
- return svInfoList[i].basebandCN0DbHz;
-}
-
-template<>
-double GnssCallback::getBasebandCn0DbHz(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList,
- size_t i) {
- return svInfoList[i].basebandCN0DbHz;
-}
-
-template <>
-uint32_t GnssCallback::getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
- return svStatus.numSvs;
-}
-
-template <>
-uint32_t GnssCallback::getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus,
- size_t i) {
- return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
-}
-
-template <>
-uint32_t GnssCallback::getConstellationType(
- const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
- return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
-}
-
-template <class T_list, class T_sv_info>
-Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
- // In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
- if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() <= 1) {
- if (!isSvStatusRegistered) {
- return Void();
- }
- }
-
- JNIEnv* env = getJniEnv();
-
- uint32_t listSize = getGnssSvInfoListSize(svStatus);
-
- jintArray svidWithFlagArray = env->NewIntArray(listSize);
- jfloatArray cn0Array = env->NewFloatArray(listSize);
- jfloatArray elevArray = env->NewFloatArray(listSize);
- jfloatArray azimArray = env->NewFloatArray(listSize);
- jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
- jfloatArray basebandCn0Array = env->NewFloatArray(listSize);
-
- jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
- jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
- jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
- jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
- jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);
- jfloat* basebandCn0s = env->GetFloatArrayElements(basebandCn0Array, 0);
-
- /*
- * Read GNSS SV info.
- */
- for (size_t i = 0; i < listSize; ++i) {
- enum ShiftWidth: uint8_t {
- SVID_SHIFT_WIDTH = 12,
- CONSTELLATION_TYPE_SHIFT_WIDTH = 8
- };
-
- const T_sv_info& info = getGnssSvInfoOfIndex(svStatus, i);
- svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
- (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
- static_cast<uint32_t>(info.svFlag);
- cn0s[i] = info.cN0Dbhz;
- elev[i] = info.elevationDegrees;
- azim[i] = info.azimuthDegrees;
- carrierFreq[i] = info.carrierFrequencyHz;
- svidWithFlags[i] |= getHasBasebandCn0DbHzFlag(svStatus);
- basebandCn0s[i] = getBasebandCn0DbHz(svStatus, i);
- }
-
- env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
- env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
- env->ReleaseFloatArrayElements(elevArray, elev, 0);
- env->ReleaseFloatArrayElements(azimArray, azim, 0);
- env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);
- env->ReleaseFloatArrayElements(basebandCn0Array, basebandCn0s, 0);
-
- env->CallVoidMethod(mCallbacksObj, method_reportSvStatus,
- static_cast<jint>(listSize), svidWithFlagArray, cn0Array, elevArray, azimArray,
- carrierFreqArray, basebandCn0Array);
-
- env->DeleteLocalRef(svidWithFlagArray);
- env->DeleteLocalRef(cn0Array);
- env->DeleteLocalRef(elevArray);
- env->DeleteLocalRef(azimArray);
- env->DeleteLocalRef(carrierFreqArray);
- env->DeleteLocalRef(basebandCn0Array);
-
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssNmeaCb(int64_t timestamp,
- const ::android::hardware::hidl_string& nmea) {
- // In HIDL, if no listener is registered, do not report nmea to the framework.
- if (!isNmeaRegistered) {
- return Void();
- }
- JNIEnv* env = getJniEnv();
- /*
- * The Java code will call back to read these values.
- * We do this to avoid creating unnecessary String objects.
- */
- sNmeaString = nmea.c_str();
- sNmeaStringLength = nmea.size();
-
- env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
- ALOGD("%s: %du\n", __func__, capabilities);
-
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
- return GnssCallback::gnssSetCapabilitesCb(capabilities);
-}
-
-Return<void> GnssCallback::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
- return GnssCallback::gnssSetCapabilitesCb(capabilities);
-}
-
-Return<void> GnssCallback::gnssAcquireWakelockCb() {
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
- return Void();
-}
-
-Return<void> GnssCallback::gnssReleaseWakelockCb() {
- release_wake_lock(WAKE_LOCK_NAME);
- return Void();
-}
-
-Return<void> GnssCallback::gnssRequestTimeCb() {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssRequestLocationCb(const bool independentFromGnss) {
- return GnssCallback::gnssRequestLocationCb_2_0(independentFromGnss, /* isUserEmergency= */
- false);
-}
-
-Return<void> GnssCallback::gnssRequestLocationCb_2_0(const bool independentFromGnss, const bool
- isUserEmergency) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
- boolToJbool(isUserEmergency));
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSystemInfo& info) {
- ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
-
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware,
- info.yearOfHw);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
-public:
- Status gnssSetCapabilitiesCb(const int capabilities) override;
- Status gnssStatusCb(const GnssStatusValue status) override;
- Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
- Status gnssLocationCb(const GnssLocationAidl& location) override;
- Status gnssNmeaCb(const int64_t timestamp, const std::string& nmea) override;
- Status gnssAcquireWakelockCb() override;
- Status gnssReleaseWakelockCb() override;
- Status gnssSetSystemInfoCb(const GnssSystemInfo& info) override;
- Status gnssRequestTimeCb() override;
- Status gnssRequestLocationCb(const bool independentFromGnss,
- const bool isUserEmergency) override;
-};
-
-Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
- ALOGD("GnssCallbackAidl::%s: %du\n", __func__, capabilities);
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue status) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
- GnssCallback::gnssSvStatusCbImpl<std::vector<GnssSvInfo>, GnssSvInfo>(svInfoList);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssLocationCb(const GnssLocationAidl& location) {
- GnssCallback::gnssLocationCbImpl<GnssLocationAidl>(location);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
- // In AIDL v1, if no listener is registered, do not report nmea to the framework.
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() <= 1) {
- if (!isNmeaRegistered) {
- return Status::ok();
- }
- }
- JNIEnv* env = getJniEnv();
- /*
- * The Java code will call back to read these values.
- * We do this to avoid creating unnecessary String objects.
- */
- GnssCallback::sNmeaString = nmea.c_str();
- GnssCallback::sNmeaStringLength = nmea.size();
-
- env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssAcquireWakelockCb() {
- acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssReleaseWakelockCb() {
- release_wake_lock(WAKE_LOCK_NAME);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
- ALOGD("%s: yearOfHw=%d, name=%s\n", __func__, info.yearOfHw, info.name.c_str());
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
- jstring jstringName = env->NewStringUTF(info.name.c_str());
- env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
- if (jstringName) {
- env->DeleteLocalRef(jstringName);
- }
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssRequestTimeCb() {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
-Status GnssCallbackAidl::gnssRequestLocationCb(const bool independentFromGnss,
- const bool isUserEmergency) {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
- boolToJbool(isUserEmergency));
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
-}
-
/*
* GnssPowerIndicationCallback class implements the callback methods for the IGnssPowerIndication
* interface.
@@ -756,35 +196,6 @@
}
/*
- * GnssPsdsCallback class implements the callback methods for the IGnssPsds
- * interface.
- */
-struct GnssPsdsCallbackAidl : public android::hardware::gnss::BnGnssPsdsCallback {
- Status downloadRequestCb(PsdsType psdsType) override {
- ALOGD("%s. psdsType: %d", __func__, static_cast<int32_t>(psdsType));
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, psdsType);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Status::ok();
- }
-};
-
-/**
- * GnssXtraCallback class implements the callback methods for the IGnssXtra
- * interface.
- */
-class GnssXtraCallback : public IGnssXtraCallback {
- Return<void> downloadRequestCb() override;
-};
-
-Return<void> GnssXtraCallback::downloadRequestCb() {
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, /* psdsType= */ 1);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
-}
-
-/*
* GnssNiCallback implements callback methods required by the IGnssNi interface.
*/
struct GnssNiCallback : public IGnssNiCallback {
@@ -822,41 +233,7 @@
/* Initializes the GNSS service handle. */
static void android_location_gnss_hal_GnssNative_set_gps_service_handle() {
- gnssHalAidl = waitForVintfService<IGnssAidl>();
- if (gnssHalAidl != nullptr) {
- ALOGD("Successfully got GNSS AIDL handle. Version=%d.", gnssHalAidl->getInterfaceVersion());
- if (gnssHalAidl->getInterfaceVersion() >= 2) {
- return;
- }
- }
-
- ALOGD("Trying IGnss_V2_1::getService()");
- gnssHal_V2_1 = IGnss_V2_1::getService();
- if (gnssHal_V2_1 != nullptr) {
- gnssHal = gnssHal_V2_1;
- gnssHal_V2_0 = gnssHal_V2_1;
- gnssHal_V1_1 = gnssHal_V2_1;
- gnssHal = gnssHal_V2_1;
- return;
- }
-
- ALOGD("gnssHal 2.1 was null, trying 2.0");
- gnssHal_V2_0 = IGnss_V2_0::getService();
- if (gnssHal_V2_0 != nullptr) {
- gnssHal = gnssHal_V2_0;
- gnssHal_V1_1 = gnssHal_V2_0;
- return;
- }
-
- ALOGD("gnssHal 2.0 was null, trying 1.1");
- gnssHal_V1_1 = IGnss_V1_1::getService();
- if (gnssHal_V1_1 != nullptr) {
- gnssHal = gnssHal_V1_1;
- return;
- }
-
- ALOGD("gnssHal 1.1 was null, trying 1.0");
- gnssHal = IGnss_V1_0::getService();
+ gnssHal = std::make_unique<gnss::GnssHal>();
}
/* One time initialization at system boot */
@@ -865,21 +242,10 @@
android_location_gnss_hal_GnssNative_set_gps_service_handle();
// Cache methodIDs and class IDs.
- method_reportLocation = env->GetMethodID(clazz, "reportLocation",
- "(ZLandroid/location/Location;)V");
- method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
- method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F[F)V");
- method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
- method_setTopHalCapabilities = env->GetMethodID(clazz, "setTopHalCapabilities", "(I)V");
- method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
- method_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName",
- "(Ljava/lang/String;)V");
- method_psdsDownloadRequest = env->GetMethodID(clazz, "psdsDownloadRequest", "(I)V");
+
method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification",
"(IIIIILjava/lang/String;Ljava/lang/String;II)V");
- method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(ZZ)V");
- method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
- method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
+
method_reportNfwNotification = env->GetMethodID(clazz, "reportNfwNotification",
"(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
method_reportGnssPowerStats =
@@ -894,17 +260,19 @@
class_gnssPowerStats = (jclass)env->NewGlobalRef(gnssPowerStatsClass);
method_gnssPowerStatsCtor = env->GetMethodID(class_gnssPowerStats, "<init>", "(IJDDDDDD[D)V");
+ gnss::AGnss_class_init_once(env, clazz);
+ gnss::AGnssRil_class_init_once(env, clazz);
+ gnss::Gnss_class_init_once(env, clazz);
gnss::GnssAntennaInfo_class_init_once(env, clazz);
gnss::GnssBatching_class_init_once(env, clazz);
gnss::GnssConfiguration_class_init_once(env);
gnss::GnssGeofence_class_init_once(env, clazz);
gnss::GnssMeasurement_class_init_once(env, clazz);
gnss::GnssNavigationMessage_class_init_once(env, clazz);
+ gnss::GnssPsds_class_init_once(env, clazz);
gnss::GnssVisibilityControl_class_init_once(env, clazz);
gnss::MeasurementCorrections_class_init_once(env, clazz);
gnss::MeasurementCorrectionsCallback_class_init_once(env, clazz);
- gnss::AGnss_class_init_once(env, clazz);
- gnss::AGnssRil_class_init_once(env, clazz);
gnss::Utils_class_init_once(env);
}
@@ -923,313 +291,26 @@
android_location_gnss_hal_GnssNative_set_gps_service_handle();
}
- if (gnssHal == nullptr && gnssHalAidl == nullptr) {
+ if (gnssHal == nullptr || !gnssHal->isSupported()) {
ALOGE("Unable to get GPS service\n");
return;
}
- // TODO: linkToDeath for AIDL HAL
-
- if (gnssHal != nullptr) {
- gnssHalDeathRecipient = new GnssDeathRecipient();
- hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to GnssHAL death: %s",
- linked.description().c_str());
- } else if (!linked) {
- ALOGW("Unable to link to GnssHal death notifications");
- } else {
- ALOGD("Link to death notification successful");
- }
- }
-
- if (gnssHalAidl != nullptr) {
- sp<IGnssPsdsAidl> gnssPsdsAidl;
- auto status = gnssHalAidl->getExtensionPsds(&gnssPsdsAidl);
- if (status.isOk()) {
- gnssPsdsAidlIface = gnssPsdsAidl;
- } else {
- ALOGD("Unable to get a handle to PSDS AIDL interface.");
- }
- } else if (gnssHal != nullptr) {
- auto gnssXtra = gnssHal->getExtensionXtra();
- if (!gnssXtra.isOk()) {
- ALOGD("Unable to get a handle to Xtra");
- } else {
- gnssXtraIface = gnssXtra;
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IAGnssRilAidl> agnssRilAidl;
- auto status = gnssHalAidl->getExtensionAGnssRil(&agnssRilAidl);
- if (checkAidlStatus(status, "Unable to get a handle to AGnssRil interface.")) {
- agnssRilIface = std::make_unique<gnss::AGnssRil>(agnssRilAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto agnssRil_V2_0 = gnssHal_V2_0->getExtensionAGnssRil_2_0();
- if (checkHidlReturn(agnssRil_V2_0, "Unable to get a handle to AGnssRil_V2_0")) {
- agnssRilIface = std::make_unique<gnss::AGnssRil_V2_0>(agnssRil_V2_0);
- }
- } else if (gnssHal != nullptr) {
- auto agnssRil_V1_0 = gnssHal->getExtensionAGnssRil();
- if (checkHidlReturn(agnssRil_V1_0, "Unable to get a handle to AGnssRil_V1_0")) {
- agnssRilIface = std::make_unique<gnss::AGnssRil_V1_0>(agnssRil_V1_0);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IAGnssAidl> agnssAidl;
- auto status = gnssHalAidl->getExtensionAGnss(&agnssAidl);
- if (checkAidlStatus(status, "Unable to get a handle to AGnss interface.")) {
- agnssIface = std::make_unique<gnss::AGnss>(agnssAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto agnss_V2_0 = gnssHal_V2_0->getExtensionAGnss_2_0();
- if (checkHidlReturn(agnss_V2_0, "Unable to get a handle to AGnss_V2_0")) {
- agnssIface = std::make_unique<gnss::AGnss_V2_0>(agnss_V2_0);
- }
- } else if (gnssHal != nullptr) {
- auto agnss_V1_0 = gnssHal->getExtensionAGnss();
- if (checkHidlReturn(agnss_V1_0, "Unable to get a handle to AGnss_V1_0")) {
- agnssIface = std::make_unique<gnss::AGnss_V1_0>(agnss_V1_0);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<hardware::gnss::IGnssNavigationMessageInterface> gnssNavigationMessage;
- auto status = gnssHalAidl->getExtensionGnssNavigationMessage(&gnssNavigationMessage);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssNavigationMessage AIDL interface.")) {
- gnssNavigationMessageIface =
- std::make_unique<gnss::GnssNavigationMessageAidl>(gnssNavigationMessage);
- }
- } else if (gnssHal != nullptr) {
- auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage();
- if (checkHidlReturn(gnssNavigationMessage,
- "Unable to get a handle to GnssNavigationMessage interface.")) {
- gnssNavigationMessageIface =
- std::make_unique<gnss::GnssNavigationMessageHidl>(gnssNavigationMessage);
- }
- }
-
- // Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
- // 2.1@IGnss can be paired with {1.0, 1,1, 2.0, 2.1}@IGnssMeasurement
- // 2.0@IGnss can be paired with {1.0, 1,1, 2.0}@IGnssMeasurement
- // 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement
- // 1.0@IGnss is paired with 1.0@IGnssMeasurement
- gnssMeasurementIface = nullptr;
- if (gnssHalAidl != nullptr) {
- sp<hardware::gnss::IGnssMeasurementInterface> gnssMeasurement;
- auto status = gnssHalAidl->getExtensionGnssMeasurement(&gnssMeasurement);
- if (checkAidlStatus(status, "Unable to get a handle to GnssMeasurement AIDL interface.")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement>(gnssMeasurement);
- }
- }
- if (gnssHal_V2_1 != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal_V2_1->getExtensionGnssMeasurement_2_1();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_1")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V2_1>(gnssMeasurement);
- }
- }
- if (gnssHal_V2_0 != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_0")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V2_0>(gnssMeasurement);
- }
- }
- if (gnssHal_V1_1 != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_1")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V1_1>(gnssMeasurement);
- }
- }
- if (gnssHal != nullptr && gnssMeasurementIface == nullptr) {
- auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
- if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_0")) {
- gnssMeasurementIface =
- std::make_unique<android::gnss::GnssMeasurement_V1_0>(gnssMeasurement);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IGnssAntennaInfoAidl> gnssAntennaInfoAidl;
- auto status = gnssHalAidl->getExtensionGnssAntennaInfo(&gnssAntennaInfoAidl);
- if (checkAidlStatus(status, "Unable to get a handle to GnssAntennaInfo interface.")) {
- gnssAntennaInfoIface = std::make_unique<gnss::GnssAntennaInfoAidl>(gnssAntennaInfoAidl);
- }
- } else if (gnssHal_V2_1 != nullptr) {
- auto gnssAntennaInfo_V2_1 = gnssHal_V2_1->getExtensionGnssAntennaInfo();
- if (checkHidlReturn(gnssAntennaInfo_V2_1,
- "Unable to get a handle to GnssAntennaInfo_V2_1")) {
- gnssAntennaInfoIface =
- std::make_unique<gnss::GnssAntennaInfo_V2_1>(gnssAntennaInfo_V2_1);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface>
- gnssMeasurementCorrectionsAidl;
- auto status =
- gnssHalAidl->getExtensionMeasurementCorrections(&gnssMeasurementCorrectionsAidl);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
- gnssMeasurementCorrectionsIface =
- std::make_unique<gnss::MeasurementCorrectionsIface_Aidl>(
- gnssMeasurementCorrectionsAidl);
- }
- }
- if (gnssHal_V2_1 != nullptr && gnssMeasurementCorrectionsIface == nullptr) {
- auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1();
- if (checkHidlReturn(gnssCorrections,
- "Unable to get a handle to GnssMeasurementCorrections HIDL "
- "interface")) {
- gnssMeasurementCorrectionsIface =
- std::make_unique<gnss::MeasurementCorrectionsIface_V1_1>(gnssCorrections);
- }
- }
- if (gnssHal_V2_0 != nullptr && gnssMeasurementCorrectionsIface == nullptr) {
- auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
- if (checkHidlReturn(gnssCorrections,
- "Unable to get a handle to GnssMeasurementCorrections HIDL "
- "interface")) {
- gnssMeasurementCorrectionsIface =
- std::make_unique<gnss::MeasurementCorrectionsIface_V1_0>(gnssCorrections);
- }
- }
-
- // Allow all causal combinations between IGnss.hal and IGnssDebug.hal. That means,
- // 2.0@IGnss can be paired with {1.0, 2.0}@IGnssDebug
- // 1.0@IGnss is paired with 1.0@IGnssDebug
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<IGnssDebugAidl> gnssDebugAidl;
- auto status = gnssHalAidl->getExtensionGnssDebug(&gnssDebugAidl);
- if (checkAidlStatus(status, "Unable to get a handle to GnssDebug interface.")) {
- gnssDebugIface = std::make_unique<gnss::GnssDebug>(gnssDebugAidl);
- }
- }
- if (gnssHal_V2_0 != nullptr && gnssDebugIface == nullptr) {
- auto gnssDebug_V2_0 = gnssHal_V2_0->getExtensionGnssDebug_2_0();
- if (checkHidlReturn(gnssDebug_V2_0, "Unable to get a handle to GnssDebug_V2_0.")) {
- gnssDebugIface = std::make_unique<gnss::GnssDebug_V2_0>(gnssDebug_V2_0);
- }
- }
- if (gnssHal != nullptr && gnssDebugIface == nullptr) {
- auto gnssDebug_V1_0 = gnssHal->getExtensionGnssDebug();
- if (checkHidlReturn(gnssDebug_V1_0, "Unable to get a handle to GnssDebug_V1_0.")) {
- gnssDebugIface = std::make_unique<gnss::GnssDebug_V1_0>(gnssDebug_V1_0);
- }
- }
-
- if (gnssHal != nullptr) {
- auto gnssNi = gnssHal->getExtensionGnssNi();
- if (!gnssNi.isOk()) {
- ALOGD("Unable to get a handle to GnssNi");
- } else {
- gnssNiIface = gnssNi;
- }
- }
-
- if (gnssHalAidl != nullptr) {
- sp<IGnssConfigurationAidl> gnssConfigurationAidl;
- auto status = gnssHalAidl->getExtensionGnssConfiguration(&gnssConfigurationAidl);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssConfiguration AIDL interface.")) {
- gnssConfigurationIface =
- std::make_unique<android::gnss::GnssConfiguration>(gnssConfigurationAidl);
- }
- } else if (gnssHal_V2_1 != nullptr) {
- auto gnssConfiguration = gnssHal_V2_1->getExtensionGnssConfiguration_2_1();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V2_1")) {
- gnssConfigurationIface =
- std::make_unique<android::gnss::GnssConfiguration_V2_1>(gnssConfiguration);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V2_0")) {
- gnssConfigurationIface =
- std::make_unique<android::gnss::GnssConfiguration_V2_0>(gnssConfiguration);
- }
- } else if (gnssHal_V1_1 != nullptr) {
- auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V1_1")) {
- gnssConfigurationIface =
- std::make_unique<gnss::GnssConfiguration_V1_1>(gnssConfiguration);
- }
- } else if (gnssHal != nullptr) {
- auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
- if (checkHidlReturn(gnssConfiguration,
- "Unable to get a handle to GnssConfiguration_V1_0")) {
- gnssConfigurationIface =
- std::make_unique<gnss::GnssConfiguration_V1_0>(gnssConfiguration);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<hardware::gnss::IGnssGeofence> gnssGeofence;
- auto status = gnssHalAidl->getExtensionGnssGeofence(&gnssGeofence);
- if (checkAidlStatus(status, "Unable to get a handle to GnssGeofence AIDL interface.")) {
- gnssGeofencingIface = std::make_unique<gnss::GnssGeofenceAidl>(gnssGeofence);
- }
- } else if (gnssHal != nullptr) {
- auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
- if (checkHidlReturn(gnssGeofencing, "Unable to get a handle to GnssGeofencing")) {
- gnssGeofencingIface = std::make_unique<gnss::GnssGeofenceHidl>(gnssGeofencing);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<android::hardware::gnss::IGnssBatching> gnssBatchingAidl;
- auto status = gnssHalAidl->getExtensionGnssBatching(&gnssBatchingAidl);
- if (checkAidlStatus(status, "Unable to get a handle to GnssBatching interface.")) {
- gnssBatchingIface = std::make_unique<gnss::GnssBatching>(gnssBatchingAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto gnssBatching_V2_0 = gnssHal_V2_0->getExtensionGnssBatching_2_0();
- if (checkHidlReturn(gnssBatching_V2_0, "Unable to get a handle to GnssBatching_V2_0")) {
- gnssBatchingIface = std::make_unique<gnss::GnssBatching_V2_0>(gnssBatching_V2_0);
- }
- }
- if (gnssHal != nullptr && gnssBatchingIface == nullptr) {
- auto gnssBatching_V1_0 = gnssHal->getExtensionGnssBatching();
- if (checkHidlReturn(gnssBatching_V1_0, "Unable to get a handle to GnssBatching")) {
- gnssBatchingIface = std::make_unique<gnss::GnssBatching_V1_0>(gnssBatching_V1_0);
- }
- }
-
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- sp<android::hardware::gnss::visibility_control::IGnssVisibilityControl>
- gnssVisibilityControlAidl;
- auto status = gnssHalAidl->getExtensionGnssVisibilityControl(&gnssVisibilityControlAidl);
- if (checkAidlStatus(status,
- "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
- gnssVisibilityControlIface =
- std::make_unique<gnss::GnssVisibilityControlAidl>(gnssVisibilityControlAidl);
- }
- } else if (gnssHal_V2_0 != nullptr) {
- auto gnssVisibilityControlHidl = gnssHal_V2_0->getExtensionVisibilityControl();
- if (checkHidlReturn(gnssVisibilityControlHidl,
- "Unable to get a handle to GnssVisibilityControl HIDL interface")) {
- gnssVisibilityControlIface =
- std::make_unique<gnss::GnssVisibilityControlHidl>(gnssVisibilityControlHidl);
- }
- }
-
- if (gnssHalAidl != nullptr) {
- sp<IGnssPowerIndication> gnssPowerIndication;
- auto status = gnssHalAidl->getExtensionGnssPowerIndication(&gnssPowerIndication);
- if (checkAidlStatus(status, "Unable to get a handle to GnssPowerIndication interface.")) {
- gnssPowerIndicationIface = gnssPowerIndication;
- }
- }
+ gnssHal->linkToDeath();
+ gnssPsdsIface = gnssHal->getGnssPsdsInterface();
+ agnssRilIface = gnssHal->getAGnssRilInterface();
+ agnssIface = gnssHal->getAGnssInterface();
+ gnssNavigationMessageIface = gnssHal->getGnssNavigationMessageInterface();
+ gnssMeasurementIface = gnssHal->getGnssMeasurementInterface();
+ gnssAntennaInfoIface = gnssHal->getGnssAntennaInfoInterface();
+ gnssMeasurementCorrectionsIface = gnssHal->getMeasurementCorrectionsInterface();
+ gnssDebugIface = gnssHal->getGnssDebugInterface();
+ gnssNiIface = gnssHal->getGnssNiInterface();
+ gnssConfigurationIface = gnssHal->getGnssConfigurationInterface();
+ gnssGeofencingIface = gnssHal->getGnssGeofenceInterface();
+ gnssBatchingIface = gnssHal->getGnssBatchingInterface();
+ gnssVisibilityControlIface = gnssHal->getGnssVisibilityControlInterface();
+ gnssPowerIndicationIface = gnssHal->getGnssPowerIndicationInterface();
if (mCallbacksObj) {
ALOGE("Callbacks already initialized");
@@ -1239,7 +320,7 @@
}
static jboolean android_location_gnss_hal_GnssNative_is_supported(JNIEnv* /* env */, jclass) {
- return (gnssHalAidl != nullptr || gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssHal != nullptr && gnssHal->isSupported()) ? JNI_TRUE : JNI_FALSE;
}
static jboolean android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported(
@@ -1268,52 +349,18 @@
/*
* Fail if the main interface fails to initialize
*/
- if (gnssHal == nullptr && gnssHalAidl == nullptr) {
+ if (!gnssHal->isSupported()) {
ALOGE("Unable to initialize GNSS HAL.");
return JNI_FALSE;
}
- // Set top level IGnss.hal callback.
- if (gnssHal != nullptr) {
- Return<bool> result = false;
- sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
- if (gnssHal_V2_1 != nullptr) {
- result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
- } else if (gnssHal_V2_0 != nullptr) {
- result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
- } else if (gnssHal_V1_1 != nullptr) {
- result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
- } else {
- result = gnssHal->setCallback(gnssCbIface);
- }
- if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
- return JNI_FALSE;
- }
- }
+ // Set top level IGnss HAL callback.
+ gnssHal->setCallback();
- if (gnssHalAidl != nullptr) {
- sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
- auto status = gnssHalAidl->setCallback(gnssCbIfaceAidl);
- if (!checkAidlStatus(status, "IGnssAidl setCallback() failed.")) {
- return JNI_FALSE;
- }
- }
-
- // Set IGnssPsds or IGnssXtra callback.
- if (gnssPsdsAidlIface != nullptr) {
- sp<IGnssPsdsCallbackAidl> gnssPsdsCallbackAidl = new GnssPsdsCallbackAidl();
- auto status = gnssPsdsAidlIface->setCallback(gnssPsdsCallbackAidl);
- if (!checkAidlStatus(status, "IGnssPsdsAidl setCallback() failed.")) {
- gnssPsdsAidlIface = nullptr;
- }
- } else if (gnssXtraIface != nullptr) {
- sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
- auto result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if (!checkHidlReturn(result, "IGnssXtra setCallback() failed.")) {
- gnssXtraIface = nullptr;
- } else {
- ALOGI("Unable to initialize IGnssXtra interface.");
- }
+ // Set IGnssPsds callback.
+ if (gnssPsdsIface == nullptr ||
+ !gnssPsdsIface->setCallback(std::make_unique<gnss::GnssPsdsCallback>())) {
+ ALOGI("Unable to initialize IGnssPsds interface.");
}
// Set IAGnss callback.
@@ -1373,145 +420,47 @@
}
static void android_location_gnss_hal_GnssNative_cleanup(JNIEnv* /* env */, jclass) {
- if (gnssHalAidl != nullptr) {
- auto status = gnssHalAidl->close();
- checkAidlStatus(status, "IGnssAidl close() failed.");
- }
-
- if (gnssHal != nullptr) {
- auto result = gnssHal->cleanup();
- checkHidlReturn(result, "IGnss cleanup() failed.");
- }
+ gnssHal->close();
}
static jboolean android_location_gnss_hal_GnssNative_set_position_mode(
JNIEnv* /* env */, jclass, jint mode, jint recurrence, jint min_interval,
jint preferred_accuracy, jint preferred_time, jboolean low_power_mode) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- IGnssAidl::PositionModeOptions options;
- options.mode = static_cast<IGnssAidl::GnssPositionMode>(mode);
- options.recurrence = static_cast<IGnssAidl::GnssPositionRecurrence>(recurrence);
- options.minIntervalMs = min_interval;
- options.preferredAccuracyMeters = preferred_accuracy;
- options.preferredTimeMs = preferred_time;
- options.lowPowerMode = low_power_mode;
- auto status = gnssHalAidl->setPositionMode(options);
- return checkAidlStatus(status, "IGnssAidl setPositionMode() failed.");
- }
-
- Return<bool> result = false;
- if (gnssHal_V1_1 != nullptr) {
- result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
- static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence),
- min_interval,
- preferred_accuracy,
- preferred_time,
- low_power_mode);
- } else if (gnssHal != nullptr) {
- result = gnssHal->setPositionMode(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
- static_cast<IGnss_V1_0::GnssPositionRecurrence>(recurrence),
- min_interval,
- preferred_accuracy,
- preferred_time);
- }
-
- return checkHidlReturn(result, "IGnss setPositionMode() failed.");
+ return gnssHal->setPositionMode(mode, recurrence, min_interval, preferred_accuracy,
+ preferred_time, low_power_mode);
}
static jboolean android_location_gnss_hal_GnssNative_start(JNIEnv* /* env */, jclass) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->start();
- return checkAidlStatus(status, "IGnssAidl start() failed.");
- }
-
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
-
- auto result = gnssHal->start();
- return checkHidlReturn(result, "IGnss start() failed.");
+ return gnssHal->start();
}
static jboolean android_location_gnss_hal_GnssNative_stop(JNIEnv* /* env */, jclass) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->stop();
- return checkAidlStatus(status, "IGnssAidl stop() failed.");
- }
-
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
-
- auto result = gnssHal->stop();
- return checkHidlReturn(result, "IGnss stop() failed.");
+ return gnssHal->stop();
}
static jboolean android_location_gnss_hal_GnssNative_start_sv_status_collection(JNIEnv* /* env */,
jclass) {
- isSvStatusRegistered = true;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->startSvStatus();
- return checkAidlStatus(status, "IGnssAidl startSvStatus() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->startSvStatus();
}
static jboolean android_location_gnss_hal_GnssNative_stop_sv_status_collection(JNIEnv* /* env */,
jclass) {
- isSvStatusRegistered = false;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->stopSvStatus();
- return checkAidlStatus(status, "IGnssAidl stopSvStatus() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->stopSvStatus();
}
static jboolean android_location_gnss_hal_GnssNative_start_nmea_message_collection(
JNIEnv* /* env */, jclass) {
- isNmeaRegistered = true;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->startNmea();
- return checkAidlStatus(status, "IGnssAidl startNmea() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->startNmea();
}
static jboolean android_location_gnss_hal_GnssNative_stop_nmea_message_collection(JNIEnv* /* env */,
jclass) {
- isNmeaRegistered = false;
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->stopNmea();
- return checkAidlStatus(status, "IGnssAidl stopNmea() failed.");
- }
- if (gnssHal == nullptr) {
- return JNI_FALSE;
- }
- return JNI_TRUE;
+ return gnssHal->stopNmea();
}
static void android_location_gnss_hal_GnssNative_delete_aiding_data(JNIEnv* /* env */, jclass,
jint flags) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->deleteAidingData(static_cast<IGnssAidl::GnssAidingData>(flags));
- checkAidlStatus(status, "IGnssAidl deleteAidingData() failed.");
- return;
- }
-
- if (gnssHal == nullptr) {
- return;
- }
-
- auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
- checkHidlReturn(result, "IGnss deleteAidingData() failed.");
+ gnssHal->deleteAidingData(flags);
}
static void android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid(
@@ -1535,30 +484,13 @@
static jint android_location_gnss_hal_GnssNative_read_nmea(JNIEnv* env, jclass,
jbyteArray nmeaArray, jint buffer_size) {
- // this should only be called from within a call to reportNmea
- jbyte* nmea = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(nmeaArray, 0));
- int length = GnssCallback::sNmeaStringLength;
- if (length > buffer_size)
- length = buffer_size;
- memcpy(nmea, GnssCallback::sNmeaString, length);
- env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
- return (jint) length;
+ return gnssHal->readNmea(nmeaArray, buffer_size);
}
static void android_location_gnss_hal_GnssNative_inject_time(JNIEnv* /* env */, jclass, jlong time,
jlong timeReference,
jint uncertainty) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- auto status = gnssHalAidl->injectTime(time, timeReference, uncertainty);
- checkAidlStatus(status, "IGnssAidl injectTime() failed.");
- return;
- }
-
- if (gnssHal == nullptr) {
- return;
- }
- auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- checkHidlReturn(result, "IGnss injectTime() failed.");
+ gnssHal->injectTime(time, timeReference, uncertainty);
}
static void android_location_gnss_hal_GnssNative_inject_best_location(
@@ -1568,58 +500,12 @@
jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
jdouble elapsedRealtimeUncertaintyNanos) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- GnssLocationAidl location =
- createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
- altitudeMeters, speedMetersPerSec, bearingDegrees,
- horizontalAccuracyMeters, verticalAccuracyMeters,
- speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
- elapsedRealtimeFlags, elapsedRealtimeNanos,
- elapsedRealtimeUncertaintyNanos);
- auto status = gnssHalAidl->injectBestLocation(location);
- checkAidlStatus(status, "IGnssAidl injectBestLocation() failed.");
- return;
- }
-
- if (gnssHal_V2_0 != nullptr) {
- GnssLocation_V2_0 location = createGnssLocation_V2_0(
- gnssLocationFlags,
- latitudeDegrees,
- longitudeDegrees,
- altitudeMeters,
- speedMetersPerSec,
- bearingDegrees,
- horizontalAccuracyMeters,
- verticalAccuracyMeters,
- speedAccuracyMetersPerSecond,
- bearingAccuracyDegrees,
- timestamp,
- elapsedRealtimeFlags,
- elapsedRealtimeNanos,
- elapsedRealtimeUncertaintyNanos);
- auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
- checkHidlReturn(result, "IGnss injectBestLocation_2_0() failed.");
- return;
- }
-
- if (gnssHal_V1_1 != nullptr) {
- GnssLocation_V1_0 location = createGnssLocation_V1_0(
- gnssLocationFlags,
- latitudeDegrees,
- longitudeDegrees,
- altitudeMeters,
- speedMetersPerSec,
- bearingDegrees,
- horizontalAccuracyMeters,
- verticalAccuracyMeters,
- speedAccuracyMetersPerSecond,
- bearingAccuracyDegrees,
- timestamp);
- auto result = gnssHal_V1_1->injectBestLocation(location);
- checkHidlReturn(result, "IGnss injectBestLocation() failed.");
- }
-
- ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
+ gnssHal->injectBestLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
}
static void android_location_gnss_hal_GnssNative_inject_location(
@@ -1629,51 +515,25 @@
jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees, jlong timestamp,
jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
jdouble elapsedRealtimeUncertaintyNanos) {
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
- GnssLocationAidl location =
- createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
- altitudeMeters, speedMetersPerSec, bearingDegrees,
- horizontalAccuracyMeters, verticalAccuracyMeters,
- speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
- elapsedRealtimeFlags, elapsedRealtimeNanos,
- elapsedRealtimeUncertaintyNanos);
- auto status = gnssHalAidl->injectLocation(location);
- checkAidlStatus(status, "IGnssAidl injectLocation() failed.");
- return;
- }
-
- if (gnssHal == nullptr) {
- return;
- }
- auto result =
- gnssHal->injectLocation(latitudeDegrees, longitudeDegrees, horizontalAccuracyMeters);
- checkHidlReturn(result, "IGnss injectLocation() failed.");
+ gnssHal->injectLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters,
+ speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
+ verticalAccuracyMeters, speedAccuracyMetersPerSecond,
+ bearingAccuracyDegrees, timestamp, elapsedRealtimeFlags,
+ elapsedRealtimeNanos, elapsedRealtimeUncertaintyNanos);
}
static jboolean android_location_gnss_hal_GnssNative_supports_psds(JNIEnv* /* env */, jclass) {
- return (gnssPsdsAidlIface != nullptr || gnssXtraIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+ return (gnssPsdsIface != nullptr) ? JNI_TRUE : JNI_FALSE;
}
static void android_location_gnss_hal_GnssNative_inject_psds_data(JNIEnv* env, jclass,
jbyteArray data, jint length,
jint psdsType) {
- if (gnssPsdsAidlIface == nullptr && gnssXtraIface == nullptr) {
- ALOGE("%s: IGnssPsdsAidl or IGnssXtra interface not available.", __func__);
+ if (gnssPsdsIface == nullptr) {
+ ALOGE("%s: IGnssPsds or IGnssXtra interface not available.", __func__);
return;
}
-
- jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- if (gnssPsdsAidlIface != nullptr) {
- auto status = gnssPsdsAidlIface->injectPsdsData(static_cast<PsdsType>(psdsType),
- std::vector<uint8_t>((const uint8_t*)bytes,
- (const uint8_t*)bytes +
- length));
- checkAidlStatus(status, "IGnssPsdsAidl injectPsdsData() failed.");
- } else if (gnssXtraIface != nullptr) {
- auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
- checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
- }
- env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+ gnssPsdsIface->injectPsdsData(data, length, psdsType);
}
static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
diff --git a/services/core/jni/gnss/Android.bp b/services/core/jni/gnss/Android.bp
index e52df15..0531ae2 100644
--- a/services/core/jni/gnss/Android.bp
+++ b/services/core/jni/gnss/Android.bp
@@ -28,6 +28,8 @@
"AGnssRil.cpp",
"AGnssRilCallback.cpp",
"GnssAntennaInfo.cpp",
+ "Gnss.cpp",
+ "GnssCallback.cpp",
"GnssAntennaInfoCallback.cpp",
"GnssBatching.cpp",
"GnssBatchingCallback.cpp",
@@ -39,6 +41,8 @@
"GnssMeasurementCallback.cpp",
"GnssNavigationMessage.cpp",
"GnssNavigationMessageCallback.cpp",
+ "GnssPsds.cpp",
+ "GnssPsdsCallback.cpp",
"GnssVisibilityControl.cpp",
"GnssVisibilityControlCallback.cpp",
"MeasurementCorrections.cpp",
@@ -55,6 +59,7 @@
"libhidlbase",
"liblog",
"libnativehelper",
+ "libhardware_legacy",
"libutils",
"android.hardware.gnss-V2-cpp",
"android.hardware.gnss@1.0",
diff --git a/services/core/jni/gnss/Gnss.cpp b/services/core/jni/gnss/Gnss.cpp
new file mode 100644
index 0000000..f6459ea
--- /dev/null
+++ b/services/core/jni/gnss/Gnss.cpp
@@ -0,0 +1,759 @@
+/*
+ * 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.
+ */
+
+// Define LOG_TAG before <log/log.h> to overwrite the default value.
+#define LOG_TAG "GnssJni"
+
+#include "Gnss.h"
+
+#include <binder/IServiceManager.h>
+
+#include "Utils.h"
+
+namespace android::gnss {
+
+using hardware::Return;
+
+using GnssLocationAidl = hardware::gnss::GnssLocation;
+using GnssLocation_V1_0 = hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_V2_0 = hardware::gnss::V2_0::GnssLocation;
+using IAGnssAidl = hardware::gnss::IAGnss;
+using IAGnssRilAidl = hardware::gnss::IAGnssRil;
+using IGnssAidl = hardware::gnss::IGnss;
+using IGnss_V1_0 = hardware::gnss::V1_0::IGnss;
+using IGnss_V1_1 = hardware::gnss::V1_1::IGnss;
+using IGnss_V2_0 = hardware::gnss::V2_0::IGnss;
+using IGnss_V2_1 = hardware::gnss::V2_1::IGnss;
+using IGnssAntennaInfoAidl = hardware::gnss::IGnssAntennaInfo;
+using IGnssCallbackAidl = hardware::gnss::IGnssCallback;
+using IGnssCallback_V1_0 = hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_V2_0 = hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_V2_1 = hardware::gnss::V2_1::IGnssCallback;
+using IGnssConfigurationAidl = android::hardware::gnss::IGnssConfiguration;
+using IGnssDebugAidl = hardware::gnss::IGnssDebug;
+using android::hardware::gnss::IGnssPsds;
+
+namespace {
+
+GnssLocationAidl createGnssLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees, jlong timestamp,
+ jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ GnssLocationAidl location;
+ location.gnssLocationFlags = static_cast<int>(gnssLocationFlags);
+ location.latitudeDegrees = static_cast<double>(latitudeDegrees);
+ location.longitudeDegrees = static_cast<double>(longitudeDegrees);
+ location.altitudeMeters = static_cast<double>(altitudeMeters);
+ location.speedMetersPerSec = static_cast<double>(speedMetersPerSec);
+ location.bearingDegrees = static_cast<double>(bearingDegrees);
+ location.horizontalAccuracyMeters = static_cast<double>(horizontalAccuracyMeters);
+ location.verticalAccuracyMeters = static_cast<double>(verticalAccuracyMeters);
+ location.speedAccuracyMetersPerSecond = static_cast<double>(speedAccuracyMetersPerSecond);
+ location.bearingAccuracyDegrees = static_cast<double>(bearingAccuracyDegrees);
+ location.timestampMillis = static_cast<uint64_t>(timestamp);
+
+ location.elapsedRealtime.flags = static_cast<int>(elapsedRealtimeFlags);
+ location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
+ location.elapsedRealtime.timeUncertaintyNs =
+ static_cast<double>(elapsedRealtimeUncertaintyNanos);
+
+ return location;
+}
+
+GnssLocation_V1_0 createGnssLocation_V1_0(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters,
+ jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees, jlong timestamp) {
+ GnssLocation_V1_0 location;
+ location.gnssLocationFlags = static_cast<uint16_t>(gnssLocationFlags);
+ location.latitudeDegrees = static_cast<double>(latitudeDegrees);
+ location.longitudeDegrees = static_cast<double>(longitudeDegrees);
+ location.altitudeMeters = static_cast<double>(altitudeMeters);
+ location.speedMetersPerSec = static_cast<float>(speedMetersPerSec);
+ location.bearingDegrees = static_cast<float>(bearingDegrees);
+ location.horizontalAccuracyMeters = static_cast<float>(horizontalAccuracyMeters);
+ location.verticalAccuracyMeters = static_cast<float>(verticalAccuracyMeters);
+ location.speedAccuracyMetersPerSecond = static_cast<float>(speedAccuracyMetersPerSecond);
+ location.bearingAccuracyDegrees = static_cast<float>(bearingAccuracyDegrees);
+ location.timestamp = static_cast<uint64_t>(timestamp);
+
+ return location;
+}
+
+GnssLocation_V2_0 createGnssLocation_V2_0(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters,
+ jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond,
+ jfloat bearingAccuracyDegrees, jlong timestamp,
+ jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ GnssLocation_V2_0 location;
+ location.v1_0 = createGnssLocation_V1_0(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp);
+
+ location.elapsedRealtime.flags = static_cast<uint16_t>(elapsedRealtimeFlags);
+ location.elapsedRealtime.timestampNs = static_cast<uint64_t>(elapsedRealtimeNanos);
+ location.elapsedRealtime.timeUncertaintyNs =
+ static_cast<uint64_t>(elapsedRealtimeUncertaintyNanos);
+
+ return location;
+}
+
+} // anonymous namespace
+
+// Implementation of GnssHal, which unifies all versions of GNSS HALs
+
+GnssHal::GnssHal() {
+ gnssHalAidl = waitForVintfService<IGnssAidl>();
+ if (gnssHalAidl != nullptr) {
+ ALOGD("Successfully got GNSS AIDL handle. Version=%d.", gnssHalAidl->getInterfaceVersion());
+ if (gnssHalAidl->getInterfaceVersion() >= 2) {
+ return;
+ }
+ }
+
+ ALOGD("Trying IGnss_V2_1::getService()");
+ gnssHal_V2_1 = IGnss_V2_1::getService();
+ if (gnssHal_V2_1 != nullptr) {
+ gnssHal_V2_0 = gnssHal_V2_1;
+ gnssHal_V1_1 = gnssHal_V2_1;
+ gnssHal = gnssHal_V2_1;
+ return;
+ }
+
+ ALOGD("gnssHal 2.1 was null, trying 2.0");
+ gnssHal_V2_0 = IGnss_V2_0::getService();
+ if (gnssHal_V2_0 != nullptr) {
+ gnssHal_V1_1 = gnssHal_V2_0;
+ gnssHal = gnssHal_V2_0;
+ return;
+ }
+
+ ALOGD("gnssHal 2.0 was null, trying 1.1");
+ gnssHal_V1_1 = IGnss_V1_1::getService();
+ if (gnssHal_V1_1 != nullptr) {
+ gnssHal = gnssHal_V1_1;
+ return;
+ }
+
+ ALOGD("gnssHal 1.1 was null, trying 1.0");
+ gnssHal = IGnss_V1_0::getService();
+}
+
+jboolean GnssHal::isSupported() {
+ return (gnssHalAidl != nullptr || gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
+void GnssHal::linkToDeath() {
+ // TODO: linkToDeath for AIDL HAL
+
+ if (gnssHal != nullptr) {
+ gnssHalDeathRecipient = new GnssDeathRecipient();
+ hardware::Return<bool> linked = gnssHal->linkToDeath(gnssHalDeathRecipient, /*cookie*/ 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to GnssHAL death: %s",
+ linked.description().c_str());
+ } else if (!linked) {
+ ALOGW("Unable to link to GnssHal death notifications");
+ } else {
+ ALOGD("Link to death notification successful");
+ }
+ }
+}
+
+jboolean GnssHal::setCallback() {
+ if (gnssHalAidl != nullptr) {
+ sp<IGnssCallbackAidl> gnssCbIfaceAidl = new GnssCallbackAidl();
+ auto status = gnssHalAidl->setCallback(gnssCbIfaceAidl);
+ if (!checkAidlStatus(status, "IGnssAidl setCallback() failed.")) {
+ return JNI_FALSE;
+ }
+ }
+ if (gnssHal != nullptr) {
+ Return<bool> result = false;
+ sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallbackHidl();
+ if (gnssHal_V2_1 != nullptr) {
+ result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
+ } else if (gnssHal_V2_0 != nullptr) {
+ result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
+ } else if (gnssHal_V1_1 != nullptr) {
+ result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
+ } else {
+ result = gnssHal->setCallback(gnssCbIface);
+ }
+ if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
+ return JNI_FALSE;
+ }
+ }
+ return JNI_TRUE;
+}
+
+void GnssHal::close() {
+ if (gnssHalAidl != nullptr) {
+ auto status = gnssHalAidl->close();
+ checkAidlStatus(status, "IGnssAidl close() failed.");
+ }
+
+ if (gnssHal != nullptr) {
+ auto result = gnssHal->cleanup();
+ checkHidlReturn(result, "IGnss cleanup() failed.");
+ }
+}
+
+jboolean GnssHal::start() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->start();
+ return checkAidlStatus(status, "IGnssAidl start() failed.");
+ }
+
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+
+ auto result = gnssHal->start();
+ return checkHidlReturn(result, "IGnss start() failed.");
+}
+
+jboolean GnssHal::stop() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stop();
+ return checkAidlStatus(status, "IGnssAidl stop() failed.");
+ }
+
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+
+ auto result = gnssHal->stop();
+ return checkHidlReturn(result, "IGnss stop() failed.");
+}
+
+jboolean GnssHal::startSvStatus() {
+ isSvStatusRegistered = true;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->startSvStatus();
+ return checkAidlStatus(status, "IGnssAidl startSvStatus() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jboolean GnssHal::stopSvStatus() {
+ isSvStatusRegistered = false;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stopSvStatus();
+ return checkAidlStatus(status, "IGnssAidl stopSvStatus() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jboolean GnssHal::startNmea() {
+ isNmeaRegistered = true;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->startNmea();
+ return checkAidlStatus(status, "IGnssAidl startNmea() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jboolean GnssHal::stopNmea() {
+ isNmeaRegistered = false;
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->stopNmea();
+ return checkAidlStatus(status, "IGnssAidl stopNmea() failed.");
+ }
+ if (gnssHal == nullptr) {
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+jint GnssHal::readNmea(jbyteArray& nmeaArray, jint& buffer_size) {
+ // this should only be called from within a call to reportNmea
+ JNIEnv* env = getJniEnv();
+ jbyte* nmea = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(nmeaArray, 0));
+ int length = GnssCallbackHidl::sNmeaStringLength;
+ if (length > buffer_size) {
+ length = buffer_size;
+ }
+ memcpy(nmea, GnssCallbackHidl::sNmeaString, length);
+ env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
+ return (jint)length;
+}
+
+jboolean GnssHal::setPositionMode(jint mode, jint recurrence, jint min_interval,
+ jint preferred_accuracy, jint preferred_time,
+ jboolean low_power_mode) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ IGnssAidl::PositionModeOptions options;
+ options.mode = static_cast<IGnssAidl::GnssPositionMode>(mode);
+ options.recurrence = static_cast<IGnssAidl::GnssPositionRecurrence>(recurrence);
+ options.minIntervalMs = min_interval;
+ options.preferredAccuracyMeters = preferred_accuracy;
+ options.preferredTimeMs = preferred_time;
+ options.lowPowerMode = low_power_mode;
+ auto status = gnssHalAidl->setPositionMode(options);
+ return checkAidlStatus(status, "IGnssAidl setPositionMode() failed.");
+ }
+
+ Return<bool> result = false;
+ if (gnssHal_V1_1 != nullptr) {
+ result = gnssHal_V1_1->setPositionMode_1_1(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
+ static_cast<IGnss_V1_0::GnssPositionRecurrence>(
+ recurrence),
+ min_interval, preferred_accuracy, preferred_time,
+ low_power_mode);
+ } else if (gnssHal != nullptr) {
+ result = gnssHal->setPositionMode(static_cast<IGnss_V1_0::GnssPositionMode>(mode),
+ static_cast<IGnss_V1_0::GnssPositionRecurrence>(
+ recurrence),
+ min_interval, preferred_accuracy, preferred_time);
+ }
+ return checkHidlReturn(result, "IGnss setPositionMode() failed.");
+}
+
+void GnssHal::deleteAidingData(jint flags) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->deleteAidingData(static_cast<IGnssAidl::GnssAidingData>(flags));
+ checkAidlStatus(status, "IGnssAidl deleteAidingData() failed.");
+ return;
+ }
+
+ if (gnssHal == nullptr) {
+ return;
+ }
+
+ auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
+ checkHidlReturn(result, "IGnss deleteAidingData() failed.");
+}
+
+void GnssHal::injectTime(jlong time, jlong timeReference, jint uncertainty) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ auto status = gnssHalAidl->injectTime(time, timeReference, uncertainty);
+ checkAidlStatus(status, "IGnssAidl injectTime() failed.");
+ return;
+ }
+
+ if (gnssHal == nullptr) {
+ return;
+ }
+ auto result = gnssHal->injectTime(time, timeReference, uncertainty);
+ checkHidlReturn(result, "IGnss injectTime() failed.");
+}
+
+void GnssHal::injectLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ GnssLocationAidl location =
+ createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto status = gnssHalAidl->injectLocation(location);
+ checkAidlStatus(status, "IGnssAidl injectLocation() failed.");
+ return;
+ }
+
+ if (gnssHal == nullptr) {
+ return;
+ }
+ auto result =
+ gnssHal->injectLocation(latitudeDegrees, longitudeDegrees, horizontalAccuracyMeters);
+ checkHidlReturn(result, "IGnss injectLocation() failed.");
+}
+
+void GnssHal::injectBestLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags,
+ jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ GnssLocationAidl location =
+ createGnssLocation(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
+ elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto status = gnssHalAidl->injectBestLocation(location);
+ checkAidlStatus(status, "IGnssAidl injectBestLocation() failed.");
+ return;
+ }
+
+ if (gnssHal_V2_0 != nullptr) {
+ GnssLocation_V2_0 location =
+ createGnssLocation_V2_0(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp, elapsedRealtimeFlags, elapsedRealtimeNanos,
+ elapsedRealtimeUncertaintyNanos);
+ auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
+ checkHidlReturn(result, "IGnss injectBestLocation_2_0() failed.");
+ return;
+ }
+
+ if (gnssHal_V1_1 != nullptr) {
+ GnssLocation_V1_0 location =
+ createGnssLocation_V1_0(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
+ altitudeMeters, speedMetersPerSec, bearingDegrees,
+ horizontalAccuracyMeters, verticalAccuracyMeters,
+ speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
+ timestamp);
+ auto result = gnssHal_V1_1->injectBestLocation(location);
+ checkHidlReturn(result, "IGnss injectBestLocation() failed.");
+ return;
+ }
+
+ ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
+}
+
+std::unique_ptr<AGnssInterface> GnssHal::getAGnssInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IAGnssAidl> agnssAidl;
+ auto status = gnssHalAidl->getExtensionAGnss(&agnssAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to AGnss interface.")) {
+ return std::make_unique<gnss::AGnss>(agnssAidl);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto agnss_V2_0 = gnssHal_V2_0->getExtensionAGnss_2_0();
+ if (checkHidlReturn(agnss_V2_0, "Unable to get a handle to AGnss_V2_0")) {
+ return std::make_unique<gnss::AGnss_V2_0>(agnss_V2_0);
+ }
+ } else if (gnssHal != nullptr) {
+ auto agnss_V1_0 = gnssHal->getExtensionAGnss();
+ if (checkHidlReturn(agnss_V1_0, "Unable to get a handle to AGnss_V1_0")) {
+ return std::make_unique<gnss::AGnss_V1_0>(agnss_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<AGnssRilInterface> GnssHal::getAGnssRilInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IAGnssRilAidl> agnssRilAidl;
+ auto status = gnssHalAidl->getExtensionAGnssRil(&agnssRilAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to AGnssRil interface.")) {
+ return std::make_unique<gnss::AGnssRil>(agnssRilAidl);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto agnssRil_V2_0 = gnssHal_V2_0->getExtensionAGnssRil_2_0();
+ if (checkHidlReturn(agnssRil_V2_0, "Unable to get a handle to AGnssRil_V2_0")) {
+ return std::make_unique<gnss::AGnssRil_V2_0>(agnssRil_V2_0);
+ }
+ } else if (gnssHal != nullptr) {
+ auto agnssRil_V1_0 = gnssHal->getExtensionAGnssRil();
+ if (checkHidlReturn(agnssRil_V1_0, "Unable to get a handle to AGnssRil_V1_0")) {
+ return std::make_unique<gnss::AGnssRil_V1_0>(agnssRil_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssNavigationMessageInterface> GnssHal::getGnssNavigationMessageInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<hardware::gnss::IGnssNavigationMessageInterface> gnssNavigationMessage;
+ auto status = gnssHalAidl->getExtensionGnssNavigationMessage(&gnssNavigationMessage);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssNavigationMessage AIDL interface.")) {
+ return std::make_unique<gnss::GnssNavigationMessageAidl>(gnssNavigationMessage);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssNavigationMessage = gnssHal->getExtensionGnssNavigationMessage();
+ if (checkHidlReturn(gnssNavigationMessage,
+ "Unable to get a handle to GnssNavigationMessage interface.")) {
+ return std::make_unique<gnss::GnssNavigationMessageHidl>(gnssNavigationMessage);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssMeasurementInterface> GnssHal::getGnssMeasurementInterface() {
+ // Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
+ // 2.1@IGnss can be paired with {1.0, 1,1, 2.0, 2.1}@IGnssMeasurement
+ // 2.0@IGnss can be paired with {1.0, 1,1, 2.0}@IGnssMeasurement
+ // 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement
+ // 1.0@IGnss is paired with 1.0@IGnssMeasurement
+ if (gnssHalAidl != nullptr) {
+ sp<hardware::gnss::IGnssMeasurementInterface> gnssMeasurement;
+ auto status = gnssHalAidl->getExtensionGnssMeasurement(&gnssMeasurement);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssMeasurement AIDL interface.")) {
+ return std::make_unique<android::gnss::GnssMeasurement>(gnssMeasurement);
+ }
+ }
+ if (gnssHal_V2_1 != nullptr) {
+ auto gnssMeasurement = gnssHal_V2_1->getExtensionGnssMeasurement_2_1();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_1")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V2_1>(gnssMeasurement);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V2_0")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V2_0>(gnssMeasurement);
+ }
+ }
+ if (gnssHal_V1_1 != nullptr) {
+ auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_1")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V1_1>(gnssMeasurement);
+ }
+ }
+ if (gnssHal != nullptr) {
+ auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
+ if (checkHidlReturn(gnssMeasurement, "Unable to get a handle to GnssMeasurement_V1_0")) {
+ return std::make_unique<android::gnss::GnssMeasurement_V1_0>(gnssMeasurement);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssDebugInterface> GnssHal::getGnssDebugInterface() {
+ // Allow all causal combinations between IGnss.hal and IGnssDebug.hal. That means,
+ // 2.0@IGnss can be paired with {1.0, 2.0}@IGnssDebug
+ // 1.0@IGnss is paired with 1.0@IGnssDebug
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IGnssDebugAidl> gnssDebugAidl;
+ auto status = gnssHalAidl->getExtensionGnssDebug(&gnssDebugAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssDebug interface.")) {
+ return std::make_unique<gnss::GnssDebug>(gnssDebugAidl);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssDebug_V2_0 = gnssHal_V2_0->getExtensionGnssDebug_2_0();
+ if (checkHidlReturn(gnssDebug_V2_0, "Unable to get a handle to GnssDebug_V2_0.")) {
+ return std::make_unique<gnss::GnssDebug_V2_0>(gnssDebug_V2_0);
+ }
+ }
+ if (gnssHal != nullptr) {
+ auto gnssDebug_V1_0 = gnssHal->getExtensionGnssDebug();
+ if (checkHidlReturn(gnssDebug_V1_0, "Unable to get a handle to GnssDebug_V1_0.")) {
+ return std::make_unique<gnss::GnssDebug_V1_0>(gnssDebug_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssConfigurationInterface> GnssHal::getGnssConfigurationInterface() {
+ if (gnssHalAidl != nullptr) {
+ sp<IGnssConfigurationAidl> gnssConfigurationAidl;
+ auto status = gnssHalAidl->getExtensionGnssConfiguration(&gnssConfigurationAidl);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssConfiguration AIDL interface.")) {
+ return std::make_unique<android::gnss::GnssConfiguration>(gnssConfigurationAidl);
+ }
+ } else if (gnssHal_V2_1 != nullptr) {
+ auto gnssConfiguration = gnssHal_V2_1->getExtensionGnssConfiguration_2_1();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V2_1")) {
+ return std::make_unique<android::gnss::GnssConfiguration_V2_1>(gnssConfiguration);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V2_0")) {
+ return std::make_unique<android::gnss::GnssConfiguration_V2_0>(gnssConfiguration);
+ }
+ } else if (gnssHal_V1_1 != nullptr) {
+ auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V1_1")) {
+ return std::make_unique<gnss::GnssConfiguration_V1_1>(gnssConfiguration);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
+ if (checkHidlReturn(gnssConfiguration,
+ "Unable to get a handle to GnssConfiguration_V1_0")) {
+ return std::make_unique<gnss::GnssConfiguration_V1_0>(gnssConfiguration);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssGeofenceInterface> GnssHal::getGnssGeofenceInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<hardware::gnss::IGnssGeofence> gnssGeofence;
+ auto status = gnssHalAidl->getExtensionGnssGeofence(&gnssGeofence);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssGeofence AIDL interface.")) {
+ return std::make_unique<gnss::GnssGeofenceAidl>(gnssGeofence);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
+ if (checkHidlReturn(gnssGeofencing, "Unable to get a handle to GnssGeofencing")) {
+ return std::make_unique<gnss::GnssGeofenceHidl>(gnssGeofencing);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssBatchingInterface> GnssHal::getGnssBatchingInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<android::hardware::gnss::IGnssBatching> gnssBatchingAidl;
+ auto status = gnssHalAidl->getExtensionGnssBatching(&gnssBatchingAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssBatching interface.")) {
+ return std::make_unique<gnss::GnssBatching>(gnssBatchingAidl);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssBatching_V2_0 = gnssHal_V2_0->getExtensionGnssBatching_2_0();
+ if (checkHidlReturn(gnssBatching_V2_0, "Unable to get a handle to GnssBatching_V2_0")) {
+ return std::make_unique<gnss::GnssBatching_V2_0>(gnssBatching_V2_0);
+ }
+ }
+ if (gnssHal != nullptr) {
+ auto gnssBatching_V1_0 = gnssHal->getExtensionGnssBatching();
+ if (checkHidlReturn(gnssBatching_V1_0, "Unable to get a handle to GnssBatching")) {
+ return std::make_unique<gnss::GnssBatching_V1_0>(gnssBatching_V1_0);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<MeasurementCorrectionsInterface> GnssHal::getMeasurementCorrectionsInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<android::hardware::gnss::measurement_corrections::IMeasurementCorrectionsInterface>
+ gnssMeasurementCorrectionsAidl;
+ auto status =
+ gnssHalAidl->getExtensionMeasurementCorrections(&gnssMeasurementCorrectionsAidl);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
+ return std::make_unique<gnss::MeasurementCorrectionsIface_Aidl>(
+ gnssMeasurementCorrectionsAidl);
+ }
+ }
+ if (gnssHal_V2_1 != nullptr) {
+ auto gnssCorrections = gnssHal_V2_1->getExtensionMeasurementCorrections_1_1();
+ if (checkHidlReturn(gnssCorrections,
+ "Unable to get a handle to GnssMeasurementCorrections HIDL "
+ "interface")) {
+ return std::make_unique<gnss::MeasurementCorrectionsIface_V1_1>(gnssCorrections);
+ }
+ }
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
+ if (checkHidlReturn(gnssCorrections,
+ "Unable to get a handle to GnssMeasurementCorrections HIDL "
+ "interface")) {
+ return std::make_unique<gnss::MeasurementCorrectionsIface_V1_0>(gnssCorrections);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssVisibilityControlInterface> GnssHal::getGnssVisibilityControlInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<android::hardware::gnss::visibility_control::IGnssVisibilityControl>
+ gnssVisibilityControlAidl;
+ auto status = gnssHalAidl->getExtensionGnssVisibilityControl(&gnssVisibilityControlAidl);
+ if (checkAidlStatus(status,
+ "Unable to get a handle to GnssVisibilityControl AIDL interface.")) {
+ return std::make_unique<gnss::GnssVisibilityControlAidl>(gnssVisibilityControlAidl);
+ }
+ } else if (gnssHal_V2_0 != nullptr) {
+ auto gnssVisibilityControlHidl = gnssHal_V2_0->getExtensionVisibilityControl();
+ if (checkHidlReturn(gnssVisibilityControlHidl,
+ "Unable to get a handle to GnssVisibilityControl HIDL interface")) {
+ return std::make_unique<gnss::GnssVisibilityControlHidl>(gnssVisibilityControlHidl);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssAntennaInfoInterface> GnssHal::getGnssAntennaInfoInterface() {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() >= 2) {
+ sp<IGnssAntennaInfoAidl> gnssAntennaInfoAidl;
+ auto status = gnssHalAidl->getExtensionGnssAntennaInfo(&gnssAntennaInfoAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssAntennaInfo interface.")) {
+ return std::make_unique<gnss::GnssAntennaInfoAidl>(gnssAntennaInfoAidl);
+ }
+ } else if (gnssHal_V2_1 != nullptr) {
+ auto gnssAntennaInfo_V2_1 = gnssHal_V2_1->getExtensionGnssAntennaInfo();
+ if (checkHidlReturn(gnssAntennaInfo_V2_1,
+ "Unable to get a handle to GnssAntennaInfo_V2_1")) {
+ return std::make_unique<gnss::GnssAntennaInfo_V2_1>(gnssAntennaInfo_V2_1);
+ }
+ }
+ return nullptr;
+}
+
+std::unique_ptr<GnssPsdsInterface> GnssHal::getGnssPsdsInterface() {
+ if (gnssHalAidl != nullptr) {
+ sp<IGnssPsds> gnssPsdsAidl;
+ auto status = gnssHalAidl->getExtensionPsds(&gnssPsdsAidl);
+ if (checkAidlStatus(status, "Unable to get a handle to PSDS interface.")) {
+ return std::make_unique<gnss::GnssPsdsAidl>(gnssPsdsAidl);
+ }
+ } else if (gnssHal != nullptr) {
+ auto gnssXtra = gnssHal->getExtensionXtra();
+ if (checkHidlReturn(gnssXtra, "Unable to get a handle to XTRA interface.")) {
+ return std::make_unique<gnss::GnssPsdsHidl>(gnssXtra);
+ }
+ }
+ return nullptr;
+}
+
+sp<hardware::gnss::IGnssPowerIndication> GnssHal::getGnssPowerIndicationInterface() {
+ if (gnssHalAidl != nullptr) {
+ sp<hardware::gnss::IGnssPowerIndication> gnssPowerIndication;
+ auto status = gnssHalAidl->getExtensionGnssPowerIndication(&gnssPowerIndication);
+ if (checkAidlStatus(status, "Unable to get a handle to GnssPowerIndication")) {
+ return gnssPowerIndication;
+ }
+ }
+ return nullptr;
+}
+
+sp<hardware::gnss::V1_0::IGnssNi> GnssHal::getGnssNiInterface() {
+ if (gnssHal != nullptr) {
+ auto gnssNi = gnssHal->getExtensionGnssNi();
+ if (checkHidlReturn(gnssNi, "Unable to get a handle to GnssNi")) {
+ return gnssNi;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/Gnss.h b/services/core/jni/gnss/Gnss.h
new file mode 100644
index 0000000..c6743d6
--- /dev/null
+++ b/services/core/jni/gnss/Gnss.h
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSS_H
+#define _ANDROID_SERVER_GNSS_GNSS_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <android/hardware/gnss/BnGnss.h>
+#include <log/log.h>
+
+#include "AGnss.h"
+#include "AGnssRil.h"
+#include "GnssAntennaInfo.h"
+#include "GnssBatching.h"
+#include "GnssCallback.h"
+#include "GnssConfiguration.h"
+#include "GnssDebug.h"
+#include "GnssGeofence.h"
+#include "GnssMeasurement.h"
+#include "GnssNavigationMessage.h"
+#include "GnssPsds.h"
+#include "GnssVisibilityControl.h"
+#include "MeasurementCorrections.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+struct GnssDeathRecipient : virtual public hardware::hidl_death_recipient {
+ // hidl_death_recipient interface
+ virtual void serviceDied(uint64_t cookie, const wp<hidl::base::V1_0::IBase>& who) override {
+ ALOGE("IGNSS hidl service failed, trying to recover...");
+
+ JNIEnv* env = android::AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(android::mCallbacksObj, method_reportGnssServiceDied);
+ }
+};
+
+class GnssHal {
+public:
+ GnssHal();
+ ~GnssHal() {}
+
+ jboolean isSupported();
+ jboolean setCallback();
+ jboolean start();
+ jboolean stop();
+ jboolean setPositionMode(jint mode, jint recurrence, jint min_interval, jint preferred_accuracy,
+ jint preferred_time, jboolean low_power_mode);
+ jboolean startSvStatus();
+ jboolean stopSvStatus();
+ jboolean startNmea();
+ jboolean stopNmea();
+ jint readNmea(jbyteArray& nmeaArray, jint& buffer_size);
+ void linkToDeath();
+ void close();
+ void deleteAidingData(jint flags);
+ void injectTime(jlong time, jlong timeReference, jint uncertainty);
+ void injectLocation(jint gnssLocationFlags, jdouble latitudeDegrees, jdouble longitudeDegrees,
+ jdouble altitudeMeters, jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos);
+ void injectBestLocation(jint gnssLocationFlags, jdouble latitudeDegrees,
+ jdouble longitudeDegrees, jdouble altitudeMeters,
+ jfloat speedMetersPerSec, jfloat bearingDegrees,
+ jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
+ jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
+ jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
+ jdouble elapsedRealtimeUncertaintyNanos);
+
+ std::unique_ptr<AGnssInterface> getAGnssInterface();
+ std::unique_ptr<AGnssRilInterface> getAGnssRilInterface();
+ std::unique_ptr<GnssNavigationMessageInterface> getGnssNavigationMessageInterface();
+ std::unique_ptr<GnssMeasurementInterface> getGnssMeasurementInterface();
+ std::unique_ptr<GnssDebugInterface> getGnssDebugInterface();
+ std::unique_ptr<GnssConfigurationInterface> getGnssConfigurationInterface();
+ std::unique_ptr<GnssGeofenceInterface> getGnssGeofenceInterface();
+ std::unique_ptr<GnssBatchingInterface> getGnssBatchingInterface();
+ std::unique_ptr<MeasurementCorrectionsInterface> getMeasurementCorrectionsInterface();
+ std::unique_ptr<GnssVisibilityControlInterface> getGnssVisibilityControlInterface();
+ std::unique_ptr<GnssAntennaInfoInterface> getGnssAntennaInfoInterface();
+ std::unique_ptr<GnssPsdsInterface> getGnssPsdsInterface();
+
+ sp<hardware::gnss::IGnssPowerIndication> getGnssPowerIndicationInterface();
+ sp<hardware::gnss::V1_0::IGnssNi> getGnssNiInterface();
+
+private:
+ sp<GnssDeathRecipient> gnssHalDeathRecipient = nullptr;
+ sp<hardware::gnss::V1_0::IGnss> gnssHal = nullptr;
+ sp<hardware::gnss::V1_1::IGnss> gnssHal_V1_1 = nullptr;
+ sp<hardware::gnss::V2_0::IGnss> gnssHal_V2_0 = nullptr;
+ sp<hardware::gnss::V2_1::IGnss> gnssHal_V2_1 = nullptr;
+ sp<hardware::gnss::IGnss> gnssHalAidl = nullptr;
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_Gnss_H
diff --git a/services/core/jni/gnss/GnssCallback.cpp b/services/core/jni/gnss/GnssCallback.cpp
new file mode 100644
index 0000000..b931e91
--- /dev/null
+++ b/services/core/jni/gnss/GnssCallback.cpp
@@ -0,0 +1,413 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "GnssCallbckJni"
+
+#include "GnssCallback.h"
+
+#include <hardware_legacy/power.h>
+
+#define WAKE_LOCK_NAME "GPS"
+
+namespace android::gnss {
+
+using android::hardware::gnss::V1_0::GnssLocationFlags;
+using binder::Status;
+using hardware::hidl_vec;
+using hardware::Return;
+using hardware::Void;
+
+using GnssLocationAidl = android::hardware::gnss::GnssLocation;
+using GnssLocation_V1_0 = android::hardware::gnss::V1_0::GnssLocation;
+using GnssLocation_V2_0 = android::hardware::gnss::V2_0::GnssLocation;
+using IGnssCallbackAidl = android::hardware::gnss::IGnssCallback;
+using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
+
+jmethodID method_reportGnssServiceDied;
+
+namespace {
+
+jmethodID method_reportLocation;
+jmethodID method_reportStatus;
+jmethodID method_reportSvStatus;
+jmethodID method_reportNmea;
+jmethodID method_setTopHalCapabilities;
+jmethodID method_setGnssYearOfHardware;
+jmethodID method_setGnssHardwareModelName;
+jmethodID method_requestLocation;
+jmethodID method_requestUtcTime;
+
+// Returns true if location has lat/long information.
+inline bool hasLatLong(const GnssLocationAidl& location) {
+ return (location.gnssLocationFlags & hardware::gnss::GnssLocation::HAS_LAT_LONG) != 0;
+}
+
+// Returns true if location has lat/long information.
+inline bool hasLatLong(const GnssLocation_V1_0& location) {
+ return (static_cast<uint32_t>(location.gnssLocationFlags) & GnssLocationFlags::HAS_LAT_LONG) !=
+ 0;
+}
+
+// Returns true if location has lat/long information.
+inline bool hasLatLong(const GnssLocation_V2_0& location) {
+ return hasLatLong(location.v1_0);
+}
+
+inline jboolean boolToJbool(bool value) {
+ return value ? JNI_TRUE : JNI_FALSE;
+}
+
+// Must match the value from GnssMeasurement.java
+const uint32_t SVID_FLAGS_HAS_BASEBAND_CN0 = (1 << 4);
+
+} // anonymous namespace
+
+bool isSvStatusRegistered = false;
+bool isNmeaRegistered = false;
+
+void Gnss_class_init_once(JNIEnv* env, jclass& clazz) {
+ method_reportLocation =
+ env->GetMethodID(clazz, "reportLocation", "(ZLandroid/location/Location;)V");
+ method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
+ method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F[F)V");
+ method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
+
+ method_setTopHalCapabilities = env->GetMethodID(clazz, "setTopHalCapabilities", "(I)V");
+ method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
+ method_setGnssHardwareModelName =
+ env->GetMethodID(clazz, "setGnssHardwareModelName", "(Ljava/lang/String;)V");
+
+ method_requestLocation = env->GetMethodID(clazz, "requestLocation", "(ZZ)V");
+ method_requestUtcTime = env->GetMethodID(clazz, "requestUtcTime", "()V");
+ method_reportGnssServiceDied = env->GetMethodID(clazz, "reportGnssServiceDied", "()V");
+}
+
+Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
+ ALOGD("GnssCallbackAidl::%s: %du\n", __func__, capabilities);
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue status) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) {
+ GnssCallbackHidl::gnssSvStatusCbImpl<std::vector<GnssSvInfo>, GnssSvInfo>(svInfoList);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssLocationCb(const hardware::gnss::GnssLocation& location) {
+ GnssCallbackHidl::gnssLocationCbImpl<hardware::gnss::GnssLocation>(location);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+ // In AIDL v1, if no listener is registered, do not report nmea to the framework.
+ if (getInterfaceVersion() <= 1) {
+ if (!isNmeaRegistered) {
+ return Status::ok();
+ }
+ }
+ JNIEnv* env = getJniEnv();
+ /*
+ * The Java code will call back to read these values.
+ * We do this to avoid creating unnecessary String objects.
+ */
+ GnssCallbackHidl::sNmeaString = nmea.c_str();
+ GnssCallbackHidl::sNmeaStringLength = nmea.size();
+
+ env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssAcquireWakelockCb() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssReleaseWakelockCb() {
+ release_wake_lock(WAKE_LOCK_NAME);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssSetSystemInfoCb(const GnssSystemInfo& info) {
+ ALOGD("%s: yearOfHw=%d, name=%s\n", __func__, info.yearOfHw, info.name.c_str());
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
+ jstring jstringName = env->NewStringUTF(info.name.c_str());
+ env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
+ if (jstringName) {
+ env->DeleteLocalRef(jstringName);
+ }
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestTimeCb() {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+Status GnssCallbackAidl::gnssRequestLocationCb(const bool independentFromGnss,
+ const bool isUserEmergency) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
+ boolToJbool(isUserEmergency));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+// Implementation of IGnssCallbackHidl
+
+Return<void> GnssCallbackHidl::gnssNameCb(const android::hardware::hidl_string& name) {
+ ALOGD("%s: name=%s\n", __func__, name.c_str());
+
+ JNIEnv* env = getJniEnv();
+ jstring jstringName = env->NewStringUTF(name.c_str());
+ env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName);
+ if (jstringName) {
+ env->DeleteLocalRef(jstringName);
+ }
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+
+ return Void();
+}
+
+const char* GnssCallbackHidl::sNmeaString = nullptr;
+size_t GnssCallbackHidl::sNmeaStringLength = 0;
+
+template <class T>
+Return<void> GnssCallbackHidl::gnssLocationCbImpl(const T& location) {
+ JNIEnv* env = getJniEnv();
+
+ jobject jLocation = translateGnssLocation(env, location);
+
+ env->CallVoidMethod(mCallbacksObj, method_reportLocation, boolToJbool(hasLatLong(location)),
+ jLocation);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ env->DeleteLocalRef(jLocation);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssLocationCb(const GnssLocation_V1_0& location) {
+ return gnssLocationCbImpl<GnssLocation_V1_0>(location);
+}
+
+Return<void> GnssCallbackHidl::gnssLocationCb_2_0(const GnssLocation_V2_0& location) {
+ return gnssLocationCbImpl<GnssLocation_V2_0>(location);
+}
+
+Return<void> GnssCallbackHidl::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValue status) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+template <>
+uint32_t GnssCallbackHidl::getHasBasebandCn0DbHzFlag(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svStatus) {
+ return SVID_FLAGS_HAS_BASEBAND_CN0;
+}
+
+template <>
+uint32_t GnssCallbackHidl::getHasBasebandCn0DbHzFlag(
+ const std::vector<IGnssCallbackAidl::GnssSvInfo>& svStatus) {
+ return SVID_FLAGS_HAS_BASEBAND_CN0;
+}
+
+template <>
+double GnssCallbackHidl::getBasebandCn0DbHz(
+ const std::vector<IGnssCallbackAidl::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i].basebandCN0DbHz;
+}
+
+template <>
+double GnssCallbackHidl::getBasebandCn0DbHz(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i].basebandCN0DbHz;
+}
+
+template <>
+uint32_t GnssCallbackHidl::getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
+ return svStatus.numSvs;
+}
+
+template <>
+uint32_t GnssCallbackHidl::getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus,
+ size_t i) {
+ return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
+}
+
+template <>
+uint32_t GnssCallbackHidl::getConstellationType(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+ return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
+}
+
+template <class T_list, class T_sv_info>
+Return<void> GnssCallbackHidl::gnssSvStatusCbImpl(const T_list& svStatus) {
+ // In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
+ if (!isSvStatusRegistered) {
+ return Void();
+ }
+
+ JNIEnv* env = getJniEnv();
+
+ uint32_t listSize = getGnssSvInfoListSize(svStatus);
+
+ jintArray svidWithFlagArray = env->NewIntArray(listSize);
+ jfloatArray cn0Array = env->NewFloatArray(listSize);
+ jfloatArray elevArray = env->NewFloatArray(listSize);
+ jfloatArray azimArray = env->NewFloatArray(listSize);
+ jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
+ jfloatArray basebandCn0Array = env->NewFloatArray(listSize);
+
+ jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
+ jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
+ jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
+ jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
+ jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);
+ jfloat* basebandCn0s = env->GetFloatArrayElements(basebandCn0Array, 0);
+
+ /*
+ * Read GNSS SV info.
+ */
+ for (size_t i = 0; i < listSize; ++i) {
+ enum ShiftWidth : uint8_t { SVID_SHIFT_WIDTH = 12, CONSTELLATION_TYPE_SHIFT_WIDTH = 8 };
+
+ const T_sv_info& info = getGnssSvInfoOfIndex(svStatus, i);
+ svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
+ (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+ static_cast<uint32_t>(info.svFlag);
+ cn0s[i] = info.cN0Dbhz;
+ elev[i] = info.elevationDegrees;
+ azim[i] = info.azimuthDegrees;
+ carrierFreq[i] = info.carrierFrequencyHz;
+ svidWithFlags[i] |= getHasBasebandCn0DbHzFlag(svStatus);
+ basebandCn0s[i] = getBasebandCn0DbHz(svStatus, i);
+ }
+
+ env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
+ env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
+ env->ReleaseFloatArrayElements(elevArray, elev, 0);
+ env->ReleaseFloatArrayElements(azimArray, azim, 0);
+ env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);
+ env->ReleaseFloatArrayElements(basebandCn0Array, basebandCn0s, 0);
+
+ env->CallVoidMethod(mCallbacksObj, method_reportSvStatus, static_cast<jint>(listSize),
+ svidWithFlagArray, cn0Array, elevArray, azimArray, carrierFreqArray,
+ basebandCn0Array);
+
+ env->DeleteLocalRef(svidWithFlagArray);
+ env->DeleteLocalRef(cn0Array);
+ env->DeleteLocalRef(elevArray);
+ env->DeleteLocalRef(azimArray);
+ env->DeleteLocalRef(carrierFreqArray);
+ env->DeleteLocalRef(basebandCn0Array);
+
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssNmeaCb(int64_t timestamp,
+ const ::android::hardware::hidl_string& nmea) {
+ // In HIDL, if no listener is registered, do not report nmea to the framework.
+ if (!isNmeaRegistered) {
+ return Void();
+ }
+ JNIEnv* env = getJniEnv();
+ /*
+ * The Java code will call back to read these values.
+ * We do this to avoid creating unnecessary String objects.
+ */
+ sNmeaString = nmea.c_str();
+ sNmeaStringLength = nmea.size();
+
+ env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssSetCapabilitesCb(uint32_t capabilities) {
+ ALOGD("%s: %du\n", __func__, capabilities);
+
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setTopHalCapabilities, capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
+ return GnssCallbackHidl::gnssSetCapabilitesCb(capabilities);
+}
+
+Return<void> GnssCallbackHidl::gnssSetCapabilitiesCb_2_1(uint32_t capabilities) {
+ return GnssCallbackHidl::gnssSetCapabilitesCb(capabilities);
+}
+
+Return<void> GnssCallbackHidl::gnssAcquireWakelockCb() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssReleaseWakelockCb() {
+ release_wake_lock(WAKE_LOCK_NAME);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssRequestTimeCb() {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssRequestLocationCb(const bool independentFromGnss) {
+ return GnssCallbackHidl::gnssRequestLocationCb_2_0(independentFromGnss, /* isUserEmergency= */
+ false);
+}
+
+Return<void> GnssCallbackHidl::gnssRequestLocationCb_2_0(const bool independentFromGnss,
+ const bool isUserEmergency) {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestLocation, boolToJbool(independentFromGnss),
+ boolToJbool(isUserEmergency));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+Return<void> GnssCallbackHidl::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSystemInfo& info) {
+ ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
+
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setGnssYearOfHardware, info.yearOfHw);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+} // namespace android::gnss
\ No newline at end of file
diff --git a/services/core/jni/gnss/GnssCallback.h b/services/core/jni/gnss/GnssCallback.h
new file mode 100644
index 0000000..a7f96fb
--- /dev/null
+++ b/services/core/jni/gnss/GnssCallback.h
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSCALLBACK_H
+#define _ANDROID_SERVER_GNSS_GNSSCALLBACK_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <android/hardware/gnss/BnGnssCallback.h>
+#include <log/log.h>
+
+#include <vector>
+
+#include "Utils.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+namespace {
+
+extern jmethodID method_reportLocation;
+extern jmethodID method_reportStatus;
+extern jmethodID method_reportSvStatus;
+extern jmethodID method_reportNmea;
+extern jmethodID method_setTopHalCapabilities;
+extern jmethodID method_setGnssYearOfHardware;
+extern jmethodID method_setGnssHardwareModelName;
+extern jmethodID method_requestLocation;
+extern jmethodID method_requestUtcTime;
+
+} // anonymous namespace
+
+extern bool isSvStatusRegistered;
+extern bool isNmeaRegistered;
+
+extern jmethodID method_reportGnssServiceDied;
+
+void Gnss_class_init_once(JNIEnv* env, jclass& clazz);
+
+/*
+ * GnssCallbackAidl class implements the callback methods for AIDL IGnssCallback interface.
+ */
+class GnssCallbackAidl : public hardware::gnss::BnGnssCallback {
+public:
+ binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
+ binder::Status gnssStatusCb(const GnssStatusValue status) override;
+ binder::Status gnssSvStatusCb(const std::vector<GnssSvInfo>& svInfoList) override;
+ binder::Status gnssLocationCb(const hardware::gnss::GnssLocation& location) override;
+ binder::Status gnssNmeaCb(const int64_t timestamp, const std::string& nmea) override;
+ binder::Status gnssAcquireWakelockCb() override;
+ binder::Status gnssReleaseWakelockCb() override;
+ binder::Status gnssSetSystemInfoCb(const GnssSystemInfo& info) override;
+ binder::Status gnssRequestTimeCb() override;
+ binder::Status gnssRequestLocationCb(const bool independentFromGnss,
+ const bool isUserEmergency) override;
+};
+
+/*
+ * GnssCallbackHidl class implements the callback methods for HIDL IGnssCallback interface.
+ */
+struct GnssCallbackHidl : public hardware::gnss::V2_1::IGnssCallback {
+ hardware::Return<void> gnssLocationCb(
+ const hardware::gnss::V1_0::GnssLocation& location) override;
+ hardware::Return<void> gnssStatusCb(
+ const hardware::gnss::V1_0::IGnssCallback::GnssStatusValue status) override;
+ hardware::Return<void> gnssSvStatusCb(
+ const hardware::gnss::V1_0::IGnssCallback::GnssSvStatus& svStatus) override {
+ return gnssSvStatusCbImpl<hardware::gnss::V1_0::IGnssCallback::GnssSvStatus,
+ hardware::gnss::V1_0::IGnssCallback::GnssSvInfo>(svStatus);
+ }
+ hardware::Return<void> gnssNmeaCb(int64_t timestamp,
+ const hardware::hidl_string& nmea) override;
+ hardware::Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
+ hardware::Return<void> gnssAcquireWakelockCb() override;
+ hardware::Return<void> gnssReleaseWakelockCb() override;
+ hardware::Return<void> gnssRequestTimeCb() override;
+ hardware::Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;
+
+ hardware::Return<void> gnssSetSystemInfoCb(
+ const hardware::gnss::V1_0::IGnssCallback::GnssSystemInfo& info) override;
+
+ // New in 1.1
+ hardware::Return<void> gnssNameCb(const hardware::hidl_string& name) override;
+
+ // New in 2.0
+ hardware::Return<void> gnssRequestLocationCb_2_0(const bool independentFromGnss,
+ const bool isUserEmergency) override;
+ hardware::Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
+ hardware::Return<void> gnssLocationCb_2_0(
+ const hardware::gnss::V2_0::GnssLocation& location) override;
+ hardware::Return<void> gnssSvStatusCb_2_0(
+ const hardware::hidl_vec<hardware::gnss::V2_0::IGnssCallback::GnssSvInfo>& svInfoList)
+ override {
+ return gnssSvStatusCbImpl<
+ hardware::hidl_vec<hardware::gnss::V2_0::IGnssCallback::GnssSvInfo>,
+ hardware::gnss::V1_0::IGnssCallback::GnssSvInfo>(svInfoList);
+ }
+
+ // New in 2.1
+ hardware::Return<void> gnssSvStatusCb_2_1(
+ const hardware::hidl_vec<hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>& svInfoList)
+ override {
+ return gnssSvStatusCbImpl<
+ hardware::hidl_vec<hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>,
+ hardware::gnss::V1_0::IGnssCallback::GnssSvInfo>(svInfoList);
+ }
+ hardware::Return<void> gnssSetCapabilitiesCb_2_1(uint32_t capabilities) override;
+
+ // TODO: Reconsider allocation cost vs threadsafety on these statics
+ static const char* sNmeaString;
+ static size_t sNmeaStringLength;
+
+ template <class T>
+ static hardware::Return<void> gnssLocationCbImpl(const T& location);
+
+ template <class T_list, class T_sv_info>
+ static hardware::Return<void> gnssSvStatusCbImpl(const T_list& svStatus);
+
+private:
+ template <class T>
+ static uint32_t getHasBasebandCn0DbHzFlag(const T& svStatus) {
+ return 0;
+ }
+
+ template <class T>
+ static double getBasebandCn0DbHz(const T& svStatus, size_t i) {
+ return 0.0;
+ }
+
+ template <class T>
+ static uint32_t getGnssSvInfoListSize(const T& svInfoList) {
+ return svInfoList.size();
+ }
+
+ static const hardware::gnss::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const std::vector<hardware::gnss::IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i];
+ }
+
+ static const hardware::gnss::V1_0::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hardware::gnss::V1_0::IGnssCallback::GnssSvStatus& svStatus, size_t i) {
+ return svStatus.gnssSvList.data()[i];
+ }
+
+ static const hardware::gnss::V1_0::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hardware::hidl_vec<hardware::gnss::V2_0::IGnssCallback::GnssSvInfo>& svInfoList,
+ size_t i) {
+ return svInfoList[i].v1_0;
+ }
+
+ static const hardware::gnss::V1_0::IGnssCallback::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hardware::hidl_vec<hardware::gnss::V2_1::IGnssCallback::GnssSvInfo>& svInfoList,
+ size_t i) {
+ return svInfoList[i].v2_0.v1_0;
+ }
+
+ template <class T>
+ static uint32_t getConstellationType(const T& svInfoList, size_t i) {
+ return static_cast<uint32_t>(svInfoList[i].constellation);
+ }
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSCALLBACK_H
\ No newline at end of file
diff --git a/services/core/jni/gnss/GnssDebug.cpp b/services/core/jni/gnss/GnssDebug.cpp
index da53317..263a6c6 100644
--- a/services/core/jni/gnss/GnssDebug.cpp
+++ b/services/core/jni/gnss/GnssDebug.cpp
@@ -104,4 +104,10 @@
return satelliteDataArray[i];
}
+template <>
+int64_t GnssDebugUtil::getTimeEstimateMs(
+ const android::hardware::gnss::IGnssDebug::DebugData& data) {
+ return data.time.timeEstimateMs;
+}
+
} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssDebug.h b/services/core/jni/gnss/GnssDebug.h
index 1e1a7b4..e02c2ac 100644
--- a/services/core/jni/gnss/GnssDebug.h
+++ b/services/core/jni/gnss/GnssDebug.h
@@ -113,12 +113,6 @@
return data.time.timeEstimate;
}
-template <>
-int64_t GnssDebugUtil::getTimeEstimateMs(
- const android::hardware::gnss::IGnssDebug::DebugData& data) {
- return data.time.timeEstimateMs;
-}
-
template <class T_DebugData, class T_SatelliteData>
jstring GnssDebugUtil::parseDebugData(JNIEnv* env, std::stringstream& internalState,
const T_DebugData& data) {
diff --git a/services/core/jni/gnss/GnssPsds.cpp b/services/core/jni/gnss/GnssPsds.cpp
new file mode 100644
index 0000000..51a1450
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsds.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Define LOG_TAG before <log/log.h> to overwrite the default value.
+#define LOG_TAG "GnssPsdsJni"
+
+#include "GnssPsds.h"
+
+#include "Utils.h"
+
+using android::hardware::hidl_bitfield;
+using android::hardware::gnss::PsdsType;
+using IGnssPsdsAidl = android::hardware::gnss::IGnssPsds;
+using IGnssPsdsHidl = android::hardware::gnss::V1_0::IGnssXtra;
+
+namespace android::gnss {
+
+// Implementation of GnssPsds (AIDL HAL)
+
+GnssPsdsAidl::GnssPsdsAidl(const sp<IGnssPsdsAidl>& iGnssPsds) : mIGnssPsds(iGnssPsds) {
+ assert(mIGnssPsds != nullptr);
+}
+
+jboolean GnssPsdsAidl::setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) {
+ auto status = mIGnssPsds->setCallback(callback->getAidl());
+ return checkAidlStatus(status, "IGnssPsdsAidl setCallback() failed.");
+}
+
+void GnssPsdsAidl::injectPsdsData(const jbyteArray& data, const jint& length,
+ const jint& psdsType) {
+ JNIEnv* env = getJniEnv();
+ jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(data, 0));
+ auto status = mIGnssPsds->injectPsdsData(static_cast<PsdsType>(psdsType),
+ std::vector<uint8_t>((const uint8_t*)bytes,
+ (const uint8_t*)bytes + length));
+ checkAidlStatus(status, "IGnssPsdsAidl injectPsdsData() failed.");
+ env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+}
+
+// Implementation of GnssPsdsHidl
+
+GnssPsdsHidl::GnssPsdsHidl(const sp<android::hardware::gnss::V1_0::IGnssXtra>& iGnssXtra)
+ : mIGnssXtra(iGnssXtra) {
+ assert(mIGnssXtra != nullptr);
+}
+
+jboolean GnssPsdsHidl::setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) {
+ auto result = mIGnssXtra->setCallback(callback->getHidl());
+ return checkHidlReturn(result, "IGnssPsdsHidl setCallback() failed.");
+}
+
+void GnssPsdsHidl::injectPsdsData(const jbyteArray& data, const jint& length, const jint&) {
+ JNIEnv* env = getJniEnv();
+ jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(data, 0));
+ auto result = mIGnssXtra->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
+ env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssPsds.h b/services/core/jni/gnss/GnssPsds.h
new file mode 100644
index 0000000..6b65ee8
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsds.h
@@ -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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSPSDS_H
+#define _ANDROID_SERVER_GNSS_GNSSPSDS_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnssXtra.h>
+#include <android/hardware/gnss/BnGnssPsds.h>
+#include <log/log.h>
+
+#include "GnssPsdsCallback.h"
+#include "jni.h"
+
+namespace android::gnss {
+
+class GnssPsdsInterface {
+public:
+ virtual ~GnssPsdsInterface() {}
+ virtual jboolean setCallback(const std::unique_ptr<GnssPsdsCallback>& callback);
+ virtual void injectPsdsData(const jbyteArray& data, const jint& length, const jint& psdsType);
+};
+
+class GnssPsdsAidl : public GnssPsdsInterface {
+public:
+ GnssPsdsAidl(const sp<android::hardware::gnss::IGnssPsds>& iGnssPsds);
+ jboolean setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) override;
+ void injectPsdsData(const jbyteArray& data, const jint& length, const jint& psdsType) override;
+
+private:
+ const sp<android::hardware::gnss::IGnssPsds> mIGnssPsds;
+};
+
+class GnssPsdsHidl : public GnssPsdsInterface {
+public:
+ GnssPsdsHidl(const sp<android::hardware::gnss::V1_0::IGnssXtra>& iGnssXtra);
+ jboolean setCallback(const std::unique_ptr<GnssPsdsCallback>& callback) override;
+ void injectPsdsData(const jbyteArray& data, const jint& length, const jint& psdsType) override;
+
+private:
+ const sp<android::hardware::gnss::V1_0::IGnssXtra> mIGnssXtra;
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSPSDS_H
diff --git a/services/core/jni/gnss/GnssPsdsCallback.cpp b/services/core/jni/gnss/GnssPsdsCallback.cpp
new file mode 100644
index 0000000..1dd7022
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsdsCallback.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define LOG_TAG "GnssPsdsCbJni"
+
+#include "GnssPsdsCallback.h"
+
+#include <vector>
+
+#include "Utils.h"
+
+namespace android::gnss {
+
+namespace {
+jmethodID method_psdsDownloadRequest;
+} // anonymous namespace
+
+using binder::Status;
+using hardware::Return;
+using hardware::Void;
+using hardware::gnss::PsdsType;
+
+void GnssPsds_class_init_once(JNIEnv* env, jclass clazz) {
+ method_psdsDownloadRequest = env->GetMethodID(clazz, "psdsDownloadRequest", "(I)V");
+}
+
+// Implementation of android::hardware::gnss::IGnssPsdsCallback
+
+Status GnssPsdsCallbackAidl::downloadRequestCb(PsdsType psdsType) {
+ ALOGD("%s. psdsType: %d", __func__, static_cast<int32_t>(psdsType));
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, psdsType);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Status::ok();
+}
+
+// Implementation of android::hardware::gnss::V1_0::IGnssPsdsCallback
+
+Return<void> GnssPsdsCallbackHidl::downloadRequestCb() {
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_psdsDownloadRequest, /* psdsType= */ 1);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+} // namespace android::gnss
diff --git a/services/core/jni/gnss/GnssPsdsCallback.h b/services/core/jni/gnss/GnssPsdsCallback.h
new file mode 100644
index 0000000..3ac7473
--- /dev/null
+++ b/services/core/jni/gnss/GnssPsdsCallback.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_GNSS_GNSSPSDSCALLBACK_H
+#define _ANDROID_SERVER_GNSS_GNSSPSDSCALLBACK_H
+
+#pragma once
+
+#ifndef LOG_TAG
+#error LOG_TAG must be defined before including this file.
+#endif
+
+#include <android/hardware/gnss/1.0/IGnssXtraCallback.h>
+#include <android/hardware/gnss/BnGnssPsdsCallback.h>
+#include <log/log.h>
+
+#include "jni.h"
+
+namespace android::gnss {
+
+namespace {
+extern jmethodID method_psdsDownloadRequest;
+} // anonymous namespace
+
+void GnssPsds_class_init_once(JNIEnv* env, jclass clazz);
+
+class GnssPsdsCallbackAidl : public hardware::gnss::BnGnssPsdsCallback {
+public:
+ GnssPsdsCallbackAidl() {}
+ binder::Status downloadRequestCb(hardware::gnss::PsdsType psdsType) override;
+};
+
+class GnssPsdsCallbackHidl : public hardware::gnss::V1_0::IGnssXtraCallback {
+public:
+ GnssPsdsCallbackHidl() {}
+ hardware::Return<void> downloadRequestCb() override;
+};
+
+class GnssPsdsCallback {
+public:
+ GnssPsdsCallback() {}
+ sp<GnssPsdsCallbackAidl> getAidl() {
+ if (callbackAidl == nullptr) {
+ callbackAidl = sp<GnssPsdsCallbackAidl>::make();
+ }
+ return callbackAidl;
+ }
+
+ sp<GnssPsdsCallbackHidl> getHidl() {
+ if (callbackHidl == nullptr) {
+ callbackHidl = sp<GnssPsdsCallbackHidl>::make();
+ }
+ return callbackHidl;
+ }
+
+private:
+ sp<GnssPsdsCallbackAidl> callbackAidl;
+ sp<GnssPsdsCallbackHidl> callbackHidl;
+};
+
+} // namespace android::gnss
+
+#endif // _ANDROID_SERVER_GNSS_GNSSPSDSCALLBACK_H
\ No newline at end of file
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 33e97aa..5aa3dfe 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1999,9 +1999,6 @@
mOwners.load();
setDeviceOwnershipSystemPropertyLocked();
findOwnerComponentIfNecessaryLocked();
-
- // TODO PO may not have a class name either due to b/17652534. Address that too.
- updateDeviceOwnerLocked();
}
}
@@ -3142,23 +3139,6 @@
}
}
- private void updateDeviceOwnerLocked() {
- long ident = mInjector.binderClearCallingIdentity();
- try {
- // TODO This is to prevent DO from getting "clear data"ed, but it should also check the
- // user id and also protect all other DAs too.
- final ComponentName deviceOwnerComponent = mOwners.getDeviceOwnerComponent();
- if (deviceOwnerComponent != null) {
- mInjector.getIActivityManager()
- .updateDeviceOwner(deviceOwnerComponent.getPackageName());
- }
- } catch (RemoteException e) {
- // Not gonna happen.
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
- }
-
static void validateQualityConstant(int quality) {
switch (quality) {
case PASSWORD_QUALITY_UNSPECIFIED:
@@ -8590,7 +8570,6 @@
mOwners.setDeviceOwner(admin, ownerName, userId);
mOwners.writeDeviceOwner();
- updateDeviceOwnerLocked();
setDeviceOwnershipSystemPropertyLocked();
//TODO(b/180371154): when provisionFullyManagedDevice is used in tests, remove this
@@ -8951,7 +8930,6 @@
mOwners.clearDeviceOwner();
mOwners.writeDeviceOwner();
- updateDeviceOwnerLocked();
clearDeviceOwnerUserRestriction(UserHandle.of(userId));
mInjector.securityLogSetLoggingEnabledProperty(false);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e895d37..5098abe 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -386,8 +386,8 @@
"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 @@
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 cd2d0fc..83ccabf 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 @@
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 d2358a0..023608c 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 @@
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 890a549..4e4854c 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 @@
@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 @@
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/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 2398e36..b601d14 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1137,9 +1137,6 @@
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
// Verify internal calls.
- verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
verify(getServices().userManager, times(1)).setUserRestriction(
eq(UserManager.DISALLOW_ADD_MANAGED_PROFILE),
eq(true), eq(UserHandle.SYSTEM));
@@ -1205,9 +1202,6 @@
assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
// Verify internal calls.
- verify(getServices().iactivityManager).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
verify(mContext.spiedContext).sendBroadcastAsUser(
MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
@@ -1392,11 +1386,6 @@
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
-
- // Verify internal calls.
- verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
@@ -1501,11 +1490,6 @@
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
dpm.setActiveAdmin(admin1, /* replace =*/ false);
assertThat(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)).isTrue();
-
- // Verify internal calls.
- verify(getServices().iactivityManager, times(1)).updateDeviceOwner(
- eq(admin1.getPackageName()));
-
assertThat(dpm.getDeviceOwnerComponentOnAnyUser()).isEqualTo(admin1);
// Now call clear from the secondary user, which should throw.
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 c771000..0287510 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.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 @@
*/
@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 @@
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 ca5b0cb..0b3ef45 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 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 @@
private ActivityTaskManagerInternal mMockActivityTaskManager;
@Mock
private ActivityManagerInternal mMockActivityManager;
+ @Mock
+ PackageMonitor mMockPackageMonitor;
@Before
public void setUp() throws Exception {
@@ -93,6 +96,7 @@
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 @@
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 b0fc636..ad9be0d 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 @@
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 @@
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/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f57c32c..0394a54 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4189,7 +4189,8 @@
* {@link UiccSlotMapping} which consist of both physical slot index and port index.
* Logical slot is the slot that is seen by modem. Physical slot is the actual physical slot.
* Port index is the index (enumerated value) for the associated port available on the SIM.
- * Each physical slot can have multiple ports if multi-enabled profile(MEP) is supported.
+ * Each physical slot can have multiple ports if
+ * {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP} is supported.
*
* Example: no. of logical slots 1 and physical slots 2 do not support MEP, each physical slot
* has one port:
@@ -4285,11 +4286,11 @@
/**
* Get the mapping from logical slots to physical sim slots and port indexes. Initially the
* logical slot index was mapped to physical slot index, but with support for multi-enabled
- * profile(MEP) logical slot is now mapped to port index.
+ * profile(MEP){@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP},logical slot is now mapped to
+ * port index.
*
* @return a collection of {@link UiccSlotMapping} which indicates the mapping from logical
* slots to ports and physical slots.
- *
* @hide
*/
@SystemApi
diff --git a/telephony/java/android/telephony/UiccCardInfo.java b/telephony/java/android/telephony/UiccCardInfo.java
index 30ca162..3843a62 100644
--- a/telephony/java/android/telephony/UiccCardInfo.java
+++ b/telephony/java/android/telephony/UiccCardInfo.java
@@ -17,6 +17,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -147,9 +148,10 @@
* Note that this field may be omitted if the caller does not have the correct permissions
* (see {@link TelephonyManager#getUiccCardsInfo()}).
*
- * @deprecated with support for MEP(multiple enabled profile), a SIM card can have more than one
- * ICCID active at the same time.Instead use {@link UiccPortInfo#getIccId()} to retrieve ICCID.
- * To find {@link UiccPortInfo} use {@link UiccCardInfo#getPorts()}
+ * @deprecated with support for MEP(multiple enabled profile)
+ * {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, a SIM card can have more than one
+ * ICCID active at the same time. Instead use {@link UiccPortInfo#getIccId()} to retrieve ICCID.
+ * To find {@link UiccPortInfo} use {@link UiccCardInfo#getPorts()}.
*
* @throws UnsupportedOperationException if the calling app's target SDK is T and beyond.
*/
@@ -192,11 +194,11 @@
}
/*
- * Whether the UICC card supports multiple enable profile(MEP)
+ * Whether the UICC card supports multiple enabled profile(MEP)
* UICCs are generally MEP disabled, there can be only one active profile on the physical
* sim card.
*
- * @return {@code true} if the eUICC is supporting multiple enabled profile(MEP).
+ * @return {@code true} if the UICC is supporting multiple enabled profile(MEP).
*/
public boolean isMultipleEnabledProfilesSupported() {
return mIsMultipleEnabledProfilesSupported;
@@ -205,6 +207,9 @@
/**
* Get information regarding port, ICCID and its active status.
*
+ * For device which support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, it should return
+ * more than one {@link UiccPortInfo} object if the card is eUICC.
+ *
* @return Collection of {@link UiccPortInfo}
*/
public @NonNull Collection<UiccPortInfo> getPorts() {
diff --git a/telephony/java/android/telephony/UiccPortInfo.java b/telephony/java/android/telephony/UiccPortInfo.java
index d1838c0..6fb0470 100644
--- a/telephony/java/android/telephony/UiccPortInfo.java
+++ b/telephony/java/android/telephony/UiccPortInfo.java
@@ -29,7 +29,9 @@
* Per GSMA SGP.22 V3.0, a port is a logical entity to which an active UICC profile can be bound on
* a UICC card. If UICC supports 2 ports, then the port index is numbered 0,1.
* Each port index is unique within an UICC, but not necessarily unique across UICC’s.
- * For UICC's does not support MEP(Multi-enabled profile), just return the default port index 0.
+ * For UICC's does not support MEP(Multi-enabled profile)
+ * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, just return the default
+ * port index 0.
*/
public final class UiccPortInfo implements Parcelable{
private final String mIccId;
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 17f34db..17ce450 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
@@ -225,6 +226,9 @@
/**
* Get Information regarding port, iccid and its active status.
*
+ * For device which support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP}, it should return
+ * more than one {@link UiccPortInfo} object if the card is eUICC.
+ *
* @return Collection of {@link UiccPortInfo}
*/
public @NonNull Collection<UiccPortInfo> getPorts() {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index b6ae530..4820d33 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -37,6 +37,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.TelephonyManager;
+import android.telephony.UiccCardInfo;
import android.telephony.euicc.EuiccCardManager.ResetOption;
import android.util.Log;
@@ -931,6 +932,21 @@
* intent to prompt the user to accept the download. The caller should also be authorized to
* manage the subscription to be downloaded.
*
+ * <p>If device support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP} and
+ * switchAfterDownload is {@code true}, the subscription will be enabled on an esim port based
+ * on the following selection rules:
+ * <ul>
+ * <li>In SS(Single SIM) mode, if the embedded slot already has an active port, then download
+ * and enable the subscription on this port.
+ * <li>In SS mode, if the embedded slot is not active, then try to download and enable the
+ * subscription on the default port 0 of eUICC.
+ * <li>In DSDS mode, find first available port to download and enable the subscription.
+ * (see {@link #isSimPortAvailable(int)})
+ *</ul>
+ * If there is no available port, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}
+ * will be returned in the callback intent to prompt the user to disable an already-active
+ * subscription.
+ *
* @param subscription the subscription to download.
* @param switchAfterDownload if true, the profile will be activated upon successful download.
* @param callbackIntent a PendingIntent to launch when the operation completes.
@@ -1141,14 +1157,25 @@
* intent to prompt the user to accept the download. The caller should also be authorized to
* manage the subscription to be enabled.
*
- * <p> From Android T, devices might support MEP(Multiple Enabled Profiles), the subscription
- * can be installed on different port from the eUICC. Calling apps with carrier privilege
- * (see {@link TelephonyManager#hasCarrierPrivileges}) over the currently active subscriptions
- * can use {@link #switchToSubscription(int, int, PendingIntent)} to specify which port to
- * enable the subscription. Otherwise, use this API to enable the subscription on the eUICC
- * and the platform will internally resolve a port. If there is no available port,
- * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} might be returned in the callback
- * intent to prompt the user to disable an already-active subscription.
+ * <p> From Android T, devices might support {@link PackageManager#FEATURE_TELEPHONY_EUICC_MEP},
+ * the subscription can be installed on different port from the eUICC. Calling apps with
+ * carrier privilege (see {@link TelephonyManager#hasCarrierPrivileges}) over the currently
+ * active subscriptions can use {@link #switchToSubscription(int, int, PendingIntent)} to
+ * specify which port to enable the subscription. Otherwise, use this API to enable the
+ * subscription on the eUICC and the platform will internally resolve a port based on following
+ * rules:
+ * <ul>
+ * <li>always use the default port 0 is eUICC does not support MEP.
+ * <li>In SS(Single SIM) mode, if the embedded slot already has an active port, then enable
+ * the subscription on this port.
+ * <li>In SS mode, if the embedded slot is not active, then try to enable the subscription on
+ * the default port 0 of eUICC.
+ * <li>In DSDS mode, find first available port to enable the subscription.
+ * (see {@link #isSimPortAvailable(int)})
+ *</ul>
+ * If there is no available port, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR}
+ * will be returned in the callback intent to prompt the user to disable an already-active
+ * subscription.
*
* @param subscriptionId the ID of the subscription to enable. May be
* {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
@@ -1197,7 +1224,15 @@
*
* <p> If the caller is passing invalid port index,
* an {@link #EMBEDDED_SUBSCRIPTION_RESULT_ERROR} with detailed error code
- * {@link #ERROR_INVALID_PORT} will be returned.
+ * {@link #ERROR_INVALID_PORT} will be returned. The port index is invalid if one of the
+ * following requirements is met:
+ * <ul>
+ * <li>index is beyond the range of {@link UiccCardInfo#getPorts()}.
+ * <li>In SS(Single SIM) mode, the embedded slot already has an active port with different
+ * port index.
+ * <li>In DSDS mode, if the psim slot is active and the embedded slot already has an active
+ * empty port with different port index.
+ * </ul>
*
* <p> Depending on the target port and permission check,
* an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} might be returned to the callback
@@ -1522,8 +1557,8 @@
/**
* Returns whether the passing portIndex is available.
- * A port is available if it has no profiles enabled on it or calling app has carrier privilege
- * over the profile installed on the selected port.
+ * A port is available if it is active without enabled profile on it or
+ * calling app has carrier privilege over the profile installed on the selected port.
* Always returns false if the cardId is a physical card.
*
* @param portIndex is an enumeration of the ports available on the UICC.
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 8d60466..4cddd85 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 @@
}
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 7ee6451..5bd365c 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 @@
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 b66c45c7..a135e0a 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 @@
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 ba5698c..a9564fd 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 @@
}
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 19e2c92..7e3ed82 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 @@
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.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 @@
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 b5e13be..cc808a0 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 @@
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.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 @@
}
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 53560cc..4313b8d 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 @@
}
teardown {
test {
- testApp.exit()
+ testApp.exit(wmHelper)
}
}
}