Merge "dynamic link to "aconfig_settingslib_flags_java_lib"" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 6e37b7e..6393fdb 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -112,6 +112,7 @@
"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 dc7ccd4..4526de4d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -8075,6 +8075,7 @@
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 @@
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 @@
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 @@
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 @@
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 c8ecfa9..1192713 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2065,6 +2065,29 @@
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 0654ac2..9bb16ae 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -124,7 +124,7 @@
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 0381ee0..3d9c55c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5003,7 +5003,7 @@
/**
* 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 0000000..89bcfa2
--- /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 bff77f9..c789c41 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8920,12 +8920,9 @@
/**
* 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 @@
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 @@
}
/**
+ * 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 0b8f538..a406802 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -375,6 +375,9 @@
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 8b6441a..74a96c8 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 @@
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 b776b59..8853304 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -87,7 +87,6 @@
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 @@
}
/** @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 e349b81..f00c3a5 100644
--- a/core/java/android/hardware/display/DisplayTopology.java
+++ b/core/java/android/hardware/display/DisplayTopology.java
@@ -23,6 +23,7 @@
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 @@
}
}
+ /**
+ * 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 @@
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 8c3f0ef..70a1909 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -3436,7 +3436,7 @@
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 4bc8fe0..9ab9228 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -3928,9 +3928,9 @@
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 33040be..6264fbb 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -391,3 +391,12 @@
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 ae12132..a42eece 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -614,7 +614,7 @@
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 fb3e083..a560339 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.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 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 @@
}
/**
+ * 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 6026e60..6303c76 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -5179,7 +5179,7 @@
// 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 @@
// 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 edd9d6c..e619ab0 100644
--- a/core/java/android/view/inputmethod/flags.aconfig
+++ b/core/java/android/view/inputmethod/flags.aconfig
@@ -165,4 +165,13 @@
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 6c72544..76ead2a 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 @@
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 @@
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 @@
}
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 @@
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 52445e2..4a95686c 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 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 dc054a4..969ee2e 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 badb986..9dd3027 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 1721e1e..9dd196d 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 @@
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 @@
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 @@
@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 a6de611..8969b2b 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 @@
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 7446b88..6928c25 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 @@
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 5ffc64f..79a9ce5 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.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 @@
}
/** 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 02f5955..d415c10 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 @@
}
// 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 0000000..7e0b81a
--- /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 0000000..a2b88f2
--- /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 2ae89d3..82e9503 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.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 @@
*/
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 @@
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 @@
}
/**
+ * @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 @@
}
/**
+ * @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 @@
@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 3bc6b86..5c11def 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.util.Objects;
/**
+ * Ambient backlight event
* @hide
*/
+@FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW)
public final class AmbientBacklightEvent implements Parcelable {
/** @hide */
@@ -64,6 +68,9 @@
@Nullable
private final AmbientBacklightMetadata mMetadata;
+ /**
+ * Constructor of AmbientBacklightEvent.
+ */
public AmbientBacklightEvent(int eventType,
@Nullable AmbientBacklightMetadata metadata) {
mEventType = eventType;
@@ -75,10 +82,19 @@
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 @@
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 fc77934..9c11f9a 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 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 @@
@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 @@
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 bb782bf..4ed7bc7 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 @@
* 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 @@
/**
* The color format is RGB888.
+ * @hide
*/
public static final int COLOR_FORMAT_RGB888 = 1;
@@ -76,7 +82,7 @@
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 @@
*/
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 @@
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 26d83ac..4d4526c 100644
--- a/media/java/android/media/quality/MediaQualityManager.java
+++ b/media/java/android/media/quality/MediaQualityManager.java
@@ -567,7 +567,6 @@
/**
* Registers a {@link AmbientBacklightCallback}.
- * @hide
*/
public void registerAmbientBacklightCallback(
@NonNull @CallbackExecutor Executor executor,
@@ -581,7 +580,6 @@
/**
* Unregisters the existing {@link AmbientBacklightCallback}.
- * @hide
*/
public void unregisterAmbientBacklightCallback(
@NonNull final AmbientBacklightCallback callback) {
@@ -602,7 +600,6 @@
* 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 @@
* 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 @@
/**
* 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 4de6863..6441652 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 @@
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 c44e26f..f09dc72 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -104,6 +104,7 @@
"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 001653b..fc184fe 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 @@
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 @@
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 @@
obj = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
break;
}
+ case MediaCodec::CB_REQUIRED_RESOURCES_CHANGED:
+ {
+ break;
+ }
default:
TRESPASS();
@@ -3560,6 +3613,64 @@
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 @@
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 @@
{ "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 c9b6b7f6..930dbbe 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -185,6 +185,8 @@
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 a23845f..c25f77b 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -107,6 +107,7 @@
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 b102e87..fb793b0 100644
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -52,5 +52,6 @@
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 abd99bc..57ee981 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -394,6 +394,13 @@
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 @@
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 6671941..4f3e199 100644
--- a/nfc/java/android/nfc/OemLogItems.java
+++ b/nfc/java/android/nfc/OemLogItems.java
@@ -142,8 +142,11 @@
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 @@
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 bffda8b..0948931 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -497,6 +497,9 @@
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 @@
],
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 91dc3e3..9f15983 100644
--- a/packages/SystemUI/common/Android.bp
+++ b/packages/SystemUI/common/Android.bp
@@ -30,5 +30,9 @@
"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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/common/coroutine/ConflatedCallbackFlow.kt
rename to 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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/coroutines/Tracing.kt
rename to 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 93dede5..f1f6c61 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.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 ba7a65d..47bfda4 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.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 b536520..b47dcb5 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.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 0000000..e45f317
--- /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 0000000..df90be8
--- /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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/dagger/SysUISingleton.java
rename to 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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Application.java
rename to 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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/dagger/qualifiers/Background.java
rename to 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 0000000..f047848
--- /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
similarity index 83%
rename from packages/SystemUI/src/com/android/systemui/retail/dagger/RetailModeModule.kt
rename to packages/SystemUI/pods/com/android/systemui/retail/RetailModeModule.kt
index e863949..c20e368 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 0000000..f148a7c
--- /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 0000000..c9eac25
--- /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
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/retail/data/repository/RetailModeRepository.kt
rename to packages/SystemUI/pods/com/android/systemui/retail/data/repository/impl/RetailModeSettingsRepository.kt
index 09fd7df..8955263 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.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.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 0000000..787861c
--- /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/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
similarity index 65%
copy from packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
copy to packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
index eea452c..748e34d 100644
--- a/packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
+++ b/packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -16,22 +16,8 @@
package com.android.systemui.retail.domain.interactor
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.retail.data.repository.RetailModeRepository
-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
-constructor(
- private val repository: RetailModeRepository,
-) : RetailModeInteractor {
- override val isInRetailMode: Boolean
- get() = repository.inRetailMode
-}
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
similarity index 79%
rename from packages/SystemUI/src/com/android/systemui/retail/domain/interactor/RetailModeInteractor.kt
rename to packages/SystemUI/pods/com/android/systemui/retail/domain/interactor/impl/RetailModeInteractorImpl.kt
index eea452c..8dbe562 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 0000000..1aa7729
--- /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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettings.java
rename to 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
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/util/settings/GlobalSettingsImpl.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java
index 7fcabe4..d68501f 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.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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SecureSettings.java
rename to 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
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SecureSettingsImpl.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java
index c296481..211a6f4 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.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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxy.kt
rename to 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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
rename to 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
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/util/kotlin/SettingsSingleThreadBackground.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SettingsSingleThreadBackground.java
index e13981d..5632a36 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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SystemSettings.java
rename to 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
similarity index 97%
rename from packages/SystemUI/src/com/android/systemui/util/settings/SystemSettingsImpl.java
rename to packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java
index e670b2c..1b3f74e 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.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
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/util/settings/UserSettingsProxy.kt
rename to 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 4447dff..b7d3c92 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.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 24dba59..4d77e3e 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.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 @@
// 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 0000000..6bb50f9
--- /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 3c06828..2a9b1b9 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.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 b221d74..827e3ef 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 @@
// ... 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 cb89f28..dfddc08 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 @@
*/
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 @@
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 3dd5ec9..ef5296e 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 @@
"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 c3205af..0defd27 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.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 @@
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 @@
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 @@
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 @@
}
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 c62e323..6536ca0 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 84413d5..c5c8a5e 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 @@
@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 @@
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 d5d4070..52ddb80 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.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 4d0c7ec..207764b 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.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.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 @@
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 @@
"canNotifyAsPackage for uid " + uid);
}
- return areNotificationsEnabledForPackageInt(pkg, uid);
+ return areNotificationsEnabledForPackageInt(uid);
}
/**
@@ -4864,30 +4864,20 @@
}
@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 @@
@Override
public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
- return areNotificationsEnabledForPackageInt(pkg, uid);
+ return areNotificationsEnabledForPackageInt(uid);
}
@Override
@@ -8742,7 +8732,7 @@
}
// blocked apps
- boolean isBlocked = !areNotificationsEnabledForPackageInt(pkg, uid);
+ boolean isBlocked = !areNotificationsEnabledForPackageInt(uid);
synchronized (mNotificationLock) {
isBlocked |= isRecordBlockedLocked(r);
}
@@ -8792,7 +8782,7 @@
}
}
- private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
+ private boolean areNotificationsEnabledForPackageInt(int uid) {
return mPermissionHelper.hasPermission(uid);
}
@@ -9328,7 +9318,7 @@
* 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 9f0b4b0..e6f784c 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.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 @@
}
/**
+ * 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 cfeacdf..ca4f83f 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_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 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 @@
}
/**
+ * @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 76ea0b9..4690e02 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 @@
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 5518bfa..1052c94 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 @@
// 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 @@
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 @@
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 @@
// 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 d221e8c..8ad8786 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 @@
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,26 +9026,77 @@
if (!mHasFeature) {
return false;
}
- CallerIdentity caller;
- if (Flags.setAutoTimeEnabledCoexistence()) {
- caller = getCallerIdentity(who, callerPackageName);
- } else {
- caller = getCallerIdentity(who);
- }
+ CallerIdentity caller = getCallerIdentity(who);
- if (Flags.setAutoTimeEnabledCoexistence()) {
- enforceCanQuery(SET_TIME, caller.getPackageName(), UserHandle.USER_ALL);
- } else {
- Objects.requireNonNull(who, "ComponentName is null");
- Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
- || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(
- caller));
- }
+ 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;
+ }
+
+ 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 {
+ 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();
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
* Set whether auto time zone is enabled on the device.
*/
@Override
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index a5aeaac..24b16b7 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 @@
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 @@
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 40d8dae..8f80004 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 @@
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 19b0343..d0bf02d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -2761,8 +2761,9 @@
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 e2ac22d..4412968 100644
--- a/services/java/com/android/server/flags.aconfig
+++ b/services/java/com/android/server/flags.aconfig
@@ -39,6 +39,14 @@
}
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 eae587b..704c1b8 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.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.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.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 @@
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 @@
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 @@
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 @@
.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 @@
}
@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 @@
@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 @@
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 @@
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 e1b478c..dda060d 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.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 @@
}
@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 4b94e10..020670d 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_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.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 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.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.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 @@
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 ea61ad9..9f5e6d1 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 @@
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 58fb4e1..938e2f8 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 @@
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.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.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 @@
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 @@
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 @@
@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 @@
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 @@
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 @@
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",