diff options
104 files changed, 1391 insertions, 1051 deletions
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java index c251529ae0b1..e5b07429a5c6 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobService.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java @@ -125,7 +125,7 @@ public abstract class JobService extends Service { * will not be invoked. * * @param params Parameters specifying info about this job, including the optional - * extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle). + * extras configured with {@link JobInfo.Builder#setExtras(android.os.PersistableBundle)}. * This object serves to identify this specific running job instance when calling * {@link #jobFinished(JobParameters, boolean)}. * @return {@code true} if your service will continue running, using a separate thread diff --git a/core/api/current.txt b/core/api/current.txt index fa148475e529..17beece326df 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20246,6 +20246,7 @@ package android.location { public final class GnssMeasurementRequest implements android.os.Parcelable { method public int describeContents(); + method @IntRange(from=0) public int getIntervalMillis(); method public boolean isFullTracking(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.location.GnssMeasurementRequest> CREATOR; @@ -20256,6 +20257,7 @@ package android.location { ctor public GnssMeasurementRequest.Builder(@NonNull android.location.GnssMeasurementRequest); method @NonNull public android.location.GnssMeasurementRequest build(); method @NonNull public android.location.GnssMeasurementRequest.Builder setFullTracking(boolean); + method @NonNull public android.location.GnssMeasurementRequest.Builder setIntervalMillis(@IntRange(from=0) int); } public final class GnssMeasurementsEvent implements android.os.Parcelable { @@ -35712,6 +35714,7 @@ package android.provider { field public static final String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS"; field public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS"; field public static final String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS"; + field public static final String ACTION_APP_LOCALE_SETTINGS = "android.settings.APP_LOCALE_SETTINGS"; field public static final String ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS = "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS"; field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS"; field public static final String ACTION_APP_OPEN_BY_DEFAULT_SETTINGS = "android.settings.APP_OPEN_BY_DEFAULT_SETTINGS"; @@ -51385,9 +51388,9 @@ package android.view.accessibility { method public int getRecordCount(); method public int getWindowChanges(); method public void initFromParcel(android.os.Parcel); - method public static android.view.accessibility.AccessibilityEvent obtain(int); - method public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent); - method public static android.view.accessibility.AccessibilityEvent obtain(); + method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(int); + method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(android.view.accessibility.AccessibilityEvent); + method @Deprecated public static android.view.accessibility.AccessibilityEvent obtain(); method public void setAction(int); method public void setContentChangeTypes(int); method public void setEventTime(long); @@ -51575,13 +51578,13 @@ package android.view.accessibility { method public boolean isShowingHintText(); method public boolean isTextEntryKey(); method public boolean isVisibleToUser(); - method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View); - method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int); - method public static android.view.accessibility.AccessibilityNodeInfo obtain(); - method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.accessibility.AccessibilityNodeInfo); method public boolean performAction(int); method public boolean performAction(int, android.os.Bundle); - method public void recycle(); + method @Deprecated public void recycle(); method public boolean refresh(); method public boolean refreshWithExtraData(String, android.os.Bundle); method @Deprecated public void removeAction(int); @@ -51760,8 +51763,8 @@ package android.view.accessibility { method public int getRowCount(); method public int getSelectionMode(); method public boolean isHierarchical(); - method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean); - method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean, int); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean, int); field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2 field public static final int SELECTION_MODE_NONE = 0; // 0x0 field public static final int SELECTION_MODE_SINGLE = 1; // 0x1 @@ -51778,9 +51781,9 @@ package android.view.accessibility { method @Nullable public String getRowTitle(); method @Deprecated public boolean isHeading(); method public boolean isSelected(); - method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean); - method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean); - method @NonNull public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean); + method @Deprecated @NonNull public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(@Nullable String, int, int, @Nullable String, int, int, boolean, boolean); } public static final class AccessibilityNodeInfo.CollectionItemInfo.Builder { @@ -51808,7 +51811,7 @@ package android.view.accessibility { method public float getMax(); method public float getMin(); method public int getType(); - method public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float); + method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo.RangeInfo obtain(int, float, float, float); field public static final int RANGE_TYPE_FLOAT = 1; // 0x1 field public static final int RANGE_TYPE_INT = 0; // 0x0 field public static final int RANGE_TYPE_PERCENT = 2; // 0x2 @@ -51862,9 +51865,9 @@ package android.view.accessibility { method public boolean isFullScreen(); method public boolean isPassword(); method public boolean isScrollable(); - method public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord); - method public static android.view.accessibility.AccessibilityRecord obtain(); - method public void recycle(); + method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain(android.view.accessibility.AccessibilityRecord); + method @Deprecated public static android.view.accessibility.AccessibilityRecord obtain(); + method @Deprecated public void recycle(); method public void setAddedCount(int); method public void setBeforeText(CharSequence); method public void setChecked(boolean); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 75c9be966f81..3a48d7cc674c 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -6473,6 +6473,7 @@ package android.media.tv.tuner { method @Nullable public android.media.tv.tuner.DemuxCapabilities getDemuxCapabilities(); method @Nullable public android.media.tv.tuner.frontend.FrontendInfo getFrontendInfo(); method @Nullable public android.media.tv.tuner.frontend.FrontendStatus getFrontendStatus(@NonNull int[]); + method @IntRange(from=0xffffffff) public int getMaxNumberOfFrontends(int); method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean hasUnusedFrontend(int); method public boolean isLowestPriority(int); method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler(); @@ -6485,6 +6486,7 @@ package android.media.tv.tuner { method @Nullable public android.media.tv.tuner.filter.TimeFilter openTimeFilter(); method public int scan(@NonNull android.media.tv.tuner.frontend.FrontendSettings, int, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.ScanCallback); method public int setLnaEnabled(boolean); + method public int setMaxNumberOfFrontends(int, @IntRange(from=0) int); method public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener); method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener); method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index f48c717fd1b4..8ae6e4cfced2 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2838,7 +2838,6 @@ package android.view.accessibility { method public void addChild(@NonNull android.os.IBinder); method public long getSourceNodeId(); method public void setLeashedParent(@Nullable android.os.IBinder, int); - method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger); method public void writeToParcelNoRecycle(android.os.Parcel, int); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 251d5e8b6134..495100b0ae52 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -2374,7 +2374,7 @@ public class PackageInstaller { STAGED_SESSION_UNKNOWN, STAGED_SESSION_CONFLICT}) @Retention(RetentionPolicy.SOURCE) - public @interface StagedSessionErrorCode{} + public @interface SessionErrorCode {} /** * Constant indicating that no error occurred during the preparation or the activation of * this staged session. @@ -2486,13 +2486,13 @@ public class PackageInstaller { public int[] childSessionIds = NO_SESSIONS; /** {@hide} */ - public boolean isStagedSessionApplied; + public boolean isSessionApplied; /** {@hide} */ - public boolean isStagedSessionReady; + public boolean isSessionReady; /** {@hide} */ - public boolean isStagedSessionFailed; - private int mStagedSessionErrorCode; - private String mStagedSessionErrorMessage; + public boolean isSessionFailed; + private int mSessionErrorCode; + private String mSessionErrorMessage; /** {@hide} */ public boolean isCommitted; @@ -2553,11 +2553,11 @@ public class PackageInstaller { if (childSessionIds == null) { childSessionIds = NO_SESSIONS; } - isStagedSessionApplied = source.readBoolean(); - isStagedSessionReady = source.readBoolean(); - isStagedSessionFailed = source.readBoolean(); - mStagedSessionErrorCode = source.readInt(); - mStagedSessionErrorMessage = source.readString(); + isSessionApplied = source.readBoolean(); + isSessionReady = source.readBoolean(); + isSessionFailed = source.readBoolean(); + mSessionErrorCode = source.readInt(); + mSessionErrorMessage = source.readString(); isCommitted = source.readBoolean(); rollbackDataPolicy = source.readInt(); createdMillis = source.readLong(); @@ -2951,7 +2951,7 @@ public class PackageInstaller { * since that is the one that should have been {@link Session#commit committed}. */ public boolean isStagedSessionActive() { - return isStaged && isCommitted && !isStagedSessionApplied && !isStagedSessionFailed + return isStaged && isCommitted && !isSessionApplied && !isSessionFailed && !hasParentSessionId(); } @@ -2992,7 +2992,7 @@ public class PackageInstaller { */ public boolean isStagedSessionApplied() { checkSessionIsStaged(); - return isStagedSessionApplied; + return isSessionApplied; } /** @@ -3001,7 +3001,7 @@ public class PackageInstaller { */ public boolean isStagedSessionReady() { checkSessionIsStaged(); - return isStagedSessionReady; + return isSessionReady; } /** @@ -3010,16 +3010,16 @@ public class PackageInstaller { */ public boolean isStagedSessionFailed() { checkSessionIsStaged(); - return isStagedSessionFailed; + return isSessionFailed; } /** * If something went wrong with a staged session, clients can check this error code to * understand which kind of failure happened. Only meaningful if {@code isStaged} is true. */ - public @StagedSessionErrorCode int getStagedSessionErrorCode() { + public @SessionErrorCode int getStagedSessionErrorCode() { checkSessionIsStaged(); - return mStagedSessionErrorCode; + return mSessionErrorCode; } /** @@ -3028,14 +3028,13 @@ public class PackageInstaller { */ public @NonNull String getStagedSessionErrorMessage() { checkSessionIsStaged(); - return mStagedSessionErrorMessage; + return mSessionErrorMessage; } /** {@hide} */ - public void setStagedSessionErrorCode(@StagedSessionErrorCode int errorCode, - String errorMessage) { - mStagedSessionErrorCode = errorCode; - mStagedSessionErrorMessage = errorMessage; + public void setSessionErrorCode(@SessionErrorCode int errorCode, String errorMessage) { + mSessionErrorCode = errorCode; + mSessionErrorMessage = errorMessage; } /** @@ -3124,11 +3123,11 @@ public class PackageInstaller { dest.writeBoolean(forceQueryable); dest.writeInt(parentSessionId); dest.writeIntArray(childSessionIds); - dest.writeBoolean(isStagedSessionApplied); - dest.writeBoolean(isStagedSessionReady); - dest.writeBoolean(isStagedSessionFailed); - dest.writeInt(mStagedSessionErrorCode); - dest.writeString(mStagedSessionErrorMessage); + dest.writeBoolean(isSessionApplied); + dest.writeBoolean(isSessionReady); + dest.writeBoolean(isSessionFailed); + dest.writeInt(mSessionErrorCode); + dest.writeString(mSessionErrorMessage); dest.writeBoolean(isCommitted); dest.writeInt(rollbackDataPolicy); dest.writeLong(createdMillis); diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index 01833fda5b95..e73116556758 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -965,7 +965,7 @@ public final class DisplayManagerGlobal { private static final class DisplayListenerDelegate extends Handler { public final DisplayListener mListener; - public long mEventsMask; + public volatile long mEventsMask; private final DisplayInfo mDisplayInfo = new DisplayInfo(); @@ -985,12 +985,12 @@ public final class DisplayManagerGlobal { removeCallbacksAndMessages(null); } - public synchronized void setEventsMask(@EventsMask long newEventsMask) { + public void setEventsMask(@EventsMask long newEventsMask) { mEventsMask = newEventsMask; } @Override - public synchronized void handleMessage(Message msg) { + public void handleMessage(Message msg) { switch (msg.what) { case EVENT_DISPLAY_ADDED: if ((mEventsMask & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) { diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java index 66288d6d3efe..6c8eb41d8724 100644 --- a/core/java/android/inputmethodservice/SoftInputWindow.java +++ b/core/java/android/inputmethodservice/SoftInputWindow.java @@ -17,11 +17,7 @@ package android.inputmethodservice; import static android.inputmethodservice.SoftInputWindowProto.BOUNDS; -import static android.inputmethodservice.SoftInputWindowProto.GRAVITY; -import static android.inputmethodservice.SoftInputWindowProto.NAME; -import static android.inputmethodservice.SoftInputWindowProto.TAKES_FOCUS; import static android.inputmethodservice.SoftInputWindowProto.WINDOW_STATE; -import static android.inputmethodservice.SoftInputWindowProto.WINDOW_TYPE; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -33,7 +29,6 @@ import android.os.Debug; import android.os.IBinder; import android.util.Log; import android.util.proto.ProtoOutputStream; -import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; @@ -268,11 +263,6 @@ final class SoftInputWindow extends Dialog { void dumpDebug(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); - // TODO(b/192412909): Deprecate the following 4 entries, as they are all constant. - proto.write(NAME, "InputMethod"); - proto.write(WINDOW_TYPE, WindowManager.LayoutParams.TYPE_INPUT_METHOD); - proto.write(GRAVITY, Gravity.BOTTOM); - proto.write(TAKES_FOCUS, false); mBounds.dumpDebug(proto, BOUNDS); proto.write(WINDOW_STATE, mWindowState); proto.end(token); diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java index f0e6624f3f4f..658e033d10ea 100644 --- a/core/java/android/permission/PermissionUsageHelper.java +++ b/core/java/android/permission/PermissionUsageHelper.java @@ -318,7 +318,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis String permGroup = usedPermGroups.get(permGroupNum); ArrayMap<OpUsage, CharSequence> usagesWithLabels = - getUniqueUsagesWithLabels(rawUsages.get(permGroup)); + getUniqueUsagesWithLabels(permGroup, rawUsages.get(permGroup)); if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) { isPhone = true; @@ -439,7 +439,8 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis return ListFormatter.getInstance().format(labels); } - private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) { + private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(String permGroup, + List<OpUsage> usages) { ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>(); if (usages == null || usages.isEmpty()) { @@ -474,7 +475,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // If this usage has a proxy, but is not a proxy, it is the end of a chain. // TODO remove once camera converted if (!proxies.containsKey(usageAttr) && usage.proxy != null - && !usage.op.equals(OPSTR_RECORD_AUDIO)) { + && !MICROPHONE.equals(permGroup)) { proxyLabels.put(usage, new ArrayList<>()); proxyPackages.add(usage.getPackageIdHash()); } @@ -546,7 +547,7 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource // For now: don't add mic proxy usages - if (!start.op.equals(OPSTR_RECORD_AUDIO)) { + if (!MICROPHONE.equals(permGroup)) { usagesAndLabels.put(start, proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList)); } @@ -560,7 +561,8 @@ public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedLis // if the list is empty or incomplete, do not show it. if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd() || !usageList.get(0).isStart() - || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) { + || !permGroup.equals(getGroupForOp(usageList.get(0).usage.op)) + || !MICROPHONE.equals(permGroup)) { continue; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 190b8f66949b..910fec646e83 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -950,6 +950,19 @@ public final class Settings { "android.settings.LOCALE_SETTINGS"; /** + * Activity Action: Show settings to allow configuration of per application locale. + * <p> + * Input: The Intent's data URI can specify the application package name to directly invoke the + * app locale details GUI specific to the package name. + * For example "package:com.my.app". + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_APP_LOCALE_SETTINGS = + "android.settings.APP_LOCALE_SETTINGS"; + + /** * Activity Action: Show settings to allow configuration of lockscreen. * <p> * In some cases, a matching Activity may not exist, so ensure you @@ -6524,6 +6537,16 @@ public final class Settings { @Readable public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled"; + + /** + * Setting to indicate live caption button show or hide in the volume + * rocker. + * + * @hide + */ + public static final String ODI_CAPTIONS_VOLUME_UI_ENABLED = + "odi_captions_volume_ui_enabled"; + /** * On Android 8.0 (API level 26) and higher versions of the platform, * a 64-bit number (expressed as a hexadecimal string), unique to diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index e3c396976f6c..34e35d4512b9 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -3589,7 +3589,7 @@ public final class Telephony { * @hide */ public static final Uri PREFERRED_APN_URI = Uri.parse( - "content://telephony/carriers/preferapn/subId/"); + "content://telephony/carriers/preferapn/subId"); /** * The {@code content://} style URL for the perferred APN set id. @@ -3597,8 +3597,15 @@ public final class Telephony { * @hide */ public static final Uri PREFERRED_APN_SET_URI = Uri.parse( - "content://telephony/carriers/preferapnset/subId/"); + "content://telephony/carriers/preferapnset/subId"); + /** + * The id of preferred APN. + * + * @see #PREFERRED_APN_URI + * @hide + */ + public static final String APN_ID = "apn_id"; /** * The column name for ENFORCE_MANAGED_URI, indicates whether DPC-owned APNs are enforced. diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 8fda48b1a36a..258359e98264 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -15272,7 +15272,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param event the KeyEvent object that defines the button action */ public boolean onKeyDown(int keyCode, KeyEvent event) { - if (KeyEvent.isConfirmKey(keyCode)) { + if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) { if ((mViewFlags & ENABLED_MASK) == DISABLED) { return true; } @@ -15329,7 +15329,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param event The KeyEvent object that defines the button action. */ public boolean onKeyUp(int keyCode, KeyEvent event) { - if (KeyEvent.isConfirmKey(keyCode)) { + if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) { if ((mViewFlags & ENABLED_MASK) == DISABLED) { return true; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 748e551ecfc4..f86abec353cc 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -7596,7 +7596,7 @@ public final class ViewRootImpl implements ViewParent, // When a new focused view is selected, we consume the navigation key because // navigation doesn't make much sense unless a view already has focus so // the key's purpose is to set focus. - if (isNavigationKey(event)) { + if (event.hasNoModifiers() && isNavigationKey(event)) { return ensureTouchMode(false); } diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 83712b40c452..a427ab8fe837 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -24,7 +24,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; -import android.util.Pools.SynchronizedPool; import com.android.internal.util.BitUtils; @@ -806,10 +805,6 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static final int TYPES_ALL_MASK = 0xFFFFFFFF; - private static final int MAX_POOL_SIZE = 10; - private static final SynchronizedPool<AccessibilityEvent> sPool = - new SynchronizedPool<>(MAX_POOL_SIZE); - @UnsupportedAppUsage private @EventType int mEventType; private CharSequence mPackageName; @@ -1170,7 +1165,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static AccessibilityEvent obtainWindowsChangedEvent( int windowId, int windowChangeTypes) { - final AccessibilityEvent event = AccessibilityEvent.obtain(TYPE_WINDOWS_CHANGED); + final AccessibilityEvent event = new AccessibilityEvent(TYPE_WINDOWS_CHANGED); event.setWindowId(windowId); event.setWindowChanges(windowChangeTypes); event.setImportantForAccessibility(true); @@ -1178,69 +1173,58 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par } /** - * Returns a cached instance if such is available or a new one is - * instantiated with its type property set. - * - * <p>In most situations object pooling is not beneficial. Create a new instance using the - * constructor {@link #AccessibilityEvent(int)} instead. + * Instantiates a new AccessibilityEvent instance with its type property set. * + * @deprecated Object pooling has been discontinued. Create a new instance using the + * constructor {@link #AccessibilityEvent()} instead. * @param eventType The event type. * @return An instance. */ + @Deprecated public static AccessibilityEvent obtain(int eventType) { - AccessibilityEvent event = AccessibilityEvent.obtain(); + AccessibilityEvent event = new AccessibilityEvent(); event.setEventType(eventType); return event; } /** - * Returns a cached instance if such is available or a new one is - * created. The returned instance is initialized from the given + * Instantiates a new AccessibilityEvent instance. + * The returned instance is initialized from the given * <code>event</code>. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the - * constructor {@link #AccessibilityEvent(AccessibilityEvent)} instead. - * + * @deprecated Object pooling has been discontinued. Create a new instance using the + * constructor {@link #AccessibilityEvent()} instead. * @param event The other event. * @return An instance. */ + @Deprecated public static AccessibilityEvent obtain(AccessibilityEvent event) { - AccessibilityEvent eventClone = AccessibilityEvent.obtain(); + AccessibilityEvent eventClone = new AccessibilityEvent(); eventClone.init(event); return eventClone; } /** - * Returns a cached instance if such is available or a new one is - * instantiated. + * Instantiates a new AccessibilityEvent instance. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link #AccessibilityEvent()} instead. - * * @return An instance. */ + @Deprecated public static AccessibilityEvent obtain() { - AccessibilityEvent event = sPool.acquire(); - if (event == null) event = new AccessibilityEvent(); - if (DEBUG_ORIGIN) event.originStackTrace = Thread.currentThread().getStackTrace(); - return event; + return new AccessibilityEvent(); } /** - * Recycles an instance back to be reused. - * <p> - * <b>Note: You must not touch the object after calling this function.</b> - * </p> + * Previously would recycle an instance back to be reused. * - * <p>In most situations object pooling is not beneficial, and recycling is not necessary. - * - * @throws IllegalStateException If the event is already recycled. + * @deprecated Object pooling has been discontinued. Calling this function now will have + * no effect. */ @Override - public void recycle() { - clear(); - sPool.release(this); - } + @Deprecated + public void recycle() {} /** * Clears the state of this instance. @@ -1260,7 +1244,6 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par if (mRecords != null) { while (!mRecords.isEmpty()) { AccessibilityRecord record = mRecords.remove(0); - record.recycle(); } } if (DEBUG_ORIGIN) originStackTrace = null; @@ -1288,7 +1271,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par if (recordCount > 0) { mRecords = new ArrayList<>(recordCount); for (int i = 0; i < recordCount; i++) { - AccessibilityRecord record = AccessibilityRecord.obtain(); + AccessibilityRecord record = new AccessibilityRecord(); readAccessibilityRecordFromParcel(record, parcel); record.mConnectionId = mConnectionId; mRecords.add(record); @@ -1527,7 +1510,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityEvent> CREATOR = new Parcelable.Creator<AccessibilityEvent>() { public AccessibilityEvent createFromParcel(Parcel parcel) { - AccessibilityEvent event = AccessibilityEvent.obtain(); + AccessibilityEvent event = new AccessibilityEvent(); event.initFromParcel(parcel); return event; } diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index 9511958529e5..db7c6634c8a7 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -50,7 +50,6 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.LongArray; -import android.util.Pools.SynchronizedPool; import android.util.Size; import android.util.TypedValue; import android.view.SurfaceView; @@ -68,7 +67,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; /** * This class represents a node of the window content as well as actions that @@ -723,9 +721,6 @@ public class AccessibilityNodeInfo implements Parcelable { */ private static final int VIRTUAL_DESCENDANT_ID_SHIFT = 32; - // TODO(b/129300068): Remove sNumInstancesInUse. - private static AtomicInteger sNumInstancesInUse; - /** * Gets the accessibility view id which identifies a View in the view three. * @@ -769,11 +764,6 @@ public class AccessibilityNodeInfo implements Parcelable { return (((long) virtualDescendantId) << VIRTUAL_DESCENDANT_ID_SHIFT) | accessibilityViewId; } - // Housekeeping. - private static final int MAX_POOL_SIZE = 50; - private static final SynchronizedPool<AccessibilityNodeInfo> sPool = - new SynchronizedPool<>(MAX_POOL_SIZE); - private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo(); @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -869,7 +859,7 @@ public class AccessibilityNodeInfo implements Parcelable { * @param info The other info. */ public AccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) { - init(info, false /* usePoolingInfo */); + init(info); } /** @@ -1009,13 +999,7 @@ public class AccessibilityNodeInfo implements Parcelable { if (refreshedInfo == null) { return false; } - // Hard-to-reproduce bugs seem to be due to some tools recycling a node on another - // thread. If that happens, the init will re-seal the node, which then is in a bad state - // when it is obtained. Enforce sealing again before we init to fail when a node has been - // recycled during a refresh to catch such errors earlier. - enforceSealed(); - init(refreshedInfo, true /* usePoolingInfo */); - refreshedInfo.recycle(); + init(refreshedInfo); return true; } @@ -3599,25 +3583,23 @@ public class AccessibilityNodeInfo implements Parcelable { * Returns a cached instance if such is available otherwise a new one * and sets the source. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link #AccessibilityNodeInfo(View)} instead. - * * @param source The source view. * @return An instance. * * @see #setSource(View) */ + @Deprecated public static AccessibilityNodeInfo obtain(View source) { - AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); - info.setSource(source); - return info; + return new AccessibilityNodeInfo(source); } /** * Returns a cached instance if such is available otherwise a new one * and sets the source. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link #AccessibilityNodeInfo(View, int)} instead. * * @param root The root of the virtual subtree. @@ -3626,71 +3608,45 @@ public class AccessibilityNodeInfo implements Parcelable { * * @see #setSource(View, int) */ + @Deprecated public static AccessibilityNodeInfo obtain(View root, int virtualDescendantId) { - AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); - info.setSource(root, virtualDescendantId); - return info; + return new AccessibilityNodeInfo(root, virtualDescendantId); } /** - * Returns a cached instance if such is available otherwise a new one. + * Instantiates a new AccessibilityNodeInfo. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link #AccessibilityNodeInfo()} instead. - * * @return An instance. */ + @Deprecated public static AccessibilityNodeInfo obtain() { - AccessibilityNodeInfo info = sPool.acquire(); - if (sNumInstancesInUse != null) { - sNumInstancesInUse.incrementAndGet(); - } - return (info != null) ? info : new AccessibilityNodeInfo(); + return new AccessibilityNodeInfo(); } /** - * Returns a cached instance if such is available or a new one is - * create. The returned instance is initialized from the given + * Instantiates a new AccessibilityNodeInfo initialized from the given * <code>info</code>. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link #AccessibilityNodeInfo(AccessibilityNodeInfo)} instead. - * * @param info The other info. * @return An instance. */ + @Deprecated public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) { - AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain(); - infoClone.init(info, true /* usePoolingInfo */); - return infoClone; + return new AccessibilityNodeInfo(info); } /** - * Return an instance back to be reused. - * <p> - * <strong>Note:</strong> You must not touch the object after calling this function. - * - * <p>In most situations object pooling is not beneficial, and recycling is not necessary. + * Would previously return an instance back to be reused. * - * @throws IllegalStateException If the info is already recycled. + * @deprecated Object pooling has been discontinued. Calling this function now will have + * no effect. */ - public void recycle() { - clear(); - sPool.release(this); - if (sNumInstancesInUse != null) { - sNumInstancesInUse.decrementAndGet(); - } - } - - /** - * Specify a counter that will be incremented on obtain() and decremented on recycle() - * - * @hide - */ - @TestApi - public static void setNumInstancesInUseCounter(AtomicInteger counter) { - sNumInstancesInUse = counter; - } + @Deprecated + public void recycle() {} /** * {@inheritDoc} @@ -3704,7 +3660,6 @@ public class AccessibilityNodeInfo implements Parcelable { writeToParcelNoRecycle(parcel, flags); // Since instances of this class are fetched via synchronous i.e. blocking // calls in IPCs we always recycle as soon as the instance is marshaled. - recycle(); } /** @hide */ @@ -4000,9 +3955,8 @@ public class AccessibilityNodeInfo implements Parcelable { * Initializes this instance from another one. * * @param other The other instance. - * @param usePoolingInfos whether using pooled object internally or not */ - private void init(AccessibilityNodeInfo other, boolean usePoolingInfos) { + private void init(AccessibilityNodeInfo other) { mSealed = other.mSealed; mSourceNodeId = other.mSourceNodeId; mParentNodeId = other.mParentNodeId; @@ -4062,11 +4016,7 @@ public class AccessibilityNodeInfo implements Parcelable { mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null; - if (usePoolingInfos) { - initPoolingInfos(other); - } else { - initCopyInfos(other); - } + initCopyInfos(other); final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo; mTouchDelegateInfo = (otherInfo != null) @@ -4077,21 +4027,6 @@ public class AccessibilityNodeInfo implements Parcelable { mLeashedParentNodeId = other.mLeashedParentNodeId; } - private void initPoolingInfos(AccessibilityNodeInfo other) { - if (mRangeInfo != null) mRangeInfo.recycle(); - mRangeInfo = (other.mRangeInfo != null) - ? RangeInfo.obtain(other.mRangeInfo) : null; - if (mCollectionInfo != null) mCollectionInfo.recycle(); - mCollectionInfo = (other.mCollectionInfo != null) - ? CollectionInfo.obtain(other.mCollectionInfo) : null; - if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); - mCollectionItemInfo = (other.mCollectionItemInfo != null) - ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null; - if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle(); - mExtraRenderingInfo = (other.mExtraRenderingInfo != null) - ? ExtraRenderingInfo.obtain(other.mExtraRenderingInfo) : null; - } - private void initCopyInfos(AccessibilityNodeInfo other) { RangeInfo ri = other.mRangeInfo; mRangeInfo = (ri == null) ? null @@ -4205,27 +4140,24 @@ public class AccessibilityNodeInfo implements Parcelable { ? parcel.readBundle() : null; - if (mRangeInfo != null) mRangeInfo.recycle(); mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++) - ? RangeInfo.obtain( + ? new RangeInfo( parcel.readInt(), parcel.readFloat(), parcel.readFloat(), parcel.readFloat()) : null; - if (mCollectionInfo != null) mCollectionInfo.recycle(); mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++) - ? CollectionInfo.obtain( + ? new CollectionInfo( parcel.readInt(), parcel.readInt(), parcel.readInt() == 1, parcel.readInt()) : null; - if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++) - ? CollectionItemInfo.obtain( + ? new CollectionItemInfo( parcel.readString(), parcel.readInt(), parcel.readInt(), @@ -4241,8 +4173,7 @@ public class AccessibilityNodeInfo implements Parcelable { } if (isBitSet(nonDefaultFields, fieldIndex++)) { - if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle(); - mExtraRenderingInfo = ExtraRenderingInfo.obtain(); + mExtraRenderingInfo = new ExtraRenderingInfo(null); mExtraRenderingInfo.mLayoutSize = (Size) parcel.readValue(null); mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat(); mExtraRenderingInfo.mTextSizeUnit = parcel.readInt(); @@ -4265,7 +4196,7 @@ public class AccessibilityNodeInfo implements Parcelable { * Clears the state of this instance. */ private void clear() { - init(DEFAULT, true /* usePoolingInfo */); + init(DEFAULT); } private static boolean isDefaultStandardAction(AccessibilityAction action) { @@ -5235,7 +5166,6 @@ public class AccessibilityNodeInfo implements Parcelable { * handled by the {@link AccessibilityNodeInfo} to which this object is attached. */ public static final class RangeInfo { - private static final int MAX_POOL_SIZE = 10; /** Range type: integer. */ public static final int RANGE_TYPE_INT = 0; @@ -5244,35 +5174,16 @@ public class AccessibilityNodeInfo implements Parcelable { /** Range type: percent with values from zero to one hundred. */ public static final int RANGE_TYPE_PERCENT = 2; - private static final SynchronizedPool<RangeInfo> sPool = - new SynchronizedPool<AccessibilityNodeInfo.RangeInfo>(MAX_POOL_SIZE); - private int mType; private float mMin; private float mMax; private float mCurrent; - - /** - * Obtains a pooled instance that is a clone of another one. - * - * <p>In most situations object pooling is not beneficial. Create a new instance using the - * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int, - * float, float, float)} instead. - * - * @param other The instance to clone. - * - * @hide - */ - public static RangeInfo obtain(RangeInfo other) { - return obtain(other.mType, other.mMin, other.mMax, other.mCurrent); - } - /** - * Obtains a pooled instance. + * Instantiates a new RangeInfo. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the - * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int, - * float, float, float)} instead. + * @deprecated Object pooling has been discontinued. Create a new instance using the + * constructor {@link AccessibilityNodeInfo.RangeInfo#RangeInfo(int, float, float, + * float)} instead. * * @param type The type of the range. * @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no @@ -5281,17 +5192,9 @@ public class AccessibilityNodeInfo implements Parcelable { * maximum. * @param current The current value. */ + @Deprecated public static RangeInfo obtain(int type, float min, float max, float current) { - RangeInfo info = sPool.acquire(); - if (info == null) { - return new RangeInfo(type, min, max, current); - } - - info.mType = type; - info.mMin = min; - info.mMax = max; - info.mCurrent = current; - return info; + return new RangeInfo(type, min, max, current); } /** @@ -5354,12 +5257,11 @@ public class AccessibilityNodeInfo implements Parcelable { /** * Recycles this instance. * - * <p>In most situations object pooling is not beneficial, and recycling is not necessary. + * @deprecated Object pooling has been discontinued. Calling this function now will have + * no effect. */ - void recycle() { - clear(); - sPool.release(this); - } + @Deprecated + void recycle() {} private void clear() { mType = 0; @@ -5392,20 +5294,15 @@ public class AccessibilityNodeInfo implements Parcelable { /** Selection mode where multiple items may be selected. */ public static final int SELECTION_MODE_MULTIPLE = 2; - private static final int MAX_POOL_SIZE = 20; - - private static final SynchronizedPool<CollectionInfo> sPool = - new SynchronizedPool<>(MAX_POOL_SIZE); - private int mRowCount; private int mColumnCount; private boolean mHierarchical; private int mSelectionMode; /** - * Obtains a pooled instance that is a clone of another one. + * Instantiates a CollectionInfo that is a clone of another one. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link * AccessibilityNodeInfo.CollectionInfo#CollectionInfo} instead. * @@ -5413,14 +5310,14 @@ public class AccessibilityNodeInfo implements Parcelable { * @hide */ public static CollectionInfo obtain(CollectionInfo other) { - return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical, + return new CollectionInfo(other.mRowCount, other.mColumnCount, other.mHierarchical, other.mSelectionMode); } /** * Obtains a pooled instance. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int, * boolean)} instead. @@ -5431,13 +5328,13 @@ public class AccessibilityNodeInfo implements Parcelable { */ public static CollectionInfo obtain(int rowCount, int columnCount, boolean hierarchical) { - return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE); + return new CollectionInfo(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE); } /** * Obtains a pooled instance. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link * AccessibilityNodeInfo.CollectionInfo#CollectionInfo(int, int, * boolean, int)} instead. @@ -5454,16 +5351,7 @@ public class AccessibilityNodeInfo implements Parcelable { */ public static CollectionInfo obtain(int rowCount, int columnCount, boolean hierarchical, int selectionMode) { - final CollectionInfo info = sPool.acquire(); - if (info == null) { - return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode); - } - - info.mRowCount = rowCount; - info.mColumnCount = columnCount; - info.mHierarchical = hierarchical; - info.mSelectionMode = selectionMode; - return info; + return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode); } /** @@ -5535,14 +5423,13 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Recycles this instance. + * Previously would recycle this instance. * - * <p>In most situations object pooling is not beneficial, and recycling is not necessary. + * @deprecated Object pooling has been discontinued. Calling this function now will have + * no effect. */ - void recycle() { - clear(); - sPool.release(this); - } + @Deprecated + void recycle() {} private void clear() { mRowCount = 0; @@ -5566,15 +5453,10 @@ public class AccessibilityNodeInfo implements Parcelable { * </p> */ public static final class CollectionItemInfo { - private static final int MAX_POOL_SIZE = 20; - - private static final SynchronizedPool<CollectionItemInfo> sPool = - new SynchronizedPool<>(MAX_POOL_SIZE); - /** - * Obtains a pooled instance that is a clone of another one. + * Instantiates a CollectionItemInfo that is a clone of another one. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo} * instead. @@ -5582,20 +5464,20 @@ public class AccessibilityNodeInfo implements Parcelable { * @param other The instance to clone. * @hide */ + @Deprecated public static CollectionItemInfo obtain(CollectionItemInfo other) { - return CollectionItemInfo.obtain(other.mRowTitle, other.mRowIndex, other.mRowSpan, - other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading, - other.mSelected); + return new CollectionItemInfo(other.mRowTitle, other.mRowIndex, other.mRowSpan, + other.mColumnTitle, other.mColumnIndex, other.mColumnSpan, other.mHeading, + other.mSelected); } /** - * Obtains a pooled instance. + * Instantiates a new CollectionItemInfo. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int, * int, int, int, boolean)} instead. - * * @param rowIndex The row index at which the item is located. * @param rowSpan The number of rows the item spans. * @param columnIndex The column index at which the item is located. @@ -5603,37 +5485,39 @@ public class AccessibilityNodeInfo implements Parcelable { * @param heading Whether the item is a heading. (Prefer * {@link AccessibilityNodeInfo#setHeading(boolean)}). */ + @Deprecated public static CollectionItemInfo obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading) { - return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false); + return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading, + false); } /** - * Obtains a pooled instance. + * Instantiates a new CollectionItemInfo. * - * <p>In most situations object pooling is not beneficial. Creates a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int, - * int, int, int, boolean, boolean)} instead. - * + * int, int, int, boolean)} instead. * @param rowIndex The row index at which the item is located. * @param rowSpan The number of rows the item spans. * @param columnIndex The column index at which the item is located. * @param columnSpan The number of columns the item spans. * @param heading Whether the item is a heading. (Prefer - * {@link AccessibilityNodeInfo#setHeading(boolean)}) + * {@link AccessibilityNodeInfo#setHeading(boolean)}). * @param selected Whether the item is selected. */ + @Deprecated public static CollectionItemInfo obtain(int rowIndex, int rowSpan, int columnIndex, int columnSpan, boolean heading, boolean selected) { - return obtain(null, rowIndex, rowSpan, null, columnIndex, - columnSpan, heading, selected); + return new CollectionItemInfo(rowIndex, rowSpan, columnIndex, columnSpan, heading, + selected); } /** - * Obtains a pooled instance. + * Instantiates a new CollectionItemInfo. * - * <p>In most situations object pooling is not beneficial. Creates a new instance using the + * @deprecated Object pooling has been discontinued. Creates a new instance using the * constructor {@link * AccessibilityNodeInfo.CollectionItemInfo#CollectionItemInfo(int, * int, int, int, boolean, boolean)} instead. @@ -5648,25 +5532,13 @@ public class AccessibilityNodeInfo implements Parcelable { * {@link AccessibilityNodeInfo#setHeading(boolean)}) * @param selected Whether the item is selected. */ + @Deprecated @NonNull public static CollectionItemInfo obtain(@Nullable String rowTitle, int rowIndex, int rowSpan, @Nullable String columnTitle, int columnIndex, int columnSpan, boolean heading, boolean selected) { - final CollectionItemInfo info = sPool.acquire(); - if (info == null) { - return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle, - columnIndex, columnSpan, heading, selected); - } - - info.mRowIndex = rowIndex; - info.mRowSpan = rowSpan; - info.mColumnIndex = columnIndex; - info.mColumnSpan = columnSpan; - info.mHeading = heading; - info.mSelected = selected; - info.mRowTitle = rowTitle; - info.mColumnTitle = columnTitle; - return info; + return new CollectionItemInfo(rowTitle, rowIndex, rowSpan, columnTitle, columnIndex, + columnSpan, heading, selected); } private boolean mHeading; @@ -5817,12 +5689,11 @@ public class AccessibilityNodeInfo implements Parcelable { /** * Recycles this instance. * - * <p>In most situations object pooling is not beneficial, and recycling is not necessary. + * @deprecated Object pooling has been discontinued. Calling this function now will have + * no effect. */ - void recycle() { - clear(); - sPool.release(this); - } + @Deprecated + void recycle() {} private void clear() { mColumnIndex = 0; @@ -6151,34 +6022,34 @@ public class AccessibilityNodeInfo implements Parcelable { */ public static final class ExtraRenderingInfo { private static final int UNDEFINED_VALUE = -1; - private static final int MAX_POOL_SIZE = 20; - private static final SynchronizedPool<ExtraRenderingInfo> sPool = - new SynchronizedPool<>(MAX_POOL_SIZE); private Size mLayoutSize; private float mTextSizeInPx = UNDEFINED_VALUE; private int mTextSizeUnit = UNDEFINED_VALUE; /** - * Obtains a pooled instance. + * Instantiates an ExtraRenderingInfo, by copying an existing one. + * * @hide + * @deprecated Object pooling has been discontinued. Create a new instance using the + * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead. */ + @Deprecated @NonNull public static ExtraRenderingInfo obtain() { - final ExtraRenderingInfo info = sPool.acquire(); - if (info == null) { - return new ExtraRenderingInfo(null); - } - return info; + return new ExtraRenderingInfo(null); } - /** Obtains a pooled instance that is a clone of another one. */ + /** + * Instantiates an ExtraRenderingInfo, by copying an existing one. + * + * @deprecated Object pooling has been discontinued. Create a new instance using the + * constructor {@link #ExtraRenderingInfo(ExtraRenderingInfo)} instead. + * @param other + */ + @Deprecated private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) { - ExtraRenderingInfo extraRenderingInfo = ExtraRenderingInfo.obtain(); - extraRenderingInfo.mLayoutSize = other.mLayoutSize; - extraRenderingInfo.mTextSizeInPx = other.mTextSizeInPx; - extraRenderingInfo.mTextSizeUnit = other.mTextSizeUnit; - return extraRenderingInfo; + return new ExtraRenderingInfo(other); } /** @@ -6268,14 +6139,13 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Recycles this instance. + * Previously would recycle this instance. * - * <p>In most situations object pooling is not beneficial, and recycling is not necessary. + * @deprecated Object pooling has been discontinued. Calling this function now will have + * no effect. */ - void recycle() { - clear(); - sPool.release(this); - } + @Deprecated + void recycle() {} private void clear() { mLayoutSize = null; @@ -6291,7 +6161,7 @@ public class AccessibilityNodeInfo implements Parcelable { new Parcelable.Creator<AccessibilityNodeInfo>() { @Override public AccessibilityNodeInfo createFromParcel(Parcel parcel) { - AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); + AccessibilityNodeInfo info = new AccessibilityNodeInfo(); info.initFromParcel(parcel); return info; } diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java index f26abb2b46ef..426a3f448543 100644 --- a/core/java/android/view/accessibility/AccessibilityRecord.java +++ b/core/java/android/view/accessibility/AccessibilityRecord.java @@ -78,13 +78,6 @@ public class AccessibilityRecord { | AccessibilityNodeInfo.FLAG_PREFETCH_SIBLINGS | AccessibilityNodeInfo.FLAG_PREFETCH_DESCENDANTS; - // Housekeeping - private static final int MAX_POOL_SIZE = 10; - private static final Object sPoolLock = new Object(); - private static AccessibilityRecord sPool; - private static int sPoolSize; - private AccessibilityRecord mNext; - private boolean mIsInPool; @UnsupportedAppUsage boolean mSealed; @@ -821,15 +814,14 @@ public class AccessibilityRecord { } /** - * Returns a cached instance if such is available or a new one is - * instantiated. The instance is initialized with data from the + * Instantiates a new record initialized with data from the * given record. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the - * constructor {@link #AccessibilityRecord(AccessibilityRecord)} instead. - * + * @deprecated Object pooling has been discontinued. Create a new instance using the + * constructor {@link #AccessibilityRecord()} instead. * @return An instance. */ + @Deprecated public static AccessibilityRecord obtain(AccessibilityRecord record) { AccessibilityRecord clone = AccessibilityRecord.obtain(); clone.init(record); @@ -837,51 +829,25 @@ public class AccessibilityRecord { } /** - * Returns a cached instance if such is available or a new one is - * instantiated. + * Instantiates a new record. * - * <p>In most situations object pooling is not beneficial. Create a new instance using the + * @deprecated Object pooling has been discontinued. Create a new instance using the * constructor {@link #AccessibilityRecord()} instead. - * * @return An instance. */ + @Deprecated public static AccessibilityRecord obtain() { - synchronized (sPoolLock) { - if (sPool != null) { - AccessibilityRecord record = sPool; - sPool = sPool.mNext; - sPoolSize--; - record.mNext = null; - record.mIsInPool = false; - return record; - } - return new AccessibilityRecord(); - } + return new AccessibilityRecord(); } /** - * Return an instance back to be reused. - * <p> - * <strong>Note:</strong> You must not touch the object after calling this function. + * Would previously return an instance back to be reused. * - * <p>In most situations object pooling is not beneficial, and recycling is not necessary. - * - * @throws IllegalStateException If the record is already recycled. + * @deprecated Object pooling has been discontinued. Calling this function now will have + * no effect. */ - public void recycle() { - if (mIsInPool) { - throw new IllegalStateException("Record already recycled!"); - } - clear(); - synchronized (sPoolLock) { - if (sPoolSize <= MAX_POOL_SIZE) { - mNext = sPool; - sPool = this; - mIsInPool = true; - sPoolSize++; - } - } - } + @Deprecated + public void recycle() { } /** * Initialize this record from another one. diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 862829bf9b55..dbf3570b1d24 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -74,6 +74,9 @@ import java.util.List; * <p> * Note that toasts being sent from the background are rate limited, so avoid sending such toasts * in quick succession. + * <p> + * Starting with Android 12 (API level 31), apps targeting Android 12 or newer will have + * their toasts limited to two lines. * * <div class="special reference"> * <h3>Developer Guides</h3> diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index bc3c2f5872fc..025f7118334c 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -190,7 +190,7 @@ public class ChooserActivity extends ResolverActivity implements * the handover intent. * TODO: investigate whether the privileged query is necessary to determine the availability. */ - protected static final String EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE = + public static final String EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE = "com.android.internal.app.ChooserActivity.EXTRA_IS_APP_PREDICTION_SERVICE_AVAILABLE"; /** diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java index 88425be84313..c1111ec259c9 100644 --- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java +++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java @@ -21,11 +21,13 @@ import android.hardware.SensorManager; import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; +import android.os.Parcel; import android.os.SystemClock; import android.os.UidBatteryConsumer; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; @@ -133,9 +135,12 @@ public class BatteryUsageStatsProvider { */ @VisibleForTesting public BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query) { - return getBatteryUsageStats(query, currentTimeMillis()); + synchronized (mStats) { + return getBatteryUsageStats(query, currentTimeMillis()); + } } + @GuardedBy("mStats") private BatteryUsageStats getBatteryUsageStats(BatteryUsageStatsQuery query, long currentTimeMs) { if (query.getToTimestamp() == 0) { @@ -145,6 +150,7 @@ public class BatteryUsageStatsProvider { } } + @GuardedBy("mStats") private BatteryUsageStats getCurrentBatteryUsageStats(BatteryUsageStatsQuery query, long currentTimeMs) { final long realtimeUs = elapsedRealtime() * 1000; @@ -189,7 +195,12 @@ public class BatteryUsageStatsProvider { } BatteryStatsImpl batteryStatsImpl = (BatteryStatsImpl) mStats; - batteryUsageStatsBuilder.setBatteryHistory(batteryStatsImpl.mHistoryBuffer); + + // Make a copy of battery history to avoid concurrent modification. + Parcel historyBuffer = Parcel.obtain(); + historyBuffer.appendFrom(batteryStatsImpl.mHistoryBuffer, 0, + batteryStatsImpl.mHistoryBuffer.dataSize()); + batteryUsageStatsBuilder.setBatteryHistory(historyBuffer); } return batteryUsageStatsBuilder.build(); diff --git a/core/proto/android/inputmethodservice/softinputwindow.proto b/core/proto/android/inputmethodservice/softinputwindow.proto index 85b7d7382805..e0ba6bf33567 100644 --- a/core/proto/android/inputmethodservice/softinputwindow.proto +++ b/core/proto/android/inputmethodservice/softinputwindow.proto @@ -23,10 +23,10 @@ package android.inputmethodservice; option java_multiple_files = true; message SoftInputWindowProto { - optional string name = 1; - optional int32 window_type = 2; - optional int32 gravity = 3; - optional bool takes_focus = 4; + reserved 1; // name + reserved 2; // window_type + reserved 3; // gravity + reserved 4; // takes_focus optional .android.graphics.RectProto bounds = 5; optional int32 window_state = 6; }
\ No newline at end of file diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index ba4a5b0ce222..5090d8cb5c3a 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -85,6 +85,7 @@ message SecureSettingsProto { optional SettingProto accessibility_floating_menu_icon_type = 39 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_floating_menu_opacity = 40 [ (android.privacy).dest = DEST_AUTOMATIC ]; optional SettingProto accessibility_floating_menu_fade_enabled = 41 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto odi_captions_volume_ui_enabled = 42 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Accessibility accessibility = 2; diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index bfc1c83e8fc5..1705371a7f4a 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8440,6 +8440,8 @@ <!-- Component name of an activity that allows the user to modify the settings for this dream. --> <attr name="settingsActivity" /> + <!-- A preview, in a drawable resource id, of what the Dream will look like. --> + <attr name="previewImage" format="reference" /> </declare-styleable> <!-- Use <code>trust-agent</code> as the root tag of the XML resource that diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 06f347f4daff..db24475cf780 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -3070,7 +3070,6 @@ <declare-styleable name="AndroidManifestMetaData" parent="AndroidManifestApplication AndroidManifestActivity - AndroidManifestApexSystemService AndroidManifestReceiver AndroidManifestProvider AndroidManifestService @@ -3105,7 +3104,6 @@ <declare-styleable name="AndroidManifestProperty" parent="AndroidManifestApplication AndroidManifestActivity - AndroidManifestApexSystemService AndroidManifestReceiver AndroidManifestProvider AndroidManifestService"> diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java index 2c8c38532d10..6df9002608af 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityEventTest.java @@ -42,14 +42,14 @@ public class AccessibilityEventTest { // and assertAccessibilityEventCleared /** The number of properties of the {@link AccessibilityEvent} class. */ - private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 34; + private static final int A11Y_EVENT_NON_STATIC_FIELD_COUNT = 32; // The number of fields tested in the corresponding CTS AccessibilityRecordTest: // assertAccessibilityRecordCleared, fullyPopulateAccessibilityRecord, // and assertEqualAccessibilityRecord /** The number of properties of the {@link AccessibilityRecord} class. */ - private static final int A11Y_RECORD_NON_STATIC_FIELD_COUNT = 25; + private static final int A11Y_RECORD_NON_STATIC_FIELD_COUNT = 23; @Test public void testImportantForAccessibiity_getSetWorkAcrossParceling() { diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java index 212fdcace6ac..bb1a3b182f91 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java @@ -17,7 +17,6 @@ package android.view.accessibility; import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertSame; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -188,17 +187,6 @@ public class AccessibilityManagerTest { } @Test - public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception { - AccessibilityEvent sentEvent = AccessibilityEvent.obtain( - AccessibilityEvent.TYPE_ANNOUNCEMENT); - - AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); - manager.sendAccessibilityEvent(sentEvent); - - assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain()); - } - - @Test public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception { AccessibilityEvent sentEvent = AccessibilityEvent.obtain(); diff --git a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java b/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java deleted file mode 100644 index 11f4e3cf9304..000000000000 --- a/core/tests/coretests/src/android/view/accessibility/RecycleAccessibilityEventTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (C) 2009 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 android.view.accessibility; - -import androidx.test.filters.SmallTest; - -import junit.framework.TestCase; - -/** - * This class exercises the caching and recycling of {@link AccessibilityEvent}s. - */ -public class RecycleAccessibilityEventTest extends TestCase { - - private static final String CLASS_NAME = "foo.bar.baz.Test"; - private static final String PACKAGE_NAME = "foo.bar.baz"; - private static final String TEXT = "Some stuff"; - - private static final String CONTENT_DESCRIPTION = "Content description"; - private static final int ITEM_COUNT = 10; - private static final int CURRENT_ITEM_INDEX = 1; - - private static final int FROM_INDEX = 1; - private static final int ADDED_COUNT = 2; - private static final int REMOVED_COUNT = 1; - - /** - * If an {@link AccessibilityEvent} is marshaled/unmarshaled correctly - */ - @SmallTest - public void testAccessibilityEventViewTextChangedType() { - AccessibilityEvent first = - AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED); - assertNotNull(first); - - first.setClassName(CLASS_NAME); - first.setPackageName(PACKAGE_NAME); - first.getText().add(TEXT); - first.setFromIndex(FROM_INDEX); - first.setAddedCount(ADDED_COUNT); - first.setRemovedCount(REMOVED_COUNT); - first.setChecked(true); - first.setContentDescription(CONTENT_DESCRIPTION); - first.setItemCount(ITEM_COUNT); - first.setCurrentItemIndex(CURRENT_ITEM_INDEX); - first.setEnabled(true); - first.setPassword(true); - - first.recycle(); - - assertNotNull(first); - assertNull(first.getClassName()); - assertNull(first.getPackageName()); - assertEquals(0, first.getText().size()); - assertFalse(first.isChecked()); - assertNull(first.getContentDescription()); - assertEquals(-1, first.getItemCount()); - assertEquals(AccessibilityEvent.INVALID_POSITION, first.getCurrentItemIndex()); - assertFalse(first.isEnabled()); - assertFalse(first.isPassword()); - assertEquals(-1, first.getFromIndex()); - assertEquals(-1, first.getAddedCount()); - assertEquals(-1, first.getRemovedCount()); - - // get another event from the pool (this must be the recycled first) - AccessibilityEvent second = AccessibilityEvent.obtain(); - assertEquals(first, second); - } -} diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java index c0ced6c9ecdb..69ff7c636934 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java @@ -180,6 +180,16 @@ public class ChooserActivityTest { return clientIntent; } + /** + * Whether {@code #testIsAppPredictionServiceAvailable} should verify the behavior after + * changing the availability conditions at runtime. In the unbundled chooser, the availability + * is cached at start and will never be re-evaluated. + * TODO: remove when we no longer want to test the system's on-the-fly evaluation. + */ + protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() { + return true; + } + /* -------- * The code in this section is unorthodox and can be simplified/reverted when we no longer need * to support the parallel chooser implementations. @@ -784,7 +794,8 @@ public class ChooserActivityTest { assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); assertThat(logger.get(1).mimeType, is("text/plain")); - assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).packageName, is( + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); assertThat(logger.get(1).appProvidedApp, is(0)); assertThat(logger.get(1).appProvidedDirect, is(0)); assertThat(logger.get(1).isWorkprofile, is(false)); @@ -802,7 +813,7 @@ public class ChooserActivityTest { assertThat(logger.event(4).getId(), is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); - // SHARESHEET_EDIT_TARGET_SELECTED: + // SHARESHEET_NEARBY_TARGET_SELECTED: assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); assertThat(logger.get(5).targetType, is(ChooserActivityLogger @@ -814,7 +825,7 @@ public class ChooserActivityTest { - @Test + @Test @Ignore public void testEditImageLogs() throws Exception { Intent sendIntent = createSendImageIntent( Uri.parse("android.resource://com.android.frameworks.coretests/" @@ -853,7 +864,8 @@ public class ChooserActivityTest { assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); assertThat(logger.get(1).mimeType, is("image/png")); - assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).packageName, is( + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); assertThat(logger.get(1).appProvidedApp, is(0)); assertThat(logger.get(1).appProvidedDirect, is(0)); assertThat(logger.get(1).isWorkprofile, is(false)); @@ -1321,6 +1333,10 @@ public class ChooserActivityTest { } else { assertThat(activity.isAppPredictionServiceAvailable(), is(true)); + if (!shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime()) { + return; + } + ChooserActivityOverrideData.getInstance().resources = Mockito.spy(activity.getResources()); when( @@ -2101,7 +2117,8 @@ public class ChooserActivityTest { assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); assertThat(logger.get(1).mimeType, is("text/plain")); - assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).packageName, is( + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); assertThat(logger.get(1).appProvidedApp, is(0)); assertThat(logger.get(1).appProvidedDirect, is(0)); assertThat(logger.get(1).isWorkprofile, is(false)); @@ -2119,7 +2136,7 @@ public class ChooserActivityTest { assertThat(logger.event(4).getId(), is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); - // SHARESHEET_EDIT_TARGET_SELECTED: + // SHARESHEET_APP_TARGET_SELECTED: assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); assertThat(logger.get(5).targetType, is(ChooserActivityLogger @@ -2197,7 +2214,8 @@ public class ChooserActivityTest { assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); assertThat(logger.get(1).mimeType, is("text/plain")); - assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).packageName, is( + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); assertThat(logger.get(1).appProvidedApp, is(0)); assertThat(logger.get(1).appProvidedDirect, is(0)); assertThat(logger.get(1).isWorkprofile, is(false)); @@ -2215,7 +2233,7 @@ public class ChooserActivityTest { .SharesheetTargetSelectedEvent.SHARESHEET_SERVICE_TARGET_SELECTED.getId())); } - @Test + @Test @Ignore public void testEmptyDirectRowLogging() throws InterruptedException { Intent sendIntent = createSendTextIntent(); // We need app targets for direct targets to get displayed @@ -2259,7 +2277,8 @@ public class ChooserActivityTest { assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); assertThat(logger.get(1).mimeType, is("text/plain")); - assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).packageName, is( + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); assertThat(logger.get(1).appProvidedApp, is(0)); assertThat(logger.get(1).appProvidedDirect, is(0)); assertThat(logger.get(1).isWorkprofile, is(false)); @@ -2320,7 +2339,8 @@ public class ChooserActivityTest { assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); assertThat(logger.get(1).mimeType, is("text/plain")); - assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).packageName, is( + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); assertThat(logger.get(1).appProvidedApp, is(0)); assertThat(logger.get(1).appProvidedDirect, is(0)); assertThat(logger.get(1).isWorkprofile, is(false)); @@ -2338,7 +2358,7 @@ public class ChooserActivityTest { assertThat(logger.event(4).getId(), is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); - // SHARESHEET_EDIT_TARGET_SELECTED: + // SHARESHEET_COPY_TARGET_SELECTED: assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); assertThat(logger.get(5).targetType, is(ChooserActivityLogger @@ -2386,7 +2406,8 @@ public class ChooserActivityTest { assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); assertThat(logger.get(1).mimeType, is(TEST_MIME_TYPE)); - assertThat(logger.get(1).packageName, is("com.android.frameworks.coretests")); + assertThat(logger.get(1).packageName, is( + InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); assertThat(logger.get(1).appProvidedApp, is(0)); assertThat(logger.get(1).appProvidedDirect, is(0)); assertThat(logger.get(1).isWorkprofile, is(false)); diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index cdff5858c77d..e9b3c4990ef2 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -43,7 +43,7 @@ filegroup { name: "wm_shell_util-sources", srcs: [ "src/com/android/wm/shell/util/**/*.java", - "src/com/android/wm/shell/common/split/SplitScreenConstants.java" + "src/com/android/wm/shell/common/split/SplitScreenConstants.java", ], path: "src", } @@ -74,13 +74,13 @@ genrule { ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + - "--protolog-class com.android.internal.protolog.common.ProtoLog " + - "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " + - "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " + - "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + - "--loggroups-jar $(location :wm_shell_protolog-groups) " + - "--output-srcjar $(out) " + - "$(locations :wm_shell-sources)", + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " + + "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " + + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + + "--loggroups-jar $(location :wm_shell_protolog-groups) " + + "--output-srcjar $(out) " + + "$(locations :wm_shell-sources)", out: ["wm_shell_protolog.srcjar"], } @@ -92,13 +92,14 @@ genrule { ], tools: ["protologtool"], cmd: "$(location protologtool) generate-viewer-config " + - "--protolog-class com.android.internal.protolog.common.ProtoLog " + - "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + - "--loggroups-jar $(location :wm_shell_protolog-groups) " + - "--viewer-conf $(out) " + - "$(locations :wm_shell-sources)", + "--protolog-class com.android.internal.protolog.common.ProtoLog " + + "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " + + "--loggroups-jar $(location :wm_shell_protolog-groups) " + + "--viewer-conf $(out) " + + "$(locations :wm_shell-sources)", out: ["wm_shell_protolog.json"], } + // End ProtoLog java_library { @@ -123,11 +124,12 @@ android_library { "res", ], java_resources: [ - ":generate-wm_shell_protolog.json" + ":generate-wm_shell_protolog.json", ], static_libs: [ "androidx.appcompat_appcompat", "androidx.arch.core_core-runtime", + "androidx-constraintlayout_constraintlayout", "androidx.dynamicanimation_dynamicanimation", "androidx.recyclerview_recyclerview", "kotlinx-coroutines-android", diff --git a/libs/WindowManager/Shell/res/layout/badged_image_view.xml b/libs/WindowManager/Shell/res/layout/badged_image_view.xml new file mode 100644 index 000000000000..5f07121ec7d3 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/badged_image_view.xml @@ -0,0 +1,55 @@ +<?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. + --> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <ImageView + android:id="@+id/icon_view" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:contentDescription="@null" /> + + <!-- + Icon badge size is defined in Launcher3 BaseIconFactory as 0.444 of icon size. + Constraint guide starts from left, which means for a badge positioned on the right, + percent has to be 1 - 0.444 to have the same effect. + --> + <androidx.constraintlayout.widget.Guideline + android:id="@+id/app_icon_constraint_horizontal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + app:layout_constraintGuide_percent="0.556" /> + + <androidx.constraintlayout.widget.Guideline + android:id="@+id/app_icon_constraint_vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="vertical" + app:layout_constraintGuide_percent="0.556" /> + + <ImageView + android:id="@+id/app_icon_view" + android:layout_width="0dp" + android:layout_height="0dp" + android:contentDescription="@null" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="@id/app_icon_constraint_vertical" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toTopOf="@id/app_icon_constraint_horizontal" /> + +</merge>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java index 686fbbfd6f7c..c52d87dde07f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java @@ -19,7 +19,6 @@ import android.annotation.DrawableRes; import android.annotation.Nullable; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Outline; import android.graphics.Path; @@ -27,14 +26,16 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.PathParser; -import android.view.Gravity; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewOutlineProvider; -import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.constraintlayout.widget.ConstraintLayout; + import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.icons.IconNormalizer; +import com.android.wm.shell.R; import com.android.wm.shell.animation.Interpolators; import java.util.EnumSet; @@ -46,14 +47,12 @@ import java.util.EnumSet; * Badge = the icon associated with the app that created this bubble, this will show work profile * badge if appropriate. */ -public class BadgedImageView extends FrameLayout { +public class BadgedImageView extends ConstraintLayout { /** Same value as Launcher3 dot code */ public static final float WHITE_SCRIM_ALPHA = 0.54f; /** Same as value in Launcher3 IconShape */ public static final int DEFAULT_PATH_SIZE = 100; - /** Same as value in Launcher3 BaseIconFactory */ - private static final float ICON_BADGE_SCALE = 0.444f; /** * Flags that suppress the visibility of the 'new' dot, for one reason or another. If any of @@ -105,11 +104,13 @@ public class BadgedImageView extends FrameLayout { public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + // We manage positioning the badge ourselves + setLayoutDirection(LAYOUT_DIRECTION_LTR); + + LayoutInflater.from(context).inflate(R.layout.badged_image_view, this); - mBubbleIcon = new ImageView(context); - addView(mBubbleIcon); - mAppIcon = new ImageView(context); - addView(mAppIcon); + mBubbleIcon = findViewById(R.id.icon_view); + mAppIcon = findViewById(R.id.app_icon_view); final TypedArray ta = mContext.obtainStyledAttributes(attrs, new int[]{android.R.attr.src}, defStyleAttr, defStyleRes); @@ -161,6 +162,7 @@ public class BadgedImageView extends FrameLayout { public void setRenderedBubble(BubbleViewProvider bubble) { mBubble = bubble; mBubbleIcon.setImageBitmap(bubble.getBubbleIcon()); + mAppIcon.setImageBitmap(bubble.getAppBadge()); if (mDotSuppressionFlags.contains(SuppressionFlag.BEHIND_STACK)) { hideBadge(); } else { @@ -348,26 +350,17 @@ public class BadgedImageView extends FrameLayout { } void showBadge() { - Bitmap badge = mBubble.getAppBadge(); - if (badge == null) { + if (mBubble.getAppBadge() == null) { mAppIcon.setVisibility(GONE); return; } - - final int bubbleSize = mBubble.getBubbleIcon().getWidth(); - final int badgeSize = (int) (ICON_BADGE_SCALE * bubbleSize); - - FrameLayout.LayoutParams appIconParams = (LayoutParams) mAppIcon.getLayoutParams(); - appIconParams.height = badgeSize; - appIconParams.width = badgeSize; + int translationX; if (mOnLeft) { - appIconParams.gravity = Gravity.BOTTOM | Gravity.LEFT; + translationX = -(mBubbleIcon.getWidth() - mAppIcon.getWidth()); } else { - appIconParams.gravity = Gravity.BOTTOM | Gravity.RIGHT; + translationX = 0; } - mAppIcon.setLayoutParams(appIconParams); - - mAppIcon.setImageBitmap(badge); + mAppIcon.setTranslationX(translationX); mAppIcon.setVisibility(VISIBLE); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index af59062ba0f3..9ae67a9bf227 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -386,13 +386,14 @@ public class BubbleExpandedView extends LinearLayout { final TypedArray ta = mContext.obtainStyledAttributes(new int[] { android.R.attr.dialogCornerRadius, android.R.attr.colorBackgroundFloating}); - mCornerRadius = ta.getDimensionPixelSize(0, 0); + boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows( + mContext.getResources()); + mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0; mBackgroundColorFloating = ta.getColor(1, Color.WHITE); mExpandedViewContainer.setBackgroundColor(mBackgroundColorFloating); ta.recycle(); - if (mTaskView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows( - mContext.getResources())) { + if (mTaskView != null) { mTaskView.setCornerRadius(mCornerRadius); } updatePointerView(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index b40021ec82a7..79b765356e9e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -70,6 +70,7 @@ import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.policy.ScreenDecorationsUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.wm.shell.R; import com.android.wm.shell.animation.Interpolators; @@ -822,7 +823,9 @@ public class BubbleStackView extends FrameLayout mAnimatingOutSurfaceView = new SurfaceView(getContext()); mAnimatingOutSurfaceView.setUseAlpha(); mAnimatingOutSurfaceView.setZOrderOnTop(true); - mAnimatingOutSurfaceView.setCornerRadius(mCornerRadius); + boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows( + mContext.getResources()); + mAnimatingOutSurfaceView.setCornerRadius(supportsRoundedCorners ? mCornerRadius : 0); mAnimatingOutSurfaceView.setLayoutParams(new ViewGroup.LayoutParams(0, 0)); mAnimatingOutSurfaceView.getHolder().addCallback(new SurfaceHolder.Callback() { @Override diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 507204ce0229..c9c73fd8f191 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -277,6 +277,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, registerSettingObservers(mUserId); setupTimeoutListener(); updateSettings(); + updateDisplayLayout(mContext.getDisplayId()); mAccessibilityManager = AccessibilityManager.getInstance(context); mAccessibilityManager.addAccessibilityStateChangeListener( @@ -448,8 +449,13 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, onShortcutEnabledChanged(); } - private void updateDisplayLayout(int displayId) { + @VisibleForTesting + void updateDisplayLayout(int displayId) { final DisplayLayout newDisplayLayout = mDisplayController.getDisplayLayout(displayId); + if (newDisplayLayout == null) { + Slog.w(TAG, "Failed to get new DisplayLayout."); + return; + } mDisplayAreaOrganizer.setDisplayLayout(newDisplayLayout); mTutorialHandler.onDisplayChanged(newDisplayLayout); mBackgroundPanelOrganizer.onDisplayChanged(newDisplayLayout); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java index 1b2f4768110b..ec3ef5a27fe0 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java @@ -123,9 +123,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer, ShellExecutor mainExecutor) { super(mainExecutor); - mDisplayLayout.set(displayLayout); + setDisplayLayout(displayLayout); mOneHandedSettingsUtil = oneHandedSettingsUtil; - updateDisplayBounds(); mAnimationController = animationController; final int animationDurationConfig = context.getResources().getInteger( R.integer.config_one_handed_translate_animation_duration); @@ -282,6 +281,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { @VisibleForTesting void setDisplayLayout(@NonNull DisplayLayout displayLayout) { mDisplayLayout.set(displayLayout); + updateDisplayBounds(); } @VisibleForTesting @@ -289,6 +289,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { return mDisplayAreaTokenMap; } + @VisibleForTesting void updateDisplayBounds() { mDefaultDisplayBounds.set(0, 0, mDisplayLayout.width(), mDisplayLayout.height()); mLastVisualDisplayBounds.set(mDefaultDisplayBounds); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java index a8d4d1c28107..ae7b82ff9156 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java @@ -1435,7 +1435,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener, /** * Fades out and removes an overlay surface. */ - private void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback, + void fadeOutAndRemoveOverlay(SurfaceControl surface, Runnable callback, boolean withStartDelay) { if (surface == null) { return; 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 e440feb59825..2749bc8e45b4 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 @@ -65,6 +65,7 @@ public class PipTransition extends PipTransitionController { private static final String TAG = PipTransition.class.getSimpleName(); + private final Context mContext; private final PipTransitionState mPipTransitionState; private final int mEnterExitAnimationDuration; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; @@ -86,6 +87,7 @@ public class PipTransition extends PipTransitionController { Optional<SplitScreenController> splitScreenOptional) { super(pipBoundsState, pipMenuController, pipBoundsAlgorithm, pipAnimationController, transitions, shellTaskOrganizer); + mContext = context; mPipTransitionState = pipTransitionState; mEnterExitAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); @@ -359,6 +361,11 @@ public class PipTransition extends PipTransitionController { animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds, currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP, 0 /* startingAngle */, rotationDelta); + if (sourceHintRect == null) { + // We use content overlay when there is no source rect hint to enter PiP use bounds + // animation. + animator.setUseContentOverlay(mContext); + } } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { startTransaction.setAlpha(leash, 0f); // PiP menu is attached late in the process here to avoid any artifacts on the leash diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java index 1c8b9bc21ae1..22b3ef3bfe0b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java @@ -19,6 +19,7 @@ package com.android.wm.shell.pip; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK; +import static com.android.wm.shell.pip.PipAnimationController.isInPipDirection; import android.annotation.Nullable; import android.app.PictureInPictureParams; @@ -69,6 +70,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH if (direction == TRANSITION_DIRECTION_REMOVE_STACK) { return; } + if (isInPipDirection(direction) && animator.getContentOverlay() != null) { + mPipOrganizer.fadeOutAndRemoveOverlay(animator.getContentOverlay(), + animator::clearContentOverlay, true /* withStartDelay*/); + } onFinishResize(taskInfo, animator.getDestinationBounds(), direction, tx); sendOnPipTransitionFinished(direction); } @@ -76,6 +81,11 @@ public abstract class PipTransitionController implements Transitions.TransitionH @Override public void onPipAnimationCancel(TaskInfo taskInfo, PipAnimationController.PipTransitionAnimator animator) { + final int direction = animator.getTransitionDirection(); + if (isInPipDirection(direction) && animator.getContentOverlay() != null) { + mPipOrganizer.fadeOutAndRemoveOverlay(animator.getContentOverlay(), + animator::clearContentOverlay, true /* withStartDelay */); + } sendOnPipTransitionCancelled(animator.getTransitionDirection()); } }; 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 4c28be042196..83830ec56c32 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 @@ -382,6 +382,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, float splitRatio, RemoteAnimationAdapter adapter) { // Init divider first to make divider leash for remote animation target. mSplitLayout.init(); + // Set false to avoid record new bounds with old task still on top; + mShouldUpdateRecents = false; final WindowContainerTransaction wct = new WindowContainerTransaction(); final WindowContainerTransaction evictWct = new WindowContainerTransaction(); prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct); @@ -406,6 +408,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, new IRemoteAnimationFinishedCallback.Stub() { @Override public void onAnimationFinished() throws RemoteException { + mShouldUpdateRecents = true; mSyncQueue.queue(evictWct); mSyncQueue.runInSync(t -> setDividerVisibility(true, t)); finishedCallback.onAnimationFinished(); @@ -428,6 +431,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onAnimationCancelled() { + mShouldUpdateRecents = true; mSyncQueue.queue(evictWct); mSyncQueue.runInSync(t -> setDividerVisibility(true, t)); try { @@ -834,7 +838,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(), mSplitLayout.isLandscape()); } - updateRecentTasksSplitPair(); + if (present && visible) { + updateRecentTasksSplitPair(); + } for (int i = mListeners.size() - 1; i >= 0; --i) { mListeners.get(i).onTaskStageChanged(taskId, stage, visible); @@ -850,7 +856,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (!mShouldUpdateRecents) { return; } - mRecentTasks.ifPresent(recentTasks -> { Rect topLeftBounds = mSplitLayout.getBounds1(); Rect bottomRightBounds = mSplitLayout.getBounds2(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java index 0683a25ecd41..59eecb5db136 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java @@ -105,6 +105,9 @@ public class StageTaskUnfoldController implements UnfoldListener, OnInsetsChange * @param leash surface leash for the appeared task */ public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { + // Only handle child task surface here. + if (!taskInfo.hasParentTask()) return; + AnimationContext context = new AnimationContext(leash); mAnimationContextByTaskId.put(taskInfo.taskId, context); } @@ -114,6 +117,8 @@ public class StageTaskUnfoldController implements UnfoldListener, OnInsetsChange * @param taskInfo info for the vanished task */ public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { + if (!taskInfo.hasParentTask()) return; + AnimationContext context = mAnimationContextByTaskId.get(taskInfo.taskId); if (context != null) { final SurfaceControl.Transaction transaction = mTransactionPool.acquire(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index 711510d9c133..33a98b2fd80e 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -359,6 +359,28 @@ public class Transitions implements RemoteCallable<Transitions> { return; } + // apply transfer starting window directly if there is no other task change. + final int changeSize = info.getChanges().size(); + if (changeSize == 2) { + boolean nonTaskChange = true; + boolean transferStartingWindow = false; + for (int i = changeSize - 1; i >= 0; --i) { + final TransitionInfo.Change change = info.getChanges().get(i); + if (change.getTaskInfo() != null) { + nonTaskChange = false; + break; + } + if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) { + transferStartingWindow = true; + } + } + if (nonTaskChange && transferStartingWindow) { + t.apply(); + onFinish(transitionToken, null /* wct */, null /* wctCB */); + return; + } + } + final ActiveTransition active = mActiveTransitions.get(activeIdx); active.mInfo = info; active.mStartT = t; diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index 0a3a84923053..16bc50750e1d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -109,6 +109,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { mSpiedTransitionState = spy(new OneHandedState()); when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay); + when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(null); when(mMockDisplayAreaOrganizer.getDisplayAreaTokenMap()).thenReturn(new ArrayMap<>()); when(mMockDisplayAreaOrganizer.isReady()).thenReturn(true); when(mMockBackgroundOrganizer.isRegistered()).thenReturn(true); @@ -153,6 +154,13 @@ public class OneHandedControllerTest extends OneHandedTestCase { } @Test + public void testNullDisplayLayout() { + mSpiedOneHandedController.updateDisplayLayout(0); + + verify(mMockDisplayAreaOrganizer, never()).setDisplayLayout(any()); + } + + @Test public void testStartOneHandedShouldTriggerScheduleOffset() { mSpiedTransitionState.setState(STATE_NONE); mSpiedOneHandedController.setOneHandedEnabled(true); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java index ef16fd391235..1d92a48c25fd 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java @@ -432,4 +432,11 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { assertThat(testSpiedDisplayAreaOrganizer.isReady()).isFalse(); } + + @Test + public void testDisplayArea_setDisplayLayout_should_updateDisplayBounds() { + mSpiedDisplayAreaOrganizer.setDisplayLayout(mDisplayLayout); + + verify(mSpiedDisplayAreaOrganizer).updateDisplayBounds(); + } } diff --git a/location/java/android/location/GnssMeasurementRequest.java b/location/java/android/location/GnssMeasurementRequest.java index f509252e7542..71cb0e32a706 100644 --- a/location/java/android/location/GnssMeasurementRequest.java +++ b/location/java/android/location/GnssMeasurementRequest.java @@ -16,10 +16,14 @@ package android.location; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.util.TimeUtils; + +import com.android.internal.util.Preconditions; import java.util.Objects; @@ -29,13 +33,16 @@ import java.util.Objects; public final class GnssMeasurementRequest implements Parcelable { private final boolean mCorrelationVectorOutputsEnabled; private final boolean mFullTracking; + private final int mIntervalMillis; /** * Creates a {@link GnssMeasurementRequest} with a full list of parameters. */ - private GnssMeasurementRequest(boolean fullTracking, boolean correlationVectorOutputsEnabled) { + private GnssMeasurementRequest(boolean fullTracking, boolean correlationVectorOutputsEnabled, + int intervalMillis) { mFullTracking = fullTracking; mCorrelationVectorOutputsEnabled = correlationVectorOutputsEnabled; + mIntervalMillis = intervalMillis; } /** @@ -68,13 +75,26 @@ public final class GnssMeasurementRequest implements Parcelable { return mFullTracking; } + /** + * Represents the requested time interval between the reported measurements in milliseconds. + * + * <p>If the time interval is not set, the default value is 0, which means the fastest rate the + * GNSS chipset can report. + * + * <p>The GNSS chipset may report measurements with a rate faster than requested. + */ + public @IntRange(from = 0) int getIntervalMillis() { + return mIntervalMillis; + } + @NonNull public static final Creator<GnssMeasurementRequest> CREATOR = new Creator<GnssMeasurementRequest>() { @Override @NonNull public GnssMeasurementRequest createFromParcel(@NonNull Parcel parcel) { - return new GnssMeasurementRequest(parcel.readBoolean(), parcel.readBoolean()); + return new GnssMeasurementRequest(parcel.readBoolean(), parcel.readBoolean(), + parcel.readInt()); } @Override @@ -87,6 +107,7 @@ public final class GnssMeasurementRequest implements Parcelable { public void writeToParcel(@NonNull Parcel parcel, int flags) { parcel.writeBoolean(mFullTracking); parcel.writeBoolean(mCorrelationVectorOutputsEnabled); + parcel.writeInt(mIntervalMillis); } @NonNull @@ -94,11 +115,13 @@ public final class GnssMeasurementRequest implements Parcelable { public String toString() { StringBuilder s = new StringBuilder(); s.append("GnssMeasurementRequest["); + s.append("@"); + TimeUtils.formatDuration(mIntervalMillis, s); if (mFullTracking) { - s.append("FullTracking"); + s.append(", FullTracking"); } if (mCorrelationVectorOutputsEnabled) { - s.append(", CorrelationVectorOutPuts"); + s.append(", CorrelationVectorOutputs"); } s.append(']'); return s.toString(); @@ -115,12 +138,15 @@ public final class GnssMeasurementRequest implements Parcelable { if (mCorrelationVectorOutputsEnabled != other.mCorrelationVectorOutputsEnabled) { return false; } + if (mIntervalMillis != other.mIntervalMillis) { + return false; + } return true; } @Override public int hashCode() { - return Objects.hash(mFullTracking, mCorrelationVectorOutputsEnabled); + return Objects.hash(mFullTracking, mCorrelationVectorOutputsEnabled, mIntervalMillis); } @Override @@ -132,6 +158,7 @@ public final class GnssMeasurementRequest implements Parcelable { public static final class Builder { private boolean mCorrelationVectorOutputsEnabled; private boolean mFullTracking; + private int mIntervalMillis; /** * Constructs a {@link Builder} instance. @@ -145,6 +172,7 @@ public final class GnssMeasurementRequest implements Parcelable { public Builder(@NonNull GnssMeasurementRequest request) { mCorrelationVectorOutputsEnabled = request.isCorrelationVectorOutputsEnabled(); mFullTracking = request.isFullTracking(); + mIntervalMillis = request.getIntervalMillis(); } /** @@ -183,10 +211,25 @@ public final class GnssMeasurementRequest implements Parcelable { return this; } + /** + * Set the time interval between the reported measurements in milliseconds, which is 0 by + * default. + * + * <p>An interval of 0 milliseconds means the fastest rate the chipset can report. + * + * <p>The GNSS chipset may report measurements with a rate faster than requested. + */ + @NonNull public Builder setIntervalMillis(@IntRange(from = 0) int value) { + mIntervalMillis = Preconditions.checkArgumentInRange(value, 0, Integer.MAX_VALUE, + "intervalMillis"); + return this; + } + /** Builds a {@link GnssMeasurementRequest} instance as specified by this builder. */ @NonNull public GnssMeasurementRequest build() { - return new GnssMeasurementRequest(mFullTracking, mCorrelationVectorOutputsEnabled); + return new GnssMeasurementRequest(mFullTracking, mCorrelationVectorOutputsEnabled, + mIntervalMillis); } } } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 7c08913c82cd..300aa15a3afd 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -19,6 +19,7 @@ package android.media.tv.tuner; import android.annotation.BytesLong; import android.annotation.CallbackExecutor; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -688,6 +689,8 @@ public class Tuner implements AutoCloseable { private native Filter nativeOpenFilter(int type, int subType, long bufferSize); private native TimeFilter nativeOpenTimeFilter(); private native String nativeGetFrontendHardwareInfo(); + private native int nativeSetMaxNumberOfFrontends(int frontendType, int maxNumber); + private native int nativeGetMaxNumberOfFrontends(int frontendType); private native Lnb nativeOpenLnbByHandle(int handle); private native Lnb nativeOpenLnbByName(String name); @@ -1307,6 +1310,55 @@ public class Tuner implements AutoCloseable { } } + /** + * Sets the maximum usable frontends number of a given frontend type. It is used to enable or + * disable frontends when cable connection status is changed by user. + * + * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return + * {@link RESULT_UNAVAILABLE}. Use {@link TunerVersionChecker#getTunerVersion()} to check the + * version. + * + * @param frontendType the {@link android.media.tv.tuner.frontend.FrontendSettings.Type} which + * the maximum usable number will be set. + * @param maxNumber the new maximum usable number. + * @return result status of the operation. + */ + @Result + public int setMaxNumberOfFrontends( + @FrontendSettings.Type int frontendType, @IntRange(from = 0) int maxNumber) { + if (!TunerVersionChecker.checkHigherOrEqualVersionTo( + TunerVersionChecker.TUNER_VERSION_2_0, "Set maximum Frontends")) { + return RESULT_UNAVAILABLE; + } + if (maxNumber < 0) { + return RESULT_INVALID_ARGUMENT; + } + int res = nativeSetMaxNumberOfFrontends(frontendType, maxNumber); + if (res == RESULT_SUCCESS) { + // TODO: b/211778848 Update Tuner Resource Manager. + } + return res; + } + + /** + * Get the maximum usable frontends number of a given frontend type. + * + * <p>This API is only supported by Tuner HAL 2.0 or higher. Unsupported version would return + * {@code -1}. Use {@link TunerVersionChecker#getTunerVersion()} to check the version. + * + * @param frontendType the {@link android.media.tv.tuner.frontend.FrontendSettings.Type} which + * the maximum usable number will be queried. + * @return the maximum usable number of the queried frontend type. + */ + @IntRange(from = -1) + public int getMaxNumberOfFrontends(@FrontendSettings.Type int frontendType) { + if (!TunerVersionChecker.checkHigherOrEqualVersionTo( + TunerVersionChecker.TUNER_VERSION_2_0, "Set maximum Frontends")) { + return -1; + } + return nativeGetMaxNumberOfFrontends(frontendType); + } + /** @hide */ public FrontendInfo getFrontendInfoById(int id) { mFrontendLock.lock(); diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index f5606bc3539f..8ccc4fb3cd02 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -1577,6 +1577,24 @@ Result JTuner::getFrontendHardwareInfo(string &info) { return mFeClient->getHardwareInfo(info); } +jint JTuner::setMaxNumberOfFrontends(int32_t type, int32_t maxNumber) { + if (mTunerClient == nullptr) { + ALOGE("tuner is not initialized"); + return (jint)Result::INVALID_STATE; + } + + return (jint)mTunerClient->setMaxNumberOfFrontends(static_cast<FrontendType>(type), maxNumber); +} + +int32_t JTuner::getMaxNumberOfFrontends(int32_t type) { + if (mTunerClient == nullptr) { + ALOGE("tuner is not initialized"); + return -1; + } + + return mTunerClient->getMaxNumberOfFrontends(static_cast<FrontendType>(type)); +} + jobject JTuner::openLnbByHandle(int handle) { if (mTunerClient == nullptr) { return nullptr; @@ -4281,6 +4299,17 @@ static jstring android_media_tv_Tuner_get_frontend_hardware_info(JNIEnv *env, jo return env->NewStringUTF(info.data()); } +static jint android_media_tv_Tuner_set_maximum_frontends(JNIEnv *env, jobject thiz, jint type, + jint maxNumber) { + sp<JTuner> tuner = getTuner(env, thiz); + return tuner->setMaxNumberOfFrontends(type, maxNumber); +} + +static jint android_media_tv_Tuner_get_maximum_frontends(JNIEnv *env, jobject thiz, jint type) { + sp<JTuner> tuner = getTuner(env, thiz); + return tuner->getMaxNumberOfFrontends(type); +} + static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) { sp<JTuner> tuner = getTuner(env, thiz); return tuner->closeFrontend(); @@ -4592,6 +4621,10 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_open_shared_filter}, { "nativeGetFrontendHardwareInfo","()Ljava/lang/String;", (void *)android_media_tv_Tuner_get_frontend_hardware_info }, + { "nativeSetMaxNumberOfFrontends", "(II)I", + (void *)android_media_tv_Tuner_set_maximum_frontends }, + { "nativeGetMaxNumberOfFrontends", "(I)I", + (void *)android_media_tv_Tuner_get_maximum_frontends }, }; static const JNINativeMethod gFilterMethods[] = { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 4cad92b7d0f8..f1b31e3520b1 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -201,6 +201,8 @@ struct JTuner : public RefBase { jint closeFrontend(); jint closeDemux(); Result getFrontendHardwareInfo(string& info); + jint setMaxNumberOfFrontends(int32_t frontendType, int32_t maxNumber); + int32_t getMaxNumberOfFrontends(int32_t frontendType); jweak getObject(); diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp index f917f016939a..3c8fdfe682af 100644 --- a/media/jni/tuner/TunerClient.cpp +++ b/media/jni/tuner/TunerClient.cpp @@ -194,4 +194,23 @@ Result TunerClient::setLna(bool bEnable) { return Result::INVALID_STATE; } +Result TunerClient::setMaxNumberOfFrontends(FrontendType frontendType, int32_t maxNumber) { + if (mTunerService != nullptr) { + Status s = mTunerService->setMaxNumberOfFrontends(frontendType, maxNumber); + return ClientHelper::getServiceSpecificErrorCode(s); + } + + return Result::INVALID_STATE; +} + +int TunerClient::getMaxNumberOfFrontends(FrontendType frontendType) { + if (mTunerService != nullptr) { + int32_t maxNumber; + mTunerService->getMaxNumberOfFrontends(frontendType, &maxNumber); + return maxNumber; + } + + return -1; +} + } // namespace android diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h index 37b8ee1526a5..a9f37e6df3aa 100644 --- a/media/jni/tuner/TunerClient.h +++ b/media/jni/tuner/TunerClient.h @@ -32,6 +32,7 @@ using Status = ::ndk::ScopedAStatus; using ::aidl::android::hardware::tv::tuner::DemuxCapabilities; using ::aidl::android::hardware::tv::tuner::FrontendInfo; +using ::aidl::android::hardware::tv::tuner::FrontendType; using ::aidl::android::hardware::tv::tuner::Result; using ::aidl::android::media::tv::tuner::ITunerService; @@ -132,6 +133,21 @@ public: */ Result setLna(bool bEnable); + /** + * Set the maximum frontend number of a given frontend type. + * + * @param frontendType the frontend type which maximum number will be set. + * @param maxNumber the new maximum number. + */ + Result setMaxNumberOfFrontends(FrontendType frontendType, int32_t maxNumber); + + /** + * Get the maximum frontend number of a given frontend type. + * + * @param frontendType the frontend type which maximum number will be queried. + */ + int getMaxNumberOfFrontends(FrontendType frontendType); + private: /** * An AIDL Tuner Service Singleton assigned at the first time the Tuner Client diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java index ab7b54d98285..c5e1c8d359f3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -57,6 +58,7 @@ public class DreamBackend { public boolean isActive; public ComponentName componentName; public ComponentName settingsComponentName; + public CharSequence description; @Override public String toString() { @@ -123,6 +125,7 @@ public class DreamBackend { DreamInfo dreamInfo = new DreamInfo(); dreamInfo.caption = resolveInfo.loadLabel(pm); dreamInfo.icon = resolveInfo.loadIcon(pm); + dreamInfo.description = getDescription(resolveInfo, pm); dreamInfo.componentName = getDreamComponentName(resolveInfo); dreamInfo.isActive = dreamInfo.componentName.equals(activeDream); dreamInfo.settingsComponentName = getSettingsComponentName(pm, resolveInfo); @@ -132,9 +135,25 @@ public class DreamBackend { return dreamInfos; } + private static CharSequence getDescription(ResolveInfo resolveInfo, PackageManager pm) { + String packageName = resolveInfo.resolvePackageName; + ApplicationInfo applicationInfo = null; + if (packageName == null) { + packageName = resolveInfo.serviceInfo.packageName; + applicationInfo = resolveInfo.serviceInfo.applicationInfo; + } + if (resolveInfo.serviceInfo.descriptionRes != 0) { + return pm.getText(packageName, + resolveInfo.serviceInfo.descriptionRes, + applicationInfo); + } + return null; + } + public ComponentName getDefaultDream() { - if (mDreamManager == null) + if (mDreamManager == null) { return null; + } try { return mDreamManager.getDefaultDreamComponentForUser(mContext.getUserId()); } catch (RemoteException e) { diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 4e2111c7d864..16cece93f2de 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -188,6 +188,7 @@ public class SecureSettings { Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, + Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, Settings.Secure.NOTIFICATION_BUBBLES, Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED, Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index dd1cb6b32d4f..688c48ddebb1 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -321,5 +321,7 @@ public class SecureSettingsValidators { } return true; }); + VALIDATORS.put(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, BOOLEAN_VALIDATOR); + } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 38a258f6ecf0..103e14175f76 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1813,6 +1813,9 @@ class SettingsProtoDumpUtil { dumpSetting(s, p, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED, SecureSettingsProto.Accessibility.ACCESSIBILITY_FLOATING_MENU_FADE_ENABLED); + dumpSetting(s, p, + Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, + SecureSettingsProto.Accessibility.ODI_CAPTIONS_VOLUME_UI_ENABLED); p.end(accessibilityToken); final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP); diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 1e9a41e4d0b8..e907efbacb08 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -260,6 +260,8 @@ <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" /> <!-- For handling silent audio recordings --> <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" /> + <!-- For asking AudioManager audio information --> + <uses-permission android:name="android.permission.QUERY_AUDIO_STATE"/> <!-- to read and change hvac values in a car --> <uses-permission android:name="android.car.permission.CONTROL_CAR_CLIMATE" /> diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 2f0957caaaae..2eff692301b1 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -42,6 +42,7 @@ <item>@string/config_systemUIVendorServiceComponent</item> <item>com.android.systemui.SliceBroadcastRelayHandler</item> <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> + <item>com.android.systemui.accessibility.WindowMagnification</item> <item>com.android.systemui.toast.ToastUI</item> <item>com.android.systemui.wmshell.WMShell</item> <item>com.android.systemui.media.systemsounds.HomeSoundEffectController</item> diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt index 99b283e8ec02..5a86723677b1 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt @@ -71,20 +71,32 @@ class MediaTttCommandLineHelper @Inject constructor( when (args[1]) { MOVE_CLOSER_TO_TRANSFER_COMMAND_NAME -> { mediaTttChipControllerSender.displayChip( - MoveCloserToTransfer(appIconDrawable, otherDeviceName) + MoveCloserToTransfer( + appIconDrawable, APP_ICON_CONTENT_DESCRIPTION, otherDeviceName + ) ) } TRANSFER_INITIATED_COMMAND_NAME -> { val futureTask = FutureTask { fakeUndoRunnable } mediaTttChipControllerSender.displayChip( - TransferInitiated(appIconDrawable, otherDeviceName, futureTask) + TransferInitiated( + appIconDrawable, + APP_ICON_CONTENT_DESCRIPTION, + otherDeviceName, + futureTask + ) ) mainExecutor.executeDelayed({ futureTask.run() }, FUTURE_WAIT_TIME) } TRANSFER_SUCCEEDED_COMMAND_NAME -> { mediaTttChipControllerSender.displayChip( - TransferSucceeded(appIconDrawable, otherDeviceName, fakeUndoRunnable) + TransferSucceeded( + appIconDrawable, + APP_ICON_CONTENT_DESCRIPTION, + otherDeviceName, + fakeUndoRunnable + ) ) } else -> { @@ -118,7 +130,9 @@ class MediaTttCommandLineHelper @Inject constructor( /** A command to DISPLAY the media ttt chip on the RECEIVER device. */ inner class AddChipCommandReceiver : Command { override fun execute(pw: PrintWriter, args: List<String>) { - mediaTttChipControllerReceiver.displayChip(ChipStateReceiver(appIconDrawable)) + mediaTttChipControllerReceiver.displayChip( + ChipStateReceiver(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION) + ) } override fun help(pw: PrintWriter) { pw.println("Usage: adb shell cmd statusbar $ADD_CHIP_COMMAND_RECEIVER_TAG") @@ -156,4 +170,5 @@ val TRANSFER_INITIATED_COMMAND_NAME = TransferInitiated::class.simpleName!! val TRANSFER_SUCCEEDED_COMMAND_NAME = TransferSucceeded::class.simpleName!! private const val FUTURE_WAIT_TIME = 2000L +private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon" private const val TAG = "MediaTapToTransferCli" diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt index 3b429c887796..67721a543427 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt @@ -99,6 +99,7 @@ abstract class MediaTttChipControllerCommon<T : MediaTttChipState>( internal fun setIcon(chipState: T, currentChipView: ViewGroup) { currentChipView.findViewById<CachingIconView>(R.id.app_icon).apply { this.setImageDrawable(chipState.appIconDrawable) + this.contentDescription = chipState.appIconContentDescription } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt index 1e475a5e7c82..c510cbba9c35 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipState.kt @@ -22,7 +22,9 @@ import android.graphics.drawable.Drawable * A superclass chip state that will be subclassed by the sender chip and receiver chip. * * @property appIconDrawable a drawable representing the icon of the app playing the media. + * @property appIconContentDescription a string to use as the content description for the icon. */ open class MediaTttChipState( - internal val appIconDrawable: Drawable + internal val appIconDrawable: Drawable, + internal val appIconContentDescription: String ) diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt index 5397235e0137..df6b93431c93 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt @@ -24,5 +24,6 @@ import com.android.systemui.media.taptotransfer.common.MediaTttChipState * the receiver device. */ class ChipStateReceiver( - appIconDrawable: Drawable -) : MediaTttChipState(appIconDrawable) + appIconDrawable: Drawable, + appIconContentDescription: String +) : MediaTttChipState(appIconDrawable, appIconContentDescription) diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt index 24943b9e2a1e..b1f6faaba924 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt @@ -34,9 +34,10 @@ import java.util.concurrent.Future */ sealed class ChipStateSender( appIconDrawable: Drawable, + appIconContentDescription: String, @StringRes internal val chipText: Int, internal val otherDeviceName: String, -) : MediaTttChipState(appIconDrawable) +) : MediaTttChipState(appIconDrawable, appIconContentDescription) /** * A state representing that the two devices are close but not close enough to initiate a transfer. @@ -44,8 +45,14 @@ sealed class ChipStateSender( */ class MoveCloserToTransfer( appIconDrawable: Drawable, + appIconContentDescription: String, otherDeviceName: String, -) : ChipStateSender(appIconDrawable, R.string.media_move_closer_to_transfer, otherDeviceName) +) : ChipStateSender( + appIconDrawable, + appIconContentDescription, + R.string.media_move_closer_to_transfer, + otherDeviceName +) /** * A state representing that a transfer has been initiated (but not completed). @@ -57,9 +64,15 @@ class MoveCloserToTransfer( */ class TransferInitiated( appIconDrawable: Drawable, + appIconContentDescription: String, otherDeviceName: String, val future: Future<Runnable?> -) : ChipStateSender(appIconDrawable, R.string.media_transfer_playing, otherDeviceName) +) : ChipStateSender( + appIconDrawable, + appIconContentDescription, + R.string.media_transfer_playing, + otherDeviceName +) /** * A state representing that a transfer has been successfully completed. @@ -69,6 +82,11 @@ class TransferInitiated( */ class TransferSucceeded( appIconDrawable: Drawable, + appIconContentDescription: String, otherDeviceName: String, val undoRunnable: Runnable? = null -) : ChipStateSender(appIconDrawable, R.string.media_transfer_playing, otherDeviceName) +) : ChipStateSender(appIconDrawable, + appIconContentDescription, + R.string.media_transfer_playing, + otherDeviceName +) diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt index fce4b98f9abe..77d3d70fc98c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt +++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt @@ -93,7 +93,10 @@ class MediaTttChipControllerSender @Inject constructor( mainExecutor.execute { displayChip( TransferSucceeded( - chipState.appIconDrawable, chipState.otherDeviceName, undoRunnable + chipState.appIconDrawable, + chipState.appIconContentDescription, + chipState.otherDeviceName, + undoRunnable ) ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt index b74ba2646ba3..927ca7a34cf8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt @@ -19,14 +19,18 @@ package com.android.systemui.media.taptotransfer.common import android.content.Context import android.graphics.drawable.Drawable import android.graphics.drawable.Icon +import android.view.View import android.view.ViewGroup import android.view.WindowManager +import android.widget.ImageView import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.util.mockito.any +import com.google.common.truth.Truth.assertThat import org.junit.Before import org.junit.Test +import org.mockito.ArgumentCaptor import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.reset @@ -50,24 +54,24 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { @Test fun displayChip_chipAdded() { - controllerCommon.displayChip(MediaTttChipState(appIconDrawable)) + controllerCommon.displayChip(getState()) verify(windowManager).addView(any(), any()) } @Test fun displayChip_twice_chipNotAddedTwice() { - controllerCommon.displayChip(MediaTttChipState(appIconDrawable)) + controllerCommon.displayChip(getState()) reset(windowManager) - controllerCommon.displayChip(MediaTttChipState(appIconDrawable)) + controllerCommon.displayChip(getState()) verify(windowManager, never()).addView(any(), any()) } @Test fun removeChip_chipRemoved() { // First, add the chip - controllerCommon.displayChip(MediaTttChipState(appIconDrawable)) + controllerCommon.displayChip(getState()) // Then, remove it controllerCommon.removeChip() @@ -82,6 +86,29 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { verify(windowManager, never()).removeView(any()) } + @Test + fun setIcon_viewHasIconAndContentDescription() { + controllerCommon.displayChip(getState()) + val chipView = getChipView() + val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context) + val contentDescription = "test description" + + controllerCommon.setIcon(MediaTttChipState(drawable, contentDescription), chipView) + + assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(contentDescription) + } + + private fun getState() = MediaTttChipState(appIconDrawable, APP_ICON_CONTENT_DESCRIPTION) + + private fun getChipView(): ViewGroup { + val viewCaptor = ArgumentCaptor.forClass(View::class.java) + verify(windowManager).addView(viewCaptor.capture(), any()) + return viewCaptor.value as ViewGroup + } + + private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon) + inner class TestControllerCommon( context: Context, windowManager: WindowManager @@ -92,3 +119,5 @@ class MediaTttChipControllerCommonTest : SysuiTestCase() { } } } + +private const val APP_ICON_CONTENT_DESCRIPTION = "Content description" diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt index 2ff472fc7abe..afaab807c74c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt @@ -16,7 +16,6 @@ package com.android.systemui.media.taptotransfer.receiver -import android.graphics.drawable.Drawable import android.graphics.drawable.Icon import android.view.View import android.view.ViewGroup @@ -50,10 +49,12 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { @Test fun displayChip_chipContainsIcon() { val drawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context) + val contentDescription = "Test description" - controllerReceiver.displayChip(ChipStateReceiver(drawable)) + controllerReceiver.displayChip(ChipStateReceiver(drawable, contentDescription)) - assertThat(getChipView().getAppIconDrawable()).isEqualTo(drawable) + assertThat(getChipView().getAppIconView().drawable).isEqualTo(drawable) + assertThat(getChipView().getAppIconView().contentDescription).isEqualTo(contentDescription) } private fun getChipView(): ViewGroup { @@ -62,6 +63,5 @@ class MediaTttChipControllerReceiverTest : SysuiTestCase() { return viewCaptor.value as ViewGroup } - private fun ViewGroup.getAppIconDrawable(): Drawable = - (this.requireViewById<ImageView>(R.id.app_icon)).drawable + private fun ViewGroup.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt index 028ec55ce28e..caef5b901e0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt @@ -70,7 +70,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { controllerSender.displayChip(moveCloserToTransfer()) val chipView = getChipView() - assertThat(chipView.getAppIconDrawable()).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC) assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) @@ -85,7 +86,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { // Assert we're still in the loading state val chipView = getChipView() - assertThat(chipView.getAppIconDrawable()).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC) assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.VISIBLE) assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE) @@ -155,7 +157,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { controllerSender.displayChip(transferSucceeded()) val chipView = getChipView() - assertThat(chipView.getAppIconDrawable()).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconDrawable) + assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_ICON_CONTENT_DESC) assertThat(chipView.getChipText()).contains(DEVICE_NAME) assertThat(chipView.getLoadingIconVisibility()).isEqualTo(View.GONE) } @@ -220,8 +223,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE) } - private fun LinearLayout.getAppIconDrawable(): Drawable = - (this.requireViewById<ImageView>(R.id.app_icon)).drawable + private fun LinearLayout.getAppIconView() = this.requireViewById<ImageView>(R.id.app_icon) private fun LinearLayout.getChipText(): String = (this.requireViewById<TextView>(R.id.text)).text as String @@ -238,20 +240,22 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() { } /** Helper method providing default parameters to not clutter up the tests. */ - private fun moveCloserToTransfer() = MoveCloserToTransfer(appIconDrawable, DEVICE_NAME) + private fun moveCloserToTransfer() = + MoveCloserToTransfer(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME) /** Helper method providing default parameters to not clutter up the tests. */ private fun transferInitiated( future: Future<Runnable?> = TEST_FUTURE - ) = TransferInitiated(appIconDrawable, DEVICE_NAME, future) + ) = TransferInitiated(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, future) /** Helper method providing default parameters to not clutter up the tests. */ private fun transferSucceeded( undoRunnable: Runnable? = null - ) = TransferSucceeded(appIconDrawable, DEVICE_NAME, undoRunnable) + ) = TransferSucceeded(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME, undoRunnable) } private const val DEVICE_NAME = "My Tablet" +private const val APP_ICON_CONTENT_DESC = "Content description" // Use a settable future that hasn't yet been set so that we don't immediately switch to the success // state. private val TEST_FUTURE: SettableFuture<Runnable?> = SettableFuture.create() diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index a63dd005f988..037dc1f6795c 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -578,7 +578,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb synchronized (mLock) { if (mWindowMagnificationMgr == null) { mWindowMagnificationMgr = new WindowMagnificationManager(mContext, - mUserId, this, mAms.getTraceManager(), + mLock, this, mAms.getTraceManager(), mScaleProvider); } return mWindowMagnificationMgr; diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java index 336f0bbbe518..c4a577d6e461 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java @@ -87,7 +87,7 @@ public class WindowMagnificationManager implements }) public @interface WindowPosition {} - private final Object mLock = new Object(); + private final Object mLock; private final Context mContext; @VisibleForTesting @GuardedBy("mLock") @@ -152,9 +152,10 @@ public class WindowMagnificationManager implements private final AccessibilityTraceManager mTrace; private final MagnificationScaleProvider mScaleProvider; - public WindowMagnificationManager(Context context, int userId, @NonNull Callback callback, + public WindowMagnificationManager(Context context, Object lock, @NonNull Callback callback, AccessibilityTraceManager trace, MagnificationScaleProvider scaleProvider) { mContext = context; + mLock = lock; mCallback = callback; mTrace = trace; mScaleProvider = scaleProvider; diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index f8da03539ae6..efa026baefac 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -3907,14 +3907,20 @@ public class UserBackupManagerService { } int operationType; + TransportConnection transportConnection = null; try { - operationType = getOperationTypeFromTransport( - mTransportManager.getTransportClientOrThrow(transport, /* caller */ - "BMS.beginRestoreSession")); + transportConnection = mTransportManager.getTransportClientOrThrow( + transport, /* caller */"BMS.beginRestoreSession"); + operationType = getOperationTypeFromTransport(transportConnection); } catch (TransportNotAvailableException | TransportNotRegisteredException | RemoteException e) { Slog.w(TAG, "Failed to get operation type from transport: " + e); return null; + } finally { + if (transportConnection != null) { + mTransportManager.disposeOfTransportClient(transportConnection, + /* caller */"BMS.beginRestoreSession"); + } } synchronized (this) { diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java index e2a814bba015..97ec3bb7127d 100644 --- a/services/companion/java/com/android/server/companion/PersistentDataStore.java +++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java @@ -38,13 +38,13 @@ import android.net.MacAddress; import android.os.Environment; import android.util.ArrayMap; import android.util.AtomicFile; -import android.util.ExceptionUtils; import android.util.Slog; import android.util.SparseArray; import android.util.TypedXmlPullParser; import android.util.TypedXmlSerializer; import android.util.Xml; +import com.android.internal.util.FunctionalUtils.ThrowingConsumer; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; @@ -53,6 +53,7 @@ import org.xmlpull.v1.XmlSerializer; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.util.Collection; import java.util.HashSet; @@ -307,26 +308,23 @@ final class PersistentDataStore { private void persistStateToFileLocked(@NonNull AtomicFile file, @Nullable Collection<AssociationInfo> associations, @NonNull Map<String, Set<Integer>> previouslyUsedIdsPerPackage) { - file.write(out -> { - try { - final TypedXmlSerializer serializer = Xml.resolveSerializer(out); - serializer.setFeature( - "http://xmlpull.org/v1/doc/features.html#indent-output", true); - - serializer.startDocument(null, true); - serializer.startTag(null, XML_TAG_STATE); - writeIntAttribute(serializer, - XML_ATTR_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION); - - writeAssociations(serializer, associations); - writePreviouslyUsedIds(serializer, previouslyUsedIdsPerPackage); - - serializer.endTag(null, XML_TAG_STATE); - serializer.endDocument(); - } catch (Exception e) { - Slog.e(LOG_TAG, "Error while writing associations file", e); - throw ExceptionUtils.propagate(e); - } + // Writing to file could fail, for example, if the user has been recently removed and so was + // their DE (/data/system_de/<user-id>/) directory. + writeToFileSafely(file, out -> { + final TypedXmlSerializer serializer = Xml.resolveSerializer(out); + serializer.setFeature( + "http://xmlpull.org/v1/doc/features.html#indent-output", true); + + serializer.startDocument(null, true); + serializer.startTag(null, XML_TAG_STATE); + writeIntAttribute(serializer, + XML_ATTR_PERSISTENCE_VERSION, CURRENT_PERSISTENCE_VERSION); + + writeAssociations(serializer, associations); + writePreviouslyUsedIds(serializer, previouslyUsedIdsPerPackage); + + serializer.endTag(null, XML_TAG_STATE); + serializer.endDocument(); }); } @@ -524,4 +522,13 @@ final class PersistentDataStore { } return associationInfo; } + + private static void writeToFileSafely(@NonNull AtomicFile file, + @NonNull ThrowingConsumer<FileOutputStream> consumer) { + try { + file.write(consumer); + } catch (Exception e) { + Slog.e(LOG_TAG, "Error while writing to file " + file, e); + } + } } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index c7f4b4d03648..780afd86b373 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -80,6 +80,7 @@ import android.content.res.ObbInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; +import android.os.Build; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; @@ -1648,7 +1649,8 @@ class StorageManagerService extends IStorageManager.Stub // obb data to its new location. This may take time depending on the size of // the data to be copied so it's done on the StorageManager worker thread. // This needs to be finished before start mounting obb directories. - if (userId == 0) { + if (userId == 0 + && Build.VERSION.DEVICE_INITIAL_SDK_INT < Build.VERSION_CODES.Q) { mPmInternal.migrateLegacyObbData(); } diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 0c94fbbcf74f..c55bbe8e971b 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -920,7 +920,7 @@ public final class CachedAppOptimizer { void unfreezeTemporarily(ProcessRecord app) { if (mUseFreezer) { synchronized (mProcLock) { - if (app.mOptRecord.isFrozen()) { + if (app.mOptRecord.isFrozen() || app.mOptRecord.isPendingFreeze()) { unfreezeAppLSP(app); freezeAppAsyncLSP(app); } diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java index 2465ec5a4ca9..6f7176816ddb 100644 --- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java @@ -38,8 +38,8 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement private static final String TAG = "Biometrics/AcquisitionClient"; - private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES = - VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH); + private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES = + VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK); private static final VibrationEffect SUCCESS_VIBRATION_EFFECT = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); @@ -196,7 +196,7 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement getContext().getOpPackageName(), SUCCESS_VIBRATION_EFFECT, getClass().getSimpleName() + "::success", - TOUCH_VIBRATION_ATTRIBUTES); + HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); } } @@ -207,7 +207,7 @@ public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implement getContext().getOpPackageName(), ERROR_VIBRATION_EFFECT, getClass().getSimpleName() + "::error", - TOUCH_VIBRATION_ATTRIBUTES); + HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES); } } } diff --git a/services/core/java/com/android/server/communal/CommunalManagerService.java b/services/core/java/com/android/server/communal/CommunalManagerService.java index df95bf597dc0..12203919a5e7 100644 --- a/services/core/java/com/android/server/communal/CommunalManagerService.java +++ b/services/core/java/com/android/server/communal/CommunalManagerService.java @@ -341,7 +341,8 @@ public final class CommunalManagerService extends SystemService { UserHandle.SYSTEM, mIntentFilter, /* broadcastPermission= */null, - /* scheduler= */ null); + /* scheduler= */ null, + Context.RECEIVER_EXPORTED_UNAUDITED); } private void unregister() { diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index c0a6abf3a121..c4f2b14e335b 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -714,7 +714,6 @@ public final class DisplayManagerService extends SystemService { display.getDisplayInfoLocked().shouldConstrainMetricsForLauncher; if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) { handleLogicalDisplayChangedLocked(display); - scheduleTraversalLocked(false); } } } diff --git a/services/core/java/com/android/server/input/InputShellCommand.java b/services/core/java/com/android/server/input/InputShellCommand.java index 9fa6fad4f926..773dc680d4cb 100644 --- a/services/core/java/com/android/server/input/InputShellCommand.java +++ b/services/core/java/com/android/server/input/InputShellCommand.java @@ -560,7 +560,12 @@ public class InputShellCommand extends ShellCommand { sleep(duration); for (KeyEvent event: events) { - injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); + final int keyCode = event.getKeyCode(); + final KeyEvent upEvent = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, + 0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/, + inputSource); + injectKeyEventAsync(upEvent); + metaState &= ~MODIFIER.getOrDefault(keyCode, 0); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java index 8f078158aa5c..220d790d1208 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java @@ -515,7 +515,7 @@ final class InputMethodBindingController { if (DEBUG) { Slog.d(TAG, "Cannot show input: no IME bound. Rebinding."); } - bindCurrentMethodLocked(); + bindCurrentMethod(); return; } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 06ba0e6aeb6b..c87dc8987b25 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -2409,7 +2409,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) { Slog.d(TAG, "Avoiding IME startup and unbinding current input method."); } - mBindingController.unbindCurrentMethodLocked(); + mBindingController.unbindCurrentMethod(); return InputBindResult.NO_EDITOR; } diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java index 0fd7cc18a11c..e40d86a55b77 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java @@ -331,15 +331,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub mAppOpsManager = context.getSystemService(AppOpsManager.class); startMonitoringOpChanges(); - - HostEndpointInfo info = new HostEndpointInfo(); - info.hostEndpointId = (char) mHostEndPointId; - info.packageName = mPackage; - info.attributionTag = mAttributionTag; - info.type = (mUid == Process.SYSTEM_UID) - ? HostEndpointInfo.Type.TYPE_FRAMEWORK - : HostEndpointInfo.Type.TYPE_APP; - mContextHubProxy.onHostEndpointConnected(info); + sendHostEndpointConnectedEvent(); } /* package */ ContextHubClientBroker( @@ -556,6 +548,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub /* package */ void onHubReset() { invokeCallback(callback -> callback.onHubReset()); sendPendingIntent(() -> createIntent(ContextHubManager.EVENT_HUB_RESET)); + + // Re-send the host endpoint connected event as the Context Hub restarted. + sendHostEndpointConnectedEvent(); } /** @@ -895,6 +890,17 @@ public class ContextHubClientBroker extends IContextHubClient.Stub } } + private void sendHostEndpointConnectedEvent() { + HostEndpointInfo info = new HostEndpointInfo(); + info.hostEndpointId = (char) mHostEndPointId; + info.packageName = mPackage; + info.attributionTag = mAttributionTag; + info.type = (mUid == Process.SYSTEM_UID) + ? HostEndpointInfo.Type.TYPE_FRAMEWORK + : HostEndpointInfo.Type.TYPE_APP; + mContextHubProxy.onHostEndpointConnected(info); + } + /** * Dump debugging info as ClientBrokerProto * diff --git a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java index 47146c1a6d70..d08e5dc94206 100644 --- a/services/core/java/com/android/server/location/eventlog/LocalEventLog.java +++ b/services/core/java/com/android/server/location/eventlog/LocalEventLog.java @@ -21,26 +21,23 @@ import static java.lang.Integer.bitCount; import android.annotation.Nullable; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.Arrays; +import java.util.ConcurrentModificationException; import java.util.NoSuchElementException; import java.util.Objects; /** * An in-memory event log to support historical event information. The log is of a constant size, * and new events will overwrite old events as the log fills up. - * - * @param <T> log event type */ public class LocalEventLog<T> { - /** - * Consumer of log events for iterating over the log. - * - * @param <T> log event type - */ + /** Consumer of log events for iterating over the log. */ public interface LogConsumer<T> { /** Invoked with a time and a logEvent. */ void acceptLog(long time, T logEvent); @@ -48,12 +45,13 @@ public class LocalEventLog<T> { // masks for the entries field. 1 bit is used to indicate whether this is a filler event or not, // and 31 bits to store the time delta. - private static final int IS_FILLER_MASK = 0b10000000000000000000000000000000; + private static final int IS_FILLER_MASK = 0b10000000000000000000000000000000; private static final int TIME_DELTA_MASK = 0b01111111111111111111111111111111; private static final int IS_FILLER_OFFSET = countTrailingZeros(IS_FILLER_MASK); private static final int TIME_DELTA_OFFSET = countTrailingZeros(TIME_DELTA_MASK); + @VisibleForTesting static final int MAX_TIME_DELTA = (1 << bitCount(TIME_DELTA_MASK)) - 1; private static int countTrailingZeros(int i) { @@ -79,7 +77,7 @@ public class LocalEventLog<T> { return (entry & IS_FILLER_MASK) != 0; } - // circular buffer of log entries and events. each entry corrosponds to the log event at the + // circular buffer of log entries and events. each entry corresponds to the log event at the // same index. the log entry holds the filler status and time delta according to the bit masks // above, and the log event is the log event. @@ -103,6 +101,9 @@ public class LocalEventLog<T> { @GuardedBy("this") long mLastLogTime; + @GuardedBy("this") + long mModificationCount; + @SuppressWarnings("unchecked") public LocalEventLog(int size, Class<T> clazz) { Preconditions.checkArgument(size > 0); @@ -143,6 +144,7 @@ public class LocalEventLog<T> { if (isEmpty()) { mStartTime = time; mLastLogTime = mStartTime; + mModificationCount++; } addLogEventInternal(false, (int) delta, logEvent); @@ -156,6 +158,7 @@ public class LocalEventLog<T> { if (mLogSize == mEntries.length) { // if log is full, size will remain the same, but update the start time mStartTime += getTimeDelta(mEntries[startIndex()]); + mModificationCount++; } else { // otherwise add an item mLogSize++; @@ -170,11 +173,12 @@ public class LocalEventLog<T> { /** Clears the log of all entries. */ public synchronized void clear() { - // clear entries to allow gc + // clear entries to aid gc Arrays.fill(mLogEvents, null); mLogEndIndex = 0; mLogSize = 0; + mModificationCount++; mStartTime = -1; mLastLogTime = -1; @@ -186,7 +190,10 @@ public class LocalEventLog<T> { return mLogSize == 0; } - /** Iterates over the event log, passing each log string to the given consumer. */ + /** + * Iterates over the event log, passing each log event to the given consumer. Locks the log + * while executing so that {@link ConcurrentModificationException}s cannot occur. + */ public synchronized void iterate(LogConsumer<? super T> consumer) { LogIterator it = new LogIterator(); while (it.hasNext()) { @@ -195,15 +202,53 @@ public class LocalEventLog<T> { } } + /** + * Iterates over all the given event logs in time order, passing each log event to the given + * consumer. It is the caller's responsibility to ensure that {@link + * ConcurrentModificationException}s cannot occur, whether through locking or other means. + */ + @SafeVarargs + public static <T> void iterate(LogConsumer<? super T> consumer, LocalEventLog<T>... logs) { + ArrayList<LocalEventLog<T>.LogIterator> its = new ArrayList<>(logs.length); + for (LocalEventLog<T> log : logs) { + LocalEventLog<T>.LogIterator it = log.new LogIterator(); + if (it.hasNext()) { + its.add(it); + it.next(); + } + } + + while (true) { + LocalEventLog<T>.LogIterator next = null; + for (LocalEventLog<T>.LogIterator it : its) { + if (it != null && (next == null || it.getTime() < next.getTime())) { + next = it; + } + } + + if (next == null) { + return; + } + + consumer.acceptLog(next.getTime(), next.getLog()); + + if (next.hasNext()) { + next.next(); + } else { + its.remove(next); + } + } + } + // returns the index of the first element @GuardedBy("this") - private int startIndex() { + int startIndex() { return wrapIndex(mLogEndIndex - mLogSize); } // returns the index after this one @GuardedBy("this") - private int incrementIndex(int index) { + int incrementIndex(int index) { if (index == -1) { return startIndex(); } else if (index >= 0) { @@ -215,12 +260,15 @@ public class LocalEventLog<T> { // rolls over the given index if necessary @GuardedBy("this") - private int wrapIndex(int index) { + int wrapIndex(int index) { // java modulo will keep negative sign, we need to rollover return (index % mEntries.length + mEntries.length) % mEntries.length; } - private class LogIterator { + /** Iterator over log times and events. */ + protected final class LogIterator { + + private final long mModificationCount; private long mLogTime; private int mIndex; @@ -229,8 +277,10 @@ public class LocalEventLog<T> { private long mCurrentTime; private T mCurrentLogEvent; - LogIterator() { + public LogIterator() { synchronized (LocalEventLog.this) { + mModificationCount = LocalEventLog.this.mModificationCount; + mLogTime = mStartTime; mIndex = -1; mCount = -1; @@ -241,6 +291,7 @@ public class LocalEventLog<T> { public boolean hasNext() { synchronized (LocalEventLog.this) { + checkModifications(); return mCount < mLogSize; } } @@ -277,5 +328,12 @@ public class LocalEventLog<T> { } } while (mCount < mLogSize && isFiller(mEntries[mIndex])); } + + @GuardedBy("LocalEventLog.this") + private void checkModifications() { + if (mModificationCount != LocalEventLog.this.mModificationCount) { + throw new ConcurrentModificationException(); + } + } } } diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java index 94953e0b72f1..45436e753191 100644 --- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java +++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java @@ -52,16 +52,28 @@ public class LocationEventLog extends LocalEventLog<Object> { if (D) { return 600; } else { + return 300; + } + } + + private static int getLocationsLogSize() { + if (D) { return 200; + } else { + return 100; } } @GuardedBy("mAggregateStats") private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats; - public LocationEventLog() { + @GuardedBy("this") + private final LocationsEventLog mLocationsLog; + + private LocationEventLog() { super(getLogSize(), Object.class); mAggregateStats = new ArrayMap<>(4); + mLocationsLog = new LocationsEventLog(getLocationsLogSize()); } /** Copies out all aggregated stats. */ @@ -95,39 +107,39 @@ public class LocationEventLog extends LocalEventLog<Object> { /** Logs a user switched event. */ public void logUserSwitched(int userIdFrom, int userIdTo) { - addLogEvent(new UserSwitchedEvent(userIdFrom, userIdTo)); + addLog(new UserSwitchedEvent(userIdFrom, userIdTo)); } /** Logs a location enabled/disabled event. */ public void logLocationEnabled(int userId, boolean enabled) { - addLogEvent(new LocationEnabledEvent(userId, enabled)); + addLog(new LocationEnabledEvent(userId, enabled)); } /** Logs a location enabled/disabled event. */ public void logAdasLocationEnabled(int userId, boolean enabled) { - addLogEvent(new LocationAdasEnabledEvent(userId, enabled)); + addLog(new LocationAdasEnabledEvent(userId, enabled)); } /** Logs a location provider enabled/disabled event. */ public void logProviderEnabled(String provider, int userId, boolean enabled) { - addLogEvent(new ProviderEnabledEvent(provider, userId, enabled)); + addLog(new ProviderEnabledEvent(provider, userId, enabled)); } /** Logs a location provider being replaced/unreplaced by a mock provider. */ public void logProviderMocked(String provider, boolean mocked) { - addLogEvent(new ProviderMockedEvent(provider, mocked)); + addLog(new ProviderMockedEvent(provider, mocked)); } /** Logs a new client registration for a location provider. */ public void logProviderClientRegistered(String provider, CallerIdentity identity, LocationRequest request) { - addLogEvent(new ProviderClientRegisterEvent(provider, true, identity, request)); + addLog(new ProviderClientRegisterEvent(provider, true, identity, request)); getAggregateStats(provider, identity).markRequestAdded(request.getIntervalMillis()); } /** Logs a client unregistration for a location provider. */ public void logProviderClientUnregistered(String provider, CallerIdentity identity) { - addLogEvent(new ProviderClientRegisterEvent(provider, false, identity, null)); + addLog(new ProviderClientRegisterEvent(provider, false, identity, null)); getAggregateStats(provider, identity).markRequestRemoved(); } @@ -144,7 +156,7 @@ public class LocationEventLog extends LocalEventLog<Object> { /** Logs a client for a location provider entering the foreground state. */ public void logProviderClientForeground(String provider, CallerIdentity identity) { if (D) { - addLogEvent(new ProviderClientForegroundEvent(provider, true, identity)); + addLog(new ProviderClientForegroundEvent(provider, true, identity)); } getAggregateStats(provider, identity).markRequestForeground(); } @@ -152,7 +164,7 @@ public class LocationEventLog extends LocalEventLog<Object> { /** Logs a client for a location provider leaving the foreground state. */ public void logProviderClientBackground(String provider, CallerIdentity identity) { if (D) { - addLogEvent(new ProviderClientForegroundEvent(provider, false, identity)); + addLog(new ProviderClientForegroundEvent(provider, false, identity)); } getAggregateStats(provider, identity).markRequestBackground(); } @@ -160,32 +172,34 @@ public class LocationEventLog extends LocalEventLog<Object> { /** Logs a client for a location provider entering the permitted state. */ public void logProviderClientPermitted(String provider, CallerIdentity identity) { if (D) { - addLogEvent(new ProviderClientPermittedEvent(provider, true, identity)); + addLog(new ProviderClientPermittedEvent(provider, true, identity)); } } /** Logs a client for a location provider leaving the permitted state. */ public void logProviderClientUnpermitted(String provider, CallerIdentity identity) { if (D) { - addLogEvent(new ProviderClientPermittedEvent(provider, false, identity)); + addLog(new ProviderClientPermittedEvent(provider, false, identity)); } } /** Logs a change to the provider request for a location provider. */ public void logProviderUpdateRequest(String provider, ProviderRequest request) { - addLogEvent(new ProviderUpdateEvent(provider, request)); + addLog(new ProviderUpdateEvent(provider, request)); } /** Logs a new incoming location for a location provider. */ public void logProviderReceivedLocations(String provider, int numLocations) { - addLogEvent(new ProviderReceiveLocationEvent(provider, numLocations)); + synchronized (this) { + mLocationsLog.logProviderReceivedLocations(provider, numLocations); + } } /** Logs a location deliver for a client of a location provider. */ public void logProviderDeliveredLocations(String provider, int numLocations, CallerIdentity identity) { - if (D) { - addLogEvent(new ProviderDeliverLocationEvent(provider, numLocations, identity)); + synchronized (this) { + mLocationsLog.logProviderDeliveredLocations(provider, numLocations, identity); } getAggregateStats(provider, identity).markLocationDelivered(); } @@ -193,19 +207,24 @@ public class LocationEventLog extends LocalEventLog<Object> { /** Logs that a provider has entered or exited stationary throttling. */ public void logProviderStationaryThrottled(String provider, boolean throttled, ProviderRequest request) { - addLogEvent(new ProviderStationaryThrottledEvent(provider, throttled, request)); + addLog(new ProviderStationaryThrottledEvent(provider, throttled, request)); } /** Logs that the location power save mode has changed. */ public void logLocationPowerSaveMode( @LocationPowerSaveMode int locationPowerSaveMode) { - addLogEvent(new LocationPowerSaveModeEvent(locationPowerSaveMode)); + addLog(new LocationPowerSaveModeEvent(locationPowerSaveMode)); } - private void addLogEvent(Object logEvent) { + private void addLog(Object logEvent) { addLog(SystemClock.elapsedRealtime(), logEvent); } + @Override + public synchronized void iterate(LogConsumer<? super Object> consumer) { + iterate(consumer, this, mLocationsLog); + } + public void iterate(Consumer<String> consumer) { iterate(consumer, null); } @@ -488,6 +507,26 @@ public class LocationEventLog extends LocalEventLog<Object> { } } + private static final class LocationsEventLog extends LocalEventLog<Object> { + + LocationsEventLog(int size) { + super(size, Object.class); + } + + public void logProviderReceivedLocations(String provider, int numLocations) { + addLog(new ProviderReceiveLocationEvent(provider, numLocations)); + } + + public void logProviderDeliveredLocations(String provider, int numLocations, + CallerIdentity identity) { + addLog(new ProviderDeliverLocationEvent(provider, numLocations, identity)); + } + + private void addLog(Object logEvent) { + this.addLog(SystemClock.elapsedRealtime(), logEvent); + } + } + /** * Aggregate statistics for a single package under a single provider. */ diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java index 699f1439538e..7bb0d4899de5 100644 --- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java @@ -114,7 +114,8 @@ public final class GnssMeasurementsProvider extends protected boolean registerWithService(GnssMeasurementRequest request, Collection<GnssListenerRegistration> registrations) { if (mGnssNative.startMeasurementCollection(request.isFullTracking(), - request.isCorrelationVectorOutputsEnabled())) { + request.isCorrelationVectorOutputsEnabled(), + request.getIntervalMillis())) { if (D) { Log.d(TAG, "starting gnss measurements (" + request + ")"); } diff --git a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java index 1eef0de3a05d..cc5dcf30c957 100644 --- a/services/core/java/com/android/server/location/gnss/hal/GnssNative.java +++ b/services/core/java/com/android/server/location/gnss/hal/GnssNative.java @@ -735,9 +735,10 @@ public class GnssNative { * Starts measurement collection. */ public boolean startMeasurementCollection(boolean enableFullTracking, - boolean enableCorrVecOutputs) { + boolean enableCorrVecOutputs, int intervalMillis) { Preconditions.checkState(mRegistered); - return mGnssHal.startMeasurementCollection(enableFullTracking, enableCorrVecOutputs); + return mGnssHal.startMeasurementCollection(enableFullTracking, enableCorrVecOutputs, + intervalMillis); } /** @@ -1310,8 +1311,9 @@ public class GnssNative { } protected boolean startMeasurementCollection(boolean enableFullTracking, - boolean enableCorrVecOutputs) { - return native_start_measurement_collection(enableFullTracking, enableCorrVecOutputs); + boolean enableCorrVecOutputs, int intervalMillis) { + return native_start_measurement_collection(enableFullTracking, enableCorrVecOutputs, + intervalMillis); } protected boolean stopMeasurementCollection() { @@ -1475,7 +1477,7 @@ public class GnssNative { private static native boolean native_is_measurement_supported(); private static native boolean native_start_measurement_collection(boolean enableFullTracking, - boolean enableCorrVecOutputs); + boolean enableCorrVecOutputs, int intervalMillis); private static native boolean native_stop_measurement_collection(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index f4740448b8a9..cfcf199d01a4 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -404,7 +404,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) { // Aggressively close old sessions because we are running low on storage // Their staging dirs will be removed too - session.abandon(); + PackageInstallerSession root = !session.hasParentSessionId() + ? session : mSessions.get(session.getParentSessionId()); + if (!root.isDestroyed()) { + root.abandon(); + } } else { // Session is new enough, so it deserves to be kept even on low storage unclaimedStagingDirsOnVolume.remove(session.stageDir); @@ -1623,7 +1627,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements progress); } - public void onStagedSessionChanged(PackageInstallerSession session) { + public void onSessionChanged(PackageInstallerSession session) { session.markUpdated(); mSettingsWriteRequest.schedule(); if (mOkToSendBroadcasts && !session.isDestroyed()) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index a94985c226ea..f45e54b04e54 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -81,7 +81,7 @@ import android.content.pm.InstallationFileParcel; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; -import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode; +import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; @@ -151,7 +151,6 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.server.LocalServices; -import com.android.server.SystemConfig; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.dex.DexManager; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -229,8 +228,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_IS_READY = "isReady"; private static final String ATTR_IS_FAILED = "isFailed"; private static final String ATTR_IS_APPLIED = "isApplied"; - private static final String ATTR_STAGED_SESSION_ERROR_CODE = "errorCode"; - private static final String ATTR_STAGED_SESSION_ERROR_MESSAGE = "errorMessage"; + private static final String ATTR_SESSION_ERROR_CODE = "errorCode"; + private static final String ATTR_SESSION_ERROR_MESSAGE = "errorMessage"; private static final String ATTR_MODE = "mode"; private static final String ATTR_INSTALL_FLAGS = "installFlags"; private static final String ATTR_INSTALL_LOCATION = "installLocation"; @@ -454,22 +453,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private ArrayMap<String, PerFileChecksum> mChecksums = new ArrayMap<>(); + @GuardedBy("mLock") + private boolean mSessionApplied; + @GuardedBy("mLock") + private boolean mSessionReady; + @GuardedBy("mLock") + private boolean mSessionFailed; + @GuardedBy("mLock") + private int mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR; + @GuardedBy("mLock") + private String mSessionErrorMessage; + @Nullable final StagedSession mStagedSession; @VisibleForTesting public class StagedSession implements StagingManager.StagedSession { - @GuardedBy("mLock") - private boolean mSessionApplied; - @GuardedBy("mLock") - private boolean mSessionReady; - @GuardedBy("mLock") - private boolean mSessionFailed; - @GuardedBy("mLock") - private int mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR; - @GuardedBy("mLock") - private String mSessionErrorMessage; - /** * The callback to run when pre-reboot verification has ended. Used by {@link #abandon()} * to delay session clean-up until it is safe to do so. @@ -478,15 +477,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Nullable private Runnable mPendingAbandonCallback; - StagedSession(boolean isReady, boolean isApplied, boolean isFailed, int errorCode, - String errorMessage) { - mSessionReady = isReady; - mSessionApplied = isApplied; - mSessionFailed = isFailed; - mSessionErrorCode = errorCode; - mSessionErrorMessage = errorMessage != null ? errorMessage : ""; - } - @Override public List<StagingManager.StagedSession> getChildSessions() { if (!params.isMultiPackage) { @@ -534,52 +524,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void setSessionReady() { - synchronized (mLock) { - // Do not allow destroyed/failed staged session to change state - if (mDestroyed || mSessionFailed) return; - mSessionReady = true; - mSessionApplied = false; - mSessionFailed = false; - mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR; - mSessionErrorMessage = ""; - } - mCallback.onStagedSessionChanged(PackageInstallerSession.this); + PackageInstallerSession.this.setSessionReady(); } @Override public void setSessionFailed(int errorCode, String errorMessage) { - List<PackageInstallerSession> childSessions; - synchronized (mLock) { - // Do not allow destroyed/failed staged session to change state - if (mDestroyed || mSessionFailed) return; - mSessionReady = false; - mSessionApplied = false; - mSessionFailed = true; - mSessionErrorCode = errorCode; - mSessionErrorMessage = errorMessage; - Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage); - childSessions = getChildSessionsLocked(); - } - destroy(); - mCallback.onStagedSessionChanged(PackageInstallerSession.this); + PackageInstallerSession.this.setSessionFailed(errorCode, errorMessage); } @Override public void setSessionApplied() { - List<PackageInstallerSession> childSessions; - synchronized (mLock) { - // Do not allow destroyed/failed staged session to change state - if (mDestroyed || mSessionFailed) return; - mSessionReady = false; - mSessionApplied = true; - mSessionFailed = false; - mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR; - mSessionErrorMessage = ""; - Slog.d(TAG, "Marking session " + sessionId + " as applied"); - childSessions = getChildSessionsLocked(); - } - destroy(); - mCallback.onStagedSessionChanged(PackageInstallerSession.this); + PackageInstallerSession.this.setSessionApplied(); } @Override @@ -656,35 +611,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public boolean isSessionReady() { - synchronized (mLock) { - return mSessionReady; - } + return PackageInstallerSession.this.isSessionReady(); } @Override public boolean isSessionApplied() { - synchronized (mLock) { - return mSessionApplied; - } + return PackageInstallerSession.this.isSessionApplied(); } @Override public boolean isSessionFailed() { - synchronized (mLock) { - return mSessionFailed; - } - } - - @StagedSessionErrorCode int getSessionErrorCode() { - synchronized (mLock) { - return mSessionErrorCode; - } - } - - String getSessionErrorMessage() { - synchronized (mLock) { - return mSessionErrorMessage; - } + return PackageInstallerSession.this.isSessionFailed(); } @Override @@ -714,7 +651,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (mStageDirInUse) { // Pre-reboot verification is ongoing, not safe to clean up the session yet. mPendingAbandonCallback = r; - mCallback.onStagedSessionChanged(PackageInstallerSession.this); + mCallback.onSessionChanged(PackageInstallerSession.this); return; } } @@ -1015,8 +952,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { ArrayMap<String, PerFileChecksum> checksums, boolean prepared, boolean committed, boolean destroyed, boolean sealed, @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, - boolean isFailed, boolean isApplied, int stagedSessionErrorCode, - String stagedSessionErrorMessage) { + boolean isFailed, boolean isApplied, int sessionErrorCode, + String sessionErrorMessage) { mCallback = callback; mContext = context; mPm = pm; @@ -1071,8 +1008,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mPrepared = prepared; mCommitted.set(committed); mDestroyed = destroyed; - mStagedSession = params.isStaged ? new StagedSession(isReady, isApplied, isFailed, - stagedSessionErrorCode, stagedSessionErrorMessage) : null; + mSessionReady = isReady; + mSessionApplied = isApplied; + mSessionFailed = isFailed; + mSessionErrorCode = sessionErrorCode; + mSessionErrorMessage = + sessionErrorMessage != null ? sessionErrorMessage : ""; + mStagedSession = params.isStaged ? new StagedSession() : null; if (isDataLoaderInstallation()) { if (isApexSession()) { @@ -1173,11 +1115,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { info.rollbackDataPolicy = params.rollbackDataPolicy; info.parentSessionId = mParentSessionId; info.childSessionIds = getChildSessionIdsLocked(); - info.isStagedSessionApplied = isStagedSessionApplied(); - info.isStagedSessionReady = isStagedSessionReady(); - info.isStagedSessionFailed = isStagedSessionFailed(); - info.setStagedSessionErrorCode(getStagedSessionErrorCode(), - getStagedSessionErrorMessage()); + info.isSessionApplied = mSessionApplied; + info.isSessionReady = mSessionReady; + info.isSessionFailed = mSessionFailed; + info.setSessionErrorCode(mSessionErrorCode, mSessionErrorMessage); info.createdMillis = createdMillis; info.updatedMillis = updatedMillis; info.requireUserAction = params.requireUserAction; @@ -2229,7 +2170,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final PackageInstallerSession root = hasParentSessionId() ? allSessions.get(getParentSessionId()) : this; - if (root != null) { + if (root != null && !root.isStagedAndInTerminalState()) { if (isApexSession()) { validateApexInstallLocked(); } else { @@ -2357,28 +2298,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } - - // Check if APEX update is allowed. We do this check in handleInstall, since this is one of - // the places that: - // * Shared between staged and non-staged APEX update flows. - // * Only is called after boot completes. - // The later is important, since isApexUpdateAllowed check depends on the - // ModuleInfoProvider, which is only populated after device has booted. - if (isApexSession()) { - boolean checkApexUpdateAllowed = - (params.installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK) - == 0; - synchronized (mLock) { - if (checkApexUpdateAllowed && !isApexUpdateAllowed(mPackageName, - mInstallSource.installerPackageName)) { - onSessionValidationFailure(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, - "Update of APEX package " + mPackageName + " is not allowed for " - + mInstallSource.installerPackageName); - return; - } - } - } - if (params.isStaged) { // TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even // though ideally, we just need to send session committed broadcast. @@ -2825,25 +2744,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return sessionContains((s) -> !s.isApexSession()); } - private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) { - if (mPm.getModuleInfo(apexPackageName, 0) != null) { - final String modulesInstaller = - SystemConfig.getInstance().getModulesInstallerPackageName(); - if (modulesInstaller == null) { - Slog.w(TAG, "No modules installer defined"); - return false; - } - return modulesInstaller.equals(installerPackageName); - } - final String vendorApexInstaller = - SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName); - if (vendorApexInstaller == null) { - Slog.w(TAG, apexPackageName + " is not allowed to be updated"); - return false; - } - return vendorApexInstaller.equals(installerPackageName); - } - /** * Validate apex install. * <p> @@ -4261,30 +4161,83 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + private void setSessionReady() { + synchronized (mLock) { + // Do not allow destroyed/failed session to change state + if (mDestroyed || mSessionFailed) return; + mSessionReady = true; + mSessionApplied = false; + mSessionFailed = false; + mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR; + mSessionErrorMessage = ""; + } + mCallback.onSessionChanged(this); + } + + private void setSessionFailed(int errorCode, String errorMessage) { + synchronized (mLock) { + // Do not allow destroyed/failed session to change state + if (mDestroyed || mSessionFailed) return; + mSessionReady = false; + mSessionApplied = false; + mSessionFailed = true; + mSessionErrorCode = errorCode; + mSessionErrorMessage = errorMessage; + Slog.d(TAG, "Marking session " + sessionId + " as failed: " + errorMessage); + } + destroy(); + mCallback.onSessionChanged(this); + } + + private void setSessionApplied() { + synchronized (mLock) { + // Do not allow destroyed/failed session to change state + if (mDestroyed || mSessionFailed) return; + mSessionReady = false; + mSessionApplied = true; + mSessionFailed = false; + mSessionErrorCode = SessionInfo.STAGED_SESSION_NO_ERROR; + mSessionErrorMessage = ""; + Slog.d(TAG, "Marking session " + sessionId + " as applied"); + } + destroy(); + mCallback.onSessionChanged(this); + } + /** {@hide} */ - boolean isStagedSessionReady() { - return params.isStaged && mStagedSession.isSessionReady(); + boolean isSessionReady() { + synchronized (mLock) { + return mSessionReady; + } } /** {@hide} */ - boolean isStagedSessionApplied() { - return params.isStaged && mStagedSession.isSessionApplied(); + boolean isSessionApplied() { + synchronized (mLock) { + return mSessionApplied; + } } /** {@hide} */ - boolean isStagedSessionFailed() { - return params.isStaged && mStagedSession.isSessionFailed(); + boolean isSessionFailed() { + synchronized (mLock) { + return mSessionFailed; + } } /** {@hide} */ - @StagedSessionErrorCode int getStagedSessionErrorCode() { - return params.isStaged ? mStagedSession.getSessionErrorCode() - : SessionInfo.STAGED_SESSION_NO_ERROR; + @SessionErrorCode + int getSessionErrorCode() { + synchronized (mLock) { + return mSessionErrorCode; + } } /** {@hide} */ - String getStagedSessionErrorMessage() { - return params.isStaged ? mStagedSession.getSessionErrorMessage() : ""; + String getSessionErrorMessage() { + synchronized (mLock) { + return mSessionErrorMessage; + } } /** @@ -4386,11 +4339,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("params.isStaged", params.isStaged); pw.printPair("mParentSessionId", mParentSessionId); pw.printPair("mChildSessionIds", getChildSessionIdsLocked()); - pw.printPair("mStagedSessionApplied", isStagedSessionApplied()); - pw.printPair("mStagedSessionFailed", isStagedSessionFailed()); - pw.printPair("mStagedSessionReady", isStagedSessionReady()); - pw.printPair("mStagedSessionErrorCode", getStagedSessionErrorCode()); - pw.printPair("mStagedSessionErrorMessage", getStagedSessionErrorMessage()); + pw.printPair("mSessionApplied", mSessionApplied); + pw.printPair("mSessionFailed", mSessionFailed); + pw.printPair("mSessionReady", mSessionReady); + pw.printPair("mSessionErrorCode", mSessionErrorCode); + pw.printPair("mSessionErrorMessage", mSessionErrorMessage); pw.println(); pw.decreaseIndent(); @@ -4556,12 +4509,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { writeBooleanAttribute(out, ATTR_MULTI_PACKAGE, params.isMultiPackage); writeBooleanAttribute(out, ATTR_STAGED_SESSION, params.isStaged); - writeBooleanAttribute(out, ATTR_IS_READY, isStagedSessionReady()); - writeBooleanAttribute(out, ATTR_IS_FAILED, isStagedSessionFailed()); - writeBooleanAttribute(out, ATTR_IS_APPLIED, isStagedSessionApplied()); - out.attributeInt(null, ATTR_STAGED_SESSION_ERROR_CODE, getStagedSessionErrorCode()); - writeStringAttribute(out, ATTR_STAGED_SESSION_ERROR_MESSAGE, - getStagedSessionErrorMessage()); + writeBooleanAttribute(out, ATTR_IS_READY, mSessionReady); + writeBooleanAttribute(out, ATTR_IS_FAILED, mSessionFailed); + writeBooleanAttribute(out, ATTR_IS_APPLIED, mSessionApplied); + out.attributeInt(null, ATTR_SESSION_ERROR_CODE, mSessionErrorCode); + writeStringAttribute(out, ATTR_SESSION_ERROR_MESSAGE, mSessionErrorMessage); // TODO(patb,109941548): avoid writing to xml and instead infer / validate this after // we've read all sessions. out.attributeInt(null, ATTR_PARENT_SESSION_ID, mParentSessionId); @@ -4752,10 +4704,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean isReady = in.getAttributeBoolean(null, ATTR_IS_READY, false); final boolean isFailed = in.getAttributeBoolean(null, ATTR_IS_FAILED, false); final boolean isApplied = in.getAttributeBoolean(null, ATTR_IS_APPLIED, false); - final int stagedSessionErrorCode = in.getAttributeInt(null, ATTR_STAGED_SESSION_ERROR_CODE, + final int sessionErrorCode = in.getAttributeInt(null, ATTR_SESSION_ERROR_CODE, SessionInfo.STAGED_SESSION_NO_ERROR); - final String stagedSessionErrorMessage = readStringAttribute(in, - ATTR_STAGED_SESSION_ERROR_MESSAGE); + final String sessionErrorMessage = readStringAttribute(in, ATTR_SESSION_ERROR_MESSAGE); if (!isStagedSessionStateValid(isReady, isApplied, isFailed)) { throw new IllegalArgumentException("Can't restore staged session with invalid state."); @@ -4869,6 +4820,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { installerUid, installSource, params, createdMillis, committedMillis, stageDir, stageCid, fileArray, checksumsMap, prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, - stagedSessionErrorCode, stagedSessionErrorMessage); + sessionErrorCode, sessionErrorMessage); } } diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java index 4f21d0e8d1c0..a532fe3a3d4d 100644 --- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java +++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java @@ -45,6 +45,7 @@ import android.util.apk.ApkSignatureVerifier; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageHelper; import com.android.server.LocalServices; +import com.android.server.SystemConfig; import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.pkg.ParsedPackage; import com.android.server.rollback.RollbackManagerInternal; @@ -99,9 +100,11 @@ final class PackageSessionVerifier { storeSession(session.mStagedSession); if (session.isMultiPackage()) { for (PackageInstallerSession child : session.getChildSessions()) { + checkApexUpdateAllowed(child); checkRebootlessApex(child); } } else { + checkApexUpdateAllowed(session); checkRebootlessApex(session); } verifyAPK(session, callback); @@ -203,7 +206,7 @@ final class PackageSessionVerifier { } private void onVerificationFailure(StagingManager.StagedSession session, Callback callback, - @SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) { + @SessionInfo.SessionErrorCode int errorCode, String errorMessage) { if (!ensureActiveApexSessionIsAborted(session)) { Slog.e(TAG, "Failed to abort apex session " + session.sessionId()); // Safe to ignore active apex session abortion failure since session will be marked @@ -461,6 +464,51 @@ final class PackageSessionVerifier { return mApexManager.abortStagedSession(sessionId); } + private boolean isApexUpdateAllowed(String apexPackageName, String installerPackageName) { + if (mPm.getModuleInfo(apexPackageName, 0) != null) { + final String modulesInstaller = + SystemConfig.getInstance().getModulesInstallerPackageName(); + if (modulesInstaller == null) { + Slog.w(TAG, "No modules installer defined"); + return false; + } + return modulesInstaller.equals(installerPackageName); + } + final String vendorApexInstaller = + SystemConfig.getInstance().getAllowedVendorApexes().get(apexPackageName); + if (vendorApexInstaller == null) { + Slog.w(TAG, apexPackageName + " is not allowed to be updated"); + return false; + } + return vendorApexInstaller.equals(installerPackageName); + } + + /** + * Checks if APEX update is allowed. + * + * This phase is shared between staged and non-staged sessions and should be called after + * boot is completed since this check depends on the ModuleInfoProvider, which is only populated + * after device has booted. + */ + private void checkApexUpdateAllowed(PackageInstallerSession session) + throws PackageManagerException { + if (!session.isApexSession()) { + return; + } + final int installFlags = session.params.installFlags; + if ((installFlags & PackageManager.INSTALL_DISABLE_ALLOWED_APEX_UPDATE_CHECK) != 0) { + return; + } + final String packageName = session.getPackageName(); + final String installerPackageName = session.getInstallSource().installerPackageName; + if (!isApexUpdateAllowed(packageName, installerPackageName)) { + throw new PackageManagerException( + PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, + "Update of APEX package " + packageName + " is not allowed for " + + installerPackageName); + } + } + /** * Fails this rebootless APEX session if the same package name found in any staged sessions. */ diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 9cb886341566..c1058bb29495 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -32,7 +32,7 @@ import android.content.pm.ApexStagedEvent; import android.content.pm.IStagedApexObserver; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; -import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode; +import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.StagedApexInfo; @@ -129,7 +129,7 @@ public class StagingManager { boolean containsApkSession(); boolean containsApexSession(); void setSessionReady(); - void setSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage); + void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage); void setSessionApplied(); void installSession(IntentSender statusReceiver); boolean hasParentSessionId(); diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java index 268de3e2182b..68e078c519ba 100644 --- a/services/core/java/com/android/server/policy/KeyCombinationManager.java +++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java @@ -17,11 +17,13 @@ package com.android.server.policy; import static android.view.KeyEvent.KEYCODE_POWER; +import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.util.SparseLongArray; import android.view.KeyEvent; +import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ToBooleanFunction; import java.io.PrintWriter; @@ -35,13 +37,18 @@ public class KeyCombinationManager { private static final String TAG = "KeyCombinationManager"; // Store the received down time of keycode. + @GuardedBy("mLock") private final SparseLongArray mDownTimes = new SparseLongArray(2); private final ArrayList<TwoKeysCombinationRule> mRules = new ArrayList(); // Selected rules according to current key down. + private final Object mLock = new Object(); + @GuardedBy("mLock") private final ArrayList<TwoKeysCombinationRule> mActiveRules = new ArrayList(); // The rule has been triggered by current keys. + @GuardedBy("mLock") private TwoKeysCombinationRule mTriggeredRule; + private final Handler mHandler = new Handler(); // Keys in a key combination must be pressed within this interval of each other. private static final long COMBINE_KEY_DELAY_MILLIS = 150; @@ -109,6 +116,12 @@ public class KeyCombinationManager { * Return true if any active rule could be triggered by the key event, otherwise false. */ boolean interceptKey(KeyEvent event, boolean interactive) { + synchronized (mLock) { + return interceptKeyLocked(event, interactive); + } + } + + private boolean interceptKeyLocked(KeyEvent event, boolean interactive) { final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final int keyCode = event.getKeyCode(); final int count = mActiveRules.size(); @@ -154,7 +167,7 @@ public class KeyCombinationManager { return false; } Log.v(TAG, "Performing combination rule : " + rule); - rule.execute(); + mHandler.post(rule::execute); mTriggeredRule = rule; return true; }); @@ -169,7 +182,7 @@ public class KeyCombinationManager { for (int index = count - 1; index >= 0; index--) { final TwoKeysCombinationRule rule = mActiveRules.get(index); if (rule.shouldInterceptKey(keyCode)) { - rule.cancel(); + mHandler.post(rule::cancel); mActiveRules.remove(index); } } @@ -181,31 +194,37 @@ public class KeyCombinationManager { * Return the interceptTimeout to tell InputDispatcher when is ready to deliver to window. */ long getKeyInterceptTimeout(int keyCode) { - if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) { - return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS; + synchronized (mLock) { + if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) { + return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS; + } + return 0; } - return 0; } /** * True if the key event had been handled. */ boolean isKeyConsumed(KeyEvent event) { - if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) { - return false; + synchronized (mLock) { + if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) { + return false; + } + return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode()); } - return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode()); } /** * True if power key is the candidate. */ boolean isPowerKeyIntercepted() { - if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) { - // return false if only if power key pressed. - return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0; + synchronized (mLock) { + if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) { + // return false if only if power key pressed. + return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0; + } + return false; } - return false; } /** diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java index e857d32c3449..784e177d6362 100644 --- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java +++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java @@ -112,10 +112,15 @@ class ModifierShortcutManager { * @return The intent that matches the shortcut, or null if not found. */ private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) { + // If a modifier key other than shift is also pressed, skip it. + final boolean isShiftOn = KeyEvent.metaStateHasModifiers(metaState, KeyEvent.META_SHIFT_ON); + if (!isShiftOn && !KeyEvent.metaStateHasNoModifiers(metaState)) { + return null; + } + ShortcutInfo shortcut = null; // If the Shift key is pressed, then search for the shift shortcuts. - boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON; SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts; // First try the exact keycode (with modifiers). diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 4cced17917f6..28f65cf6d1a0 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2696,6 +2696,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final boolean canceled = event.isCanceled(); final int displayId = event.getDisplayId(); final long key_consumed = -1; + final long key_not_consumed = 0; if (DEBUG_INPUT) { Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount=" @@ -2885,7 +2886,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_TAB: if (event.isMetaPressed()) { // Pass through keyboard navigation keys. - return 0; + return key_not_consumed; } // Display task switcher for ALT-TAB. if (down && repeatCount == 0) { @@ -2916,9 +2917,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { return key_consumed; case KeyEvent.KEYCODE_SPACE: - // Handle keyboard layout switching. - if ((metaState & (KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK)) == 0) { - return 0; + // Handle keyboard layout switching. (META + SPACE) + if ((metaState & KeyEvent.META_META_MASK) == 0) { + return key_not_consumed; } // Share the same behavior with KEYCODE_LANGUAGE_SWITCH. case KeyEvent.KEYCODE_LANGUAGE_SWITCH: @@ -2992,7 +2993,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } // Let the application handle the key. - return 0; + return key_not_consumed; } /** @@ -3058,6 +3059,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { + ", policyFlags=" + policyFlags); } + if (interceptUnhandledKey(event)) { + return null; + } + KeyEvent fallbackEvent = null; if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); @@ -3112,13 +3117,46 @@ public class PhoneWindowManager implements WindowManagerPolicy { return fallbackEvent; } + private boolean interceptUnhandledKey(KeyEvent event) { + final int keyCode = event.getKeyCode(); + final int repeatCount = event.getRepeatCount(); + final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; + final int metaState = event.getModifiers(); + + switch(keyCode) { + case KeyEvent.KEYCODE_SPACE: + if (down && repeatCount == 0) { + // Handle keyboard layout switching. (CTRL + SPACE) + if (KeyEvent.metaStateHasModifiers(metaState, KeyEvent.META_CTRL_ON)) { + int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1; + mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction); + return true; + } + } + break; + case KeyEvent.KEYCODE_Z: + if (down && KeyEvent.metaStateHasModifiers(metaState, + KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON)) { + // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users. + if (mAccessibilityShortcutController + .isAccessibilityShortcutAvailable(isKeyguardLocked())) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT)); + return true; + } + } + break; + } + + return false; + } + private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent, int policyFlags) { int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags); if ((actions & ACTION_PASS_TO_USER) != 0) { long delayMillis = interceptKeyBeforeDispatching( focusedToken, fallbackEvent, policyFlags); - if (delayMillis == 0) { + if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent)) { return true; } } @@ -3989,19 +4027,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users. - if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())) { - switch (keyCode) { - case KeyEvent.KEYCODE_Z: { - if (down && event.isCtrlPressed() && event.isAltPressed()) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT)); - result &= ~ACTION_PASS_TO_USER; - } - break; - } - } - } - if (useHapticFeedback) { performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false, "Virtual Key - Press"); diff --git a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java index 7f047f882122..fba0fb49da5c 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/ObjectPrinter.java @@ -20,8 +20,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Map; @@ -33,67 +31,28 @@ class ObjectPrinter { static public final int kDefaultMaxCollectionLength = 16; /** - * Simple version of {@link #print(Object, boolean, int)} that prints an object, without - * recursing into sub-objects. - * - * @param obj The object to print. - * @return A string representing the object. - */ - static String print(@Nullable Object obj) { - return print(obj, false, kDefaultMaxCollectionLength); - } - - /** * Pretty-prints an object. * * @param obj The object to print. - * @param deep Whether to pretty-print sub-objects (if false, just prints them - * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. * @return A string representing the object. */ - static String print(@Nullable Object obj, boolean deep, int maxCollectionLength) { + static String print(@Nullable Object obj, int maxCollectionLength) { StringBuilder builder = new StringBuilder(); - print(builder, obj, deep, maxCollectionLength); + print(builder, obj, maxCollectionLength); return builder.toString(); } /** - * This version is suitable for use inside a toString() override of an object, e.g.: - * <pre><code> - * class MyObject { - * ... - * @Override - * String toString() { - * return ObjectPrinter.printPublicFields(this, ...); - * } - * } - * </code></pre> - * - * @param obj The object to print. - * @param deep Whether to pretty-print sub-objects (if false, just prints them - * with {@link Object#toString()}). - * @param maxCollectionLength Whenever encountering collections, maximum number of elements to - * print. - */ - static String printPublicFields(@Nullable Object obj, boolean deep, int maxCollectionLength) { - StringBuilder builder = new StringBuilder(); - printPublicFields(builder, obj, deep, maxCollectionLength); - return builder.toString(); - } - - /** - * A version of {@link #print(Object, boolean, int)} that uses a {@link StringBuilder}. + * A version of {@link #print(Object, int)} that uses a {@link StringBuilder}. * * @param builder StringBuilder to print into. * @param obj The object to print. - * @param deep Whether to pretty-print sub-objects (if false, just prints them - * with {@link Object#toString()}). * @param maxCollectionLength Whenever encountering collections, maximum number of elements to * print. */ - static void print(@NonNull StringBuilder builder, @Nullable Object obj, boolean deep, + static void print(@NonNull StringBuilder builder, @Nullable Object obj, int maxCollectionLength) { try { if (obj == null) { @@ -101,16 +60,16 @@ class ObjectPrinter { return; } if (obj instanceof Boolean) { - builder.append(obj.toString()); + builder.append(obj); return; } if (obj instanceof Number) { - builder.append(obj.toString()); + builder.append(obj); return; } if (obj instanceof Character) { builder.append('\''); - builder.append(obj.toString()); + builder.append(obj); builder.append('\''); return; } @@ -137,7 +96,7 @@ class ObjectPrinter { isLong = true; break; } - print(builder, child, deep, maxCollectionLength); + print(builder, child, maxCollectionLength); ++i; } if (isLong) { @@ -163,9 +122,9 @@ class ObjectPrinter { isLong = true; break; } - print(builder, child.getKey(), deep, maxCollectionLength); + print(builder, child.getKey(), maxCollectionLength); builder.append(": "); - print(builder, child.getValue(), deep, maxCollectionLength); + print(builder, child.getValue(), maxCollectionLength); ++i; } if (isLong) { @@ -189,7 +148,7 @@ class ObjectPrinter { isLong = true; break; } - print(builder, Array.get(obj, i), deep, maxCollectionLength); + print(builder, Array.get(obj, i), maxCollectionLength); } if (isLong) { builder.append("... (+"); @@ -200,48 +159,7 @@ class ObjectPrinter { return; } - if (!deep) { - builder.append(obj.toString()); - return; - } - printPublicFields(builder, obj, deep, maxCollectionLength); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * A version of {@link #printPublicFields(Object, boolean, int)} that uses a {@link - * StringBuilder}. - * - * @param obj The object to print. - * @param deep Whether to pretty-print sub-objects (if false, just prints them - * with {@link Object#toString()}). - * @param maxCollectionLength Whenever encountering collections, maximum number of elements to - * print. - */ - static void printPublicFields(@NonNull StringBuilder builder, @Nullable Object obj, - boolean deep, - int maxCollectionLength) { - try { - Class cls = obj.getClass(); - builder.append("{ "); - - boolean first = true; - for (Field fld : cls.getDeclaredFields()) { - int mod = fld.getModifiers(); - if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.STATIC) == 0) { - if (first) { - first = false; - } else { - builder.append(", "); - } - builder.append(fld.getName()); - builder.append(": "); - print(builder, fld.get(obj), deep, maxCollectionLength); - } - } - builder.append(" }"); + builder.append(obj); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java index 559e777a8c0e..dc4bdaaa8158 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareLogging.java @@ -18,14 +18,14 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.annotation.Nullable; +import android.media.permission.Identity; +import android.media.permission.IdentityContext; import android.media.soundtrigger.ModelParameterRange; import android.media.soundtrigger.PhraseRecognitionEvent; import android.media.soundtrigger.PhraseSoundModel; import android.media.soundtrigger.RecognitionConfig; import android.media.soundtrigger.RecognitionEvent; import android.media.soundtrigger.SoundModel; -import android.media.permission.Identity; -import android.media.permission.IdentityContext; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerModule; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; @@ -387,7 +387,7 @@ public class SoundTriggerMiddlewareLogging implements ISoundTriggerMiddlewareInt } private static void printObject(@NonNull StringBuilder builder, @Nullable Object obj) { - ObjectPrinter.print(builder, obj, true, 16); + ObjectPrinter.print(builder, obj, 16); } private static String printObject(@Nullable Object obj) { diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java index 76927e15a0f7..f3d151fe5cc4 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java @@ -21,9 +21,11 @@ import static android.Manifest.permission.RECORD_AUDIO; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.AppOpsManager; import android.content.Context; import android.content.PermissionChecker; +import android.media.permission.Identity; +import android.media.permission.IdentityContext; +import android.media.permission.PermissionUtil; import android.media.soundtrigger.ModelParameterRange; import android.media.soundtrigger.PhraseRecognitionEvent; import android.media.soundtrigger.PhraseSoundModel; @@ -31,9 +33,6 @@ import android.media.soundtrigger.RecognitionConfig; import android.media.soundtrigger.RecognitionEvent; import android.media.soundtrigger.SoundModel; import android.media.soundtrigger.Status; -import android.media.permission.Identity; -import android.media.permission.IdentityContext; -import android.media.permission.PermissionUtil; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; @@ -144,7 +143,7 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware if (status != PermissionChecker.PERMISSION_GRANTED) { throw new SecurityException( String.format("Failed to obtain permission %s for identity %s", permission, - ObjectPrinter.print(identity, true, 16))); + ObjectPrinter.print(identity, 16))); } } @@ -168,7 +167,7 @@ public class SoundTriggerMiddlewarePermission implements ISoundTriggerMiddleware case PermissionChecker.PERMISSION_HARD_DENIED: throw new SecurityException( String.format("Failed to obtain permission %s for identity %s", permission, - ObjectPrinter.print(identity, true, 16))); + ObjectPrinter.print(identity, 16))); default: throw new RuntimeException("Unexpected perimission check result."); } diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java index 4243fc775ef6..09035cd1d165 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java @@ -18,6 +18,8 @@ package com.android.server.soundtrigger_middleware; import android.annotation.NonNull; import android.annotation.Nullable; +import android.media.permission.Identity; +import android.media.permission.IdentityContext; import android.media.soundtrigger.ModelParameterRange; import android.media.soundtrigger.PhraseRecognitionEvent; import android.media.soundtrigger.PhraseSoundModel; @@ -27,8 +29,6 @@ import android.media.soundtrigger.RecognitionEvent; import android.media.soundtrigger.RecognitionStatus; import android.media.soundtrigger.SoundModel; import android.media.soundtrigger.Status; -import android.media.permission.Identity; -import android.media.permission.IdentityContext; import android.media.soundtrigger_middleware.ISoundTriggerCallback; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.ISoundTriggerModule; @@ -230,7 +230,7 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware final ModuleState module = mModules.get(handle); pw.println("========================================="); pw.printf("Module %d\n%s\n", handle, - ObjectPrinter.print(module.properties, true, 16)); + ObjectPrinter.print(module.properties, 16)); pw.println("========================================="); for (Session session : module.sessions) { session.dump(pw); @@ -250,11 +250,11 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware /** State of a sound model. */ static class ModelState { ModelState(SoundModel model) { - this.description = ObjectPrinter.print(model, true, 16); + this.description = ObjectPrinter.print(model, 16); } ModelState(PhraseSoundModel model) { - this.description = ObjectPrinter.print(model, true, 16); + this.description = ObjectPrinter.print(model, 16); } /** Activity state of a sound model. */ @@ -690,8 +690,8 @@ public class SoundTriggerMiddlewareValidation implements ISoundTriggerMiddleware if (mState == ModuleStatus.ALIVE) { pw.println("-------------------------------"); pw.printf("Session %s, client: %s\n", toString(), - ObjectPrinter.print(mOriginatorIdentity, true, 16)); - pw.printf("Loaded models (handle, active, description):", toString()); + ObjectPrinter.print(mOriginatorIdentity, 16)); + pw.println("Loaded models (handle, active, description):"); pw.println(); pw.println("-------------------------------"); for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 30465aff8cae..0b0b70481589 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -6905,8 +6905,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A getSyncTransaction().hide(mSurfaceControl); } if (show) { - mActivityRecordInputSink.applyChangesToSurfaceIfChanged( - getSyncTransaction(), mSurfaceControl); + mActivityRecordInputSink.applyChangesToSurfaceIfChanged(getSyncTransaction()); } } if (mThumbnail != null) { diff --git a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java index bce288311e13..9353f6dfdabf 100644 --- a/services/core/java/com/android/server/wm/ActivityRecordInputSink.java +++ b/services/core/java/com/android/server/wm/ActivityRecordInputSink.java @@ -60,7 +60,7 @@ class ActivityRecordInputSink { // Hold on to InputEventReceiver to prevent it from getting GCd. private InputEventReceiver mInputEventReceiver; private InputWindowHandleWrapper mInputWindowHandleWrapper; - + private SurfaceControl mSurfaceControl; private int mRapidTouchCount = 0; private IBinder mToken; private boolean mDisabled = false; @@ -73,14 +73,27 @@ class ActivityRecordInputSink { + mActivityRecord.mActivityComponent.getShortClassName(); } - public void applyChangesToSurfaceIfChanged( - SurfaceControl.Transaction transaction, SurfaceControl surfaceControl) { + public void applyChangesToSurfaceIfChanged(SurfaceControl.Transaction transaction) { InputWindowHandleWrapper inputWindowHandleWrapper = getInputWindowHandleWrapper(); + if (mSurfaceControl == null) { + mSurfaceControl = createSurface(transaction); + } if (inputWindowHandleWrapper.isChanged()) { - inputWindowHandleWrapper.applyChangesToSurface(transaction, surfaceControl); + inputWindowHandleWrapper.applyChangesToSurface(transaction, mSurfaceControl); } } + private SurfaceControl createSurface(SurfaceControl.Transaction t) { + SurfaceControl surfaceControl = mActivityRecord.makeChildSurface(null) + .setName(mName) + .setHidden(false) + .setCallsite("ActivityRecordInputSink.createSurface") + .build(); + // Put layer below all siblings (and the parent surface too) + t.setLayer(surfaceControl, Integer.MIN_VALUE); + return surfaceControl; + } + private InputWindowHandleWrapper getInputWindowHandleWrapper() { if (mInputWindowHandleWrapper == null) { mInputWindowHandleWrapper = new InputWindowHandleWrapper(createInputWindowHandle()); diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 826171a0f10e..f66f119c592b 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1806,15 +1806,20 @@ static jboolean android_location_gnss_hal_GnssNative_is_measurement_supported(JN } static jboolean android_location_gnss_hal_GnssNative_start_measurement_collection( - JNIEnv* /* env */, jclass, jboolean enableFullTracking, jboolean enableCorrVecOutputs) { + JNIEnv* /* env */, jclass, jboolean enableFullTracking, jboolean enableCorrVecOutputs, + jint intervalMs) { if (gnssMeasurementIface == nullptr) { ALOGE("%s: IGnssMeasurement interface not available.", __func__); return JNI_FALSE; } + hardware::gnss::IGnssMeasurementInterface::Options options; + options.enableFullTracking = enableFullTracking; + options.enableCorrVecOutputs = enableCorrVecOutputs; + options.intervalMs = intervalMs; return gnssMeasurementIface->setCallback(std::make_unique<gnss::GnssMeasurementCallback>( mCallbacksObj), - enableFullTracking, enableCorrVecOutputs); + options); } static jboolean android_location_gnss_hal_GnssNative_stop_measurement_collection(JNIEnv* env, @@ -2269,7 +2274,7 @@ static const JNINativeMethod sMeasurementMethods[] = { /* name, signature, funcPtr */ {"native_is_measurement_supported", "()Z", reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_is_measurement_supported)}, - {"native_start_measurement_collection", "(ZZ)Z", + {"native_start_measurement_collection", "(ZZI)Z", reinterpret_cast<void*>( android_location_gnss_hal_GnssNative_start_measurement_collection)}, {"native_stop_measurement_collection", "()Z", diff --git a/services/core/jni/gnss/GnssMeasurement.cpp b/services/core/jni/gnss/GnssMeasurement.cpp index 663d839ff159..9fbf259d582a 100644 --- a/services/core/jni/gnss/GnssMeasurement.cpp +++ b/services/core/jni/gnss/GnssMeasurement.cpp @@ -50,9 +50,15 @@ GnssMeasurement::GnssMeasurement(const sp<IGnssMeasurementInterface>& iGnssMeasu : mIGnssMeasurement(iGnssMeasurement) {} jboolean GnssMeasurement::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) { - auto status = mIGnssMeasurement->setCallback(callback->getAidl(), enableFullTracking, - enableCorrVecOutputs); + const IGnssMeasurementInterface::Options& options) { + if (mIGnssMeasurement->getInterfaceVersion() >= 2) { + auto status = mIGnssMeasurement->setCallbackWithOptions(callback->getAidl(), options); + if (checkAidlStatus(status, "IGnssMeasurement setCallbackWithOptions() failed.")) { + return true; + } + } + auto status = mIGnssMeasurement->setCallback(callback->getAidl(), options.enableFullTracking, + options.enableCorrVecOutputs); return checkAidlStatus(status, "IGnssMeasurement setCallback() failed."); } @@ -67,13 +73,16 @@ GnssMeasurement_V1_0::GnssMeasurement_V1_0(const sp<IGnssMeasurement_V1_0>& iGns : mIGnssMeasurement_V1_0(iGnssMeasurement) {} jboolean GnssMeasurement_V1_0::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) { - if (enableFullTracking == true) { + const IGnssMeasurementInterface::Options& options) { + if (options.enableFullTracking == true) { ALOGW("Full tracking mode is not supported in 1.0 GNSS HAL."); } - if (enableCorrVecOutputs == true) { + if (options.enableCorrVecOutputs == true) { ALOGW("Correlation vector output is not supported in 1.0 GNSS HAL."); } + if (options.intervalMs > 1000) { + ALOGW("Measurement interval is not supported in 1.0 GNSS HAL."); + } auto status = mIGnssMeasurement_V1_0->setCallback(callback->getHidl()); if (!checkHidlReturn(status, "IGnssMeasurement setCallback() failed.")) { return JNI_FALSE; @@ -93,11 +102,15 @@ GnssMeasurement_V1_1::GnssMeasurement_V1_1(const sp<IGnssMeasurement_V1_1>& iGns : GnssMeasurement_V1_0{iGnssMeasurement}, mIGnssMeasurement_V1_1(iGnssMeasurement) {} jboolean GnssMeasurement_V1_1::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) { - if (enableCorrVecOutputs == true) { + const IGnssMeasurementInterface::Options& options) { + if (options.enableCorrVecOutputs == true) { ALOGW("Correlation vector output is not supported in 1.1 GNSS HAL."); } - auto status = mIGnssMeasurement_V1_1->setCallback_1_1(callback->getHidl(), enableFullTracking); + if (options.intervalMs > 1000) { + ALOGW("Measurement interval is not supported in 1.0 GNSS HAL."); + } + auto status = mIGnssMeasurement_V1_1->setCallback_1_1(callback->getHidl(), + options.enableFullTracking); if (!checkHidlReturn(status, "IGnssMeasurement setCallback_V1_1() failed.")) { return JNI_FALSE; } @@ -111,11 +124,15 @@ GnssMeasurement_V2_0::GnssMeasurement_V2_0(const sp<IGnssMeasurement_V2_0>& iGns : GnssMeasurement_V1_1{iGnssMeasurement}, mIGnssMeasurement_V2_0(iGnssMeasurement) {} jboolean GnssMeasurement_V2_0::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) { - if (enableCorrVecOutputs == true) { + const IGnssMeasurementInterface::Options& options) { + if (options.enableCorrVecOutputs == true) { ALOGW("Correlation vector output is not supported in 2.0 GNSS HAL."); } - auto status = mIGnssMeasurement_V2_0->setCallback_2_0(callback->getHidl(), enableFullTracking); + if (options.intervalMs > 1000) { + ALOGW("Measurement interval is not supported in 1.0 GNSS HAL."); + } + auto status = mIGnssMeasurement_V2_0->setCallback_2_0(callback->getHidl(), + options.enableFullTracking); if (!checkHidlReturn(status, "IGnssMeasurement setCallback_2_0() failed.")) { return JNI_FALSE; } @@ -129,11 +146,15 @@ GnssMeasurement_V2_1::GnssMeasurement_V2_1(const sp<IGnssMeasurement_V2_1>& iGns : GnssMeasurement_V2_0{iGnssMeasurement}, mIGnssMeasurement_V2_1(iGnssMeasurement) {} jboolean GnssMeasurement_V2_1::setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) { - if (enableCorrVecOutputs == true) { + const IGnssMeasurementInterface::Options& options) { + if (options.enableCorrVecOutputs == true) { ALOGW("Correlation vector output is not supported in 2.1 GNSS HAL."); } - auto status = mIGnssMeasurement_V2_1->setCallback_2_1(callback->getHidl(), enableFullTracking); + if (options.intervalMs > 1000) { + ALOGW("Measurement interval is not supported in 1.0 GNSS HAL."); + } + auto status = mIGnssMeasurement_V2_1->setCallback_2_1(callback->getHidl(), + options.enableFullTracking); if (!checkHidlReturn(status, "IGnssMeasurement setCallback_2_1() failed.")) { return JNI_FALSE; } diff --git a/services/core/jni/gnss/GnssMeasurement.h b/services/core/jni/gnss/GnssMeasurement.h index f0752cd3ab5b..7a95db8ed7b6 100644 --- a/services/core/jni/gnss/GnssMeasurement.h +++ b/services/core/jni/gnss/GnssMeasurement.h @@ -37,16 +37,18 @@ namespace android::gnss { class GnssMeasurementInterface { public: virtual ~GnssMeasurementInterface() {} - virtual jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) = 0; + virtual jboolean setCallback( + const std::unique_ptr<GnssMeasurementCallback>& callback, + const android::hardware::gnss::IGnssMeasurementInterface::Options& options) = 0; virtual jboolean close() = 0; }; class GnssMeasurement : public GnssMeasurementInterface { public: GnssMeasurement(const sp<android::hardware::gnss::IGnssMeasurementInterface>& iGnssMeasurement); - jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) override; + jboolean setCallback( + const std::unique_ptr<GnssMeasurementCallback>& callback, + const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override; jboolean close() override; private: @@ -57,8 +59,9 @@ class GnssMeasurement_V1_0 : public GnssMeasurementInterface { public: GnssMeasurement_V1_0( const sp<android::hardware::gnss::V1_0::IGnssMeasurement>& iGnssMeasurement); - jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) override; + jboolean setCallback( + const std::unique_ptr<GnssMeasurementCallback>& callback, + const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override; jboolean close() override; private: @@ -69,8 +72,9 @@ class GnssMeasurement_V1_1 : public GnssMeasurement_V1_0 { public: GnssMeasurement_V1_1( const sp<android::hardware::gnss::V1_1::IGnssMeasurement>& iGnssMeasurement); - jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) override; + jboolean setCallback( + const std::unique_ptr<GnssMeasurementCallback>& callback, + const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override; private: const sp<android::hardware::gnss::V1_1::IGnssMeasurement> mIGnssMeasurement_V1_1; @@ -80,8 +84,9 @@ class GnssMeasurement_V2_0 : public GnssMeasurement_V1_1 { public: GnssMeasurement_V2_0( const sp<android::hardware::gnss::V2_0::IGnssMeasurement>& iGnssMeasurement); - jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) override; + jboolean setCallback( + const std::unique_ptr<GnssMeasurementCallback>& callback, + const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override; private: const sp<android::hardware::gnss::V2_0::IGnssMeasurement> mIGnssMeasurement_V2_0; @@ -91,8 +96,9 @@ class GnssMeasurement_V2_1 : public GnssMeasurement_V2_0 { public: GnssMeasurement_V2_1( const sp<android::hardware::gnss::V2_1::IGnssMeasurement>& iGnssMeasurement); - jboolean setCallback(const std::unique_ptr<GnssMeasurementCallback>& callback, - bool enableFullTracking, bool enableCorrVecOutputs) override; + jboolean setCallback( + const std::unique_ptr<GnssMeasurementCallback>& callback, + const android::hardware::gnss::IGnssMeasurementInterface::Options& options) override; private: const sp<android::hardware::gnss::V2_1::IGnssMeasurement> mIGnssMeasurement_V2_1; diff --git a/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java index d6db1b2f2766..7ebf014549b9 100644 --- a/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/communal/CommunalManagerServiceTest.java @@ -29,6 +29,7 @@ import static com.android.server.wm.ActivityInterceptorCallback.COMMUNAL_MODE_OR import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; @@ -138,7 +139,7 @@ public class CommunalManagerServiceTest { ArgumentCaptor<BroadcastReceiver> packageReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class); verify(mContextSpy).registerReceiverAsUser(packageReceiverCaptor.capture(), - eq(UserHandle.SYSTEM), any(), any(), any()); + eq(UserHandle.SYSTEM), any(), any(), any(), anyInt()); mPackageReceiver = packageReceiverCaptor.getValue(); mBinder = mService.getBinderServiceInstance(); diff --git a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java index e0c8b09aae88..16ffda824d07 100644 --- a/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java +++ b/services/tests/mockingservicestests/src/com/android/server/location/gnss/hal/FakeGnssHal.java @@ -234,6 +234,7 @@ public final class FakeGnssHal extends GnssNative.GnssHal { private boolean mMeasurementCollectionStarted = false; private boolean mMeasurementCollectionFullTracking = false; private boolean mMeasurementCollectionCorrVecOutputsEnabled = false; + private int mMeasurementCollectionIntervalMillis = 0; private GnssHalPositionMode mPositionMode = new GnssHalPositionMode(); private GnssHalBatchingMode mBatchingMode = new GnssHalBatchingMode(); private final ArrayList<Location> mBatchedLocations = new ArrayList<>(); @@ -523,10 +524,11 @@ public final class FakeGnssHal extends GnssNative.GnssHal { @Override protected boolean startMeasurementCollection(boolean enableFullTracking, - boolean enableCorrVecOutputs) { + boolean enableCorrVecOutputs, int intervalMillis) { mState.mMeasurementCollectionStarted = true; mState.mMeasurementCollectionFullTracking = enableFullTracking; mState.mMeasurementCollectionCorrVecOutputsEnabled = enableCorrVecOutputs; + mState.mMeasurementCollectionIntervalMillis = intervalMillis; return true; } @@ -535,6 +537,7 @@ public final class FakeGnssHal extends GnssNative.GnssHal { mState.mMeasurementCollectionStarted = false; mState.mMeasurementCollectionFullTracking = false; mState.mMeasurementCollectionCorrVecOutputsEnabled = false; + mState.mMeasurementCollectionIntervalMillis = 0; return true; } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java index 663bb2bd2d67..f2415b4665d5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java @@ -41,7 +41,7 @@ import android.content.pm.ApexStagedEvent; import android.content.pm.IStagedApexObserver; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; -import android.content.pm.PackageInstaller.SessionInfo.StagedSessionErrorCode; +import android.content.pm.PackageInstaller.SessionInfo.SessionErrorCode; import android.content.pm.StagedApexInfo; import android.os.SystemProperties; import android.os.storage.IStorageManager; @@ -774,7 +774,7 @@ public class StagingManagerTest { private boolean mIsReady = false; private boolean mIsApplied = false; private boolean mIsFailed = false; - private @StagedSessionErrorCode int mErrorCode = -1; + private @SessionErrorCode int mErrorCode = -1; private String mErrorMessage; private boolean mIsDestroyed = false; private int mParentSessionId = -1; @@ -827,7 +827,7 @@ public class StagingManagerTest { return this; } - private @StagedSessionErrorCode int getErrorCode() { + private @SessionErrorCode int getErrorCode() { return mErrorCode; } @@ -939,7 +939,7 @@ public class StagingManagerTest { } @Override - public void setSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage) { + public void setSessionFailed(@SessionErrorCode int errorCode, String errorMessage) { Preconditions.checkState(!mIsApplied, "Already marked as applied"); mIsFailed = true; mErrorCode = errorCode; diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java index c9ae11a14ed3..0054fc328932 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java @@ -125,6 +125,7 @@ public class MagnificationControllerTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); FakeSettingsProvider.clearSettingsProvider(); + final Object globalLock = new Object(); LocalServices.removeServiceForTest(WindowManagerInternal.class); LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal); @@ -139,14 +140,14 @@ public class MagnificationControllerTest { CURRENT_USER_ID); mScaleProvider = spy(new MagnificationScaleProvider(mContext)); mWindowMagnificationManager = Mockito.spy( - new WindowMagnificationManager(mContext, CURRENT_USER_ID, + new WindowMagnificationManager(mContext, globalLock, mock(WindowMagnificationManager.Callback.class), mTraceManager, mScaleProvider)); mMockConnection = new MockWindowMagnificationConnection(true); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mScreenMagnificationControllerStubber = new FullScreenMagnificationControllerStubber( mScreenMagnificationController); - mMagnificationController = new MagnificationController(mService, new Object(), mContext, + mMagnificationController = new MagnificationController(mService, globalLock, mContext, mScreenMagnificationController, mWindowMagnificationManager, mScaleProvider); mMagnificationController.setMagnificationCapabilities( diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java index b807c11d5a5c..e9f0bd9db9fe 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java @@ -85,7 +85,7 @@ public class WindowMagnificationGestureHandlerTest { @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); - mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0, + mWindowMagnificationManager = new WindowMagnificationManager(mContext, new Object(), mock(WindowMagnificationManager.Callback.class), mMockTrace, new MagnificationScaleProvider(mContext)); mMockConnection = new MockWindowMagnificationConnection(); diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java index 8b7a19136f50..a62c0d5e1eaf 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationManagerTest.java @@ -94,7 +94,7 @@ public class WindowMagnificationManagerTest { LocalServices.addService(StatusBarManagerInternal.class, mMockStatusBarManagerInternal); mResolver = new MockContentResolver(); mMockConnection = new MockWindowMagnificationConnection(); - mWindowMagnificationManager = new WindowMagnificationManager(mContext, CURRENT_USER_ID, + mWindowMagnificationManager = new WindowMagnificationManager(mContext, new Object(), mMockCallback, mMockTrace, new MagnificationScaleProvider(mContext)); when(mContext.getContentResolver()).thenReturn(mResolver); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java index 6c4ae6fae2d2..62a2b1be139d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java @@ -306,12 +306,12 @@ public class PackageInstallerSessionTest { assertEquals(expected.stageCid, actual.stageCid); assertEquals(expected.isPrepared(), actual.isPrepared()); assertEquals(expected.isStaged(), actual.isStaged()); - assertEquals(expected.isStagedSessionApplied(), actual.isStagedSessionApplied()); - assertEquals(expected.isStagedSessionFailed(), actual.isStagedSessionFailed()); - assertEquals(expected.isStagedSessionReady(), actual.isStagedSessionReady()); - assertEquals(expected.getStagedSessionErrorCode(), actual.getStagedSessionErrorCode()); - assertEquals(expected.getStagedSessionErrorMessage(), - actual.getStagedSessionErrorMessage()); + assertEquals(expected.isSessionApplied(), actual.isSessionApplied()); + assertEquals(expected.isSessionFailed(), actual.isSessionFailed()); + assertEquals(expected.isSessionReady(), actual.isSessionReady()); + assertEquals(expected.getSessionErrorCode(), actual.getSessionErrorCode()); + assertEquals(expected.getSessionErrorMessage(), + actual.getSessionErrorMessage()); assertEquals(expected.isPrepared(), actual.isPrepared()); assertEquals(expected.isCommitted(), actual.isCommitted()); assertEquals(expected.createdMillis, actual.createdMillis); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index a985de50b9aa..34038c57eafc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -132,6 +132,9 @@ class WindowTestsBase extends SystemServiceTestsBase { // Default base activity name private static final String DEFAULT_COMPONENT_CLASS_NAME = ".BarActivity"; + // An id appended to the end of the component name to make it unique + static int sCurrentActivityId = 0; + ActivityTaskManagerService mAtm; RootWindowContainer mRootWindowContainer; ActivityTaskSupervisor mSupervisor; @@ -895,13 +898,16 @@ class WindowTestsBase extends SystemServiceTestsBase { doReturn(100).when(hardwareBuffer).getHeight(); } + private static ComponentName getUniqueComponentName() { + return ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, + DEFAULT_COMPONENT_CLASS_NAME + sCurrentActivityId++); + } + /** * Builder for creating new activities. */ protected static class ActivityBuilder { static final int DEFAULT_FAKE_UID = 12345; - // An id appended to the end of the component name to make it unique - private static int sCurrentActivityId = 0; private final ActivityTaskManagerService mService; @@ -1077,9 +1083,7 @@ class WindowTestsBase extends SystemServiceTestsBase { ActivityRecord buildInner() { if (mComponent == null) { - final int id = sCurrentActivityId++; - mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, - DEFAULT_COMPONENT_CLASS_NAME + id); + mComponent = getUniqueComponentName(); } Intent intent = new Intent(); @@ -1388,8 +1392,7 @@ class WindowTestsBase extends SystemServiceTestsBase { if (mIntent == null) { mIntent = new Intent(); if (mComponent == null) { - mComponent = ComponentName.createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, - DEFAULT_COMPONENT_CLASS_NAME); + mComponent = getUniqueComponentName(); } mIntent.setComponent(mComponent); mIntent.setFlags(mFlags); @@ -1422,10 +1425,11 @@ class WindowTestsBase extends SystemServiceTestsBase { doNothing().when(rootTask).startActivityLocked( any(), any(), anyBoolean(), anyBoolean(), any(), any()); - // Create child task with activity. + // Create child activity. if (mCreateActivity) { new ActivityBuilder(mSupervisor.mService) .setTask(task) + .setComponent(mComponent) .build(); if (mOnTop) { // We move the task to front again in order to regain focus after activity diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index b21d7b5d1f4a..869999e73bdb 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -303,11 +303,14 @@ public class StagedInstallInternalTest { assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1); TestApp apex = new TestApp("apex", "test.apex.rebootless", 2, /* isApex= */ true, "test.rebootless_apex_v2.apex"); + String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed " + + "for com.android.tests.stagedinstallinternal"; InstallUtils.commitExpectingFailure( - AssertionError.class, - "Update of APEX package test.apex.rebootless is not allowed " - + "for com.android.tests.stagedinstallinternal", + AssertionError.class, expectedFailMessage, Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged()); + InstallUtils.commitExpectingFailure( + AssertionError.class, expectedFailMessage, + Install.multi(apex).setBypassAllowedApexUpdateCheck(false).setStaged()); } @Test @@ -315,11 +318,14 @@ public class StagedInstallInternalTest { assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1); TestApp apex = new TestApp("apex", "test.apex.rebootless", 2, /* isApex= */ true, "test.rebootless_apex_v2.apex"); + String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed " + + "for com.android.tests.stagedinstallinternal"; InstallUtils.commitExpectingFailure( - AssertionError.class, - "Update of APEX package test.apex.rebootless is not allowed " - + "for com.android.tests.stagedinstallinternal", + AssertionError.class, expectedFailMessage, Install.single(apex).setBypassAllowedApexUpdateCheck(false)); + InstallUtils.commitExpectingFailure( + AssertionError.class, expectedFailMessage, + Install.multi(apex).setBypassAllowedApexUpdateCheck(false)); } @Test @@ -327,11 +333,14 @@ public class StagedInstallInternalTest { assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1); TestApp apex = new TestApp("apex", "test.apex.rebootless", 2, /* isApex= */ true, "test.rebootless_apex_v2.apex"); + String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed " + + "for com.android.tests.stagedinstallinternal"; InstallUtils.commitExpectingFailure( - AssertionError.class, - "Update of APEX package test.apex.rebootless is not allowed " - + "for com.android.tests.stagedinstallinternal", + AssertionError.class, expectedFailMessage, Install.single(apex).setBypassAllowedApexUpdateCheck(false).setStaged()); + InstallUtils.commitExpectingFailure( + AssertionError.class, expectedFailMessage, + Install.multi(apex).setBypassAllowedApexUpdateCheck(false).setStaged()); } @Test @@ -339,11 +348,14 @@ public class StagedInstallInternalTest { assertThat(InstallUtils.getInstalledVersion("test.apex.rebootless")).isEqualTo(1); TestApp apex = new TestApp("apex", "test.apex.rebootless", 2, /* isApex= */ true, "test.rebootless_apex_v2.apex"); + String expectedFailMessage = "Update of APEX package test.apex.rebootless is not allowed " + + "for com.android.tests.stagedinstallinternal"; InstallUtils.commitExpectingFailure( - AssertionError.class, - "Update of APEX package test.apex.rebootless is not allowed " - + "for com.android.tests.stagedinstallinternal", + AssertionError.class, expectedFailMessage, Install.single(apex).setBypassAllowedApexUpdateCheck(false)); + InstallUtils.commitExpectingFailure( + AssertionError.class, expectedFailMessage, + Install.multi(apex).setBypassAllowedApexUpdateCheck(false)); } @Test |