Merge "Extract test utilities for ConnectivityService" am: b7d270a73e am: 62857556a4 am: 6d34ffb4e6
am: 111a3c1883
Change-Id: Iedca1a5c9892993e1ab8643311912ce9553138e5
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index e57738f..9f51db8 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -108,6 +108,8 @@
ParceledListSlice getNotificationChannelsBypassingDnd(String pkg, int userId);
boolean isPackagePaused(String pkg);
+ void silenceNotificationSound();
+
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
@UnsupportedAppUsage
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index dd39376..b13a34f 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1095,6 +1095,25 @@
}
/**
+ * Silences the current notification sound, if ones currently playing.
+ * <p>
+ * It is intended to handle use-cases such as silencing a ringing call
+ * when the user presses the volume button during ringing.
+ * <p>
+ * If this method is called prior to when the notification begins playing, the sound will not be
+ * silenced. As such it is not intended as a means to avoid playing of a sound.
+ * @hide
+ */
+ public void silenceNotificationSound() {
+ INotificationManager service = getService();
+ try {
+ service.silenceNotificationSound();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns whether notifications from this package are temporarily hidden. This
* could be done because the package was marked as distracting to the user via
* {@code PackageManager#setDistractingPackageRestrictions(String[], int)} or because the
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 5ac13d8..a0170da 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -206,10 +206,16 @@
continue;
}
- if (filterTags == null || Arrays.binarySearch(filterTags,
- CameraMetadataNative.getTag(keyName, vendorId)) >= 0) {
+
+ if (filterTags != null && Arrays.binarySearch(filterTags,
+ CameraMetadataNative.getTag(keyName, vendorId)) < 0) {
+ // ignore vendor keys not in filterTags
+ continue;
+ }
+ if (instance == null || instance.getProtected(k) != null) {
keyList.add(k);
}
+
}
}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index 344d7ef..8799e3d 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -26,6 +26,8 @@
import android.util.Base64;
import android.util.Xml;
+import libcore.util.HexEncoding;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -396,16 +398,7 @@
final int N = val.length;
out.attribute(null, "num", Integer.toString(N));
- StringBuilder sb = new StringBuilder(val.length*2);
- for (int i=0; i<N; i++) {
- int b = val[i];
- int h = (b >> 4) & 0x0f;
- sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h)));
- h = b & 0x0f;
- sb.append((char)(h >= 10 ? ('a'+h-10) : ('0'+h)));
- }
-
- out.text(sb.toString());
+ out.text(HexEncoding.encodeToString(val).toLowerCase());
out.endTag(null, "byte-array");
}
@@ -1032,7 +1025,9 @@
"Not a number in num attribute in byte-array");
}
- byte[] array = new byte[num];
+ // 0 len byte array does not have a text in the XML tag. So, initialize to 0 len array.
+ // For all other array lens, HexEncoding.decode() below overrides the array.
+ byte[] array = new byte[0];
int eventType = parser.getEventType();
do {
@@ -1043,16 +1038,7 @@
throw new XmlPullParserException(
"Invalid value found in byte-array: " + values);
}
- // This is ugly, but keeping it to mirror the logic in #writeByteArrayXml.
- for (int i = 0; i < num; i ++) {
- char nibbleHighChar = values.charAt(2 * i);
- char nibbleLowChar = values.charAt(2 * i + 1);
- int nibbleHigh = nibbleHighChar > 'a' ? (nibbleHighChar - 'a' + 10)
- : (nibbleHighChar - '0');
- int nibbleLow = nibbleLowChar > 'a' ? (nibbleLowChar - 'a' + 10)
- : (nibbleLowChar - '0');
- array[i] = (byte) ((nibbleHigh & 0x0F) << 4 | (nibbleLow & 0x0F));
- }
+ array = HexEncoding.decode(values);
}
} else if (eventType == parser.END_TAG) {
if (parser.getName().equals(endTag)) {
diff --git a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
index 2596ece..27f3596 100644
--- a/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
@@ -16,13 +16,22 @@
package com.android.internal.util;
+import static org.junit.Assert.assertArrayEquals;
+
+import android.util.Xml;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
+
import junit.framework.TestCase;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
public class XmlUtilsTest extends TestCase {
// https://code.google.com/p/android/issues/detail?id=63717
@@ -38,4 +47,23 @@
assertEquals("nullValue", deserialized.get(null));
assertEquals("fooValue", deserialized.get("foo"));
}
+
+ public void testreadWriteXmlByteArrayValue() throws Exception {
+ byte[] testByteArray = {0x1 , 0xa, 0xb, 0x9, 0x34, (byte) 0xaa, (byte) 0xba, (byte) 0x99};
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(baos, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ XmlUtils.writeValueXml(testByteArray, "testByteArray", serializer);
+ serializer.endDocument();
+
+ InputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ XmlPullParser pullParser = Xml.newPullParser();
+ pullParser.setInput(bais, StandardCharsets.UTF_8.name());
+ String[] name = new String[1];
+ byte[] testByteArrayDeserialized = (byte[]) XmlUtils.readValueXml(pullParser, name);
+ assertEquals("testByteArray", name[0]);
+ assertArrayEquals(testByteArray, testByteArrayDeserialized);
+ }
}
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index cfcba76..9e81dda 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -126,7 +126,7 @@
Condition mCondition;
std::deque<wp<Surface>> mQueue;
- static const nsecs_t kWaitDuration = 20000000; // 20 ms
+ static const nsecs_t kWaitDuration = 500000000; // 500 ms
};
sp<DetachThread> mThread;
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bef1fc2..be815e1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -385,22 +385,16 @@
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
- <dimen name="volume_dialog_panel_transparent_padding_right">8dp</dimen>
+ <dimen name="volume_dialog_panel_transparent_padding_right">4dp</dimen>
<dimen name="volume_dialog_panel_transparent_padding">20dp</dimen>
<dimen name="volume_dialog_stream_padding">8dp</dimen>
- <!-- the amount the volume panel should be offset at the end from the view next to it (or
- the screen edge, in portrait-->
- <dimen name="volume_dialog_base_margin">8dp</dimen>
-
<dimen name="volume_dialog_panel_width">64dp</dimen>
<dimen name="volume_dialog_slider_height">116dp</dimen>
- <dimen name="volume_dialog_row_height">252dp</dimen>
-
<dimen name="volume_dialog_ringer_size">64dp</dimen>
<dimen name="volume_dialog_ringer_icon_padding">20dp</dimen>
@@ -417,8 +411,6 @@
<dimen name="volume_dialog_row_margin_bottom">8dp</dimen>
- <dimen name="volume_dialog_settings_icon_size">16dp</dimen>
-
<dimen name="volume_dialog_elevation">9dp</dimen>
<dimen name="volume_tool_tip_right_margin">76dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7feacb4..fab7242 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -958,6 +958,9 @@
<!-- Message shown when lock screen is tapped or face authentication fails. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to open</string>
+ <!-- Message shown when face authentication fails and the pin pad is visible. [CHAR LIMIT=60] -->
+ <string name="keyguard_retry">Swipe up to try again</string>
+
<!-- Text on keyguard screen and in Quick Settings footer indicating that the device is enterprise-managed by a Device Owner [CHAR LIMIT=60] -->
<string name="do_disclosure_generic">This device is managed by your organization</string>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 328116d..13fc702 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -236,7 +236,8 @@
@Override
public void onAnimationCanceled(boolean deferredWithScreenshot) {
- animationHandler.onAnimationCanceled(deferredWithScreenshot);
+ animationHandler.onAnimationCanceled(
+ deferredWithScreenshot ? new ThumbnailData() : null);
}
};
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index 5850fda..579858a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -18,6 +18,8 @@
import android.graphics.Rect;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
public interface RecentsAnimationListener {
/**
@@ -29,5 +31,5 @@
/**
* Called when the animation into Recents was canceled. This call is made on the binder thread.
*/
- void onAnimationCanceled(boolean deferredWithScreenshot);
+ void onAnimationCanceled(ThumbnailData thumbnailData);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 109f270..8f7070e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -844,11 +844,6 @@
getCurrentUser());
}
- // The face timeout message is not very actionable, let's ask the user to
- // manually retry.
- if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
- errString = mContext.getString(R.string.keyguard_unlock);
- }
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 20069ea..4de42cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -40,8 +40,10 @@
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
+import com.android.systemui.plugins.qs.QSIconView;
import com.android.systemui.plugins.qs.QSTile.SignalState;
import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SignalTileView;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.NetworkController;
@@ -78,6 +80,11 @@
}
@Override
+ public QSIconView createTileView(Context context) {
+ return new SignalTileView(context);
+ }
+
+ @Override
public DetailAdapter getDetailAdapter() {
return mDetailAdapter;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 4be93df..bba64d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -562,11 +562,11 @@
return;
}
- String message = mContext.getString(R.string.keyguard_unlock);
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ String message = mContext.getString(R.string.keyguard_retry);
mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
- showTransientIndication(message);
+ showTransientIndication(mContext.getString(R.string.keyguard_unlock));
hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
}
}
@@ -676,7 +676,11 @@
return;
}
animatePadlockError();
- if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ if (msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+ // The face timeout message is not very actionable, let's ask the user to
+ // manually retry.
+ showSwipeUpToUnlock();
+ } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
} else if (updateMonitor.isScreenOn()) {
showTransientIndication(errString);
diff --git a/packages/SystemUI/tools/lint/baseline.xml b/packages/SystemUI/tools/lint/baseline.xml
index 8c43222..096a639 100644
--- a/packages/SystemUI/tools/lint/baseline.xml
+++ b/packages/SystemUI/tools/lint/baseline.xml
@@ -2685,39 +2685,6 @@
<issue
id="UnusedResources"
- message="The resource `R.dimen.volume_dialog_base_margin` appears to be unused"
- errorLine1=" <dimen name="volume_dialog_base_margin">8dp</dimen>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/values/dimens.xml"
- line="308"
- column="12"/>
- </issue>
-
- <issue
- id="UnusedResources"
- message="The resource `R.dimen.volume_dialog_row_height` appears to be unused"
- errorLine1=" <dimen name="volume_dialog_row_height">252dp</dimen>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/values/dimens.xml"
- line="314"
- column="12"/>
- </issue>
-
- <issue
- id="UnusedResources"
- message="The resource `R.dimen.volume_dialog_settings_icon_size` appears to be unused"
- errorLine1=" <dimen name="volume_dialog_settings_icon_size">16dp</dimen>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/values/dimens.xml"
- line="328"
- column="12"/>
- </issue>
-
- <issue
- id="UnusedResources"
message="The resource `R.dimen.carrier_label_height` appears to be unused"
errorLine1=" <dimen name="carrier_label_height">24dp</dimen>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 4a6eb27..4828bbf 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -196,18 +196,20 @@
public void dump(PrintWriter pw, DumpFilter filter) {
pw.println(" Allowed " + getCaption() + "s:");
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final ArraySet<String> approved = approvedByType.valueAt(j);
- if (approvedByType != null && approvedByType.size() > 0) {
- pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
- + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mApproved.keyAt(i);
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ if (approvedByType != null && approvedByType.size() > 0) {
+ pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
+ + " (user: " + userId + " isPrimary: " + isPrimary + ")");
+ }
}
}
}
@@ -240,23 +242,25 @@
public void dump(ProtoOutputStream proto, DumpFilter filter) {
proto.write(ManagedServicesProto.CAPTION, getCaption());
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int userId = mApproved.keyAt(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final ArraySet<String> approved = approvedByType.valueAt(j);
- if (approvedByType != null && approvedByType.size() > 0) {
- final long sToken = proto.start(ManagedServicesProto.APPROVED);
- for (String s : approved) {
- proto.write(ServiceProto.NAME, s);
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int userId = mApproved.keyAt(i);
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ if (approvedByType != null && approvedByType.size() > 0) {
+ final long sToken = proto.start(ManagedServicesProto.APPROVED);
+ for (String s : approved) {
+ proto.write(ServiceProto.NAME, s);
+ }
+ proto.write(ServiceProto.USER_ID, userId);
+ proto.write(ServiceProto.IS_PRIMARY, isPrimary);
+ proto.end(sToken);
}
- proto.write(ServiceProto.USER_ID, userId);
- proto.write(ServiceProto.IS_PRIMARY, isPrimary);
- proto.end(sToken);
}
}
}
@@ -315,33 +319,36 @@
trimApprovedListsAccordingToInstalledServices(userId);
}
- final int N = mApproved.size();
- for (int i = 0 ; i < N; i++) {
- final int approvedUserId = mApproved.keyAt(i);
- if (forBackup && approvedUserId != userId) {
- continue;
- }
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
- if (approvedByType != null) {
- final int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final boolean isPrimary = approvedByType.keyAt(j);
- final Set<String> approved = approvedByType.valueAt(j);
- if (approved != null) {
- String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
- out.startTag(null, TAG_MANAGED_SERVICES);
- out.attribute(null, ATT_APPROVED_LIST, allowedItems);
- out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
- out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
- writeExtraAttributes(out, approvedUserId);
- out.endTag(null, TAG_MANAGED_SERVICES);
+ synchronized (mApproved) {
+ final int N = mApproved.size();
+ for (int i = 0; i < N; i++) {
+ final int approvedUserId = mApproved.keyAt(i);
+ if (forBackup && approvedUserId != userId) {
+ continue;
+ }
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
+ if (approvedByType != null) {
+ final int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final boolean isPrimary = approvedByType.keyAt(j);
+ final Set<String> approved = approvedByType.valueAt(j);
+ if (approved != null) {
+ String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ out.startTag(null, TAG_MANAGED_SERVICES);
+ out.attribute(null, ATT_APPROVED_LIST, allowedItems);
+ out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
+ out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
+ writeExtraAttributes(out, approvedUserId);
+ out.endTag(null, TAG_MANAGED_SERVICES);
- if (!forBackup && isPrimary) {
- // Also write values to settings, for observers who haven't migrated yet
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- getConfig().secureSettingName, allowedItems, approvedUserId);
+ if (!forBackup && isPrimary) {
+ // Also write values to settings, for observers who haven't migrated yet
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ getConfig().secureSettingName, allowedItems,
+ approvedUserId);
+ }
+
}
-
}
}
}
@@ -440,23 +447,25 @@
if (TextUtils.isEmpty(approved)) {
approved = "";
}
- ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
- if (approvedByType == null) {
- approvedByType = new ArrayMap<>();
- mApproved.put(userId, approvedByType);
- }
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ approvedByType = new ArrayMap<>();
+ mApproved.put(userId, approvedByType);
+ }
- ArraySet<String> approvedList = approvedByType.get(isPrimary);
- if (approvedList == null) {
- approvedList = new ArraySet<>();
- approvedByType.put(isPrimary, approvedList);
- }
+ ArraySet<String> approvedList = approvedByType.get(isPrimary);
+ if (approvedList == null) {
+ approvedList = new ArraySet<>();
+ approvedByType.put(isPrimary, approvedList);
+ }
- String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
- for (String pkgOrComponent : approvedArray) {
- String approvedItem = getApprovedValue(pkgOrComponent);
- if (approvedItem != null) {
- approvedList.add(approvedItem);
+ String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
+ for (String pkgOrComponent : approvedArray) {
+ String approvedItem = getApprovedValue(pkgOrComponent);
+ if (approvedItem != null) {
+ approvedList.add(approvedItem);
+ }
}
}
}
@@ -469,23 +478,25 @@
boolean isPrimary, boolean enabled) {
Slog.i(TAG,
(enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
- ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
- if (allowedByType == null) {
- allowedByType = new ArrayMap<>();
- mApproved.put(userId, allowedByType);
- }
- ArraySet<String> approved = allowedByType.get(isPrimary);
- if (approved == null) {
- approved = new ArraySet<>();
- allowedByType.put(isPrimary, approved);
- }
- String approvedItem = getApprovedValue(pkgOrComponent);
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
+ if (allowedByType == null) {
+ allowedByType = new ArrayMap<>();
+ mApproved.put(userId, allowedByType);
+ }
+ ArraySet<String> approved = allowedByType.get(isPrimary);
+ if (approved == null) {
+ approved = new ArraySet<>();
+ allowedByType.put(isPrimary, approved);
+ }
+ String approvedItem = getApprovedValue(pkgOrComponent);
- if (approvedItem != null) {
- if (enabled) {
- approved.add(approvedItem);
- } else {
- approved.remove(approvedItem);
+ if (approvedItem != null) {
+ if (enabled) {
+ approved.add(approvedItem);
+ } else {
+ approved.remove(approvedItem);
+ }
}
}
@@ -504,22 +515,26 @@
}
protected String getApproved(int userId, boolean primary) {
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
- return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
+ return String.join(ENABLED_SERVICES_SEPARATOR, approved);
+ }
}
protected List<ComponentName> getAllowedComponents(int userId) {
final List<ComponentName> allowedComponents = new ArrayList<>();
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
- if (cn != null) {
- allowedComponents.add(cn);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
+ if (cn != null) {
+ allowedComponents.add(cn);
+ }
}
}
}
@@ -528,14 +543,16 @@
protected List<String> getAllowedPackages(int userId) {
final List<String> allowedPackages = new ArrayList<>();
- final ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- String pkgName = getPackageName(allowed.valueAt(j));
- if (!TextUtils.isEmpty(pkgName)) {
- allowedPackages.add(pkgName);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
}
}
}
@@ -543,12 +560,14 @@
}
protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
- ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- ArraySet<String> allowed = allowedByType.valueAt(i);
- if (allowed.contains(pkgOrComponent)) {
- return true;
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ ArraySet<String> allowed = allowedByType.valueAt(i);
+ if (allowed.contains(pkgOrComponent)) {
+ return true;
+ }
}
}
return false;
@@ -558,19 +577,21 @@
if (pkg == null) {
return false;
}
- ArrayMap<Boolean, ArraySet<String>> allowedByType =
- mApproved.getOrDefault(userId, new ArrayMap<>());
- for (int i = 0; i < allowedByType.size(); i++) {
- ArraySet<String> allowed = allowedByType.valueAt(i);
- for (String allowedEntry : allowed) {
- ComponentName component = ComponentName.unflattenFromString(allowedEntry);
- if (component != null) {
- if (pkg.equals(component.getPackageName())) {
- return true;
- }
- } else {
- if (pkg.equals(allowedEntry)) {
- return true;
+ synchronized (mApproved) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType =
+ mApproved.getOrDefault(userId, new ArrayMap<>());
+ for (int i = 0; i < allowedByType.size(); i++) {
+ ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (String allowedEntry : allowed) {
+ ComponentName component = ComponentName.unflattenFromString(allowedEntry);
+ if (component != null) {
+ if (pkg.equals(component.getPackageName())) {
+ return true;
+ }
+ } else {
+ if (pkg.equals(allowedEntry)) {
+ return true;
+ }
}
}
}
@@ -616,7 +637,9 @@
public void onUserRemoved(int user) {
Slog.i(TAG, "Removing approved services for removed user " + user);
- mApproved.remove(user);
+ synchronized (mApproved) {
+ mApproved.remove(user);
+ }
rebindServices(true, user);
}
@@ -797,14 +820,16 @@
protected Set<String> getAllowedPackages() {
final Set<String> allowedPackages = new ArraySet<>();
- for (int k = 0; k < mApproved.size(); k++) {
- ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
- for (int i = 0; i < allowedByType.size(); i++) {
- final ArraySet<String> allowed = allowedByType.valueAt(i);
- for (int j = 0; j < allowed.size(); j++) {
- String pkgName = getPackageName(allowed.valueAt(j));
- if (!TextUtils.isEmpty(pkgName)) {
- allowedPackages.add(pkgName);
+ synchronized (mApproved) {
+ for (int k = 0; k < mApproved.size(); k++) {
+ ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
+ for (int i = 0; i < allowedByType.size(); i++) {
+ final ArraySet<String> allowed = allowedByType.valueAt(i);
+ for (int j = 0; j < allowed.size(); j++) {
+ String pkgName = getPackageName(allowed.valueAt(j));
+ if (!TextUtils.isEmpty(pkgName)) {
+ allowedPackages.add(pkgName);
+ }
}
}
}
@@ -813,22 +838,24 @@
}
private void trimApprovedListsAccordingToInstalledServices(int userId) {
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
- if (approvedByType == null) {
- return;
- }
- for (int i = 0; i < approvedByType.size(); i++) {
- final ArraySet<String> approved = approvedByType.valueAt(i);
- for (int j = approved.size() - 1; j >= 0; j--) {
- final String approvedPackageOrComponent = approved.valueAt(j);
- if (!isValidEntry(approvedPackageOrComponent, userId)){
- approved.removeAt(j);
- Slog.v(TAG, "Removing " + approvedPackageOrComponent
- + " from approved list; no matching services found");
- } else {
- if (DEBUG) {
- Slog.v(TAG, "Keeping " + approvedPackageOrComponent
- + " on approved list; matching services found");
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+ if (approvedByType == null) {
+ return;
+ }
+ for (int i = 0; i < approvedByType.size(); i++) {
+ final ArraySet<String> approved = approvedByType.valueAt(i);
+ for (int j = approved.size() - 1; j >= 0; j--) {
+ final String approvedPackageOrComponent = approved.valueAt(j);
+ if (!isValidEntry(approvedPackageOrComponent, userId)) {
+ approved.removeAt(j);
+ Slog.v(TAG, "Removing " + approvedPackageOrComponent
+ + " from approved list; no matching services found");
+ } else {
+ if (DEBUG) {
+ Slog.v(TAG, "Keeping " + approvedPackageOrComponent
+ + " on approved list; matching services found");
+ }
}
}
}
@@ -837,20 +864,23 @@
private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
boolean removed = false;
- final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
- if (approvedByType != null) {
- int M = approvedByType.size();
- for (int j = 0; j < M; j++) {
- final ArraySet<String> approved = approvedByType.valueAt(j);
- int O = approved.size();
- for (int k = O - 1; k >= 0; k--) {
- final String packageOrComponent = approved.valueAt(k);
- final String packageName = getPackageName(packageOrComponent);
- if (TextUtils.equals(pkg, packageName)) {
- approved.removeAt(k);
- if (DEBUG) {
- Slog.v(TAG, "Removing " + packageOrComponent
- + " from approved list; uninstalled");
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
+ uninstalledUserId);
+ if (approvedByType != null) {
+ int M = approvedByType.size();
+ for (int j = 0; j < M; j++) {
+ final ArraySet<String> approved = approvedByType.valueAt(j);
+ int O = approved.size();
+ for (int k = O - 1; k >= 0; k--) {
+ final String packageOrComponent = approved.valueAt(k);
+ final String packageName = getPackageName(packageOrComponent);
+ if (TextUtils.equals(pkg, packageName)) {
+ approved.removeAt(k);
+ if (DEBUG) {
+ Slog.v(TAG, "Removing " + packageOrComponent
+ + " from approved list; uninstalled");
+ }
}
}
}
@@ -887,17 +917,19 @@
for (int i = 0; i < nUserIds; ++i) {
final int userId = userIds.get(i);
- final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
- if (approvedLists != null) {
- final int N = approvedLists.size();
- for (int j = 0; j < N; j++) {
- ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
- if (approvedByUser == null) {
- approvedByUser = new ArraySet<>();
- componentsByUser.put(userId, approvedByUser);
+ synchronized (mApproved) {
+ final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
+ if (approvedLists != null) {
+ final int N = approvedLists.size();
+ for (int j = 0; j < N; j++) {
+ ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
+ if (approvedByUser == null) {
+ approvedByUser = new ArraySet<>();
+ componentsByUser.put(userId, approvedByUser);
+ }
+ approvedByUser.addAll(
+ loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
}
- approvedByUser.addAll(
- loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d358f9a..a1749f4 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -466,6 +466,8 @@
private MetricsLogger mMetricsLogger;
private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
+ private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable();
+
private static class Archive {
final int mBufferSize;
final ArrayDeque<StatusBarNotification> mBuffer;
@@ -659,7 +661,14 @@
@VisibleForTesting
protected void handleSavePolicyFile() {
- IoThread.getHandler().post(() -> {
+ if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) {
+ IoThread.getHandler().post(mSavePolicyFile);
+ }
+ }
+
+ private final class SavePolicyFileRunnable implements Runnable {
+ @Override
+ public void run() {
if (DBG) Slog.d(TAG, "handleSavePolicyFile");
synchronized (mPolicyFile) {
final FileOutputStream stream;
@@ -679,7 +688,7 @@
}
}
BackupManager.dataChanged(getContext().getPackageName());
- });
+ }
}
private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
@@ -1824,6 +1833,7 @@
}
if (properties.getKeyset()
.contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
+ mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
mAssistants.resetDefaultAssistantsIfNecessary();
}
});
@@ -2405,9 +2415,25 @@
}
@Override
+ public void silenceNotificationSound() {
+ checkCallerIsSystem();
+
+ mNotificationDelegate.clearEffects();
+ }
+
+ @Override
public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
+ synchronized (mNotificationLock) {
+ boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid)
+ != NotificationManager.IMPORTANCE_NONE;
+
+ if (wasEnabled == enabled) {
+ return;
+ }
+ }
+
mPreferencesHelper.setEnabled(pkg, uid, enabled);
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
.setType(MetricsEvent.TYPE_ACTION)
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
index a374e14..231168e 100644
--- a/services/core/java/com/android/server/pm/ProtectedPackages.java
+++ b/services/core/java/com/android/server/pm/ProtectedPackages.java
@@ -92,6 +92,9 @@
if (mDeviceOwnerUserId == userId) {
return mDeviceOwnerPackage;
}
+ if (mProfileOwnerPackages == null) {
+ return null;
+ }
return mProfileOwnerPackages.get(userId);
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 21b13fe..48056b4 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -107,6 +107,7 @@
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
+import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.app.UiModeManager;
@@ -2572,6 +2573,10 @@
return (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
}
+ NotificationManager getNotificationService() {
+ return mContext.getSystemService(NotificationManager.class);
+ }
+
static IAudioService getAudioService() {
IAudioService audioService = IAudioService.Stub.asInterface(
ServiceManager.checkService(Context.AUDIO_SERVICE));
@@ -3806,6 +3811,11 @@
if (down) {
sendSystemKeyToStatusBarAsync(event.getKeyCode());
+ NotificationManager nm = getNotificationService();
+ if (nm != null && !mHandleVolumeKeysInWM) {
+ nm.silenceNotificationSound();
+ }
+
TelecomManager telecomManager = getTelecommService();
if (telecomManager != null && !mHandleVolumeKeysInWM) {
// When {@link #mHandleVolumeKeysInWM} is set, volume key events
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 5ba1eb2..b5e4934 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -1508,14 +1508,22 @@
public void testUpdateAppNotifyCreatorBlock() throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
- mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
+ mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
captor.getValue().getAction());
assertEquals(PKG, captor.getValue().getPackage());
- assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false));
+ assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
+ }
+
+ @Test
+ public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
+
+ mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
+ verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
}
@Test
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4cc7097..f12753a 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2718,12 +2718,20 @@
/**
* Controls hysteresis time in milli seconds for which OpportunisticNetworkService
- * will wait before switching data to a network.
+ * will wait before switching data to an opportunistic network.
*/
public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG =
"opportunistic_network_data_switch_hysteresis_time_long";
/**
+ * Controls hysteresis time in milli seconds for which OpportunisticNetworkService
+ * will wait before switching data from opportunistic network to primary network.
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG =
+ "opportunistic_network_data_switch_exit_hysteresis_time_long";
+
+ /**
* Indicates zero or more emergency number prefix(es), because some carrier requires
* if users dial an emergency number address with a specific prefix, the combination of the
* prefix and the address is also a valid emergency number to dial. For example, an emergency
@@ -3485,6 +3493,8 @@
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG, 10000);
/* Default value is 10 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
+ /* Default value is 3 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 3000);
sDefaults.putAll(Gps.getDefaults());
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,