diff options
21 files changed, 449 insertions, 70 deletions
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java index 7180c01143a5..a6cd6d511caf 100644 --- a/core/java/android/app/AutomaticZenRule.java +++ b/core/java/android/app/AutomaticZenRule.java @@ -45,6 +45,7 @@ public final class AutomaticZenRule implements Parcelable { private long creationTime; private ZenPolicy mZenPolicy; private boolean mModified = false; + private String mPkg; /** * Creates an automatic zen rule. @@ -123,6 +124,7 @@ public final class AutomaticZenRule implements Parcelable { creationTime = source.readLong(); mZenPolicy = source.readParcelable(null); mModified = source.readInt() == ENABLED; + mPkg = source.readString(); } /** @@ -244,6 +246,20 @@ public final class AutomaticZenRule implements Parcelable { this.configurationActivity = componentName; } + /** + * @hide + */ + public void setPackageName(String pkgName) { + mPkg = pkgName; + } + + /** + * @hide + */ + public String getPackageName() { + return mPkg; + } + @Override public int describeContents() { return 0; @@ -265,6 +281,7 @@ public final class AutomaticZenRule implements Parcelable { dest.writeLong(creationTime); dest.writeParcelable(mZenPolicy, 0); dest.writeInt(mModified ? ENABLED : DISABLED); + dest.writeString(mPkg); } @Override @@ -273,6 +290,7 @@ public final class AutomaticZenRule implements Parcelable { .append("enabled=").append(enabled) .append(",name=").append(name) .append(",interruptionFilter=").append(interruptionFilter) + .append(",pkg=").append(mPkg) .append(",conditionId=").append(conditionId) .append(",owner=").append(owner) .append(",configActivity=").append(configurationActivity) @@ -294,13 +312,14 @@ public final class AutomaticZenRule implements Parcelable { && Objects.equals(other.owner, owner) && Objects.equals(other.mZenPolicy, mZenPolicy) && Objects.equals(other.configurationActivity, configurationActivity) + && Objects.equals(other.mPkg, mPkg) && other.creationTime == creationTime; } @Override public int hashCode() { return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, - configurationActivity, mZenPolicy, mModified, creationTime); + configurationActivity, mZenPolicy, mModified, creationTime, mPkg); } public static final @android.annotation.NonNull Parcelable.Creator<AutomaticZenRule> CREATOR diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index e57738fbbfdd..3661876f8f5a 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -182,7 +182,7 @@ interface INotificationManager void setNotificationPolicyAccessGrantedForUser(String pkg, int userId, boolean granted); AutomaticZenRule getAutomaticZenRule(String id); List<ZenModeConfig.ZenRule> getZenRules(); - String addAutomaticZenRule(in AutomaticZenRule automaticZenRule); + String addAutomaticZenRule(in AutomaticZenRule automaticZenRule, String pkg); boolean updateAutomaticZenRule(String id, in AutomaticZenRule automaticZenRule); boolean removeAutomaticZenRule(String id); boolean removeAutomaticZenRules(String packageName); diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index 69ec831b5d1d..0f569f6473a8 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -61,8 +61,13 @@ public final class NotificationChannel implements Parcelable { /** * The maximum length for text fields in a NotificationChannel. Fields will be truncated at this * limit. + * @hide */ - private static final int MAX_TEXT_LENGTH = 1000; + public static final int MAX_TEXT_LENGTH = 1000; + /** + * @hide + */ + public static final int MAX_VIBRATION_LENGTH = 1000; private static final String TAG_CHANNEL = "channel"; private static final String ATT_NAME = "name"; @@ -195,17 +200,17 @@ public final class NotificationChannel implements Parcelable { */ protected NotificationChannel(Parcel in) { if (in.readByte() != 0) { - mId = in.readString(); + mId = getTrimmedString(in.readString()); } else { mId = null; } if (in.readByte() != 0) { - mName = in.readString(); + mName = getTrimmedString(in.readString()); } else { mName = null; } if (in.readByte() != 0) { - mDesc = in.readString(); + mDesc = getTrimmedString(in.readString()); } else { mDesc = null; } @@ -214,18 +219,22 @@ public final class NotificationChannel implements Parcelable { mLockscreenVisibility = in.readInt(); if (in.readByte() != 0) { mSound = Uri.CREATOR.createFromParcel(in); + mSound = Uri.parse(getTrimmedString(mSound.toString())); } else { mSound = null; } mLights = in.readByte() != 0; mVibration = in.createLongArray(); + if (mVibration != null && mVibration.length > MAX_VIBRATION_LENGTH) { + mVibration = Arrays.copyOf(mVibration, MAX_VIBRATION_LENGTH); + } mUserLockedFields = in.readInt(); mFgServiceShown = in.readByte() != 0; mVibrationEnabled = in.readByte() != 0; mShowBadge = in.readByte() != 0; mDeleted = in.readByte() != 0; if (in.readByte() != 0) { - mGroup = in.readString(); + mGroup = getTrimmedString(in.readString()); } else { mGroup = null; } diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java index a8ee414cac0a..85de55e6dd2e 100644 --- a/core/java/android/app/NotificationChannelGroup.java +++ b/core/java/android/app/NotificationChannelGroup.java @@ -42,8 +42,9 @@ public final class NotificationChannelGroup implements Parcelable { /** * The maximum length for text fields in a NotificationChannelGroup. Fields will be truncated at * this limit. + * @hide */ - private static final int MAX_TEXT_LENGTH = 1000; + public static final int MAX_TEXT_LENGTH = 1000; private static final String TAG_GROUP = "channelGroup"; private static final String ATT_NAME = "name"; @@ -89,13 +90,14 @@ public final class NotificationChannelGroup implements Parcelable { */ protected NotificationChannelGroup(Parcel in) { if (in.readByte() != 0) { - mId = in.readString(); + mId = getTrimmedString(in.readString()); } else { mId = null; } mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); + mName = getTrimmedString(mName.toString()); if (in.readByte() != 0) { - mDescription = in.readString(); + mDescription = getTrimmedString(in.readString()); } else { mDescription = null; } @@ -119,7 +121,7 @@ public final class NotificationChannelGroup implements Parcelable { } else { dest.writeByte((byte) 0); } - TextUtils.writeToParcel(mName, dest, flags); + TextUtils.writeToParcel(mName.toString(), dest, flags); if (mDescription != null) { dest.writeByte((byte) 1); dest.writeString(mDescription); diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index dd39376f80ca..c84490a83d3f 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -923,10 +923,12 @@ public class NotificationManager { List<ZenModeConfig.ZenRule> rules = service.getZenRules(); Map<String, AutomaticZenRule> ruleMap = new HashMap<>(); for (ZenModeConfig.ZenRule rule : rules) { - ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component, + AutomaticZenRule azr = new AutomaticZenRule(rule.name, rule.component, rule.configurationActivity, rule.conditionId, rule.zenPolicy, zenModeToInterruptionFilter(rule.zenMode), rule.enabled, - rule.creationTime)); + rule.creationTime); + azr.setPackageName(rule.pkg); + ruleMap.put(rule.id, azr); } return ruleMap; } catch (RemoteException e) { @@ -967,7 +969,7 @@ public class NotificationManager { public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) { INotificationManager service = getService(); try { - return service.addAutomaticZenRule(automaticZenRule); + return service.addAutomaticZenRule(automaticZenRule, mContext.getPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 3e880f03b222..84d9743eec9e 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -1011,4 +1011,10 @@ public abstract class PackageManagerInternal { * that b/141413692 is not reproducible on Q. */ public abstract void userRemovedForTest(); + + /** + * Get installed SDK version of the package + * @param pkg package for which to retrieve the installed sdk version + */ + public abstract int getInstalledSdkVersion(PackageParser.Package pkg); } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 93bcdbffd133..e473417ed828 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -43,6 +43,7 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.R; +import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -151,6 +152,7 @@ public class ZenModeConfig implements Parcelable { private static final String RULE_ATT_ENABLED = "enabled"; private static final String RULE_ATT_SNOOZING = "snoozing"; private static final String RULE_ATT_NAME = "name"; + private static final String RULE_ATT_PKG = "pkg"; private static final String RULE_ATT_COMPONENT = "component"; private static final String RULE_ATT_CONFIG_ACTIVITY = "configActivity"; private static final String RULE_ATT_ZEN = "zen"; @@ -644,11 +646,11 @@ public class ZenModeConfig implements Parcelable { rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID); rt.component = safeComponentName(parser, RULE_ATT_COMPONENT); rt.configurationActivity = safeComponentName(parser, RULE_ATT_CONFIG_ACTIVITY); - rt.pkg = (rt.component != null) - ? rt.component.getPackageName() - : (rt.configurationActivity != null) - ? rt.configurationActivity.getPackageName() - : null; + rt.pkg = XmlUtils.readStringAttribute(parser, RULE_ATT_PKG); + if (rt.pkg == null) { + // backfill from component, if present. configActivity is not safe to backfill from + rt.pkg = rt.component != null ? rt.component.getPackageName() : null; + } rt.creationTime = safeLong(parser, RULE_ATT_CREATION_TIME, 0); rt.enabler = parser.getAttributeValue(null, RULE_ATT_ENABLER); rt.condition = readConditionXml(parser); @@ -670,6 +672,9 @@ public class ZenModeConfig implements Parcelable { out.attribute(null, RULE_ATT_NAME, rule.name); } out.attribute(null, RULE_ATT_ZEN, Integer.toString(rule.zenMode)); + if (rule.pkg != null) { + out.attribute(null, RULE_ATT_PKG, rule.pkg); + } if (rule.component != null) { out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString()); } diff --git a/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java new file mode 100644 index 000000000000..2a3da05eabb3 --- /dev/null +++ b/core/tests/coretests/src/android/app/NotificationChannelGroupTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import static junit.framework.TestCase.assertEquals; + +import android.os.Parcel; +import android.test.AndroidTestCase; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.google.common.base.Strings; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NotificationChannelGroupTest { + private final String CLASS = "android.app.NotificationChannelGroup"; + + @Test + public void testLongStringFields() { + NotificationChannelGroup group = new NotificationChannelGroup("my_group_01", "groupName"); + + try { + String longString = Strings.repeat("A", 65536); + Field mName = Class.forName(CLASS).getDeclaredField("mName"); + mName.setAccessible(true); + mName.set(group, longString); + Field mId = Class.forName(CLASS).getDeclaredField("mId"); + mId.setAccessible(true); + mId.set(group, longString); + Field mDescription = Class.forName(CLASS).getDeclaredField("mDescription"); + mDescription.setAccessible(true); + mDescription.set(group, longString); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + Parcel parcel = Parcel.obtain(); + group.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + NotificationChannelGroup fromParcel = + NotificationChannelGroup.CREATOR.createFromParcel(parcel); + assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getId().length()); + assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, fromParcel.getName().length()); + assertEquals(NotificationChannelGroup.MAX_TEXT_LENGTH, + fromParcel.getDescription().length()); + } +} diff --git a/core/tests/coretests/src/android/app/NotificationChannelTest.java b/core/tests/coretests/src/android/app/NotificationChannelTest.java new file mode 100644 index 000000000000..d8be502e6db6 --- /dev/null +++ b/core/tests/coretests/src/android/app/NotificationChannelTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import static junit.framework.TestCase.assertEquals; + +import android.net.Uri; +import android.os.Parcel; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.google.common.base.Strings; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class NotificationChannelTest { + private final String CLASS = "android.app.NotificationChannel"; + + @Test + public void testLongStringFields() { + NotificationChannel channel = new NotificationChannel("id", "name", 3); + + try { + String longString = Strings.repeat("A", 65536); + Field mName = Class.forName(CLASS).getDeclaredField("mName"); + mName.setAccessible(true); + mName.set(channel, longString); + Field mId = Class.forName(CLASS).getDeclaredField("mId"); + mId.setAccessible(true); + mId.set(channel, longString); + Field mDesc = Class.forName(CLASS).getDeclaredField("mDesc"); + mDesc.setAccessible(true); + mDesc.set(channel, longString); + Field mParentId = Class.forName(CLASS).getDeclaredField("mParentId"); + mParentId.setAccessible(true); + mParentId.set(channel, longString); + Field mGroup = Class.forName(CLASS).getDeclaredField("mGroup"); + mGroup.setAccessible(true); + mGroup.set(channel, longString); + Field mConversationId = Class.forName(CLASS).getDeclaredField("mConversationId"); + mConversationId.setAccessible(true); + mConversationId.set(channel, longString); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + Parcel parcel = Parcel.obtain(); + channel.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel); + assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getId().length()); + assertEquals(NotificationChannel.MAX_TEXT_LENGTH, fromParcel.getName().length()); + assertEquals(NotificationChannel.MAX_TEXT_LENGTH, + fromParcel.getDescription().length()); + assertEquals(NotificationChannel.MAX_TEXT_LENGTH, + fromParcel.getGroup().length()); + } + + @Test + public void testLongAlertFields() { + NotificationChannel channel = new NotificationChannel("id", "name", 3); + + channel.setSound(Uri.parse("content://" + Strings.repeat("A",65536)), + Notification.AUDIO_ATTRIBUTES_DEFAULT); + channel.setVibrationPattern(new long[65550/2]); + + Parcel parcel = Parcel.obtain(); + channel.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + NotificationChannel fromParcel = NotificationChannel.CREATOR.createFromParcel(parcel); + assertEquals(NotificationChannel.MAX_VIBRATION_LENGTH, + fromParcel.getVibrationPattern().length); + assertEquals(NotificationChannel.MAX_TEXT_LENGTH, + fromParcel.getSound().toString().length()); + } +} diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 46e7b211fd6e..5631a6813ae0 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3609,7 +3609,7 @@ public class NotificationManagerService extends SystemService { } @Override - public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) { + public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg) { Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null"); Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null"); if (automaticZenRule.getOwner() == null @@ -3618,6 +3618,7 @@ public class NotificationManagerService extends SystemService { "Rule must have a conditionproviderservice and/or configuration activity"); } Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null"); + checkCallerIsSameApp(pkg); if (automaticZenRule.getZenPolicy() != null && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) { throw new IllegalArgumentException("ZenPolicy is only applicable to " @@ -3625,7 +3626,7 @@ public class NotificationManagerService extends SystemService { } enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule"); - return mZenModeHelper.addAutomaticZenRule(automaticZenRule, + return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule, "addAutomaticZenRule"); } @@ -5921,7 +5922,8 @@ public class NotificationManagerService extends SystemService { boolean sentAccessibilityEvent = false; // If the notification will appear in the status bar, it should send an accessibility // event - if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) { + if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN + && isNotificationForCurrentUser(record)) { sendAccessibilityEvent(record); sentAccessibilityEvent = true; } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 48f76e18fac1..de6a8b09cc96 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -289,7 +289,8 @@ public class ZenModeHelper { return null; } - public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) { + public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule, + String reason) { if (!isSystemRule(automaticZenRule)) { PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner()); if (component == null) { @@ -306,7 +307,8 @@ public class ZenModeHelper { int newRuleInstanceCount = getCurrentInstanceCount(automaticZenRule.getOwner()) + getCurrentInstanceCount(automaticZenRule.getConfigurationActivity()) + 1; - if (newRuleInstanceCount > RULE_LIMIT_PER_PACKAGE + int newPackageRuleCount = getPackageRuleCount(pkg) + 1; + if (newPackageRuleCount > RULE_LIMIT_PER_PACKAGE || (ruleInstanceLimit > 0 && ruleInstanceLimit < newRuleInstanceCount)) { throw new IllegalArgumentException("Rule instance limit exceeded"); } @@ -322,7 +324,7 @@ public class ZenModeHelper { } newConfig = mConfig.copy(); ZenRule rule = new ZenRule(); - populateZenRule(automaticZenRule, rule, true); + populateZenRule(pkg, automaticZenRule, rule, true); newConfig.automaticRules.put(rule.id, rule); if (setConfigLocked(newConfig, reason, rule.component, true)) { return rule.id; @@ -352,7 +354,7 @@ public class ZenModeHelper { "Cannot update rules not owned by your condition provider"); } } - populateZenRule(automaticZenRule, rule, false); + populateZenRule(rule.pkg, automaticZenRule, rule, false); return setConfigLocked(newConfig, reason, rule.component, true); } } @@ -382,7 +384,14 @@ public class ZenModeHelper { newConfig = mConfig.copy(); for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) { ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i)); - if (rule.pkg.equals(packageName) && canManageAutomaticZenRule(rule)) { + String pkg = rule.pkg != null + ? rule.pkg + : (rule.component != null) + ? rule.component.getPackageName() + : (rule.configurationActivity != null) + ? rule.configurationActivity.getPackageName() + : null; + if (Objects.equals(pkg, packageName) && canManageAutomaticZenRule(rule)) { newConfig.automaticRules.removeAt(i); } } @@ -465,6 +474,23 @@ public class ZenModeHelper { return count; } + // Equivalent method to getCurrentInstanceCount, but for all rules associated with a specific + // package rather than a condition provider service or activity. + private int getPackageRuleCount(String pkg) { + if (pkg == null) { + return 0; + } + int count = 0; + synchronized (mConfig) { + for (ZenRule rule : mConfig.automaticRules.values()) { + if (pkg.equals(rule.pkg)) { + count++; + } + } + } + return count; + } + public boolean canManageAutomaticZenRule(ZenRule rule) { final int callingUid = Binder.getCallingUid(); if (callingUid == 0 || callingUid == Process.SYSTEM_UID) { @@ -546,15 +572,14 @@ public class ZenModeHelper { return null; } - private void populateZenRule(AutomaticZenRule automaticZenRule, ZenRule rule, boolean isNew) { + private void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule, + boolean isNew) { if (isNew) { rule.id = ZenModeConfig.newRuleId(); rule.creationTime = System.currentTimeMillis(); rule.component = automaticZenRule.getOwner(); rule.configurationActivity = automaticZenRule.getConfigurationActivity(); - rule.pkg = (rule.component != null) - ? rule.component.getPackageName() - : rule.configurationActivity.getPackageName(); + rule.pkg = pkg; } if (rule.enabled != automaticZenRule.isEnabled()) { @@ -571,10 +596,13 @@ public class ZenModeHelper { } protected AutomaticZenRule createAutomaticZenRule(ZenRule rule) { - return new AutomaticZenRule(rule.name, rule.component, rule.configurationActivity, + AutomaticZenRule azr = new AutomaticZenRule(rule.name, rule.component, + rule.configurationActivity, rule.conditionId, rule.zenPolicy, NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled, rule.creationTime); + azr.setPackageName(rule.pkg); + return azr; } public void setManualZenMode(int zenMode, Uri conditionId, String caller, String reason) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 48b230d80a75..5161b9f4614d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -25163,6 +25163,11 @@ public class PackageManagerService extends IPackageManager.Stub public void userRemovedForTest() { mBlockDeleteOnUserRemoveForTest.open(); } + + @Override + public int getInstalledSdkVersion(PackageParser.Package pkg) { + return PackageManagerService.this.getSettingsVersionForPackage(pkg).sdkVersion; + } } @GuardedBy("mPackages") diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 128b7f775117..c7fca39de562 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -1096,21 +1096,27 @@ public class PermissionManagerService { // or has updated its target SDK and AR is no longer implicit to it. // This is a compatibility workaround for apps when AR permission was // split in Q. - int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size(); - for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { - PermissionManager.SplitPermissionInfo sp = - PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum); - String splitPermName = sp.getSplitPermission(); - if (sp.getNewPermissions().contains(permName) - && origPermissions.hasInstallPermission(splitPermName)) { - upgradedActivityRecognitionPermission = splitPermName; - newImplicitPermissions.add(permName); + // b/210065877: Check that the installed version is pre Q to auto-grant in + // case of OS update + if (mPackageManagerInt.getInstalledSdkVersion(pkg) + < Build.VERSION_CODES.Q) { + int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size(); + for (int splitPermNum = 0; splitPermNum < numSplitPerms; + splitPermNum++) { + PermissionManager.SplitPermissionInfo sp = + PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum); + String splitPermName = sp.getSplitPermission(); + if (sp.getNewPermissions().contains(permName) + && origPermissions.hasInstallPermission(splitPermName)) { + upgradedActivityRecognitionPermission = splitPermName; + newImplicitPermissions.add(permName); - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, permName + " is newly added for " - + pkg.packageName); + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, permName + " is newly added for " + + pkg.packageName); + } + break; } - break; } } } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 81fbcbf093c0..75af02b79644 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -4308,7 +4308,23 @@ class ActivityStack extends ConfigurationContainer { parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK || parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP || (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) { - parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); + boolean abort; + try { + final int callingPid = srec.app != null ? srec.app.getPid() : 0; + abort = !mStackSupervisor.checkStartAnyActivityPermission(destIntent, + parent.info, null /* resultWho */, -1 /* requestCode */, callingPid, + callingUid, srec.info.packageName, false /* ignoreTargetSecurity */, + false /* launchingInTask */, srec.app, null /* resultRecord */, + null /* resultRootTask */); + } catch (SecurityException e) { + abort = true; + } + if (abort) { + android.util.EventLog.writeEvent(0x534e4554, "238605611", callingUid, ""); + foundParentInTask = false; + } else { + parent.deliverNewIntentLocked(callingUid, destIntent, srec.packageName); + } } else { try { ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 8a5f52f8c453..b9ff000a2129 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -25,6 +25,7 @@ import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PER import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import static android.view.WindowManager.LayoutParams.TYPE_DREAM; import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; +import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; @@ -317,13 +318,17 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } /** - * Returns true if the callingUid has any non-toast window currently visible to the user. - * Also ignores TYPE_APPLICATION_STARTING, since those windows don't belong to apps. + * Returns {@code true} if the callingUid has any non-toast window currently visible to the + * user. Also ignores {@link android.view.WindowManager.LayoutParams#TYPE_APPLICATION_STARTING}, + * and{@link android.view.WindowManager.LayoutParams#TYPE_PRIVATE_PRESENTATION}, as they + * should not count towards the apps visibility + * @see WindowState#isNonToastOrStartingOrPrivatePresentation() */ boolean isAnyNonToastWindowVisibleForUid(int callingUid) { return forAllWindows(w -> w.getOwningUid() == callingUid && w.mAttrs.type != TYPE_TOAST - && w.mAttrs.type != TYPE_APPLICATION_STARTING && w.isVisibleNow(), + && w.mAttrs.type != TYPE_APPLICATION_STARTING + && w.mAttrs.type != TYPE_PRIVATE_PRESENTATION && w.isVisibleNow(), true /* traverseTopToBottom */); } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java index d55d74e09ec0..d4195dbf2805 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java @@ -1221,6 +1221,21 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase { } @Test + public void testA11yCrossUserEventNotSent() throws Exception { + final Notification n = new Builder(getContext(), "test") + .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); + int userId = mUser.getIdentifier() + 1; + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid, + mPid, n, UserHandle.of(userId), null, System.currentTimeMillis()); + NotificationRecord r = new NotificationRecord(getContext(), sbn, + new NotificationChannel("test", "test", IMPORTANCE_HIGH)); + + mService.buzzBeepBlinkLocked(r); + + verify(mAccessibilityService, never()).sendAccessibilityEvent(any(), anyInt()); + } + + @Test public void testLightsScreenOn() { mService.mScreenOn = true; NotificationRecord r = getLightsNotification(); 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 9f24bfd2707f..85a55600f445 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -5270,7 +5270,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); try { - mBinderService.addAutomaticZenRule(rule); + mBinderService.addAutomaticZenRule(rule, mContext.getPackageName()); fail("Zen policy only applies to priority only mode"); } catch (IllegalArgumentException e) { // yay @@ -5278,11 +5278,11 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); - mBinderService.addAutomaticZenRule(rule); + mBinderService.addAutomaticZenRule(rule, mContext.getPackageName()); rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); - mBinderService.addAutomaticZenRule(rule); + mBinderService.addAutomaticZenRule(rule, mContext.getPackageName()); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java index dcab78ede287..6401987448e5 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java @@ -158,7 +158,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); rule.configurationActivity = new ComponentName("a", "a"); - rule.component = new ComponentName("a", "b"); + rule.component = new ComponentName("b", "b"); rule.conditionId = new Uri.Builder().scheme("hello").build(); rule.condition = new Condition(rule.conditionId, "", Condition.STATE_TRUE); rule.enabled = true; @@ -168,6 +168,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { rule.modified = true; rule.name = "name"; rule.snoozing = true; + rule.pkg = "b"; XmlSerializer out = new FastXmlSerializer(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -183,8 +184,7 @@ public class ZenModeConfigTest extends UiServiceTestCase { new ByteArrayInputStream(baos.toByteArray())), null); parser.nextTag(); ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser); - // read from backing component - assertEquals("a", fromXml.pkg); + assertEquals("b", fromXml.pkg); // always resets on reboot assertFalse(fromXml.snoozing); //should all match original @@ -200,6 +200,55 @@ public class ZenModeConfigTest extends UiServiceTestCase { assertEquals(rule.zenMode, fromXml.zenMode); } + @Test + public void testRuleXml_pkg_component() throws Exception { + String tag = "tag"; + + ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); + rule.configurationActivity = new ComponentName("a", "a"); + rule.component = new ComponentName("b", "b"); + + XmlSerializer out = new FastXmlSerializer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + out.setOutput(new BufferedOutputStream(baos), "utf-8"); + out.startDocument(null, true); + out.startTag(null, tag); + ZenModeConfig.writeRuleXml(rule, out); + out.endTag(null, tag); + out.endDocument(); + + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), null); + parser.nextTag(); + ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser); + assertEquals("b", fromXml.pkg); + } + + @Test + public void testRuleXml_pkg_configActivity() throws Exception { + String tag = "tag"; + + ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule(); + rule.configurationActivity = new ComponentName("a", "a"); + + XmlSerializer out = new FastXmlSerializer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + out.setOutput(new BufferedOutputStream(baos), "utf-8"); + out.startDocument(null, true); + out.startTag(null, tag); + ZenModeConfig.writeRuleXml(rule, out); + out.endTag(null, tag); + out.endDocument(); + + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream( + new ByteArrayInputStream(baos.toByteArray())), null); + parser.nextTag(); + ZenModeConfig.ZenRule fromXml = ZenModeConfig.readRuleXml(parser); + assertNull(fromXml.pkg); + } + private ZenModeConfig getMutedNotificationsConfig() { ZenModeConfig config = new ZenModeConfig(); // Allow alarms, media, and system 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 cac6f0994bcd..7c30aef30e11 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -1353,7 +1353,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { new ComponentName("android", "ScheduleConditionProvider"), ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule(zenRule, "test"); + String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); assertTrue(id != null); ZenModeConfig.ZenRule ruleInConfig = mZenModeHelperSpy.mConfig.automaticRules.get(id); @@ -1377,7 +1377,9 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(si), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule(zenRule, "test"); + // We need the package name to be something that's not "android" so there aren't any + // existing rules under that package. + String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); assertNotNull(id); } try { @@ -1387,7 +1389,37 @@ public class ZenModeHelperTest extends UiServiceTestCase { ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), new ZenPolicy.Builder().build(), NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); - String id = mZenModeHelperSpy.addAutomaticZenRule(zenRule, "test"); + String id = mZenModeHelperSpy.addAutomaticZenRule("android", zenRule, "test"); + fail("allowed too many rules to be created"); + } catch (IllegalArgumentException e) { + // yay + } + } + + @Test + public void testAddAutomaticZenRule_beyondSystemLimit_differentComponents() { + // Make sure the system limit is enforced per-package even with different component provider + // names. + for (int i = 0; i < RULE_LIMIT_PER_PACKAGE; i++) { + ScheduleInfo si = new ScheduleInfo(); + si.startHour = i; + AutomaticZenRule zenRule = new AutomaticZenRule("name" + i, + null, + new ComponentName("android", "ScheduleConditionProvider" + i), + ZenModeConfig.toScheduleConditionId(si), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); + assertNotNull(id); + } + try { + AutomaticZenRule zenRule = new AutomaticZenRule("name", + null, + new ComponentName("android", "ScheduleConditionProviderFinal"), + ZenModeConfig.toScheduleConditionId(new ScheduleInfo()), + new ZenPolicy.Builder().build(), + NotificationManager.INTERRUPTION_FILTER_PRIORITY, true); + String id = mZenModeHelperSpy.addAutomaticZenRule("pkgname", zenRule, "test"); fail("allowed too many rules to be created"); } catch (IllegalArgumentException e) { // yay diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index af5d50d03105..f932c5596c7b 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -953,7 +953,7 @@ public class TelecomManager { try { if (isServiceConnected()) { return getTelecomService().getPhoneAccountsSupportingScheme(uriScheme, - mContext.getOpPackageName()); + mContext.getOpPackageName()).getList(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getPhoneAccountsSupportingScheme", e); @@ -995,7 +995,8 @@ public class TelecomManager { public List<PhoneAccountHandle> getSelfManagedPhoneAccounts() { try { if (isServiceConnected()) { - return getTelecomService().getSelfManagedPhoneAccounts(mContext.getOpPackageName()); + return getTelecomService() + .getSelfManagedPhoneAccounts(mContext.getOpPackageName()).getList(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getSelfManagedPhoneAccounts()", e); @@ -1017,7 +1018,7 @@ public class TelecomManager { try { if (isServiceConnected()) { return getTelecomService().getCallCapablePhoneAccounts( - includeDisabledAccounts, mContext.getOpPackageName()); + includeDisabledAccounts, mContext.getOpPackageName()).getList(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" + @@ -1037,7 +1038,8 @@ public class TelecomManager { public List<PhoneAccountHandle> getPhoneAccountsForPackage() { try { if (isServiceConnected()) { - return getTelecomService().getPhoneAccountsForPackage(mContext.getPackageName()); + return getTelecomService() + .getPhoneAccountsForPackage(mContext.getPackageName()).getList(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getPhoneAccountsForPackage", e); @@ -1091,7 +1093,7 @@ public class TelecomManager { public List<PhoneAccount> getAllPhoneAccounts() { try { if (isServiceConnected()) { - return getTelecomService().getAllPhoneAccounts(); + return getTelecomService().getAllPhoneAccounts().getList(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getAllPhoneAccounts", e); @@ -1109,7 +1111,7 @@ public class TelecomManager { public List<PhoneAccountHandle> getAllPhoneAccountHandles() { try { if (isServiceConnected()) { - return getTelecomService().getAllPhoneAccountHandles(); + return getTelecomService().getAllPhoneAccountHandles().getList(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getAllPhoneAccountHandles", e); diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index 4fcda4d00883..10c49ecce1ea 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -23,6 +23,7 @@ import android.telecom.PhoneAccountHandle; import android.net.Uri; import android.os.Bundle; import android.telecom.PhoneAccount; +import android.content.pm.ParceledListSlice; /** * Interface used to interact with Telecom. Mostly this is used by TelephonyManager for passing @@ -55,24 +56,24 @@ interface ITelecomService { /** * @see TelecomServiceImpl#getCallCapablePhoneAccounts */ - List<PhoneAccountHandle> getCallCapablePhoneAccounts( + ParceledListSlice getCallCapablePhoneAccounts( boolean includeDisabledAccounts, String callingPackage); /** * @see TelecomServiceImpl#getSelfManagedPhoneAccounts */ - List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage); + ParceledListSlice getSelfManagedPhoneAccounts(String callingPackage); /** * @see TelecomManager#getPhoneAccountsSupportingScheme */ - List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(in String uriScheme, + ParceledListSlice getPhoneAccountsSupportingScheme(in String uriScheme, String callingPackage); /** * @see TelecomManager#getPhoneAccountsForPackage */ - List<PhoneAccountHandle> getPhoneAccountsForPackage(in String packageName); + ParceledListSlice getPhoneAccountsForPackage(in String packageName); /** * @see TelecomManager#getPhoneAccount @@ -87,12 +88,12 @@ interface ITelecomService { /** * @see TelecomManager#getAllPhoneAccounts */ - List<PhoneAccount> getAllPhoneAccounts(); + ParceledListSlice getAllPhoneAccounts(); /** * @see TelecomManager#getAllPhoneAccountHandles */ - List<PhoneAccountHandle> getAllPhoneAccountHandles(); + ParceledListSlice getAllPhoneAccountHandles(); /** * @see TelecomServiceImpl#getSimCallManager |