diff options
99 files changed, 2115 insertions, 332 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 6e37b7e55eef..6393fdb910e3 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -112,6 +112,7 @@ aconfig_declarations_group { "framework_graphics_flags_java_lib", "hwui_flags_java_lib", "interaction_jank_monitor_flags_lib", + "keystore2_flags_java-framework", "libcore_exported_aconfig_flags_lib", "libcore_readonly_aconfig_flags_lib", "libgui_flags_java_lib", diff --git a/core/api/current.txt b/core/api/current.txt index dc7ccd4efaa9..4526de4de6e0 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8075,6 +8075,7 @@ package android.app.admin { method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String); method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName); method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeEnabled(@Nullable android.content.ComponentName); + method @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public int getAutoTimePolicy(); method @Deprecated public boolean getAutoTimeRequired(); method @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public boolean getAutoTimeZoneEnabled(@Nullable android.content.ComponentName); method @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") @RequiresPermission(anyOf={android.Manifest.permission.SET_TIME_ZONE, "android.permission.QUERY_ADMIN_POLICY"}, conditional=true) public int getAutoTimeZonePolicy(); @@ -8233,6 +8234,7 @@ package android.app.admin { method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle); method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException; method @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimeEnabled(@Nullable android.content.ComponentName, boolean); + method @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") @RequiresPermission(value=android.Manifest.permission.SET_TIME, conditional=true) public void setAutoTimePolicy(int); method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean); method @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZoneEnabled(@Nullable android.content.ComponentName, boolean); method @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") @RequiresPermission(value=android.Manifest.permission.SET_TIME_ZONE, conditional=true) public void setAutoTimeZonePolicy(int); @@ -8354,6 +8356,9 @@ package android.app.admin { field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD"; field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION"; field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED"; + field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_DISABLED = 1; // 0x1 + field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_ENABLED = 2; // 0x2 + field @FlaggedApi("android.app.admin.flags.set_auto_time_enabled_coexistence") public static final int AUTO_TIME_NOT_CONTROLLED_BY_POLICY = 0; // 0x0 field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_DISABLED = 1; // 0x1 field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_ENABLED = 2; // 0x2 field @FlaggedApi("android.app.admin.flags.set_auto_time_zone_enabled_coexistence") public static final int AUTO_TIME_ZONE_NOT_CONTROLLED_BY_POLICY = 0; // 0x0 @@ -56907,6 +56912,7 @@ package android.view.inputmethod { ctor public EditorInfo(); method public int describeContents(); method public void dump(android.util.Printer, String); + method @FlaggedApi("android.view.inputmethod.public_autofill_id_in_editorinfo") @Nullable public android.view.autofill.AutofillId getAutofillId(); method @Nullable public CharSequence getInitialSelectedText(int); method @Nullable public android.view.inputmethod.SurroundingText getInitialSurroundingText(@IntRange(from=0) int, @IntRange(from=0) int, int); method @Nullable public CharSequence getInitialTextAfterCursor(@IntRange(from=0) int, int); @@ -56916,6 +56922,7 @@ package android.view.inputmethod { method @NonNull public java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>> getSupportedHandwritingGestures(); method @FlaggedApi("android.view.inputmethod.editorinfo_handwriting_enabled") public boolean isStylusHandwritingEnabled(); method public final void makeCompatible(int); + method @FlaggedApi("android.view.inputmethod.public_autofill_id_in_editorinfo") public void setAutofillId(@Nullable android.view.autofill.AutofillId); method public void setInitialSurroundingSubText(@NonNull CharSequence, int); method public void setInitialSurroundingText(@NonNull CharSequence); method public void setInitialToolType(int); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index c8ecfa94ec87..119271390b94 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2065,6 +2065,29 @@ package android.media { method public boolean isAidlHal(); } + public final class MediaCodec { + method @FlaggedApi("android.media.codec.codec_availability") @NonNull public static java.util.List<android.media.MediaCodec.GlobalResourceInfo> getGloballyAvailableResources(); + method @FlaggedApi("android.media.codec.codec_availability") @NonNull public java.util.List<android.media.MediaCodec.InstanceResourceInfo> getRequiredResources(); + } + + public abstract static class MediaCodec.Callback { + method @FlaggedApi("android.media.codec.codec_availability") public void onRequiredResourcesChanged(@NonNull android.media.MediaCodec); + } + + @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.GlobalResourceInfo { + ctor public MediaCodec.GlobalResourceInfo(); + method public long getAvailable(); + method public long getCapacity(); + method @NonNull public String getName(); + } + + @FlaggedApi("android.media.codec.codec_availability") public static final class MediaCodec.InstanceResourceInfo { + ctor public MediaCodec.InstanceResourceInfo(); + method @NonNull public String getName(); + method public long getPerFrameCount(); + method public long getStaticCount(); + } + public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint { ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size); ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size); diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 0654ac2f33ce..9bb16ae7fa02 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -124,7 +124,7 @@ interface INotificationManager boolean onlyHasDefaultChannel(String pkg, int uid); boolean areChannelsBypassingDnd(); ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int uid); - List<String> getPackagesBypassingDnd(int userId, boolean includeConversationChannels); + ParceledListSlice getPackagesBypassingDnd(int userId); boolean isPackagePaused(String pkg); void deleteNotificationHistoryItem(String pkg, int uid, long postedTime); boolean isPermissionFixed(String pkg, int userId); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 0381ee0e25ac..3d9c55c0f37a 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5003,7 +5003,7 @@ public class Notification implements Parcelable /** * Sets a very short string summarizing the most critical information contained in the - * notification. Suggested max length is 5 characters, and there is no guarantee how much or + * notification. Suggested max length is 7 characters, and there is no guarantee how much or * how little of this text will be shown. */ @FlaggedApi(Flags.FLAG_API_RICH_ONGOING) diff --git a/core/java/android/app/ZenBypassingApp.java b/core/java/android/app/ZenBypassingApp.java new file mode 100644 index 000000000000..89bcfa2d2e7d --- /dev/null +++ b/core/java/android/app/ZenBypassingApp.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2024 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.app; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +import java.util.Objects; + +/** + * @hide + */ +public final class ZenBypassingApp implements Parcelable { + + @NonNull private String mPkg; + private boolean mAllChannelsBypass; + + + public ZenBypassingApp(@NonNull String pkg, boolean allChannelsBypass) { + mPkg = pkg; + mAllChannelsBypass = allChannelsBypass; + } + + public ZenBypassingApp(Parcel source) { + mPkg = source.readString(); + mAllChannelsBypass = source.readBoolean(); + } + + @NonNull + public String getPkg() { + return mPkg; + } + + public boolean doAllChannelsBypass() { + return mAllChannelsBypass; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mPkg); + dest.writeBoolean(mAllChannelsBypass); + } + + public static final @android.annotation.NonNull Parcelable.Creator<ZenBypassingApp> CREATOR + = new Parcelable.Creator<ZenBypassingApp>() { + @Override + public ZenBypassingApp createFromParcel(Parcel source) { + return new ZenBypassingApp(source); + } + @Override + public ZenBypassingApp[] newArray(int size) { + return new ZenBypassingApp[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof ZenBypassingApp)) return false; + ZenBypassingApp that = (ZenBypassingApp) o; + return mAllChannelsBypass == that.mAllChannelsBypass && Objects.equals(mPkg, + that.mPkg); + } + + @Override + public int hashCode() { + return Objects.hash(mPkg, mAllChannelsBypass); + } + + @Override + public String toString() { + return "ZenBypassingApp{" + + "mPkg='" + mPkg + '\'' + + ", mAllChannelsBypass=" + mAllChannelsBypass + + '}'; + } +} diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index bff77f951b9f..c789c41ec431 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -8920,12 +8920,9 @@ public class DevicePolicyManager { /** * Called by a device owner, a profile owner for the primary user or a profile * owner of an organization-owned managed profile to turn auto time on and off. - * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} - * to prevent the user from changing this setting. * <p> - * If user restriction {@link UserManager#DISALLOW_CONFIG_DATE_TIME} is used, - * no user will be able set the date and time. Instead, the network date - * and time will be used. + * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the + * user from changing this setting, that way no user will be able set the date and time zone. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Null if the * caller is not a device admin. @@ -8938,7 +8935,13 @@ public class DevicePolicyManager { throwIfParentInstance("setAutoTimeEnabled"); if (mService != null) { try { - mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled); + if (Flags.setAutoTimeEnabledCoexistence()) { + mService.setAutoTimePolicy(mContext.getPackageName(), + enabled ? DevicePolicyManager.AUTO_TIME_ENABLED + : DevicePolicyManager.AUTO_TIME_DISABLED); + } else { + mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled); + } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -8968,6 +8971,97 @@ public class DevicePolicyManager { } /** + * Specifies that the auto time state is not controlled by device policy. + * + * @see #setAutoTimePolicy(ComponentName, int) + */ + @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE) + public static final int AUTO_TIME_NOT_CONTROLLED_BY_POLICY = 0; + + /** + * Specifies the "disabled" auto time state. + * + * @see #setAutoTimePolicy(ComponentName, int) + */ + @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE) + public static final int AUTO_TIME_DISABLED = 1; + + /** + * Specifies the "enabled" auto time state. + * + * @see #setAutoTimePolicy(ComponentName, int) + */ + @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE) + public static final int AUTO_TIME_ENABLED = 2; + + /** + * Flags supplied to {@link #setAutoTimePolicy}(ComponentName, int)}. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "AUTO_TIME_" }, value = { + AUTO_TIME_NOT_CONTROLLED_BY_POLICY, + AUTO_TIME_DISABLED, + AUTO_TIME_ENABLED + }) + public @interface AutoTimePolicy {} + + /** + * Called by a device owner, a profile owner for the primary user or a profile owner of an + * organization-owned managed profile to turn auto time on and off i.e. Whether time should be + * obtained automatically from the network or not. + * <p> + * Callers are recommended to use {@link UserManager#DISALLOW_CONFIG_DATE_TIME} to prevent the + * user from changing this setting, that way no user will be able set the date and time zone. + * + * @param policy The desired state among {@link #AUTO_TIME_ENABLED} to enable, + * {@link #AUTO_TIME_DISABLED} to disable and + * {@link #AUTO_TIME_NOT_CONTROLLED_BY_POLICY} to unset the policy. + * @throws SecurityException if caller is not a device owner, a profile owner for the + * primary user, or a profile owner of an organization-owned managed profile, or if the caller + * does not hold the required permission. + */ + @SupportsCoexistence + @RequiresPermission(value = SET_TIME, conditional = true) + @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE) + public void setAutoTimePolicy(@AutoTimePolicy int policy) { + throwIfParentInstance("setAutoTimePolicy"); + if (mService != null) { + try { + mService.setAutoTimePolicy(mContext.getPackageName(), policy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** + * Returns current auto time policy's state. + * + * @return One of {@link #AUTO_TIME_ENABLED} if enabled, {@link #AUTO_TIME_DISABLED} if disabled + * and {@link #AUTO_TIME_NOT_CONTROLLED_BY_POLICY} if it's not controlled by + * policy. + * @throws SecurityException if caller is not a device owner, a profile owner for the + * primary user, or a profile owner of an organization-owned managed profile, or if the caller + * does not hold the required permission. + */ + @SupportsCoexistence + @RequiresPermission(anyOf = {SET_TIME, QUERY_ADMIN_POLICY}, conditional = true) + @FlaggedApi(Flags.FLAG_SET_AUTO_TIME_ENABLED_COEXISTENCE) + public @AutoTimePolicy int getAutoTimePolicy() { + throwIfParentInstance("getAutoTimePolicy"); + if (mService != null) { + try { + return mService.getAutoTimePolicy(mContext.getPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY; + } + + /** * Called by a device owner, a profile owner for the primary user or a profile * owner of an organization-owned managed profile to turn auto time zone on and off. * <p> diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 0b8f53881d07..a40680218039 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -375,6 +375,9 @@ interface IDevicePolicyManager { void setAutoTimeEnabled(in ComponentName who, String callerPackageName, boolean enabled); boolean getAutoTimeEnabled(in ComponentName who, String callerPackageName); + void setAutoTimePolicy(String callerPackageName, int policy); + int getAutoTimePolicy(String callerPackageName); + void setAutoTimeZoneEnabled(in ComponentName who, String callerPackageName, boolean enabled); boolean getAutoTimeZoneEnabled(in ComponentName who, String callerPackageName); diff --git a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig index 8b6441ae5a7c..74a96c864167 100644 --- a/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig +++ b/core/java/android/app/ondeviceintelligence/flags/ondevice_intelligence.aconfig @@ -8,3 +8,10 @@ flag { description: "Make methods on OnDeviceIntelligenceManager available for local inference." bug: "304755128" } +flag { + name: "enable_on_device_intelligence_module" + is_exported: true + namespace: "ondeviceintelligence" + description: "Enable migration to mainline module and related changes." + bug: "376427781" +}
\ No newline at end of file diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index b776b59f11c2..88533049f970 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -87,7 +87,6 @@ import android.util.AttributeSet; import android.util.Log; import android.util.proto.ProtoOutputStream; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.XmlUtils; import com.android.modules.expresslog.Counter; @@ -12304,7 +12303,6 @@ public class Intent implements Parcelable, Cloneable { } /** @hide */ - @VisibleForTesting public Set<NestedIntentKey> getExtraIntentKeys() { return mCreatorTokenInfo == null ? null : mCreatorTokenInfo.mNestedIntentKeys; } diff --git a/core/java/android/hardware/display/DisplayTopology.java b/core/java/android/hardware/display/DisplayTopology.java index e349b81614bc..f00c3a53ad0c 100644 --- a/core/java/android/hardware/display/DisplayTopology.java +++ b/core/java/android/hardware/display/DisplayTopology.java @@ -23,6 +23,7 @@ import static android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP; import android.annotation.IntDef; import android.annotation.Nullable; +import android.graphics.PointF; import android.graphics.RectF; import android.os.Parcel; import android.os.Parcelable; @@ -150,6 +151,138 @@ public final class DisplayTopology implements Parcelable { } } + /** + * Rearranges the topology toward the positions given for each display. The width and height of + * each display, as well as the primary display, are not changed by this call. + * <p> + * Upon returning, the topology will be valid and normalized with each display as close to the + * requested positions as possible. + * + * @param newPos the desired positions (upper-left corner) of each display. The keys in the map + * are the display IDs. + * @throws IllegalArgumentException if the keys in {@code positions} are not the exact display + * IDs in this topology, no more, no less + */ + public void rearrange(Map<Integer, PointF> newPos) { + var availableParents = new ArrayList<TreeNode>(); + + availableParents.addLast(mRoot); + + var needsParent = allNodesIdMap(); + + // In the case of missing items, if this check doesn't detect it, a NPE will be thrown + // later. + if (needsParent.size() != newPos.size()) { + throw new IllegalArgumentException("newPos has wrong number of entries: " + newPos); + } + + mRoot.mChildren.clear(); + for (TreeNode n : needsParent.values()) { + n.mChildren.clear(); + } + + needsParent.remove(mRoot.mDisplayId); + // Start with a root island and add children to it one-by-one until the island consists of + // all the displays. The root island begins with only the root node, which has no + // parent. Then we greedily choose an optimal pairing of two nodes, consisting of a node + // from the island and a node not yet in the island. This is repeating until all nodes are + // in the island. + // + // The optimal pair is the pair which has the smallest deviation. The deviation consists of + // an x-axis component and a y-axis component, called xDeviation and yDeviation. + // + // The deviations are like distances but a little different. They are calculated in two + // steps. The first step calculates both axes in a similar way. The next step compares the + // two values and chooses which axis to attach along. Depending on which axis is chosen, + // the deviation for one axis is updated. See below for details. + while (!needsParent.isEmpty()) { + double bestDist = Double.POSITIVE_INFINITY; + TreeNode bestChild = null, bestParent = null; + + for (var child : needsParent.values()) { + PointF childPos = newPos.get(child.mDisplayId); + float childRight = childPos.x + child.getWidth(); + float childBottom = childPos.y + child.getHeight(); + for (var parent : availableParents) { + PointF parentPos = newPos.get(parent.mDisplayId); + float parentRight = parentPos.x + parent.getWidth(); + float parentBottom = parentPos.y + parent.getHeight(); + + // This is the smaller of the two ranges minus the amount of overlap shared + // between them. The "amount of overlap" is negative if there is no overlap, but + // this does not make a parenting ineligible, because we allow for attaching at + // the corner and for floating point error. The overlap is more negative the + // farther apart the closest corner pair is. + // + // For each axis, this calculates (SmallerRange - Overlap). If one range lies + // completely in the other (or they are equal), the axis' deviation will be + // zero. + // + // The "SmallerRange," which refers to smaller of the widths of the two rects, + // or smaller of the heights of the two rects, is added to the deviation so that + // a maximum overlap results in a deviation of zero. + float xSmallerRange = Math.min(child.getWidth(), parent.getWidth()); + float ySmallerRange = Math.min(child.getHeight(), parent.getHeight()); + float xOverlap + = Math.min(parentRight, childRight) + - Math.max(parentPos.x, childPos.x); + float yOverlap + = Math.min(parentBottom, childBottom) + - Math.max(parentPos.y, childPos.y); + float xDeviation = xSmallerRange - xOverlap; + float yDeviation = ySmallerRange - yOverlap; + + float offset; + int pos; + if (xDeviation <= yDeviation) { + if (childPos.y < parentPos.y) { + yDeviation = childBottom - parentPos.y; + pos = POSITION_TOP; + } else { + yDeviation = parentBottom - childPos.y; + pos = POSITION_BOTTOM; + } + offset = childPos.x - parentPos.x; + } else { + if (childPos.x < parentPos.x) { + xDeviation = childRight - parentPos.x; + pos = POSITION_LEFT; + } else { + xDeviation = parentRight - childPos.x; + pos = POSITION_RIGHT; + } + offset = childPos.y - parentPos.y; + } + + double dist = Math.hypot(xDeviation, yDeviation); + if (dist >= bestDist) { + continue; + } + + bestDist = dist; + bestChild = child; + bestParent = parent; + // Eagerly update the child's parenting info, even though we may not use it, in + // which case it will be overwritten later. + bestChild.mPosition = pos; + bestChild.mOffset = offset; + } + } + + assert bestParent != null & bestChild != null; + + bestParent.addChild(bestChild); + if (null == needsParent.remove(bestChild.mDisplayId)) { + throw new IllegalStateException("child not in pending set! " + bestChild); + } + availableParents.add(bestChild); + } + + // The conversion may have introduced an intersection of two display rects. If they are + // bigger than our error tolerance, this function will remove them. + normalize(); + } + @Override public int describeContents() { return 0; @@ -450,6 +583,20 @@ public final class DisplayTopology implements Parcelable { return a == b || (Float.isNaN(a) && Float.isNaN(b)) || Math.abs(a - b) < EPSILON; } + private Map<Integer, TreeNode> allNodesIdMap() { + var pend = new ArrayDeque<TreeNode>(); + var found = new HashMap<Integer, TreeNode>(); + + pend.push(mRoot); + do { + TreeNode node = pend.pop(); + found.put(node.mDisplayId, node); + pend.addAll(node.mChildren); + } while (!pend.isEmpty()); + + return found; + } + public static final class TreeNode implements Parcelable { public static final int POSITION_LEFT = 0; public static final int POSITION_TOP = 1; diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 8c3f0ef08039..70a1909023a0 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -3436,7 +3436,7 @@ public class InputMethodService extends AbstractInputMethodService { initialize(); mInlineSuggestionSessionController.notifyOnStartInput( editorInfo == null ? null : editorInfo.packageName, - editorInfo == null ? null : editorInfo.autofillId); + editorInfo == null ? null : editorInfo.getAutofillId()); if (DEBUG) Log.v(TAG, "CALL: onStartInput"); onStartInput(editorInfo, restarting); if (mDecorViewVisible) { diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 4bc8fe0a974c..9ab92285c167 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -3928,9 +3928,9 @@ public class UserManager { final int callingUid = Binder.getCallingUid(); final int processUid = Process.myUid(); - if (Build.isDebuggable() && callingUid != processUid) { - Log.w(TAG, "Uid " + processUid + " is fetching a copy of UserProperties on" - + " behalf of callingUid " + callingUid + ". Possibly" + if (processUid == Process.SYSTEM_UID && callingUid != processUid) { + Log.w(TAG, "The System (uid " + processUid + ") is fetching a copy of" + + " UserProperties on behalf of callingUid " + callingUid + ". Possibly" + " it should carefully first clearCallingIdentity or perhaps use" + " UserManagerInternal.getUserProperties() instead?", new Throwable()); diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 33040be7c0fb..6264fbbbcb7a 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -391,3 +391,12 @@ flag{ description: "Batch noteOperations on the client to reduce binder call volume" bug: "366013082" } + +flag { + name: "supervision_role_permission_update_enabled" + is_fixed_read_only: true + is_exported: true + namespace: "supervision" + description: "This flag is used to enable all the remaining permissions required to the supervision role" + bug: "367333883" +}
\ No newline at end of file diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index ae12132d49a1..a42eece57eec 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -614,7 +614,7 @@ public class Html { if (style[j] instanceof TypefaceSpan) { String s = ((TypefaceSpan) style[j]).getFamily(); - if (s.equals("monospace")) { + if ("monospace".equals(s)) { out.append("</tt>"); } } diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index fb3e0831fdc9..a5603399142b 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -24,6 +24,7 @@ import static android.view.inputmethod.EditorInfoProto.PACKAGE_NAME; import static android.view.inputmethod.EditorInfoProto.PRIVATE_IME_OPTIONS; import static android.view.inputmethod.EditorInfoProto.TARGET_INPUT_METHOD_USER_ID; import static android.view.inputmethod.Flags.FLAG_EDITORINFO_HANDWRITING_ENABLED; +import static android.view.inputmethod.Flags.FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -470,12 +471,10 @@ public class EditorInfo implements InputType, Parcelable { public String packageName; /** - * Autofill Id for the field that's currently on focus. - * - * <p> Marked as hide since it's only used by framework.</p> - * @hide + * Autofill Id for the field that's currently on focus. See link {@link AutofillId} for more + * details. It is set by {@link View#getAutofillId()} */ - public AutofillId autofillId; + private AutofillId autofillId; /** * Identifier for the editor's field. This is optional, and may be @@ -1200,6 +1199,28 @@ public class EditorInfo implements InputType, Parcelable { } /** + * Returns the {@link AutofillId} of the view that this {@link EditorInfo} is associated with. + * The value is filled in with the result of {@link android.view.View#getAutofillId() + * View.getAutofillId()} on the view that is being edited. + * + * Note: For virtual view(e.g. Compose or Webview), default behavior is the autofillId is the id + * of the container view, unless the virtual view provider sets the virtual id when the + * InputMethodManager calls {@link android.view.View#onCreateInputConnection()} on the container + * view. + */ + @FlaggedApi(FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO) + @Nullable + public AutofillId getAutofillId() { + return autofillId; + } + + /** Sets the {@link AutofillId} of the view that this {@link EditorInfo} is associated with. */ + @FlaggedApi(FLAG_PUBLIC_AUTOFILL_ID_IN_EDITORINFO) + public void setAutofillId(@Nullable AutofillId autofillId) { + this.autofillId = autofillId; + } + + /** * Export the state of {@link EditorInfo} into a protocol buffer output stream. * * @param proto Stream to write the state to diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 6026e60e5b59..6303c7637a59 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -5179,7 +5179,7 @@ public final class InputMethodManager { // system can verify the consistency between the uid of this process and package name passed // from here. See comment of Context#getOpPackageName() for details. editorInfo.packageName = servedView.getContext().getOpPackageName(); - editorInfo.autofillId = servedView.getAutofillId(); + editorInfo.setAutofillId(servedView.getAutofillId()); editorInfo.fieldId = servedView.getId(); final InputConnection ic = servedView.onCreateInputConnection(editorInfo); if (DEBUG) Log.v(TAG, "Starting input: editorInfo=" + editorInfo + " ic=" + ic); @@ -5188,7 +5188,7 @@ public final class InputMethodManager { // This ensures that even disconnected EditorInfos have well-defined attributes, // making them consistently and straightforwardly comparable. if (ic == null) { - editorInfo.autofillId = AutofillId.NO_AUTOFILL_ID; + editorInfo.setAutofillId(AutofillId.NO_AUTOFILL_ID); editorInfo.fieldId = 0; } return new Pair<>(ic, editorInfo); diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index edd9d6cff799..e619ab064005 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -165,4 +165,13 @@ flag { description: "Writing tools API" bug: "373788889" is_fixed_read_only: true -}
\ No newline at end of file +} + +flag { + name: "public_autofill_id_in_editorinfo" + is_exported: true + namespace: "input_method" + description: "Guarding public API autofillId in editor info" + bug: "342672560" + is_fixed_read_only: true +} diff --git a/core/jni/com_android_internal_content_FileSystemUtils.cpp b/core/jni/com_android_internal_content_FileSystemUtils.cpp index 6c72544a7958..76ead2a3ca31 100644 --- a/core/jni/com_android_internal_content_FileSystemUtils.cpp +++ b/core/jni/com_android_internal_content_FileSystemUtils.cpp @@ -22,7 +22,6 @@ #include <android-base/hex.h> #include <android-base/unique_fd.h> #include <bionic/macros.h> -#include <elf.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> @@ -204,7 +203,8 @@ bool punchHoles(const char *filePath, const uint64_t offset, return true; } -bool punchHolesInElf64(const char *filePath, const uint64_t offset) { +bool getLoadSegmentPhdrs(const char *filePath, const uint64_t offset, + std::vector<Elf64_Phdr> &programHeaders) { // Open Elf file Elf64_Ehdr ehdr; std::ifstream inputStream(filePath, std::ifstream::in); @@ -227,11 +227,6 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) { uint64_t programHeaderOffset = ehdr.e_phoff; uint16_t programHeaderNum = ehdr.e_phnum; - IF_ALOGD() { - ALOGD("Punching holes in file: %s programHeaderOffset: %" PRIu64 " programHeaderNum: %hu", - filePath, programHeaderOffset, programHeaderNum); - } - // if this is a zip file, also consider elf offset inside a file uint64_t phOffset; if (__builtin_add_overflow(offset, programHeaderOffset, &phOffset)) { @@ -240,7 +235,6 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) { } inputStream.seekg(phOffset); - std::vector<Elf64_Phdr> programHeaders; for (int headerIndex = 0; headerIndex < programHeaderNum; headerIndex++) { Elf64_Phdr header; inputStream.read((char *)&header, sizeof(header)); @@ -254,6 +248,15 @@ bool punchHolesInElf64(const char *filePath, const uint64_t offset) { programHeaders.push_back(header); } + return true; +} + +bool punchHolesInElf64(const char *filePath, const uint64_t offset) { + std::vector<Elf64_Phdr> programHeaders; + if (!getLoadSegmentPhdrs(filePath, offset, programHeaders)) { + ALOGE("Failed to read program headers from ELF file."); + return false; + } return punchHoles(filePath, offset, programHeaders); } diff --git a/core/jni/com_android_internal_content_FileSystemUtils.h b/core/jni/com_android_internal_content_FileSystemUtils.h index 52445e2b4229..4a95686c5a0c 100644 --- a/core/jni/com_android_internal_content_FileSystemUtils.h +++ b/core/jni/com_android_internal_content_FileSystemUtils.h @@ -15,8 +15,11 @@ */ #pragma once +#include <elf.h> #include <sys/types.h> +#include <vector> + namespace android { /* @@ -35,4 +38,11 @@ bool punchHolesInElf64(const char* filePath, uint64_t offset); */ bool punchHolesInZip(const char* filePath, uint64_t offset, uint16_t extraFieldLen); +/* + * This function reads program headers from ELF file. ELF can be specified with file path directly + * or it should be at offset inside Apk. Program headers passed to function is populated. + */ +bool getLoadSegmentPhdrs(const char* filePath, const uint64_t offset, + std::vector<Elf64_Phdr>& programHeaders); + } // namespace android
\ No newline at end of file diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index dc054a4a48ea..969ee2e16deb 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1849,6 +1849,10 @@ <item>-1</item> </integer-array> + <!-- Specifies the delay in milliseconds after the last user input before turning off the + keyboard backlight. + --> + <integer name="config_keyboardBacklightTimeoutMs">30000</integer> <!-- An array describing the screen's backlight values corresponding to the brightness values in the config_screenBrightnessNits array. diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index badb98686fb2..9dd302784c2c 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2098,6 +2098,7 @@ <java-symbol type="integer" name="config_autoBrightnessDarkeningLightDebounce"/> <java-symbol type="integer" name="config_autoBrightnessInitialLightSensorRate"/> <java-symbol type="integer" name="config_autoBrightnessLightSensorRate"/> + <java-symbol type="integer" name="config_keyboardBacklightTimeoutMs" /> <java-symbol type="integer" name="config_carDockKeepsScreenOn" /> <java-symbol type="integer" name="config_criticalBatteryWarningLevel" /> <java-symbol type="integer" name="config_datause_notification_type" /> diff --git a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java index 1721e1e2e935..9dd196daf412 100644 --- a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java +++ b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java @@ -79,7 +79,7 @@ public class EditorInfoTest { TEST_EDITOR_INFO.label = "testLabel"; TEST_EDITOR_INFO.packageName = "android.view.inputmethod"; TEST_EDITOR_INFO.fieldId = 0; - TEST_EDITOR_INFO.autofillId = AutofillId.NO_AUTOFILL_ID; + TEST_EDITOR_INFO.setAutofillId(AutofillId.NO_AUTOFILL_ID); TEST_EDITOR_INFO.fieldName = "testField"; TEST_EDITOR_INFO.extras = new Bundle(); TEST_EDITOR_INFO.extras.putString("testKey", "testValue"); @@ -531,7 +531,7 @@ public class EditorInfoTest { info.setStylusHandwritingEnabled(true); } info.packageName = "android.view.inputmethod"; - info.autofillId = new AutofillId(123); + info.setAutofillId(new AutofillId(123)); info.fieldId = 456; info.fieldName = "testField"; info.extras = new Bundle(); @@ -597,7 +597,7 @@ public class EditorInfoTest { @Test public void testKindofEqualsComparesAutofillId() { final EditorInfo infoCopy = TEST_EDITOR_INFO.createCopyInternal(); - infoCopy.autofillId = new AutofillId(42); + infoCopy.setAutofillId(new AutofillId(42)); assertFalse(TEST_EDITOR_INFO.kindofEquals(infoCopy)); } diff --git a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt index a6de611cc077..8969b2b72e77 100644 --- a/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt +++ b/core/tests/coretests/src/android/hardware/display/DisplayTopologyTest.kt @@ -16,7 +16,10 @@ package android.hardware.display +import android.graphics.PointF +import android.graphics.RectF import android.hardware.display.DisplayTopology.TreeNode.POSITION_BOTTOM +import android.hardware.display.DisplayTopology.TreeNode.POSITION_LEFT import android.hardware.display.DisplayTopology.TreeNode.POSITION_TOP import android.hardware.display.DisplayTopology.TreeNode.POSITION_RIGHT import android.view.Display @@ -469,4 +472,205 @@ class DisplayTopologyTest { assertThat(actualDisplay4.offset).isEqualTo(-400f) assertThat(actualDisplay4.children).isEmpty() } -}
\ No newline at end of file + + @Test + fun rearrange_twoDisplays() { + val nodes = rearrangeRects( + // Arrange in staggered manner, connected vertically. + RectF(100f, 100f, 250f, 200f), + RectF(150f, 200f, 300f, 300f), + ) + + assertThat(nodes[0].children).containsExactly(nodes[1]) + assertThat(nodes[1].children).isEmpty() + assertPositioning(nodes, Pair(POSITION_BOTTOM, 50f)) + } + + @Test + fun rearrange_reverseOrderOfSeveralDisplays() { + val nodes = rearrangeRects( + RectF(0f, 0f, 150f, 100f), + RectF(-150f, 0f, 0f, 100f), + RectF(-300f, 0f, -150f, 100f), + RectF(-450f, 0f, -300f, 100f), + ) + + assertPositioning( + nodes, + Pair(POSITION_LEFT, 0f), + Pair(POSITION_LEFT, 0f), + Pair(POSITION_LEFT, 0f), + ) + + assertThat(nodes[0].children).containsExactly(nodes[1]) + assertThat(nodes[1].children).containsExactly(nodes[2]) + assertThat(nodes[2].children).containsExactly(nodes[3]) + assertThat(nodes[3].children).isEmpty() + } + + @Test + fun rearrange_crossWithRootInCenter() { + val nodes = rearrangeRects( + RectF(0f, 0f, 150f, 100f), + RectF(-150f, 0f, 0f, 100f), + RectF(0f,-100f, 150f, 0f), + RectF(150f, 0f, 300f, 100f), + RectF(0f, 100f, 150f, 200f), + ) + + assertPositioning( + nodes, + Pair(POSITION_LEFT, 0f), + Pair(POSITION_TOP, 0f), + Pair(POSITION_RIGHT, 0f), + Pair(POSITION_BOTTOM, 0f), + ) + + assertThat(nodes[0].children) + .containsExactly(nodes[1], nodes[2], nodes[3], nodes[4]) + } + + @Test + fun rearrange_elbowArrangementDoesNotUseCornerAdjacency1() { + val nodes = rearrangeRects( + // 2 + // | + // 0 - 1 + + RectF(0f, 0f, 100f, 100f), + RectF(100f, 0f, 200f, 100f), + RectF(100f, -100f, 200f, 0f), + ) + + assertThat(nodes[0].children).containsExactly(nodes[1]) + assertThat(nodes[1].children).containsExactly(nodes[2]) + assertThat(nodes[2].children).isEmpty() + + assertPositioning( + nodes, + Pair(POSITION_RIGHT, 0f), + Pair(POSITION_TOP, 0f), + ) + } + + @Test + fun rearrange_elbowArrangementDoesNotUseCornerAdjacency2() { + val nodes = rearrangeRects( + // 0 + // | + // 1 + // | + // 3 - 2 + + RectF(0f, 0f, 100f, 100f), + RectF(0f, 100f, 100f, 200f), + RectF(0f, 200f, 100f, 300f), + RectF(-100f, 200f, 0f, 300f), + ) + + assertThat(nodes[0].children).containsExactly(nodes[1]) + assertThat(nodes[1].children).containsExactly(nodes[2]) + assertThat(nodes[2].children).containsExactly(nodes[3]) + assertThat(nodes[3].children).isEmpty() + + assertPositioning( + nodes, + Pair(POSITION_BOTTOM, 0f), + Pair(POSITION_BOTTOM, 0f), + Pair(POSITION_LEFT, 0f), + ) + } + + @Test + fun rearrange_useLargerEdge() { + val nodes = rearrangeRects( + //444111 + //444111 + //444111 + // 000222 + // 000222 + // 000222 + // 333 + // 333 + // 333 + RectF(20f, 30f, 50f, 60f), + RectF(30f, 0f, 60f, 30f), + RectF(50f, 30f, 80f, 60f), + RectF(40f, 60f, 70f, 90f), + RectF(0f, 0f, 30f, 30f), + ) + + assertPositioning( + nodes, + Pair(POSITION_TOP, 10f), + Pair(POSITION_RIGHT, 0f), + Pair(POSITION_BOTTOM, -10f), + Pair(POSITION_LEFT, 0f), + ) + + assertThat(nodes[0].children).containsExactly(nodes[1], nodes[2]) + assertThat(nodes[1].children).containsExactly(nodes[4]) + assertThat(nodes[2].children).containsExactly(nodes[3]) + (3..4).forEach { assertThat(nodes[it].children).isEmpty() } + } + + @Test + fun rearrange_closeGaps() { + val nodes = rearrangeRects( + //000 + //000 111 + //000 111 + // 111 + // + // 222 + // 222 + // 222 + RectF(0f, 0f, 30f, 30f), + RectF(40f, 10f, 70f, 40f), + RectF(80.5f, 50f, 110f, 80f), // left+=0.5 to cause a preference for TOP/BOTTOM attach + ) + + assertPositioning( + nodes, + // In the case of corner adjacency, we prefer a left/right attachment. + Pair(POSITION_RIGHT, 10f), + Pair(POSITION_BOTTOM, 40.5f), // TODO: fix implementation to remove this gap + ) + + assertThat(nodes[0].children).containsExactly(nodes[1]) + assertThat(nodes[1].children).containsExactly(nodes[2]) + assertThat(nodes[2].children).isEmpty() + } + + /** + * Runs the rearrange algorithm and returns the resulting tree as a list of nodes, with the + * root at index 0. The number of nodes is inferred from the number of positions passed. + */ + private fun rearrangeRects(vararg pos : RectF) : List<DisplayTopology.TreeNode> { + // Generates a linear sequence of nodes in order in the List from root to leaf, + // left-to-right. IDs are ascending from 0 to count - 1. + + val nodes = pos.indices.map { + DisplayTopology.TreeNode(it, pos[it].width(), pos[it].height(), POSITION_RIGHT, 0f) + } + + nodes.forEachIndexed { id, node -> + if (id > 0) { + nodes[id - 1].addChild(node) + } + } + + DisplayTopology(nodes[0], 0).rearrange(pos.indices.associateWith { + PointF(pos[it].left, pos[it].top) + }) + + return nodes + } + + private fun assertPositioning( + nodes : List<DisplayTopology.TreeNode>, vararg positions : Pair<Int, Float>) { + assertThat(nodes.drop(1).map { Pair(it.position, it.offset )}) + .containsExactly(*positions) + .inOrder() + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt index 7446b88e2507..6928c255edde 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt @@ -1179,7 +1179,7 @@ class DesktopTasksController( val userContext = context.createContextAsUser(userHandle, /* flags= */ 0) val intent = Intent(userContext, DesktopWallpaperActivity::class.java) - intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + intent.putExtra(Intent.EXTRA_USER_HANDLE, userId) val options = ActivityOptions.makeBasic().apply { launchWindowingMode = WINDOWING_MODE_FULLSCREEN 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 5ffc64f412f1..79a9ce5212c6 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 @@ -47,7 +47,6 @@ import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipMenuController; -import com.android.wm.shell.common.split.SplitScreenUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.sysui.ShellInit; import com.android.wm.shell.transition.DefaultMixedHandler; @@ -312,10 +311,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH } /** Whether a particular package is same as current pip package. */ - public boolean isPackageActiveInPip(String packageName) { - final TaskInfo inPipTask = mPipOrganizer.getTaskInfo(); - return packageName != null && inPipTask != null && mPipOrganizer.isInPip() - && packageName.equals(SplitScreenUtils.getPackageName(inPipTask.baseIntent)); + public boolean isPackageActiveInPip(@Nullable String packageName) { + return packageName != null + && mPipBoundsState.getLastPipComponentName() != null + && packageName.equals(mPipBoundsState.getLastPipComponentName().getPackageName()); } /** Add PiP-related changes to `outWCT` for the given request. */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java index 02f595537d03..d415c10b0cf8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java @@ -420,7 +420,8 @@ public class PipTransition extends PipTransitionController implements } // Update the src-rect-hint in params in place, to set up initial animator transform. - params.getSourceRectHint().set(adjustedSourceRectHint); + params.copyOnlySet(new PictureInPictureParams.Builder() + .setSourceRectHint(adjustedSourceRectHint).build()); // Config-at-end transitions need to have their activities transformed before starting // the animation; this makes the buffer seem like it's been updated to final size. diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt new file mode 100644 index 000000000000..7e0b81a783c0 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/MaximizeAppWindowWithDragToTopDragZoneTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.functional + +import android.platform.test.annotations.Postsubmit +import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone +import org.junit.runner.RunWith +import org.junit.runners.BlockJUnit4ClassRunner + +/* Functional test for [MaximizeAppWindowWithDragToTopDragZone]. */ +@RunWith(BlockJUnit4ClassRunner::class) +@Postsubmit +class MaximizeAppWindowWithDragToTopDragZoneTest : MaximizeAppWindowWithDragToTopDragZone() diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt new file mode 100644 index 000000000000..a2b88f278ff2 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.scenarios + +import android.app.Instrumentation +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import android.tools.traces.parsers.WindowManagerStateHelper +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import com.android.internal.R +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.server.wm.flicker.helpers.DesktopModeAppHelper +import com.android.server.wm.flicker.helpers.SimpleAppHelper +import com.android.window.flags.Flags +import com.android.wm.shell.Utils +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +/** + * Base scenario test for maximizing a desktop app window by dragging it to the top drag zone. + */ +@Ignore("Test Base Class") +abstract class MaximizeAppWindowWithDragToTopDragZone +constructor(private val rotation: Rotation = Rotation.ROTATION_0) { + private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation() + private val tapl = LauncherInstrumentation() + private val wmHelper = WindowManagerStateHelper(instrumentation) + private val device = UiDevice.getInstance(instrumentation) + private val testApp = DesktopModeAppHelper(SimpleAppHelper(instrumentation)) + + @Rule @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) + + @Before + fun setup() { + Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) + // Skip the test when the drag-to-maximize is disabled on this device. + Assume.assumeTrue(Flags.enableDragToMaximize() && + instrumentation.context.resources.getBoolean(R.bool.config_dragToMaximizeInDesktopMode)) + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + ChangeDisplayOrientationRule.setRotation(rotation) + testApp.enterDesktopWithDrag(wmHelper, device) + } + + @Test + open fun maximizeAppWithDragToTopDragZone() { + testApp.maximizeAppWithDragToTopDragZone(wmHelper, device) + } + + @After + fun teardown() { + testApp.exit(wmHelper) + } +} diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 2ae89d3300c1..82e950365850 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -16,6 +16,7 @@ package android.media; +import static android.media.codec.Flags.FLAG_CODEC_AVAILABILITY; import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE; import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST; import static android.media.codec.Flags.FLAG_SUBSESSION_METRICS; @@ -29,6 +30,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ImageFormat; import android.graphics.Rect; @@ -1843,6 +1845,12 @@ final public class MediaCodec { */ private static final int CB_METRICS_FLUSHED = 8; + /** + * Callback ID to notify the change in resource requirement + * for the codec component. + */ + private static final int CB_REQUIRED_RESOURCES_CHANGE = 9; + private class EventHandler extends Handler { private MediaCodec mCodec; @@ -2017,13 +2025,19 @@ final public class MediaCodec { case CB_METRICS_FLUSHED: { - if (GetFlag(() -> android.media.codec.Flags.subsessionMetrics())) { mCallback.onMetricsFlushed(mCodec, (PersistableBundle)msg.obj); } break; } + case CB_REQUIRED_RESOURCES_CHANGE: { + if (android.media.codec.Flags.codecAvailability()) { + mCallback.onRequiredResourcesChanged(mCodec); + } + break; + } + default: { break; @@ -2302,6 +2316,70 @@ final public class MediaCodec { } /** + * @hide + * Abstraction for the Global Codec resources. + * This encapsulates all the available codec resources on the device. + * + * To be able to enforce and test the implementation of codec availability hal APIs, + * globally available codec resources are exposed only as TestApi. + * This will be tracked and verified through cts. + */ + @FlaggedApi(FLAG_CODEC_AVAILABILITY) + @TestApi + public static final class GlobalResourceInfo { + /** + * Identifier for the Resource type. + */ + String mName; + /** + * Total count/capacity of resources of this type. + */ + long mCapacity; + /** + * Available count of this resource type. + */ + long mAvailable; + + @NonNull + public String getName() { + return mName; + } + + public long getCapacity() { + return mCapacity; + } + + public long getAvailable() { + return mAvailable; + } + }; + + /** + * @hide + * Get a list of globally available codec resources. + * + * To be able to enforce and test the implementation of codec availability hal APIs, + * it is exposed only as TestApi. + * This will be tracked and verified through cts. + * + * This returns a {@link java.util.List} list of codec resources. + * For every {@link GlobalResourceInfo} in the list, it encapsulates the + * information about each resources available globaly on device. + * + * @return A list of available device codec resources; an empty list if no + * device codec resources are available. + * @throws UnsupportedOperationException if not implemented. + */ + @FlaggedApi(FLAG_CODEC_AVAILABILITY) + @TestApi + public static @NonNull List<GlobalResourceInfo> getGloballyAvailableResources() { + return native_getGloballyAvailableResources(); + } + + @NonNull + private static native List<GlobalResourceInfo> native_getGloballyAvailableResources(); + + /** * Configures a component. * * @param format The format of the input data (decoder) or the desired @@ -2443,6 +2521,73 @@ final public class MediaCodec { } /** + * @hide + * Abstraction for the resources associated with a codec instance. + * This encapsulates the required codec resources for a configured codec instance. + * + * To be able to enforce and test the implementation of codec availability hal APIs, + * required codec resources are exposed only as TestApi. + * This will be tracked and verified through cts. + */ + @FlaggedApi(FLAG_CODEC_AVAILABILITY) + @TestApi + public static final class InstanceResourceInfo { + /** + * Identifier for the Resource type. + */ + String mName; + /** + * Required resource count of this type. + */ + long mStaticCount; + /** + * Per frame resource requirement of this resource type. + */ + long mPerFrameCount; + + @NonNull + public String getName() { + return mName; + } + + public long getStaticCount() { + return mStaticCount; + } + + public long getPerFrameCount() { + return mPerFrameCount; + } + }; + + /** + * @hide + * Get a list of required codec resources for this configuration. + * + * To be able to enforce and test the implementation of codec availability hal APIs, + * it is exposed only as TestApi. + * This will be tracked and verified through cts. + * + * This returns a {@link java.util.List} list of codec resources. + * For every {@link GlobalResourceInfo} in the list, it encapsulates the + * information about each resources required for the current configuration. + * + * NOTE: This may only be called after {@link #configure}. + * + * @return A list of required device codec resources; an empty list if no + * device codec resources are required. + * @throws IllegalStateException if the codec wasn't configured yet. + * @throws UnsupportedOperationException if not implemented. + */ + @FlaggedApi(FLAG_CODEC_AVAILABILITY) + @TestApi + public @NonNull List<InstanceResourceInfo> getRequiredResources() { + return native_getRequiredResources(); + } + + @NonNull + private native List<InstanceResourceInfo> native_getRequiredResources(); + + /** * Dynamically sets the output surface of a codec. * <p> * This can only be used if the codec was configured with an output surface. The @@ -5740,6 +5885,25 @@ final public class MediaCodec { @NonNull MediaCodec codec, @NonNull PersistableBundle metrics) { // default implementation ignores this callback. } + + /** + * @hide + * Called when there is a change in the required resources for the codec. + * <p> + * Upon receiving this notification, the updated resource requirement + * can be queried through {@link #getRequiredResources}. + * + * @param codec The MediaCodec object. + */ + @FlaggedApi(FLAG_CODEC_AVAILABILITY) + @TestApi + public void onRequiredResourcesChanged(@NonNull MediaCodec codec) { + /* + * A default implementation for backward compatibility. + * Since this is a TestApi, we are not enforcing the callback to be + * overridden. + */ + } } private void postEventFromNative( diff --git a/media/java/android/media/quality/AmbientBacklightEvent.java b/media/java/android/media/quality/AmbientBacklightEvent.java index 3bc6b86c0615..5c11def43209 100644 --- a/media/java/android/media/quality/AmbientBacklightEvent.java +++ b/media/java/android/media/quality/AmbientBacklightEvent.java @@ -16,9 +16,11 @@ package android.media.quality; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.media.tv.flags.Flags; import android.os.Parcel; import android.os.Parcelable; @@ -27,8 +29,10 @@ import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** + * Ambient backlight event * @hide */ +@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) public final class AmbientBacklightEvent implements Parcelable { /** @hide */ @@ -64,6 +68,9 @@ public final class AmbientBacklightEvent implements Parcelable { @Nullable private final AmbientBacklightMetadata mMetadata; + /** + * Constructor of AmbientBacklightEvent. + */ public AmbientBacklightEvent(int eventType, @Nullable AmbientBacklightMetadata metadata) { mEventType = eventType; @@ -75,10 +82,19 @@ public final class AmbientBacklightEvent implements Parcelable { mMetadata = in.readParcelable(AmbientBacklightMetadata.class.getClassLoader()); } + /** + * Gets event type. + */ public int getEventType() { return mEventType; } + /** + * Gets ambient backlight metadata. + * + * @return the metadata of the event. It's non-null only for + * {@link #AMBIENT_BACKLIGHT_EVENT_METADATA}. + */ @Nullable public AmbientBacklightMetadata getMetadata() { return mMetadata; @@ -95,7 +111,8 @@ public final class AmbientBacklightEvent implements Parcelable { return 0; } - public static final @NonNull Parcelable.Creator<AmbientBacklightEvent> CREATOR = + @NonNull + public static final Parcelable.Creator<AmbientBacklightEvent> CREATOR = new Parcelable.Creator<AmbientBacklightEvent>() { public AmbientBacklightEvent createFromParcel(Parcel in) { return new AmbientBacklightEvent(in); diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.java b/media/java/android/media/quality/AmbientBacklightMetadata.java index fc779348de11..9c11f9a3e560 100644 --- a/media/java/android/media/quality/AmbientBacklightMetadata.java +++ b/media/java/android/media/quality/AmbientBacklightMetadata.java @@ -16,6 +16,10 @@ package android.media.quality; +import android.annotation.FlaggedApi; +import android.annotation.IntRange; +import android.graphics.PixelFormat; +import android.media.tv.flags.Flags; import android.os.Parcel; import android.os.Parcelable; @@ -24,9 +28,11 @@ import androidx.annotation.NonNull; import java.util.Arrays; /** + * Metadata of ambient backlight. * @hide */ -public class AmbientBacklightMetadata implements Parcelable { +@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) +public final class AmbientBacklightMetadata implements Parcelable { @NonNull private final String mPackageName; private final int mCompressAlgorithm; @@ -37,6 +43,9 @@ public class AmbientBacklightMetadata implements Parcelable { @NonNull private final int[] mZonesColors; + /** + * Constructor of AmbientBacklightMetadata. + */ public AmbientBacklightMetadata(@NonNull String packageName, int compressAlgorithm, int source, int colorFormat, int horizontalZonesNumber, int verticalZonesNumber, @NonNull int[] zonesColors) { @@ -59,31 +68,58 @@ public class AmbientBacklightMetadata implements Parcelable { mZonesColors = in.createIntArray(); } + /** + * Gets package name. + * @hide + */ @NonNull public String getPackageName() { return mPackageName; } + /** + * Gets compress algorithm. + */ + @AmbientBacklightSettings.CompressAlgorithm public int getCompressAlgorithm() { return mCompressAlgorithm; } + /** + * Gets source of ambient backlight detection. + */ + @AmbientBacklightSettings.Source public int getSource() { return mSource; } + /** + * Gets color format. + */ + @PixelFormat.Format public int getColorFormat() { return mColorFormat; } + /** + * Gets the number of lights in each horizontal zone. + */ + @IntRange(from = 0) public int getHorizontalZonesNumber() { return mHorizontalZonesNumber; } + /** + * Gets the number of lights in each vertical zone. + */ + @IntRange(from = 0) public int getVerticalZonesNumber() { return mVerticalZonesNumber; } + /** + * @hide + */ @NonNull public int[] getZonesColors() { return mZonesColors; diff --git a/media/java/android/media/quality/AmbientBacklightSettings.java b/media/java/android/media/quality/AmbientBacklightSettings.java index bb782bf1aee4..4ed7bc79fdca 100644 --- a/media/java/android/media/quality/AmbientBacklightSettings.java +++ b/media/java/android/media/quality/AmbientBacklightSettings.java @@ -16,7 +16,11 @@ package android.media.quality; +import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.IntRange; +import android.graphics.PixelFormat; +import android.media.tv.flags.Flags; import android.os.Parcel; import android.os.Parcelable; @@ -29,7 +33,8 @@ import java.lang.annotation.RetentionPolicy; * Settings for ambient backlight. * @hide */ -public class AmbientBacklightSettings implements Parcelable { +@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) +public final class AmbientBacklightSettings implements Parcelable { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({SOURCE_NONE, SOURCE_AUDIO, SOURCE_VIDEO, SOURCE_AUDIO_VIDEO}) @@ -62,6 +67,7 @@ public class AmbientBacklightSettings implements Parcelable { /** * The color format is RGB888. + * @hide */ public static final int COLOR_FORMAT_RGB888 = 1; @@ -76,7 +82,7 @@ public class AmbientBacklightSettings implements Parcelable { public static final int ALGORITHM_NONE = 0; /** - * The compress algorithm is RLE. + * The compress algorithm is run length encoding (RLE). */ public static final int ALGORITHM_RLE = 1; @@ -115,6 +121,9 @@ public class AmbientBacklightSettings implements Parcelable { */ private final int mThreshold; + /** + * Constructs AmbientBacklightSettings. + */ public AmbientBacklightSettings(int source, int maxFps, int colorFormat, int horizontalZonesNumber, int verticalZonesNumber, boolean isLetterboxOmitted, int threshold) { @@ -137,32 +146,57 @@ public class AmbientBacklightSettings implements Parcelable { mThreshold = in.readInt(); } + /** + * Gets source of ambient backlight detection. + */ @Source public int getSource() { return mSource; } + /** + * Gets max frames per second. + */ + @IntRange(from = 1) public int getMaxFps() { return mMaxFps; } - @ColorFormat + /** + * Gets color format. + */ + @PixelFormat.Format public int getColorFormat() { return mColorFormat; } + /** + * Gets the number of lights in each horizontal zone. + */ + @IntRange(from = 0) public int getHorizontalZonesNumber() { return mHorizontalZonesNumber; } + /** + * Gets the number of lights in each vertical zone. + */ + @IntRange(from = 0) public int getVerticalZonesNumber() { return mVerticalZonesNumber; } + /** + * Returns {@code true} if letter box is omitted; {@code false} otherwise. + * @hide + */ public boolean isLetterboxOmitted() { return mIsLetterboxOmitted; } + /** + * @hide + */ public int getThreshold() { return mThreshold; } diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java index 26d83aca3e7b..4d4526cf9925 100644 --- a/media/java/android/media/quality/MediaQualityManager.java +++ b/media/java/android/media/quality/MediaQualityManager.java @@ -567,7 +567,6 @@ public final class MediaQualityManager { /** * Registers a {@link AmbientBacklightCallback}. - * @hide */ public void registerAmbientBacklightCallback( @NonNull @CallbackExecutor Executor executor, @@ -581,7 +580,6 @@ public final class MediaQualityManager { /** * Unregisters the existing {@link AmbientBacklightCallback}. - * @hide */ public void unregisterAmbientBacklightCallback( @NonNull final AmbientBacklightCallback callback) { @@ -602,7 +600,6 @@ public final class MediaQualityManager { * Set the ambient backlight settings. * * @param settings The settings to use for the backlight detector. - * @hide */ public void setAmbientBacklightSettings( @NonNull AmbientBacklightSettings settings) { @@ -618,7 +615,6 @@ public final class MediaQualityManager { * Enables or disables the ambient backlight detection. * * @param enabled {@code true} to enable, {@code false} to disable. - * @hide */ public void setAmbientBacklightEnabled(boolean enabled) { try { @@ -843,14 +839,12 @@ public final class MediaQualityManager { /** * Callback used to monitor status of ambient backlight. - * @hide */ public abstract static class AmbientBacklightCallback { /** * Called when new ambient backlight event is emitted. - * @hide */ - public void onAmbientBacklightEvent(AmbientBacklightEvent event) { + public void onAmbientBacklightEvent(@NonNull AmbientBacklightEvent event) { } } } diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig index 4de68634af5e..64416525441b 100644 --- a/media/java/android/media/tv/flags/media_tv.aconfig +++ b/media/java/android/media/tv/flags/media_tv.aconfig @@ -80,3 +80,11 @@ flag { description : "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA." bug: "372973197" } + +flag { + name: "apply_picture_profiles" + is_exported: true + namespace: "media_tv" + description : "Feature flag to enable APIs for applying picture profiles" + bug: "337330263" +} diff --git a/media/jni/Android.bp b/media/jni/Android.bp index c44e26f17b5e..f09dc7218d7d 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -104,6 +104,7 @@ cc_library_shared { "libgrallocusage", "libmedia_midiiowrapper", "android.companion.virtualdevice.flags-aconfig-cc", + "android.media.codec-aconfig-cc", "android.media.playback.flags-aconfig-cc", ], diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 001653b08f0c..fc184fe5c872 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -39,6 +39,8 @@ #include <C2Buffer.h> #include <C2PlatformSupport.h> +#include <android_media_codec.h> + #include <android/hardware/cas/native/1.0/IDescrambler.h> #include <android_runtime/android_hardware_HardwareBuffer.h> @@ -189,6 +191,22 @@ static struct { jmethodID setId; } gBufferInfo; +static struct { + jclass clazz; + jmethodID ctorId; + jfieldID resourceId; + jfieldID capacityId; + jfieldID availableId; +} gGlobalResourceInfo; + +static struct { + jclass clazz; + jmethodID ctorId; + jfieldID resourceId; + jfieldID staticCountId; + jfieldID perFrameCountId; +} gInstanceResourceInfo; + struct fields_t { jmethodID postEventFromNativeID; jmethodID lockAndGetContextID; @@ -1129,6 +1147,37 @@ status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject names return mCodec->unsubscribeFromVendorParameters(names); } +static jobject getJavaResources( + JNIEnv *env, + const std::vector<MediaCodec::InstanceResourceInfo>& resources) { + jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId); + for (const MediaCodec::InstanceResourceInfo& res : resources) { + ScopedLocalRef<jobject> object{env, env->NewObject( + gInstanceResourceInfo.clazz, gInstanceResourceInfo.ctorId)}; + ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())}; + env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get()); + env->SetLongField(object.get(), + gInstanceResourceInfo.staticCountId, + (jlong)res.mStaticCount); + env->SetLongField(object.get(), + gInstanceResourceInfo.perFrameCountId, + (jlong)res.mPerFrameCount); + (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get()); + } + + return resourcesObj; +} + +status_t JMediaCodec::getRequiredResources(JNIEnv *env, jobject *resourcesObj) { + std::vector<MediaCodec::InstanceResourceInfo> resources; + status_t status = mCodec->getRequiredResources(resources); + if (status != OK) { + return status; + } + *resourcesObj = getJavaResources(env, resources); + return OK; +} + static jthrowable createCodecException( JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) { ScopedLocalRef<jclass> clazz( @@ -1475,6 +1524,10 @@ void JMediaCodec::handleCallback(const sp<AMessage> &msg) { obj = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL); break; } + case MediaCodec::CB_REQUIRED_RESOURCES_CHANGED: + { + break; + } default: TRESPASS(); @@ -3560,6 +3613,64 @@ static void android_media_MediaCodec_unsubscribeFromVendorParameters( return; } +static jobject getJavaResources( + JNIEnv *env, + const std::vector<MediaCodec::GlobalResourceInfo>& resources) { + jobject resourcesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId); + for (const MediaCodec::GlobalResourceInfo& res : resources) { + ScopedLocalRef<jobject> object{env, env->NewObject( + gGlobalResourceInfo.clazz, gGlobalResourceInfo.ctorId)}; + ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(res.mName.c_str())}; + env->SetObjectField(object.get(), gInstanceResourceInfo.resourceId, nameStr.get()); + env->SetLongField(object.get(), gGlobalResourceInfo.capacityId, (jlong)res.mCapacity); + env->SetLongField(object.get(), gGlobalResourceInfo.availableId, (jlong)res.mAvailable); + (void)env->CallBooleanMethod(resourcesObj, gArrayListInfo.addId, object.get()); + } + + return resourcesObj; +} + +static jobject android_media_MediaCodec_getGloballyAvailableResources( + JNIEnv *env, jobject thiz) { + (void)thiz; + std::vector<MediaCodec::GlobalResourceInfo> resources; + status_t status = MediaCodec::getGloballyAvailableResources(resources); + if (status != OK) { + if (status == ERROR_UNSUPPORTED) { + jniThrowException(env, "java/lang/UnsupportedOperationException", + "Function Not Implemented"); + } else { + throwExceptionAsNecessary(env, status, nullptr); + } + return nullptr; + } + + return getJavaResources(env, resources); +} + +static jobject android_media_MediaCodec_getRequiredResources( + JNIEnv *env, jobject thiz) { + sp<JMediaCodec> codec = getMediaCodec(env, thiz); + if (codec == nullptr || codec->initCheck() != OK) { + throwExceptionAsNecessary(env, INVALID_OPERATION, codec); + return nullptr; + } + + jobject ret = nullptr; + status_t status = codec->getRequiredResources(env, &ret); + if (status != OK) { + if (status == ERROR_UNSUPPORTED) { + jniThrowException(env, "java/lang/UnsupportedOperationException", + "Function Not Implemented"); + } else { + throwExceptionAsNecessary(env, status, nullptr); + } + return nullptr; + } + + return ret; +} + static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { ScopedLocalRef<jclass> clazz( env, env->FindClass("android/media/MediaCodec")); @@ -3905,6 +4016,36 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I"); gFields.bufferInfoPresentationTimeUs = env->GetFieldID(clazz.get(), "presentationTimeUs", "J"); + + // Since these TestApis are defined under the flag, make sure they are + // accessed only when the flag is set. + if (android::media::codec::codec_availability()) { + clazz.reset(env->FindClass("android/media/MediaCodec$GlobalResourceInfo")); + CHECK(clazz.get() != NULL); + gGlobalResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); + gGlobalResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V"); + CHECK(gGlobalResourceInfo.ctorId != NULL); + gGlobalResourceInfo.resourceId = + env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;"); + CHECK(gGlobalResourceInfo.resourceId != NULL); + gGlobalResourceInfo.capacityId = env->GetFieldID(clazz.get(), "mCapacity", "J"); + CHECK(gGlobalResourceInfo.capacityId != NULL); + gGlobalResourceInfo.availableId = env->GetFieldID(clazz.get(), "mAvailable", "J"); + CHECK(gGlobalResourceInfo.availableId != NULL); + + clazz.reset(env->FindClass("android/media/MediaCodec$InstanceResourceInfo")); + CHECK(clazz.get() != NULL); + gInstanceResourceInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); + gInstanceResourceInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V"); + CHECK(gInstanceResourceInfo.ctorId != NULL); + gInstanceResourceInfo.resourceId = + env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;"); + CHECK(gInstanceResourceInfo.resourceId != NULL); + gInstanceResourceInfo.staticCountId= env->GetFieldID(clazz.get(), "mStaticCount", "J"); + CHECK(gInstanceResourceInfo.staticCountId != NULL); + gInstanceResourceInfo.perFrameCountId = env->GetFieldID(clazz.get(), "mPerFrameCount", "J"); + CHECK(gInstanceResourceInfo.perFrameCountId != NULL); + } } static void android_media_MediaCodec_native_setup( @@ -4261,6 +4402,12 @@ static const JNINativeMethod gMethods[] = { { "native_finalize", "()V", (void *)android_media_MediaCodec_native_finalize }, + + { "native_getGloballyAvailableResources", "()Ljava/util/List;", + (void *)android_media_MediaCodec_getGloballyAvailableResources}, + + { "native_getRequiredResources", "()Ljava/util/List;", + (void *)android_media_MediaCodec_getRequiredResources}, }; static const JNINativeMethod gLinearBlockMethods[] = { diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index c9b6b7f6f337..930dbbeb7f30 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -185,6 +185,8 @@ struct JMediaCodec : public AHandler { status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names); + status_t getRequiredResources(JNIEnv *env, jobject *resourcesObj); + bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; } const sp<ICrypto> &getCrypto() { return mCrypto; } diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index a23845fa17e9..c25f77b12116 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -107,6 +107,7 @@ package android.nfc { method public void onRfDiscoveryStarted(boolean); method public void onRfFieldActivated(boolean); method public void onRoutingChanged(); + method public void onRoutingTableFull(); method public void onStateUpdated(int); method public void onTagConnected(boolean); method public void onTagDispatch(@NonNull java.util.function.Consumer<java.lang.Boolean>); diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl index b102e873d737..fb793b024288 100644 --- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl +++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl @@ -52,5 +52,6 @@ interface INfcOemExtensionCallback { void onNdefMessage(in Tag tag, in NdefMessage message, in ResultReceiver hasOemExecutableContent); void onLaunchHceAppChooserActivity(in String selectedAid, in List<ApduServiceInfo> services, in ComponentName failedComponent, in String category); void onLaunchHceTapAgainActivity(in ApduServiceInfo service, in String category); + void onRoutingTableFull(); void onLogEventNotified(in OemLogItems item); } diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index abd99bc02f55..57ee981caf9c 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -394,6 +394,13 @@ public final class NfcOemExtension { void onLaunchHceTapAgainDialog(@NonNull ApduServiceInfo service, @NonNull String category); /** + * Callback to indicate that routing table is full and the OEM can optionally launch a + * dialog to request the user to remove some Card Emulation apps from the device to free + * routing table space. + */ + void onRoutingTableFull(); + + /** * Callback when OEM specified log event are notified. * @param item the log items that contains log information of NFC event. */ @@ -853,6 +860,12 @@ public final class NfcOemExtension { handleVoidCallback(enabled, cb::onReaderOptionChanged, ex)); } + public void onRoutingTableFull() throws RemoteException { + mCallbackMap.forEach((cb, ex) -> + handleVoidCallback(null, + (Object input) -> cb.onRoutingTableFull(), ex)); + } + @Override public void onGetOemAppSearchIntent(List<String> packages, ResultReceiver intentConsumer) throws RemoteException { diff --git a/nfc/java/android/nfc/OemLogItems.java b/nfc/java/android/nfc/OemLogItems.java index 6671941c1cc9..4f3e1999f5d3 100644 --- a/nfc/java/android/nfc/OemLogItems.java +++ b/nfc/java/android/nfc/OemLogItems.java @@ -142,8 +142,11 @@ public final class OemLogItems implements Parcelable { dest.writeByteArray(mCommandApdus);
dest.writeInt(mResponseApdus.length);
dest.writeByteArray(mResponseApdus);
- dest.writeLong(mRfFieldOnTime.getEpochSecond());
- dest.writeInt(mRfFieldOnTime.getNano());
+ dest.writeBoolean(mRfFieldOnTime != null);
+ if (mRfFieldOnTime != null) {
+ dest.writeLong(mRfFieldOnTime.getEpochSecond());
+ dest.writeInt(mRfFieldOnTime.getNano());
+ }
dest.writeParcelable(mTag, 0);
}
@@ -305,7 +308,12 @@ public final class OemLogItems implements Parcelable { in.readByteArray(this.mCommandApdus);
this.mResponseApdus = new byte[in.readInt()];
in.readByteArray(this.mResponseApdus);
- this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());
+ boolean isRfFieldOnTimeSet = in.readBoolean();
+ if (isRfFieldOnTimeSet) {
+ this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());
+ } else {
+ this.mRfFieldOnTime = null;
+ }
this.mTag = in.readParcelable(Tag.class.getClassLoader(), Tag.class);
}
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index bffda8bcae65..09489311ecaf 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -497,6 +497,9 @@ android_library { resource_dirs: [], static_libs: [ "//frameworks/libs/systemui:compilelib", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail:impl", "SystemUI-res", "WifiTrackerLib", "WindowManager-Shell", @@ -770,6 +773,9 @@ android_library { ], static_libs: [ "//frameworks/libs/systemui:compilelib", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail:impl", "SystemUI-tests-base", "androidx.test.uiautomator_uiautomator", "androidx.core_core-animation-testing", diff --git a/packages/SystemUI/common/Android.bp b/packages/SystemUI/common/Android.bp index 91dc3e338c59..9f1598364dbc 100644 --- a/packages/SystemUI/common/Android.bp +++ b/packages/SystemUI/common/Android.bp @@ -30,5 +30,9 @@ java_library { "src/**/*.kt", ], + static_libs: ["SystemUI-shared-utils"], + + libs: ["//frameworks/libs/systemui:tracinglib-platform"], + kotlincflags: ["-Xjvm-default=all"], } diff --git a/packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt b/packages/SystemUI/common/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt index 0c181e99b21c..0c181e99b21c 100644 --- a/packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt +++ b/packages/SystemUI/common/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt diff --git a/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt b/packages/SystemUI/common/src/com/android/systemui/coroutines/Tracing.kt index efbdf4d1533d..efbdf4d1533d 100644 --- a/packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt +++ b/packages/SystemUI/common/src/com/android/systemui/coroutines/Tracing.kt diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java index 93dede5a3dae..f1f6c61a16e4 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSFooterViewControllerTest.java @@ -38,7 +38,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.res.R; import com.android.systemui.retail.data.repository.FakeRetailModeRepository; -import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl; +import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl; import com.android.systemui.settings.UserTracker; import com.android.systemui.utils.leaks.LeakCheckedTest; diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt index ba7a65dd8e65..47bfda41c7ad 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/data/repository/RetailModeSettingsRepositoryTest.kt @@ -21,6 +21,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.retail.data.repository.impl.RetailModeSettingsRepository import com.android.systemui.util.settings.FakeGlobalSettings import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt index b53652067755..b47dcb567135 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/retail/domain/interactor/RetailModeInteractorImplTest.kt @@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.retail.data.repository.FakeRetailModeRepository +import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith diff --git a/packages/SystemUI/pods/Android.bp b/packages/SystemUI/pods/Android.bp new file mode 100644 index 000000000000..e45f3170d9ad --- /dev/null +++ b/packages/SystemUI/pods/Android.bp @@ -0,0 +1,22 @@ +// +// Copyright (C) 2024 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 { + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], + // The package default_visibility specified here is inherited to subpackages that do not + // specify default_visibility: + default_visibility: ["//visibility:private"], +} diff --git a/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp b/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp new file mode 100644 index 000000000000..df90be8ecb97 --- /dev/null +++ b/packages/SystemUI/pods/com/android/systemui/dagger/Android.bp @@ -0,0 +1,34 @@ +// +// Copyright (C) 2024 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. +// + +soong_namespace { +} + +package { + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +java_library { + name: "api", + srcs: [ + "**/*.java", + "**/*.kt", + ], + libs: [ + "jsr330", + ], + visibility: ["//frameworks/base/packages/SystemUI:__subpackages__"], +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java b/packages/SystemUI/pods/com/android/systemui/dagger/SysUISingleton.java index a4b33427cbda..a4b33427cbda 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java +++ b/packages/SystemUI/pods/com/android/systemui/dagger/SysUISingleton.java diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Application.java index 21e53a5b51d0..21e53a5b51d0 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java +++ b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Application.java diff --git a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Background.java index 141c9019b3e4..141c9019b3e4 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java +++ b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Background.java diff --git a/packages/SystemUI/pods/com/android/systemui/retail/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/Android.bp new file mode 100644 index 000000000000..f04784885c10 --- /dev/null +++ b/packages/SystemUI/pods/com/android/systemui/retail/Android.bp @@ -0,0 +1,38 @@ +// +// Copyright (C) 2024 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. +// + +soong_namespace { +} + +package { + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +java_library { + name: "impl", + srcs: ["*.kt"], + libs: [ + "jsr330", + "dagger2", + "SystemUICommon", + "kotlinx_coroutines", + ], + static_libs: [ + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/data:impl", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain:impl", + ], + visibility: ["//frameworks/base/packages/SystemUI"], +} diff --git a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt b/packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt index e8639498b7c0..c20e368f1690 100644 --- a/packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt +++ b/packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt @@ -14,12 +14,12 @@ * limitations under the License. */ -package com.android.systemui.retail.dagger +package com.android.systemui.retail import com.android.systemui.retail.data.repository.RetailModeRepository -import com.android.systemui.retail.data.repository.RetailModeSettingsRepository +import com.android.systemui.retail.data.repository.impl.RetailModeSettingsRepository import com.android.systemui.retail.domain.interactor.RetailModeInteractor -import com.android.systemui.retail.domain.interactor.RetailModeInteractorImpl +import com.android.systemui.retail.domain.interactor.impl.RetailModeInteractorImpl import dagger.Binds import dagger.Module diff --git a/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp new file mode 100644 index 000000000000..f148a7c69ecc --- /dev/null +++ b/packages/SystemUI/pods/com/android/systemui/retail/data/Android.bp @@ -0,0 +1,55 @@ +// +// Copyright (C) 2024 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. +// + +soong_namespace { +} + +package { + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +java_library { + name: "api", + srcs: ["repository/*.kt"], + libs: [ + "kotlinx_coroutines", + ], + visibility: [ + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/dagger", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain", + ], +} + +java_library { + name: "impl", + srcs: ["repository/impl/*.kt"], + libs: [ + "jsr330", + "kotlinx_coroutines", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/util/settings:api", + "SystemUICommon", + ], + static_libs: [ + "api", + ], + visibility: [ + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/dagger", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/domain", + ], +} diff --git a/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt new file mode 100644 index 000000000000..c9eac2588811 --- /dev/null +++ b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/RetailModeRepository.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.data.repository + +import kotlinx.coroutines.flow.StateFlow + +/** Repository to track if the device is in Retail mode */ +interface RetailModeRepository { + /** Flow of whether the device is currently in retail mode. */ + val retailMode: StateFlow<Boolean> + + /** Last value of whether the device is in retail mode. */ + val inRetailMode: Boolean + get() = retailMode.value +} diff --git a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt index 09fd7df15dc2..8955263595f3 100644 --- a/packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt +++ b/packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.retail.data.repository +package com.android.systemui.retail.data.repository.impl import android.database.ContentObserver import android.provider.Settings @@ -22,6 +22,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.retail.data.repository.RetailModeRepository import com.android.systemui.util.settings.GlobalSettings import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher @@ -34,16 +35,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn -/** Repository to track if the device is in Retail mode */ -interface RetailModeRepository { - /** Flow of whether the device is currently in retail mode. */ - val retailMode: StateFlow<Boolean> - - /** Last value of whether the device is in retail mode. */ - val inRetailMode: Boolean - get() = retailMode.value -} - /** * Tracks [Settings.Global.DEVICE_DEMO_MODE]. * diff --git a/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp b/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp new file mode 100644 index 000000000000..787861ce5eb8 --- /dev/null +++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/Android.bp @@ -0,0 +1,46 @@ +// +// Copyright (C) 2024 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. +// + +soong_namespace { +} + +package { + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +java_library { + name: "api", + srcs: ["interactor/*.kt"], + visibility: [ + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail", + ], +} + +java_library { + name: "impl", + srcs: ["interactor/impl/*.kt"], + libs: [ + "jsr330", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail/data:api", + ], + static_libs: [ + "api", + ], + visibility: [ + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/retail", + ], +} diff --git a/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt new file mode 100644 index 000000000000..748e34d430d8 --- /dev/null +++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.retail.domain.interactor + +/** Interactor to determine if the device is currently in retail mode */ +interface RetailModeInteractor { + /** Whether the device is currently in retail mode */ + val isInRetailMode: Boolean +} diff --git a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt index eea452c78ea5..8dbe562c2ed7 100644 --- a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt +++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt @@ -14,18 +14,13 @@ * limitations under the License. */ -package com.android.systemui.retail.domain.interactor +package com.android.systemui.retail.domain.interactor.impl import com.android.systemui.dagger.SysUISingleton import com.android.systemui.retail.data.repository.RetailModeRepository +import com.android.systemui.retail.domain.interactor.RetailModeInteractor import javax.inject.Inject -/** Interactor to determine if the device is currently in retail mode */ -interface RetailModeInteractor { - /** Whether the device is currently in retail mode */ - val isInRetailMode: Boolean -} - @SysUISingleton class RetailModeInteractorImpl @Inject diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp b/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp new file mode 100644 index 000000000000..1aa772961408 --- /dev/null +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/Android.bp @@ -0,0 +1,40 @@ +// +// Copyright (C) 2024 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. +// + +soong_namespace { +} + +package { + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +java_library { + name: "api", + srcs: [ + "*.java", + "*.kt", + ], + libs: [ + "//frameworks/libs/systemui:tracinglib-platform", + "//frameworks/base/packages/SystemUI/pods/com/android/systemui/dagger:api", + "SystemUICommon", + "androidx.annotation_annotation", + "kotlinx_coroutines_android", + "jsr330", + ], + kotlincflags: ["-Xjvm-default=all"], + visibility: ["//frameworks/base/packages/SystemUI:__subpackages__"], +} diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettings.java index 84ab66b66a7c..84ab66b66a7c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettings.java diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java index 7fcabe4a4363..d68501f69bc0 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java @@ -23,7 +23,7 @@ import android.content.ContentResolver; import android.net.Uri; import android.provider.Settings; -import com.android.systemui.util.kotlin.SettingsSingleThreadBackground; +import com.android.systemui.util.settings.SettingsSingleThreadBackground; import kotlinx.coroutines.CoroutineDispatcher; diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettings.java index 6031a4e05629..6031a4e05629 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettings.java diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java index c29648186d54..211a6f48e475 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java @@ -21,7 +21,7 @@ import android.content.ContentResolver; import android.net.Uri; import android.provider.Settings; -import com.android.systemui.util.kotlin.SettingsSingleThreadBackground; +import com.android.systemui.util.settings.SettingsSingleThreadBackground; import kotlinx.coroutines.CoroutineDispatcher; diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt index 5d0b0d55e1f6..5d0b0d55e1f6 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxyExt.kt index 364681444c1b..364681444c1b 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxyExt.kt diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java index e13981dfe5c7..5632a36a2942 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.util.kotlin; +package com.android.systemui.util.settings; import static java.lang.annotation.RetentionPolicy.RUNTIME; diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettings.java index c67c60375b2c..c67c60375b2c 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettings.java diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java index e670b2c2edd0..1b3f74e0c983 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java @@ -21,7 +21,7 @@ import android.content.ContentResolver; import android.net.Uri; import android.provider.Settings; -import com.android.systemui.util.kotlin.SettingsSingleThreadBackground; +import com.android.systemui.util.settings.SettingsSingleThreadBackground; import kotlinx.coroutines.CoroutineDispatcher; diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt index 4b03df6b0070..4b03df6b0070 100644 --- a/packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java index 4447dff7af00..b7d3c9253f51 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java @@ -100,7 +100,7 @@ import com.android.systemui.qs.QSFragmentStartableModule; import com.android.systemui.qs.footer.dagger.FooterActionsModule; import com.android.systemui.recents.Recents; import com.android.systemui.recordissue.RecordIssueModule; -import com.android.systemui.retail.dagger.RetailModeModule; +import com.android.systemui.retail.RetailModeModule; import com.android.systemui.scene.shared.model.SceneContainerConfig; import com.android.systemui.scene.shared.model.SceneDataSource; import com.android.systemui.scene.shared.model.SceneDataSourceDelegator; diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java index 24dba59a1d54..4d77e3ecea7b 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowControllerImpl.java @@ -17,8 +17,6 @@ package com.android.systemui.shade; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; -import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; -import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE; import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; @@ -27,16 +25,13 @@ import android.app.IActivityManager; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Configuration; -import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.Region; -import android.os.Binder; import android.os.Build; import android.os.RemoteException; import android.os.Trace; import android.util.Log; import android.view.Display; -import android.view.Gravity; import android.view.IWindow; import android.view.IWindowSession; import android.view.View; @@ -271,33 +266,7 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW // Now that the notification shade encompasses the sliding panel and its // translucent backdrop, the entire thing is made TRANSLUCENT and is // hardware-accelerated. - mLp = new LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT, - LayoutParams.TYPE_NOTIFICATION_SHADE, - LayoutParams.FLAG_NOT_FOCUSABLE - | LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING - | LayoutParams.FLAG_SPLIT_TOUCH - | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH - | LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, - PixelFormat.TRANSLUCENT); - mLp.token = new Binder(); - mLp.gravity = Gravity.TOP; - mLp.setFitInsetsTypes(0 /* types */); - mLp.setTitle("NotificationShade"); - mLp.packageName = mContext.getPackageName(); - mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; - mLp.privateFlags |= PRIVATE_FLAG_OPTIMIZE_MEASURE; - - if (SceneContainerFlag.isEnabled()) { - // This prevents the appearance and disappearance of the software keyboard (also known - // as the "IME") from scrolling/panning the window to make room for the keyboard. - // - // The scene container logic does its own adjustment and animation when the IME appears - // or disappears. - mLp.softInputMode = LayoutParams.SOFT_INPUT_ADJUST_NOTHING; - } - + mLp = ShadeWindowLayoutParams.INSTANCE.create(mContext); mWindowManager.addView(mWindowRootView, mLp); // We use BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE here, however, there is special logic in diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt new file mode 100644 index 000000000000..6bb50f99b5e7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeWindowLayoutParams.kt @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.shade + +import android.content.Context +import android.graphics.PixelFormat +import android.os.Binder +import android.view.Gravity +import android.view.ViewGroup +import android.view.WindowManager.LayoutParams +import com.android.systemui.scene.shared.flag.SceneContainerFlag + +object ShadeWindowLayoutParams { + /** + * Creates [LayoutParams] for the shade window. + * + * This is extracted to a single place as those layout params will be used by several places: + * - When sysui starts, and the shade is added the first time + * - When the shade moves to a different window (e.g. while an external display is connected) + */ + fun create(context: Context): LayoutParams { + return LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT, + LayoutParams.TYPE_NOTIFICATION_SHADE, + LayoutParams.FLAG_NOT_FOCUSABLE or + LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING or + LayoutParams.FLAG_SPLIT_TOUCH or + LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH or + LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, + // Now that the notification shade encompasses the sliding panel and its + // translucent backdrop, the entire thing is made TRANSLUCENT and is + // hardware-accelerated. + PixelFormat.TRANSLUCENT, + ) + .apply { + token = Binder() + gravity = Gravity.TOP + fitInsetsTypes = 0 + title = "NotificationShade" + packageName = context.packageName + layoutInDisplayCutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS + privateFlags = privateFlags or LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE + if (SceneContainerFlag.isEnabled) { + // This prevents the appearance and disappearance of the software keyboard (also + // known as the "IME") from scrolling/panning the window to make room for the + // keyboard. + // + // The scene container logic does its own adjustment and animation when the IME + // appears or disappears. + softInputMode = LayoutParams.SOFT_INPUT_ADJUST_NOTHING + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt index 3c0682822564..2a9b1b97b48f 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt @@ -22,6 +22,7 @@ import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Tracing import com.android.systemui.dagger.qualifiers.UiBackground +import com.android.systemui.util.settings.SettingsSingleThreadBackground import dagger.Module import dagger.Provides import kotlinx.coroutines.CoroutineDispatcher diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index b221d74e2d86..827e3effcf32 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -607,7 +607,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // ... and see if these are hosts we've been awaiting. // NOTE: We are backing up and restoring only the owner. // TODO: http://b/22388012 - if (newPackageAdded && userId == UserHandle.USER_SYSTEM) { + UserHandle mainUser = mUserManager.getMainUser(); + if (newPackageAdded && mainUser != null && userId == mainUser.getIdentifier()) { final int uid = getUidForPackage(pkgName, userId); if (uid >= 0 ) { resolveHostUidLocked(pkgName, uid); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index cb89f2895902..dfddc089e4a4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -668,6 +668,8 @@ public class ActivityManagerService extends IActivityManager.Stub */ private static final boolean ENABLE_PROC_LOCK = true; + private static final int DEFAULT_INTENT_CREATOR_UID = -1; + /** * The lock for process management. * @@ -19308,22 +19310,36 @@ public class ActivityManagerService extends IActivityManager.Stub if (!preventIntentRedirect()) return; if (intent == null) return; + + String targetPackage = intent.getComponent() != null + ? intent.getComponent().getPackageName() + : intent.getPackage(); + final boolean isCreatorSameAsTarget = creatorPackage != null && creatorPackage.equals( + targetPackage); + final boolean noExtraIntentKeys = + intent.getExtraIntentKeys() == null || intent.getExtraIntentKeys().isEmpty(); + final int creatorUid = noExtraIntentKeys ? DEFAULT_INTENT_CREATOR_UID : Binder.getCallingUid(); + intent.forEachNestedCreatorToken(extraIntent -> { - IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent, creatorPackage); + if (isCreatorSameAsTarget) { + FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, true); + return; + } + IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent, creatorUid, + creatorPackage); if (creatorToken != null) { extraIntent.setCreatorToken(creatorToken); // TODO remove Slog.wtf once proven FrameworkStatsLog works. b/375396329 Slog.wtf(TAG, "A creator token is added to an intent. creatorPackage: " + creatorPackage + "; intent: " + extraIntent); - FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, - creatorToken.getCreatorUid()); + FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED, creatorUid, false); } }); } - private IntentCreatorToken createIntentCreatorToken(Intent intent, String creatorPackage) { + private IntentCreatorToken createIntentCreatorToken(Intent intent, int creatorUid, + String creatorPackage) { if (IntentCreatorToken.isValid(intent)) return null; - int creatorUid = getCallingUid(); IntentCreatorToken.Key key = new IntentCreatorToken.Key(creatorUid, creatorPackage, intent); IntentCreatorToken token; synchronized (sIntentCreatorTokenCache) { diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java index 3dd5ec9a3834..ef5296eef492 100644 --- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java +++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java @@ -221,6 +221,7 @@ public class SettingsToPropertiesMapper { "preload_safety", "printing", "privacy_infra_policy", + "psap_ai", "ravenwood", "resource_manager", "responsible_apis", diff --git a/services/core/java/com/android/server/input/KeyboardBacklightController.java b/services/core/java/com/android/server/input/KeyboardBacklightController.java index c3205afe14f2..0defd27eaae2 100644 --- a/services/core/java/com/android/server/input/KeyboardBacklightController.java +++ b/services/core/java/com/android/server/input/KeyboardBacklightController.java @@ -20,6 +20,7 @@ import android.animation.ValueAnimator; import android.annotation.BinderThread; import android.annotation.Nullable; import android.content.Context; +import android.content.res.Resources; import android.graphics.Color; import android.hardware.input.IKeyboardBacklightListener; import android.hardware.input.IKeyboardBacklightState; @@ -81,9 +82,6 @@ final class KeyboardBacklightController implements private static final String UEVENT_KEYBOARD_BACKLIGHT_TAG = "kbd_backlight"; @VisibleForTesting - static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis(); - - @VisibleForTesting static final int[] DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL = new int[DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS + 1]; @@ -112,6 +110,7 @@ final class KeyboardBacklightController implements private AmbientKeyboardBacklightController.AmbientKeyboardBacklightListener mAmbientListener; private int mAmbientBacklightValue = 0; + private final int mUserInactivityThresholdMs; static { // Fixed brightness levels to avoid issues when converting back and forth from the @@ -139,6 +138,9 @@ final class KeyboardBacklightController implements mAnimatorFactory = animatorFactory; mAmbientController = new AmbientKeyboardBacklightController(context, looper); mUEventManager = uEventManager; + Resources res = mContext.getResources(); + mUserInactivityThresholdMs = res.getInteger( + com.android.internal.R.integer.config_keyboardBacklightTimeoutMs); } @Override @@ -300,7 +302,7 @@ final class KeyboardBacklightController implements } mHandler.removeMessages(MSG_NOTIFY_USER_INACTIVITY); mHandler.sendEmptyMessageAtTime(MSG_NOTIFY_USER_INACTIVITY, - SystemClock.uptimeMillis() + USER_INACTIVITY_THRESHOLD_MILLIS); + SystemClock.uptimeMillis() + mUserInactivityThresholdMs); } private void handleUserInactivity() { diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS index c62e3237e487..6536ca084421 100644 --- a/services/core/java/com/android/server/location/contexthub/OWNERS +++ b/services/core/java/com/android/server/location/contexthub/OWNERS @@ -1,3 +1,4 @@ bduddie@google.com +arthuri@google.com matthewsedam@google.com stange@google.com diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java index 84413d5710d0..c5c8a5ea9d82 100644 --- a/services/core/java/com/android/server/media/quality/MediaQualityService.java +++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java @@ -96,7 +96,35 @@ public class MediaQualityService extends SystemService { @Override public PictureProfile getPictureProfile(int type, String name) { - return null; + SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase(); + + String selection = PictureQuality.PARAMETER_TYPE + " = ? AND " + + PictureQuality.PARAMETER_NAME + " = ?"; + String[] selectionArguments = {Integer.toString(type), name}; + + try ( + Cursor cursor = db.query( + mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, + getAllPictureProfileColumns(), + selection, + selectionArguments, + /*groupBy=*/ null, + /*having=*/ null, + /*orderBy=*/ null) + ) { + int count = cursor.getCount(); + if (count == 0) { + return null; + } + if (count > 1) { + Log.wtf(TAG, String.format(Locale.US, "%d entries found for type=%d and name=%s" + + " in %s. Should only ever be 0 or 1.", count, type, name, + mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME)); + return null; + } + cursor.moveToFirst(); + return getPictureProfileFromCursor(cursor); + } } private String bundleToJson(Bundle bundle) { @@ -145,17 +173,79 @@ public class MediaQualityService extends SystemService { return bundle; } + private String[] getAllPictureProfileColumns() { + return new String[]{ + PictureQuality.PARAMETER_ID, + PictureQuality.PARAMETER_TYPE, + PictureQuality.PARAMETER_NAME, + PictureQuality.PARAMETER_INPUT_ID, + PictureQuality.PARAMETER_PACKAGE, + mMediaQualityDbHelper.SETTINGS + }; + } + + private PictureProfile getPictureProfileFromCursor(Cursor cursor) { + String returnId = cursor.getString( + cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_ID)); + int type = cursor.getInt( + cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_TYPE)); + String name = cursor.getString( + cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_NAME)); + String inputId = cursor.getString( + cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_INPUT_ID)); + String packageName = cursor.getString( + cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_PACKAGE)); + String settings = cursor.getString( + cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS)); + return new PictureProfile(returnId, type, name, inputId, + packageName, jsonToBundle(settings)); + } + @Override public List<PictureProfile> getPictureProfilesByPackage(String packageName) { - return new ArrayList<>(); + String selection = PictureQuality.PARAMETER_PACKAGE + " = ?"; + String[] selectionArguments = {packageName}; + return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection, + selectionArguments); } + @Override public List<PictureProfile> getAvailablePictureProfiles() { return new ArrayList<>(); } + @Override public List<String> getPictureProfilePackageNames() { - return new ArrayList<>(); + String [] column = {PictureQuality.PARAMETER_NAME}; + List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column, + null, null); + List<String> packageNames = new ArrayList<>(); + for (PictureProfile pictureProfile: pictureProfiles) { + packageNames.add(pictureProfile.getName()); + } + return packageNames; + } + + private List<PictureProfile> getPictureProfilesBasedOnConditions(String[] columns, + String selection, String[] selectionArguments) { + SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase(); + + try ( + Cursor cursor = db.query( + mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, + columns, + selection, + selectionArguments, + /*groupBy=*/ null, + /*having=*/ null, + /*orderBy=*/ null) + ) { + List<PictureProfile> pictureProfiles = new ArrayList<>(); + while (cursor.moveToNext()) { + pictureProfiles.add(getPictureProfileFromCursor(cursor)); + } + return pictureProfiles; + } } @Override diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java index d5d4070ee4c3..52ddb800fa40 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java +++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java @@ -22,8 +22,11 @@ import android.app.NotificationChannelGroup; import android.app.backup.BackupRestoreEventLogger; import android.service.notification.DeviceEffectsApplier; +import com.android.internal.annotations.Keep; + import java.util.Set; +@Keep public interface NotificationManagerInternal { NotificationChannel getNotificationChannel(String pkg, int uid, String channelId); NotificationChannelGroup getNotificationChannelGroup(String pkg, int uid, String channelId); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 4d0c7ec64317..207764b4e555 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -211,6 +211,7 @@ import android.app.RemoteServiceException.BadForegroundServiceNotificationExcept import android.app.RemoteServiceException.BadUserInitiatedJobNotificationException; import android.app.StatsManager; import android.app.UriGrantsManager; +import android.app.ZenBypassingApp; import android.app.admin.DevicePolicyManagerInternal; import android.app.backup.BackupManager; import android.app.backup.BackupRestoreEventLogger; @@ -238,7 +239,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.LauncherApps; import android.content.pm.ModuleInfo; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManagerInternal; @@ -3089,7 +3089,7 @@ public class NotificationManagerService extends SystemService { migrateDefaultNAS(); maybeShowInitialReviewPermissionsNotification(); - if (android.app.Flags.modesApi()) { + if (android.app.Flags.modesApi() && !mZenModeHelper.hasDeviceEffectsApplier()) { // Cannot be done earlier, as some services aren't ready until this point. mZenModeHelper.setDeviceEffectsApplier( new DefaultDeviceEffectsApplier(getContext())); @@ -4043,7 +4043,7 @@ public class NotificationManagerService extends SystemService { "canNotifyAsPackage for uid " + uid); } - return areNotificationsEnabledForPackageInt(pkg, uid); + return areNotificationsEnabledForPackageInt(uid); } /** @@ -4864,30 +4864,20 @@ public class NotificationManagerService extends SystemService { } @Override - public List<String> getPackagesBypassingDnd(int userId, - boolean includeConversationChannels) { + public ParceledListSlice<ZenBypassingApp> getPackagesBypassingDnd(int userId) + throws RemoteException { checkCallerIsSystem(); - final ArraySet<String> packageNames = new ArraySet<>(); - - List<PackageInfo> pkgs = mPackageManagerClient.getInstalledPackagesAsUser(0, userId); - for (PackageInfo pi : pkgs) { - String pkg = pi.packageName; - // If any NotificationChannel for this package is bypassing, the - // package is considered bypassing. - for (NotificationChannel channel : getNotificationChannelsBypassingDnd(pkg, - pi.applicationInfo.uid).getList()) { - // Skips non-demoted conversation channels. - if (!includeConversationChannels - && !TextUtils.isEmpty(channel.getConversationId()) - && !channel.isDemoted()) { - continue; - } - packageNames.add(pkg); + UserHandle user = UserHandle.of(userId); + ArrayList<ZenBypassingApp> bypassing = + mPreferencesHelper.getPackagesBypassingDnd(userId); + for (int i = bypassing.size() - 1; i >= 0; i--) { + String pkg = bypassing.get(i).getPkg(); + if (!areNotificationsEnabledForPackage(pkg, getUidForPackageAndUser(pkg, user))) { + bypassing.remove(i); } } - - return new ArrayList<String>(packageNames); + return new ParceledListSlice<>(bypassing); } @Override @@ -7763,7 +7753,7 @@ public class NotificationManagerService extends SystemService { @Override public boolean areNotificationsEnabledForPackage(String pkg, int uid) { - return areNotificationsEnabledForPackageInt(pkg, uid); + return areNotificationsEnabledForPackageInt(uid); } @Override @@ -8742,7 +8732,7 @@ public class NotificationManagerService extends SystemService { } // blocked apps - boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid); + boolean isBlocked = !areNotificationsEnabledForPackageInt(uid); synchronized (mNotificationLock) { isBlocked |= isRecordBlockedLocked(r); } @@ -8792,7 +8782,7 @@ public class NotificationManagerService extends SystemService { } } - private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) { + private boolean areNotificationsEnabledForPackageInt(int uid) { return mPermissionHelper.hasPermission(uid); } @@ -9328,7 +9318,7 @@ public class NotificationManagerService extends SystemService { * notifying all listeners to a background thread; false otherwise. */ private boolean postNotification() { - boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid); + boolean appBanned = !areNotificationsEnabledForPackageInt(uid); boolean isCallNotification = isCallNotification(pkg, uid); boolean posted = false; synchronized (NotificationManagerService.this.mNotificationLock) { diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 9f0b4b0b6299..e6f784c71ef3 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -57,6 +57,7 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationManager; +import android.app.ZenBypassingApp; import android.content.AttributionSource; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -1950,6 +1951,35 @@ public class PreferencesHelper implements RankingConfig { } /** + * Gets all apps that can bypass DND, and a boolean indicating whether all (true) or some + * (false) of its notification channels can currently bypass. + */ + public @NonNull ArrayList<ZenBypassingApp> getPackagesBypassingDnd(@UserIdInt int userId) { + ArrayList<ZenBypassingApp> bypassing = new ArrayList<>(); + synchronized (mLock) { + for (PackagePreferences p : mPackagePreferences.values()) { + if (p.userId != userId) { + continue; + } + int totalChannelCount = p.channels.size(); + int bypassingCount = 0; + if (totalChannelCount == 0) { + continue; + } + for (NotificationChannel channel : p.channels.values()) { + if (channelIsLiveLocked(p, channel) && channel.canBypassDnd()) { + bypassingCount++; + } + } + if (bypassingCount > 0) { + bypassing.add(new ZenBypassingApp(p.pkg, totalChannelCount == bypassingCount)); + } + } + } + return bypassing; + } + + /** * True for pre-O apps that only have the default channel, or pre O apps that have no * channels yet. This method will create the default channel for pre-O apps that don't have it. * Should never be true for O+ targeting apps, but that's enforced on boot/when an app diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index cfeacdf2bb0d..ca4f83fd46f6 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -24,6 +24,8 @@ import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_UNKNOWN; import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY; +import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; +import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING; import static android.service.notification.Condition.SOURCE_UNKNOWN; import static android.service.notification.Condition.SOURCE_USER_ACTION; import static android.service.notification.Condition.STATE_FALSE; @@ -44,8 +46,6 @@ import static android.service.notification.ZenModeConfig.isImplicitRuleId; import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; import static com.android.internal.util.Preconditions.checkArgument; -import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; -import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING; import static java.util.Objects.requireNonNull; @@ -303,6 +303,15 @@ public class ZenModeHelper { } /** + * @return whether a {@link DeviceEffectsApplier} has already been set or not + */ + boolean hasDeviceEffectsApplier() { + synchronized (mConfigLock) { + return mDeviceEffectsApplier != null; + } + } + + /** * Set the {@link DeviceEffectsApplier} used to apply the consolidated effects. * * <p>Previously calculated effects (as loaded from the user's {@link ZenModeConfig}) will be diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index 76ea0b963036..4690e020b12a 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -880,7 +880,8 @@ public class PackageArchiver { PackageInstaller.STATUS_PENDING_USER_ACTION); broadcastIntent.putExtra(Intent.EXTRA_INTENT, dialogIntent); broadcastIntent.putExtra(Intent.EXTRA_USER, user); - sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent); + mPm.mHandler.post( + () -> sendIntent(statusReceiver, packageName, /* message= */ "", broadcastIntent)); } private void verifyUninstallPermissions() { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 5518bfae8277..1052c94d7799 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -1022,7 +1022,7 @@ public class ShortcutService extends IShortcutService.Stub { // Close. file.finishWrite(outs); } catch (IOException e) { - Slog.e(TAG, "Failed to write to file " + file.getBaseFile(), e); + Slog.w(TAG, "Failed to write to file " + file.getBaseFile(), e); file.failWrite(outs); } } @@ -1055,7 +1055,7 @@ public class ShortcutService extends IShortcutService.Stub { final String tag = parser.getName(); if (depth == 1) { if (!TAG_ROOT.equals(tag)) { - Slog.e(TAG, "Invalid root tag: " + tag); + Slog.v(TAG, "Invalid root tag: " + tag); return; } continue; @@ -1066,7 +1066,7 @@ public class ShortcutService extends IShortcutService.Stub { mRawLastResetTime.set(parseLongAttribute(parser, ATTR_VALUE)); break; default: - Slog.e(TAG, "Invalid tag: " + tag); + Slog.v(TAG, "Invalid tag: " + tag); break; } } @@ -1113,7 +1113,7 @@ public class ShortcutService extends IShortcutService.Stub { // Remove all dangling bitmap files. cleanupDanglingBitmapDirectoriesLocked(userId); } catch (XmlPullParserException | IOException e) { - Slog.e(TAG, "Failed to write to file " + file, e); + Slog.w(TAG, "Failed to write to file " + file, e); file.failWrite(os); } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d221e8ccb9b7..8ad878627804 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -9004,26 +9004,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return; } - - CallerIdentity caller; - if (Flags.setAutoTimeEnabledCoexistence()) { - caller = getCallerIdentity(who, callerPackageName); - } else { - caller = getCallerIdentity(who); - } - - if (Flags.setAutoTimeEnabledCoexistence()) { - // The effect of this policy is device-wide. - enforcePermission(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL); - } else { - Objects.requireNonNull(who, "ComponentName is null"); - Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller) - || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner( - caller)); - } + CallerIdentity caller = getCallerIdentity(who); + Objects.requireNonNull(who, "ComponentName is null"); + Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller) + || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner( + caller)); mInjector.binderWithCleanCallingIdentity(() -> mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, enabled ? 1 : 0)); - DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_AUTO_TIME) .setAdmin(caller.getPackageName()) @@ -9039,23 +9026,74 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return false; } - CallerIdentity caller; - if (Flags.setAutoTimeEnabledCoexistence()) { - caller = getCallerIdentity(who, callerPackageName); - } else { - caller = getCallerIdentity(who); + CallerIdentity caller = getCallerIdentity(who); + + Objects.requireNonNull(who, "ComponentName is null"); + Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller) + || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(caller)); + + return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0; + } + + /** + * Set whether auto time is enabled on the device. + */ + @Override + public void setAutoTimePolicy(String callerPackageName, int policy) { + if (!mHasFeature) { + return; } - if (Flags.setAutoTimeEnabledCoexistence()) { - enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL); + final Set<Integer> allowedValues = + Set.of( + DevicePolicyManager.AUTO_TIME_ENABLED, + DevicePolicyManager.AUTO_TIME_DISABLED, + DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY); + Preconditions.checkArgument( + allowedValues.contains(policy), "Provided mode is not one of the allowed values."); + + CallerIdentity caller = getCallerIdentity(callerPackageName); + // The effect of this policy is device-wide. + EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin( + /* who */ null, + SET_TIME, + caller.getPackageName(), + UserHandle.USER_ALL + ); + if (policy == DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY) { + mDevicePolicyEngine.removeGlobalPolicy(PolicyDefinition.AUTO_TIME, enforcingAdmin); } else { - Objects.requireNonNull(who, "ComponentName is null"); - Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller) - || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner( - caller)); + mDevicePolicyEngine.setGlobalPolicy( + PolicyDefinition.AUTO_TIME, + enforcingAdmin, + new IntegerPolicyValue(policy)); + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.SET_AUTO_TIME) + .setAdmin(caller.getPackageName()) + .setBoolean(policy == DevicePolicyManager.AUTO_TIME_ENABLED) + .write(); } + } - return mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) > 0; + /** + * Returns whether auto time is used on the device or not. + */ + @Override + public int getAutoTimePolicy(String callerPackageName) { + if (!mHasFeature) { + return DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY; + } + CallerIdentity caller = getCallerIdentity(callerPackageName); + // The effect of this policy is device-wide. + EnforcingAdmin enforcingAdmin = enforcePermissionAndGetEnforcingAdmin( + /* who */ null, + SET_TIME, + caller.getPackageName(), + UserHandle.USER_ALL + ); + Integer state = mDevicePolicyEngine.getGlobalPolicySetByAdmin( + PolicyDefinition.AUTO_TIME, enforcingAdmin); + return state != null ? state : DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY; } /** diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java index a5aeaace94bc..24b16b7c2c60 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java @@ -349,6 +349,16 @@ final class PolicyDefinition<V> { PolicyEnforcerCallbacks::setMtePolicy, new IntegerPolicySerializer()); + static PolicyDefinition<Integer> AUTO_TIME = new PolicyDefinition<>( + new NoArgsPolicyKey(DevicePolicyIdentifiers.AUTO_TIME_POLICY), + new TopPriority<>(List.of( + EnforcingAdmin.getRoleAuthorityOf(SYSTEM_SUPERVISION_ROLE), + EnforcingAdmin.getRoleAuthorityOf(DEVICE_LOCK_CONTROLLER_ROLE), + EnforcingAdmin.DPC_AUTHORITY)), + POLICY_FLAG_GLOBAL_ONLY_POLICY, + PolicyEnforcerCallbacks::setAutoTimePolicy, + new IntegerPolicySerializer()); + private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>(); private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>(); @@ -397,6 +407,7 @@ final class PolicyDefinition<V> { PACKAGES_SUSPENDED); POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.MEMORY_TAGGING_POLICY, MEMORY_TAGGING); + POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.AUTO_TIME_POLICY, AUTO_TIME); // User Restriction Policies USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java index 40d8dae41dcf..8f80004a7ea5 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java @@ -212,6 +212,25 @@ final class PolicyEnforcerCallbacks { return AndroidFuture.completedFuture(true); } + public static CompletableFuture<Boolean> setAutoTimePolicy( + Integer policy, Context context, Integer userId, PolicyKey policyKey) { + if (!Flags.setAutoTimeEnabledCoexistence()) { + Slogf.w(LOG_TAG, "Trying to enforce setAutoTimePolicy while flag is off."); + return AndroidFuture.completedFuture(true); + } + return Binder.withCleanCallingIdentity(() -> { + Objects.requireNonNull(context); + if (policy != null + && policy == DevicePolicyManager.AUTO_TIME_NOT_CONTROLLED_BY_POLICY) { + return AndroidFuture.completedFuture(false); + } + int enabled = policy != null && policy == DevicePolicyManager.AUTO_TIME_ENABLED ? 1 : 0; + return AndroidFuture.completedFuture( + Settings.Global.putInt( + context.getContentResolver(), Settings.Global.AUTO_TIME, enabled)); + }); + } + private static class BlockingCallback { private final CountDownLatch mLatch = new CountDownLatch(1); private final AtomicReference<Boolean> mValue = new AtomicReference<>(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 19b03437292f..d0bf02dab60c 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -2761,8 +2761,9 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(WEAR_MODE_SERVICE_CLASS); t.traceEnd(); - boolean enableWristOrientationService = SystemProperties.getBoolean( - "config.enable_wristorientation", false); + boolean enableWristOrientationService = + !android.server.Flags.migrateWristOrientation() + && SystemProperties.getBoolean("config.enable_wristorientation", false); if (enableWristOrientationService) { t.traceBegin("StartWristOrientationService"); mSystemServiceManager.startService(WRIST_ORIENTATION_SERVICE_CLASS); diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig index e2ac22de29a4..4412968999e5 100644 --- a/services/java/com/android/server/flags.aconfig +++ b/services/java/com/android/server/flags.aconfig @@ -39,6 +39,14 @@ flag { } flag { + name: "migrate_wrist_orientation" + namespace: "wear_frameworks" + description: "Migrate wrist orientation service functionality to wear settings service" + bug: "352725980" + is_fixed_read_only: true +} + +flag { name: "allow_network_time_update_service" namespace: "wear_systems" description: "Allow NetworkTimeUpdateService on Wear" diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index eae587bc0187..704c1b858b8d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -210,6 +210,7 @@ import android.app.Person; import android.app.RemoteInput; import android.app.RemoteInputHistoryItem; import android.app.StatsManager; +import android.app.ZenBypassingApp; import android.app.admin.DevicePolicyManagerInternal; import android.app.backup.BackupRestoreEventLogger; import android.app.job.JobScheduler; @@ -360,6 +361,9 @@ import org.mockito.MockitoAnnotations; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; @@ -374,9 +378,6 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; -import platform.test.runner.parameterized.ParameterizedAndroidJunit4; -import platform.test.runner.parameterized.Parameters; - @SmallTest @RunWith(ParameterizedAndroidJunit4.class) @RunWithLooper @@ -489,7 +490,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { private final NotificationChannel mParentChannel = new NotificationChannel(PARENT_CHANNEL_ID, "parentName", IMPORTANCE_DEFAULT); private final NotificationChannel mConversationChannel = - new NotificationChannel(CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT); + new NotificationChannel( + CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT); private static final String PARENT_CHANNEL_ID = "parentChannelId"; private static final String CONVERSATION_CHANNEL_ID = "conversationChannelId"; @@ -4296,8 +4298,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { new NotificationChannel("foo", "foo", IMPORTANCE_HIGH)); Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); - mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_onTv", 0, - generateNotificationRecord(null, tv).getNotification(), mUserId); + mBinderService.enqueueNotificationWithTag( + mPkg, + mPkg, + "testTvExtenderChannelOverride_onTv", + 0, + generateNotificationRecord(null, tv).getNotification(), + mUserId); verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean()); } @@ -4311,8 +4318,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mTestNotificationChannel); Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); - mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_notOnTv", - 0, generateNotificationRecord(null, tv).getNotification(), mUserId); + mBinderService.enqueueNotificationWithTag( + mPkg, + mPkg, + "testTvExtenderChannelOverride_notOnTv", + 0, + generateNotificationRecord(null, tv).getNotification(), + mUserId); verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null), anyBoolean(), anyBoolean()); @@ -7745,9 +7757,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon) .setStyle(new Notification.MessagingStyle("").addMessage(message2)); - NotificationRecord recordB = new NotificationRecord(mContext, new StatusBarNotification(mPkg, - mPkg, 0, "tag", mUid, 0, nbB.build(), UserHandle.getUserHandleForUid(mUid), null, 0), - c); + NotificationRecord recordB = + new NotificationRecord( + mContext, + new StatusBarNotification( + mPkg, + mPkg, + 0, + "tag", + mUid, + 0, + nbB.build(), + UserHandle.getUserHandleForUid(mUid), + null, + 0), + c); // Update means we drop access to first reset(mUgmInternal); @@ -13174,6 +13198,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + public void getPackagesBypassingDnd_blocked() + throws RemoteException, PackageManager.NameNotFoundException { + + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel2 = new NotificationChannel("id3", "name3", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel3 = new NotificationChannel("id4", "name3", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(true); + channel2.setBypassDnd(true); + channel3.setBypassDnd(false); + // has DND access, so can set bypassDnd attribute + mService.mPreferencesHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, + /*has DND access*/ true, UID_N_MR1, false); + mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel2, true, true, + UID_P, false); + mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true, + UID_P, false); + + when(mPackageManager.getPackageUid(eq(PKG_P), anyLong(), anyInt())).thenReturn(UID_P); + when(mPackageManager.getPackageUid(eq(PKG_N_MR1), anyLong(), anyInt())) + .thenReturn(UID_N_MR1); + when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false); + when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true); + + assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList()) + .containsExactly(new ZenBypassingApp(PKG_P, false)); + } + + @Test public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); @@ -13187,125 +13242,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetPackagesBypassingDnd_empty() throws RemoteException { mService.setPreferencesHelper(mPreferencesHelper); - List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); + List<String> result = mBinderService.getPackagesBypassingDnd(mUserId).getList(); assertThat(result).isEmpty(); } @Test - public void testGetPackagesBypassingDnd_excludeConversationChannels() throws RemoteException { - mService.setPreferencesHelper(mPreferencesHelper); - - // Set packages - PackageInfo pkg0 = new PackageInfo(); - pkg0.packageName = "pkg0"; - pkg0.applicationInfo = new ApplicationInfo(); - pkg0.applicationInfo.uid = mUid; - PackageInfo pkg1 = new PackageInfo(); - pkg1.packageName = "pkg1"; - pkg1.applicationInfo = new ApplicationInfo(); - pkg1.applicationInfo.uid = mUid; - PackageInfo pkg2 = new PackageInfo(); - pkg2.packageName = "pkg2"; - pkg2.applicationInfo = new ApplicationInfo(); - pkg2.applicationInfo.uid = mUid; - - when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) - .thenReturn(List.of(pkg0, pkg1, pkg2)); - - // Conversation channels - NotificationChannel nc0 = new NotificationChannel("id0", "id0", - NotificationManager.IMPORTANCE_HIGH); - nc0.setConversationId("parentChannel", "conversationId"); - - // Demoted conversation channel - NotificationChannel nc1 = new NotificationChannel("id1", "id1", - NotificationManager.IMPORTANCE_HIGH); - nc1.setConversationId("parentChannel", "conversationId"); - nc1.setDemoted(true); - - // Non-conversation channels - NotificationChannel nc2 = new NotificationChannel("id2", "id2", - NotificationManager.IMPORTANCE_HIGH); - NotificationChannel nc3 = new NotificationChannel("id3", "id3", - NotificationManager.IMPORTANCE_HIGH); - - ParceledListSlice<NotificationChannel> pls0 = - new ParceledListSlice(ImmutableList.of(nc0)); - ParceledListSlice<NotificationChannel> pls1 = - new ParceledListSlice(ImmutableList.of(nc1)); - ParceledListSlice<NotificationChannel> pls2 = - new ParceledListSlice(ImmutableList.of(nc2, nc3)); - - when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) - .thenReturn(pls0); - when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) - .thenReturn(pls1); - when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) - .thenReturn(pls2); - - List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, false); - - assertThat(result).containsExactly("pkg1", "pkg2"); - } - - @Test - public void testGetPackagesBypassingDnd_includeConversationChannels() throws RemoteException { - mService.setPreferencesHelper(mPreferencesHelper); - - // Set packages - PackageInfo pkg0 = new PackageInfo(); - pkg0.packageName = "pkg0"; - pkg0.applicationInfo = new ApplicationInfo(); - pkg0.applicationInfo.uid = mUid; - PackageInfo pkg1 = new PackageInfo(); - pkg1.packageName = "pkg1"; - pkg1.applicationInfo = new ApplicationInfo(); - pkg1.applicationInfo.uid = mUid; - PackageInfo pkg2 = new PackageInfo(); - pkg2.packageName = "pkg2"; - pkg2.applicationInfo = new ApplicationInfo(); - pkg2.applicationInfo.uid = mUid; - - when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) - .thenReturn(List.of(pkg0, pkg1, pkg2)); - - // Conversation channels - NotificationChannel nc0 = new NotificationChannel("id0", "id0", - NotificationManager.IMPORTANCE_HIGH); - nc0.setConversationId("parentChannel", "conversationId"); - - // Demoted conversation channel - NotificationChannel nc1 = new NotificationChannel("id1", "id1", - NotificationManager.IMPORTANCE_HIGH); - nc1.setConversationId("parentChannel", "conversationId"); - nc1.setDemoted(true); - - // Non-conversation channels - NotificationChannel nc2 = new NotificationChannel("id2", "id2", - NotificationManager.IMPORTANCE_HIGH); - NotificationChannel nc3 = new NotificationChannel("id3", "id3", - NotificationManager.IMPORTANCE_HIGH); - - ParceledListSlice<NotificationChannel> pls0 = - new ParceledListSlice(ImmutableList.of(nc0)); - ParceledListSlice<NotificationChannel> pls1 = - new ParceledListSlice(ImmutableList.of(nc1)); - ParceledListSlice<NotificationChannel> pls2 = - new ParceledListSlice(ImmutableList.of(nc2, nc3)); - - when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) - .thenReturn(pls0); - when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) - .thenReturn(pls1); - when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) - .thenReturn(pls2); - - List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); - - assertThat(result).containsExactly("pkg0", "pkg1", "pkg2"); - } - - @Test public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception { // set the testable NMS to not system uid/appid mService.isSystemUid = false; @@ -15482,8 +15423,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, i, null, false).getSbn(); - mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCannotPostNonUijWhenOverLimit", - sbn.getId(), sbn.getNotification(), sbn.getUserId()); + mBinderService.enqueueNotificationWithTag( + mPkg, + mPkg, + "testCannotPostNonUijWhenOverLimit", + sbn.getId(), + sbn.getNotification(), + sbn.getUserId()); waitForIdle(); } @@ -16213,6 +16159,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY); mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)); + + mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); // No exception! } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index e1b478cd1a1b..dda060d5d586 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -108,6 +108,7 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; import android.app.NotificationManager; +import android.app.ZenBypassingApp; import android.content.AttributionSource; import android.content.ContentProvider; import android.content.ContentResolver; @@ -2620,6 +2621,72 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test + public void getPackagesBypassingDnd_noChannelsBypassing() throws Exception { + assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty(); + } + + @Test + public void getPackagesBypassingDnd_oneChannelBypassing_deleted() { + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(true); + channel1.setDeleted(true); + // has DND access, so can set bypassDnd attribute + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, + /*has DND access*/ true, UID_N_MR1, false); + + assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_N_MR1))).isEmpty(); + } + + @Test + public void getPackagesBypassingDnd_oneChannelBypassing_groupBlocked() { + int uid = UID_N_MR1; + NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(true); + channel1.setGroup(ncg.getId()); + mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ true, + uid, false); + mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true, + uid, false); + ncg.setBlocked(true); + + assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(uid))).isEmpty(); + } + + @Test + public void getPackagesBypassingDnd_multipleApps() { + List<ZenBypassingApp> expected = ImmutableList.of( + new ZenBypassingApp(PKG_O, true), new ZenBypassingApp(PKG_P, false)); + + NotificationChannel channel1 = new NotificationChannel("id1", "name1", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel2 = new NotificationChannel("id2", "name2", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel3 = new NotificationChannel("id3", "name3", + NotificationManager.IMPORTANCE_MAX); + NotificationChannel channel4 = new NotificationChannel("id4", "name3", + NotificationManager.IMPORTANCE_MAX); + channel1.setBypassDnd(false); + channel2.setBypassDnd(true); + channel3.setBypassDnd(true); + channel4.setBypassDnd(false); + // has DND access, so can set bypassDnd attribute + mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, + /*has DND access*/ true, UID_N_MR1, false); + mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, true, + UID_O, false); + mHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true, + UID_P, false); + mHelper.createNotificationChannel(PKG_P, UID_P, channel4, true, true, + UID_P, false); + + assertThat(mHelper.getPackagesBypassingDnd(UserHandle.getUserId(UID_O))) + .containsExactlyElementsIn(expected); + } + + @Test public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() { int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; when(mPermissionHelper.hasPermission(uid)).thenReturn(true); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 4b94e103b9f4..020670dc0f0a 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -49,6 +49,8 @@ import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS; import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED; import static android.app.NotificationManager.Policy.STATE_PRIORITY_CHANNELS_BLOCKED; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; +import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; +import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; import static android.provider.Settings.Global.ZEN_MODE_ALARMS; @@ -84,8 +86,6 @@ import static com.android.os.dnd.DNDProtoEnums.PEOPLE_STARRED; import static com.android.os.dnd.DNDProtoEnums.ROOT_CONFIG; import static com.android.os.dnd.DNDProtoEnums.STATE_ALLOW; import static com.android.os.dnd.DNDProtoEnums.STATE_DISALLOW; -import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; -import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES; import static com.android.server.notification.ZenModeEventLogger.ACTIVE_RULE_TYPE_MANUAL; import static com.android.server.notification.ZenModeHelper.RULE_LIMIT_PER_PACKAGE; @@ -102,6 +102,7 @@ import static junit.framework.TestCase.fail; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; @@ -200,6 +201,9 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.xmlpull.v1.XmlPullParserException; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; @@ -219,9 +223,6 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import platform.test.runner.parameterized.ParameterizedAndroidJunit4; -import platform.test.runner.parameterized.Parameters; - @SmallTest @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. @RunWith(ParameterizedAndroidJunit4.class) @@ -5348,6 +5349,22 @@ public class ZenModeHelperTest extends UiServiceTestCase { mTestableLooper.processAllMessages(); verify(mDeviceEffectsApplier).apply(eq(effects), eq(ORIGIN_APP)); + assertTrue(mZenModeHelper.hasDeviceEffectsApplier()); + } + + @Test + public void testHasDeviceEffectsApplier_returnsFalseIfNotSet() { + assertFalse(mZenModeHelper.hasDeviceEffectsApplier()); + } + + @Test + @EnableFlags(FLAG_MODES_API) + public void testSettingDeviceEffects_throwsExceptionIfAlreadySet() { + mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier); + + assertThrows( + IllegalStateException.class, + () -> mZenModeHelper.setDeviceEffectsApplier(mDeviceEffectsApplier)); } @Test diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt index ea61ad9d4481..9f5e6d18dc03 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt @@ -347,6 +347,14 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : waitForTransitionToFullscreen(wmHelper) } + /** Maximize an app by dragging the app handle to the top drag zone. */ + fun maximizeAppWithDragToTopDragZone( + wmHelper: WindowManagerStateHelper, + device: UiDevice, + ) { + dragAppWindowToTopDragZone(wmHelper, device) + } + private fun dragAppWindowToTopDragZone(wmHelper: WindowManagerStateHelper, device: UiDevice) { val windowRect = wmHelper.getWindowRegion(innerHelper).bounds val displayRect = getDisplayRect(wmHelper) diff --git a/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt index 58fb4e1ed103..938e2f8a3611 100644 --- a/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyboardBacklightControllerTests.kt @@ -19,6 +19,7 @@ package com.android.server.input import android.animation.ValueAnimator import android.content.Context import android.content.ContextWrapper +import android.content.res.Resources import android.graphics.Color import android.hardware.input.IKeyboardBacklightListener import android.hardware.input.IKeyboardBacklightState @@ -28,11 +29,12 @@ import android.os.UEventObserver import android.os.test.TestLooper import android.platform.test.annotations.Presubmit import android.view.InputDevice +import android.util.TypedValue import androidx.test.annotation.UiThreadTest import androidx.test.core.app.ApplicationProvider +import com.android.internal.R import com.android.server.input.KeyboardBacklightController.DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL import com.android.server.input.KeyboardBacklightController.MAX_BRIGHTNESS_CHANGE_STEPS -import com.android.server.input.KeyboardBacklightController.USER_INACTIVITY_THRESHOLD_MILLIS import com.android.test.input.MockInputManagerRule import java.io.FileNotFoundException import java.io.FileOutputStream @@ -49,6 +51,7 @@ import org.junit.Rule import org.junit.Test import org.mockito.Mock import org.mockito.Mockito.any +import org.mockito.Mockito.anyBoolean import org.mockito.Mockito.anyInt import org.mockito.Mockito.eq import org.mockito.Mockito.spy @@ -94,6 +97,7 @@ class KeyboardBacklightControllerTests { const val LIGHT_ID = 2 const val SECOND_LIGHT_ID = 3 const val MAX_BRIGHTNESS = 255 + const val USER_INACTIVITY_THRESHOLD_MILLIS = 30000 } @get:Rule @@ -105,6 +109,8 @@ class KeyboardBacklightControllerTests { private lateinit var native: NativeInputManagerService @Mock private lateinit var uEventManager: UEventManager + @Mock + private lateinit var resources: Resources private lateinit var keyboardBacklightController: KeyboardBacklightController private lateinit var context: Context private lateinit var dataStore: PersistentDataStore @@ -117,6 +123,7 @@ class KeyboardBacklightControllerTests { @Before fun setup() { context = spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + `when`(context.resources).thenReturn(resources) dataStore = PersistentDataStore(object : PersistentDataStore.Injector() { override fun openRead(): InputStream? { throw FileNotFoundException() @@ -129,6 +136,7 @@ class KeyboardBacklightControllerTests { override fun finishWrite(fos: FileOutputStream?, success: Boolean) {} }) testLooper = TestLooper() + setupConfig() keyboardBacklightController = KeyboardBacklightController(context, native, dataStore, testLooper.looper, FakeAnimatorFactory(), uEventManager) val inputManager = InputManager(context) @@ -147,7 +155,31 @@ class KeyboardBacklightControllerTests { sysfsNodeChanges++ } } - + private fun setupConfig() { + val brightnessValues = intArrayOf(100, 200, 0) + val decreaseThresholds = intArrayOf(-1, 900, 1900) + val increaseThresholds = intArrayOf(1000, 2000, -1) + `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightBrightnessValues)) + .thenReturn(brightnessValues) + `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightDecreaseLuxThreshold)) + .thenReturn(decreaseThresholds) + `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightIncreaseLuxThreshold)) + .thenReturn(increaseThresholds) + `when`(resources.getInteger(R.integer.config_keyboardBacklightTimeoutMs)) + .thenReturn(USER_INACTIVITY_THRESHOLD_MILLIS) + `when`( + resources.getValue( + eq(R.dimen.config_autoKeyboardBrightnessSmoothingConstant), + any(TypedValue::class.java), + anyBoolean() + ) + ).then { + val args = it.arguments + val outValue = args[1] as TypedValue + outValue.data = java.lang.Float.floatToRawIntBits(1.0f) + Unit + } + } @Test fun testKeyboardBacklightIncrementDecrement() { KeyboardBacklightFlags( @@ -365,7 +397,7 @@ class KeyboardBacklightControllerTests { lightColorMap[LIGHT_ID] ) - testLooper.moveTimeForward(USER_INACTIVITY_THRESHOLD_MILLIS + 1000) + testLooper.moveTimeForward((USER_INACTIVITY_THRESHOLD_MILLIS + 1000).toLong()) testLooper.dispatchNext() assertEquals( "Keyboard backlight level should be turned off after inactivity", |