Merge "Fix a lock issue in AudioPortEventHandler" am: 0985eea389 am: 41c9e7092e am: 4b98ce6898
am: bb3c59e776
Change-Id: I8b84cbaceae238201ef65cfd4168def364e66d4e
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 3bf659b..2b4ff01 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -120,7 +120,10 @@
mActivityTaskManager = ActivityTaskManager.getService();
mSurfaceView = new SurfaceView(context);
- mSurfaceView.setAlpha(0f);
+ // Since ActivityView#getAlpha has been overridden, we should use parent class's alpha
+ // as master to synchronize surface view's alpha value.
+ mSurfaceView.setAlpha(super.getAlpha());
+ mSurfaceView.setUseAlpha();
mSurfaceCallback = new SurfaceCallback();
mSurfaceView.getHolder().addCallback(mSurfaceCallback);
addView(mSurfaceView);
@@ -347,9 +350,20 @@
mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
}
+ /**
+ * Sets the alpha value when the content of {@link SurfaceView} needs to show or hide.
+ * <p>Note: The surface view may ignore the alpha value in some cases. Refer to
+ * {@link SurfaceView#setAlpha} for more details.
+ *
+ * @param alpha The opacity of the view.
+ */
@Override
public void setAlpha(float alpha) {
- mSurfaceView.setAlpha(alpha);
+ super.setAlpha(alpha);
+
+ if (mSurfaceView != null) {
+ mSurfaceView.setAlpha(alpha);
+ }
}
@Override
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/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index be2846f..aa5480a 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -271,6 +271,8 @@
mCallback.setProgramListObserver(list, () -> {
try {
mTuner.stopProgramListUpdates();
+ } catch (IllegalStateException ex) {
+ // it's fine to not stop updates if tuner is already closed
} catch (RemoteException ex) {
Log.e(TAG, "Couldn't stop program list updates", ex);
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 254d04e..85ea3d3 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -100,6 +100,7 @@
public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
private static final String TAG = "SurfaceView";
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_POSITION = false;
@UnsupportedAppUsage
final ArrayList<SurfaceHolder.Callback> mCallbacks
@@ -126,6 +127,7 @@
// we need to preserve the old one until the new one has drawn.
SurfaceControl mDeferredDestroySurfaceControl;
SurfaceControl mBackgroundControl;
+ final Object mSurfaceControlLock = new Object();
final Rect mTmpRect = new Rect();
final Configuration mConfiguration = new Configuration();
@@ -173,6 +175,9 @@
@UnsupportedAppUsage
int mRequestedFormat = PixelFormat.RGB_565;
+ boolean mUseAlpha = false;
+ float mSurfaceAlpha = 1f;
+
@UnsupportedAppUsage
boolean mHaveFrame = false;
boolean mSurfaceCreated = false;
@@ -200,6 +205,7 @@
private int mPendingReportDraws;
private SurfaceControl.Transaction mRtTransaction = new SurfaceControl.Transaction();
+ private SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
public SurfaceView(Context context) {
this(context, null);
@@ -288,6 +294,152 @@
updateSurface();
}
+ /**
+ * Make alpha value of this view reflect onto the surface. This can only be called from at most
+ * one SurfaceView within a view tree.
+ *
+ * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
+ * surface is rendered opaque by default.</p>
+ *
+ * @hide
+ */
+ public void setUseAlpha() {
+ if (!mUseAlpha) {
+ mUseAlpha = true;
+ updateSurfaceAlpha();
+ }
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ // Sets the opacity of the view to a value, where 0 means the view is completely transparent
+ // and 1 means the view is completely opaque.
+ //
+ // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
+ // to call setUseAlpha() as well.
+ // This view doesn't support translucent opacity if the view is located z-below, since the
+ // logic to punch a hole in the view hierarchy cannot handle such case. See also
+ // #clearSurfaceViewPort(Canvas)
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
+ }
+ super.setAlpha(alpha);
+ updateSurfaceAlpha();
+ }
+
+ private float getFixedAlpha() {
+ // Compute alpha value to be set on the underlying surface.
+ final float alpha = getAlpha();
+ return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
+ }
+
+ private void updateSurfaceAlpha() {
+ if (!mUseAlpha) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
+ }
+ return;
+ }
+ final float viewAlpha = getAlpha();
+ if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
+ Log.w(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha:"
+ + " translucent color is not supported for a surface placed z-below.");
+ }
+ if (!mHaveFrame) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: has no surface.");
+ }
+ return;
+ }
+ final ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot == null) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: ViewRootImpl not available.");
+ }
+ return;
+ }
+ if (mSurfaceControl == null) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + "updateSurfaceAlpha:"
+ + " surface is not yet created, or already released.");
+ }
+ return;
+ }
+ final Surface parent = viewRoot.mSurface;
+ if (parent == null || !parent.isValid()) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
+ }
+ return;
+ }
+ final float alpha = getFixedAlpha();
+ if (alpha != mSurfaceAlpha) {
+ if (isHardwareAccelerated()) {
+ /*
+ * Schedule a callback that reflects an alpha value onto the underlying surfaces.
+ * This gets called on a RenderThread worker thread, so members accessed here must
+ * be protected by a lock.
+ */
+ viewRoot.registerRtFrameCallback(frame -> {
+ try {
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ synchronized (mSurfaceControlLock) {
+ if (!parent.isValid()) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha RT:"
+ + " ViewRootImpl has no valid surface");
+ }
+ return;
+ }
+ if (mSurfaceControl == null) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + "updateSurfaceAlpha RT:"
+ + " mSurfaceControl has already released");
+ }
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha RT: set alpha=" + alpha);
+ }
+ t.setAlpha(mSurfaceControl, alpha);
+ t.deferTransactionUntilSurface(mSurfaceControl, parent, frame);
+ }
+ // It's possible that mSurfaceControl is released in the UI thread before
+ // the transaction completes. If that happens, an exception is thrown, which
+ // must be caught immediately.
+ t.apply();
+ } catch (Exception e) {
+ Log.e(TAG, System.identityHashCode(this)
+ + "updateSurfaceAlpha RT: Exception during surface transaction", e);
+ }
+ });
+ damageInParent();
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: set alpha=" + alpha);
+ }
+ SurfaceControl.openTransaction();
+ try {
+ mSurfaceControl.setAlpha(alpha);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ mSurfaceAlpha = alpha;
+ }
+ }
+
private void performDrawFinished() {
if (mPendingReportDraws > 0) {
mDrawFinished = true;
@@ -337,11 +489,7 @@
mRequestedVisible = false;
updateSurface();
- if (mSurfaceControl != null) {
- mSurfaceControl.remove();
- }
- mSurfaceControl = null;
-
+ releaseSurfaces();
mHaveFrame = false;
super.onDetachedFromWindow();
@@ -510,15 +658,6 @@
}
}
- private Rect getParentSurfaceInsets() {
- final ViewRootImpl root = getViewRootImpl();
- if (root == null) {
- return null;
- } else {
- return root.mWindowAttributes.surfaceInsets;
- }
- }
-
private void updateBackgroundVisibilityInTransaction(SurfaceControl viewRoot) {
if (mBackgroundControl == null) {
return;
@@ -532,23 +671,34 @@
}
private void releaseSurfaces() {
- if (mSurfaceControl != null) {
- mSurfaceControl.remove();
- mSurfaceControl = null;
+ synchronized (mSurfaceControlLock) {
+ if (mSurfaceControl != null) {
+ mTmpTransaction.remove(mSurfaceControl);
+ mSurfaceControl = null;
+ }
+ if (mBackgroundControl != null) {
+ mTmpTransaction.remove(mBackgroundControl);
+ mBackgroundControl = null;
+ }
+ mTmpTransaction.apply();
}
- if (mBackgroundControl != null) {
- mBackgroundControl.remove();
- mBackgroundControl = null;
- }
+ mSurfaceAlpha = 1f;
}
/** @hide */
protected void updateSurface() {
if (!mHaveFrame) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
+ }
return;
}
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurface: no valid surface");
+ }
return;
}
@@ -562,20 +712,25 @@
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
+ final float alpha = getFixedAlpha();
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean visibleChanged = mVisible != mRequestedVisible;
+ final boolean alphaChanged = mSurfaceAlpha != alpha;
final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
&& mRequestedVisible;
final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
boolean redrawNeeded = false;
- if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
+ if (creating || formatChanged || sizeChanged || visibleChanged || (mUseAlpha
+ && alphaChanged) || windowVisibleChanged) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ + " visible=" + visibleChanged + " alpha=" + alphaChanged
+ + " mUseAlpha=" + mUseAlpha
+ " visible=" + visibleChanged
+ " left=" + (mWindowSpaceLeft != mLocation[0])
+ " top=" + (mWindowSpaceTop != mLocation[1]));
@@ -597,7 +752,7 @@
mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
- final Rect surfaceInsets = getParentSurfaceInsets();
+ final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
if (creating) {
@@ -646,6 +801,10 @@
mSurfaceControl.hide();
}
updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl());
+ if (mUseAlpha) {
+ mSurfaceControl.setAlpha(alpha);
+ mSurfaceAlpha = alpha;
+ }
// While creating the surface, we will set it's initial
// geometry. Outside of that though, we should generally
@@ -788,7 +947,6 @@
mIsCreating = false;
if (mSurfaceControl != null && !mSurfaceCreated) {
mSurface.release();
-
releaseSurfaces();
}
}
@@ -828,10 +986,13 @@
if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
- "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mScreenRect.left, mScreenRect.top,
- mScreenRect.right, mScreenRect.bottom));
+ if (DEBUG_POSITION) {
+ Log.d(TAG, String.format("%d updateSurfacePosition UI, "
+ + "position = [%d, %d, %d, %d]",
+ System.identityHashCode(this),
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ }
setParentSpaceRectangle(mScreenRect, -1);
} catch (Exception ex) {
Log.e(TAG, "Exception configuring surface", ex);
@@ -884,7 +1045,6 @@
if (mViewVisibility) {
mRtTransaction.show(surface);
}
-
}
private void setParentSpaceRectangle(Rect position, long frameNumber) {
@@ -925,7 +1085,7 @@
return;
}
try {
- if (DEBUG) {
+ if (DEBUG_POSITION) {
Log.d(TAG, String.format(
"%d updateSurfacePosition RenderWorker, frameNr = %d, "
+ "postion = [%d, %d, %d, %d]",
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..7a0eeee 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -26,6 +26,7 @@
#include <gui/IProducerListener.h>
#include <gui/Surface.h>
+#include <ui/PublicFormat.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
@@ -126,7 +127,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;
@@ -401,8 +402,28 @@
return 0;
}
} else {
+ // Set consumer buffer format to user specified format
+ PublicFormat publicFormat = static_cast<PublicFormat>(userFormat);
+ int nativeFormat = mapPublicFormatToHalFormat(publicFormat);
+ android_dataspace nativeDataspace = mapPublicFormatToHalDataspace(publicFormat);
+ res = native_window_set_buffers_format(anw.get(), nativeFormat);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure consumer native buffer format to %#x",
+ __FUNCTION__, nativeFormat);
+ jniThrowRuntimeException(env, "Failed to set Surface format");
+ return 0;
+ }
+
+ res = native_window_set_buffers_data_space(anw.get(), nativeDataspace);
+ if (res != OK) {
+ ALOGE("%s: Unable to configure consumer dataspace %#x",
+ __FUNCTION__, nativeDataspace);
+ jniThrowRuntimeException(env, "Failed to set Surface dataspace");
+ return 0;
+ }
surfaceFormat = userFormat;
}
+
ctx->setBufferFormat(surfaceFormat);
env->SetIntField(thiz,
gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(surfaceFormat));
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 21c2c6b..1bfc4c0 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -24,48 +24,7 @@
android:outlineProvider="none"
android:elevation="5dp" > <!-- Put it above the status bar header -->
- <LinearLayout
- android:id="@+id/keyguard_indication_area"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
- android:layout_gravity="bottom|center_horizontal"
- android:orientation="horizontal">
-
- <include layout="@layout/left_docked_overlay" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical|center_horizontal"
- android:orientation="vertical">
-
- <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@+id/keyguard_indication_enterprise_disclosure"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingStart="@dimen/keyguard_indication_text_padding"
- android:paddingEnd="@dimen/keyguard_indication_text_padding"
- android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
- android:visibility="gone" />
-
- <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
- android:id="@+id/keyguard_indication_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:paddingStart="@dimen/keyguard_indication_text_padding"
- android:paddingEnd="@dimen/keyguard_indication_text_padding"
- android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
- android:accessibilityLiveRegion="polite" />
-
- </LinearLayout>
-
- <include layout="@layout/right_docked_overlay" />
-
- </LinearLayout>
+ <include layout="@layout/keyguard_indication_area_overlay" />
<FrameLayout
android:id="@+id/preview_container"
diff --git a/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
new file mode 100644
index 0000000..cc30a68
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_indication_area_overlay.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyguard_indication_area"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
+ android:layout_gravity="bottom|center_horizontal"
+ android:orientation="vertical">
+
+ <include layout="@layout/keyguard_indication_text_view" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/keyguard_indication_text_view.xml b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
new file mode 100644
index 0000000..2b2100c
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyguard_indication_text_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+ android:id="@+id/keyguard_indication_enterprise_disclosure"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingStart="@dimen/keyguard_indication_text_padding"
+ android:paddingEnd="@dimen/keyguard_indication_text_padding"
+ android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+ android:visibility="gone"/>
+
+ <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
+ android:id="@+id/keyguard_indication_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingStart="@dimen/keyguard_indication_text_padding"
+ android:paddingEnd="@dimen/keyguard_indication_text_padding"
+ android:textAppearance="@style/TextAppearance.Keyguard.BottomArea"
+ android:accessibilityLiveRegion="polite"/>
+</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/left_docked_overlay.xml b/packages/SystemUI/res/layout/left_docked_overlay.xml
deleted file mode 100644
index 430143c..0000000
--- a/packages/SystemUI/res/layout/left_docked_overlay.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 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.
- -->
-
-<!-- empty stub -->
-<merge />
diff --git a/packages/SystemUI/res/layout/right_docked_overlay.xml b/packages/SystemUI/res/layout/right_docked_overlay.xml
deleted file mode 100644
index 430143c..0000000
--- a/packages/SystemUI/res/layout/right_docked_overlay.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2019 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.
- -->
-
-<!-- empty stub -->
-<merge />
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 340cb3a..6e8e823 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -196,9 +196,6 @@
<!-- Doze: duration to avoid false pickup gestures triggered by notification vibrations -->
<integer name="doze_pickup_vibration_threshold">2000</integer>
- <!-- Doze: can we assume the pickup sensor includes a proximity check? -->
- <bool name="doze_pickup_performs_proximity_check">false</bool>
-
<!-- Type of a sensor that provides a low-power estimate of the desired display
brightness, suitable to listen to while the device is asleep (e.g. during
always-on display) -->
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/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index a4b6958..517abac 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -253,6 +253,7 @@
protected void onUserInput() {
if (mCallback != null) {
mCallback.userActivity();
+ mCallback.onUserInput();
}
mSecurityMessageDisplay.setMessage("");
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 55ddfc3..56b38f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -274,6 +274,7 @@
@Override
public void onPatternCellAdded(List<LockPatternView.Cell> pattern) {
mCallback.userActivity();
+ mCallback.onUserInput();
}
@Override
@@ -336,6 +337,7 @@
});
if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
mCallback.userActivity();
+ mCallback.onUserInput();
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
index cbfbffb..49dcfff 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -55,4 +55,9 @@
default void onCancelClicked() {
// No-op
}
+
+ /**
+ * Invoked whenever users are typing their password or drawing a pattern.
+ */
+ void onUserInput();
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 8059dcf..169c97b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -596,6 +596,11 @@
}
}
+ @Override
+ public void onUserInput() {
+ mUpdateMonitor.cancelFaceAuth();
+ }
+
public void dismiss(boolean authenticated, int targetId) {
mSecurityCallback.dismiss(authenticated, targetId);
}
@@ -640,6 +645,8 @@
@Override
public void dismiss(boolean securityVerified, int targetUserId) { }
@Override
+ public void onUserInput() { }
+ @Override
public void reset() {}
};
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 109f270..72ad993 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) {
@@ -1646,6 +1641,13 @@
updateFaceListeningState();
}
+ /**
+ * In case face auth is running, cancel it.
+ */
+ public void cancelFaceAuth() {
+ stopListeningForFace();
+ }
+
private void updateFaceListeningState() {
// If this message exists, we should not authenticate again until this message is
// consumed by the handler
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 923ca20..de08a8c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -182,7 +182,7 @@
mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */,
true /* singleTaskInstance */);
-
+ // Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
addView(mActivityView);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index f6a921d..f79bb3a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -107,8 +107,7 @@
config.dozePickupSensorAvailable(),
DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
false /* touchscreen */,
- false /* ignoresSetting */,
- mDozeParameters.getPickupPerformsProxCheck()),
+ false /* ignoresSetting */),
new TriggerSensor(
findSensorWithType(config.doubleTapSensorType()),
Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
@@ -205,11 +204,8 @@
public void updateListening() {
boolean anyListening = false;
for (TriggerSensor s : mSensors) {
- // We don't want to be listening while we're PAUSED (prox sensor is covered)
- // except when the sensor is already gated by prox.
- boolean listen = mListening && (!mPaused || s.performsProxCheck());
- s.setListening(listen);
- if (listen) {
+ s.setListening(mListening);
+ if (mListening) {
anyListening = true;
}
}
@@ -384,7 +380,6 @@
private final boolean mReportsTouchCoordinates;
private final boolean mSettingDefault;
private final boolean mRequiresTouchscreen;
- private final boolean mSensorPerformsProxCheck;
protected boolean mRequested;
protected boolean mRegistered;
@@ -401,14 +396,12 @@
boolean configured, int pulseReason, boolean reportsTouchCoordinates,
boolean requiresTouchscreen) {
this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
- requiresTouchscreen, false /* ignoresSetting */,
- false /* sensorPerformsProxCheck */);
+ requiresTouchscreen, false /* ignoresSetting */);
}
private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
boolean configured, int pulseReason, boolean reportsTouchCoordinates,
- boolean requiresTouchscreen, boolean ignoresSetting,
- boolean sensorPerformsProxCheck) {
+ boolean requiresTouchscreen, boolean ignoresSetting) {
mSensor = sensor;
mSetting = setting;
mSettingDefault = settingDef;
@@ -417,7 +410,6 @@
mReportsTouchCoordinates = reportsTouchCoordinates;
mRequiresTouchscreen = requiresTouchscreen;
mIgnoresSetting = ignoresSetting;
- mSensorPerformsProxCheck = sensorPerformsProxCheck;
}
public void setListening(boolean listen) {
@@ -491,23 +483,13 @@
screenX = event.values[0];
screenY = event.values[1];
}
- mCallback.onSensorPulse(mPulseReason, mSensorPerformsProxCheck, screenX, screenY,
- event.values);
+ mCallback.onSensorPulse(mPulseReason, screenX, screenY, event.values);
if (!mRegistered) {
updateListening(); // reregister, this sensor only fires once
}
}));
}
- /**
- * If the sensor itself performs proximity checks, to avoid pocket dialing.
- * Gated sensors don't need to be stopped when the {@link DozeMachine} is
- * {@link DozeMachine.State#DOZE_AOD_PAUSED}.
- */
- public boolean performsProxCheck() {
- return mSensorPerformsProxCheck;
- }
-
public void registerSettingsObserver(ContentObserver settingsObserver) {
if (mConfigured && !TextUtils.isEmpty(mSetting)) {
mResolver.registerContentObserver(
@@ -603,8 +585,7 @@
return;
}
if (DEBUG) Log.d(TAG, "onSensorEvent: " + triggerEventToString(event));
- mCallback.onSensorPulse(mPulseReason, true /* sensorPerformsProxCheck */, -1, -1,
- event.getValues());
+ mCallback.onSensorPulse(mPulseReason, -1, -1, event.getValues());
}));
}
}
@@ -614,13 +595,11 @@
/**
* Called when a sensor requests a pulse
* @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
- * @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity.
* @param screenX the location on the screen where the sensor fired or -1
- * if the sensor doesn't support reporting screen locations.
+ * if the sensor doesn't support reporting screen locations.
* @param screenY the location on the screen where the sensor fired or -1
* @param rawValues raw values array from the event.
*/
- void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck,
- float screenX, float screenY, float[] rawValues);
+ void onSensorPulse(int pulseReason, float screenX, float screenY, float[] rawValues);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 310f04a..00bfb3f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -41,6 +41,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
import com.android.systemui.Dependency;
+import com.android.systemui.R;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.Assert;
@@ -156,8 +157,7 @@
}
@VisibleForTesting
- void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
- float screenX, float screenY, float[] rawValues) {
+ void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) {
boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP;
boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP;
boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP;
@@ -169,10 +169,11 @@
if (isWakeDisplay) {
onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
} else if (isLongPress) {
- requestPulse(pulseReason, sensorPerformedProxCheck, null /* onPulseSupressedListener */);
+ requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
+ null /* onPulseSupressedListener */);
} else if (isWakeLockScreen) {
if (wakeEvent) {
- requestPulse(pulseReason, sensorPerformedProxCheck,
+ requestPulse(pulseReason, true /* alreadyPerformedProxCheck */,
null /* onPulseSupressedListener */);
}
} else {
@@ -191,8 +192,7 @@
} else {
mDozeHost.extendPulse(pulseReason);
}
- }, sensorPerformedProxCheck
- || (mDockManager != null && mDockManager.isDocked()), pulseReason);
+ }, true /* alreadyPerformedProxCheck */, pulseReason);
}
if (isPickup) {
@@ -278,7 +278,7 @@
.setType(MetricsEvent.TYPE_OPEN)
.setSubtype(DozeLog.REASON_SENSOR_WAKE_UP));
}
- }, false /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
+ }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
} else {
boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
@@ -433,7 +433,11 @@
public void check() {
Preconditions.checkState(!mFinished && !mRegistered);
- final Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ Sensor sensor = DozeSensors.findSensorWithType(mSensorManager,
+ mContext.getString(R.string.doze_brightness_sensor_type));
+ if (sensor == null) {
+ sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+ }
if (sensor == null) {
if (DozeMachine.DEBUG) Log.d(TAG, "ProxCheck: No sensor found");
finishWithResult(RESULT_UNKNOWN);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index f0413cd..be8a8fd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -111,13 +111,25 @@
+ mQSPanel.getMeasuredHeight() + getPaddingBottom();
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
-
// QSCustomizer will always be the height of the screen, but do this after
// other measuring to avoid changing the height of the QS.
mQSCustomizer.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
}
+
+ @Override
+ protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
+ int parentHeightMeasureSpec, int heightUsed) {
+ // Do not measure QSPanel again when doing super.onMeasure.
+ // This prevents the pages in PagedTileLayout to be remeasured with a different (incorrect)
+ // size to the one used for determining the number of rows and then the number of pages.
+ if (child != mQSPanel) {
+ super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
+ parentHeightMeasureSpec, heightUsed);
+ }
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
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/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index ea31be4..d6aeb4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1209,12 +1209,12 @@
mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
}
if (mGuts != null) {
- View oldGuts = mGuts;
+ NotificationGuts oldGuts = mGuts;
int index = indexOfChild(oldGuts);
removeView(oldGuts);
mGuts = (NotificationGuts) LayoutInflater.from(mContext).inflate(
R.layout.notification_guts, this, false);
- mGuts.setVisibility(oldGuts.getVisibility());
+ mGuts.setVisibility(oldGuts.isExposed() ? VISIBLE : GONE);
addView(mGuts, index);
}
View oldMenu = mMenuRow == null ? null : mMenuRow.getMenuView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 10b48e7..bb6a38e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -207,10 +207,6 @@
return SystemProperties.get(propName, mContext.getString(resId));
}
- public boolean getPickupPerformsProxCheck() {
- return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
- }
-
public int getPulseVisibleDurationExtended() {
return 2 * getPulseVisibleDuration();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 2ed0970..0c124ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -37,7 +37,6 @@
when(params.getPulseOnSigMotion()).thenReturn(false);
when(params.getPickupVibrationThreshold()).thenReturn(0);
when(params.getProxCheckBeforePulse()).thenReturn(true);
- when(params.getPickupPerformsProxCheck()).thenReturn(true);
when(params.getPolicy()).thenReturn(mock(AlwaysOnDisplayPolicy.class));
when(params.doubleTapReportsTouchCoordinates()).thenReturn(false);
when(params.getDisplayNeedsBlanking()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 7df45a3..cd6d1e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -19,7 +19,6 @@
import static com.android.systemui.plugins.SensorManagerPlugin.Sensor.TYPE_WAKE_LOCK_SCREEN;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -79,8 +78,6 @@
private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
@Mock
private TriggerSensor mTriggerSensor;
- @Mock
- private TriggerSensor mProxGatedTriggerSensor;
private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
private TestableLooper mTestableLooper;
private DozeSensors mDozeSensors;
@@ -88,7 +85,6 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mProxGatedTriggerSensor.performsProxCheck()).thenReturn(true);
mTestableLooper = TestableLooper.get(this);
when(mAmbientDisplayConfiguration.getWakeLockScreenDebounce()).thenReturn(5000L);
when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(true);
@@ -106,14 +102,14 @@
mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
mTestableLooper.processAllMessages();
verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
- anyBoolean(), anyFloat(), anyFloat(), eq(null));
+ anyFloat(), anyFloat(), eq(null));
mDozeSensors.requestTemporaryDisable();
reset(mCallback);
mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
mTestableLooper.processAllMessages();
verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
- anyBoolean(), anyFloat(), anyFloat(), eq(null));
+ anyFloat(), anyFloat(), eq(null));
}
@Test
@@ -132,20 +128,17 @@
}
@Test
- public void testSetPaused_onlyPausesNonGatedSensors() {
+ public void testSetPaused_doesntPause_sensors() {
mDozeSensors.setListening(true);
verify(mTriggerSensor).setListening(eq(true));
- verify(mProxGatedTriggerSensor).setListening(eq(true));
- clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
+ clearInvocations(mTriggerSensor);
mDozeSensors.setPaused(true);
- verify(mTriggerSensor).setListening(eq(false));
- verify(mProxGatedTriggerSensor).setListening(eq(true));
-
- clearInvocations(mTriggerSensor, mProxGatedTriggerSensor);
- mDozeSensors.setPaused(false);
verify(mTriggerSensor).setListening(eq(true));
- verify(mProxGatedTriggerSensor).setListening(eq(true));
+
+ clearInvocations(mTriggerSensor);
+ mDozeSensors.setListening(false);
+ verify(mTriggerSensor).setListening(eq(false));
}
private class TestableDozeSensors extends DozeSensors {
@@ -161,7 +154,7 @@
mWakeLockScreenListener = (PluginSensor) sensor;
}
}
- mSensors = new TriggerSensor[] {mTriggerSensor, mProxGatedTriggerSensor};
+ mSensors = new TriggerSensor[] {mTriggerSensor};
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index d464223..e190f99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -20,7 +20,6 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -134,28 +133,4 @@
mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
verify(mDockManagerFake).removeListener(any());
}
-
- @Test
- public void testOnSensor_whenUndockedWithNearAndDoubleTapScreen_shouldNotWakeUp() {
- mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
-
- mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
- false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
- null /* rawValues */);
- verify(mMachine, never()).wakeUp();
- }
-
- @Test
- public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() {
- doReturn(true).when(mDockManagerFake).isDocked();
- doReturn(true).when(mParameters).getDisplayNeedsBlanking();
- mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
-
- mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
- false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
- null /* rawValues */);
-
- verify(mHost).setAodDimmingScrim(eq(1f));
- verify(mMachine).wakeUp();
- }
}
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/accounts/AccountManagerServiceShellCommand.java b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
index 9e5f722..9bf0bd3 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerServiceShellCommand.java
@@ -17,6 +17,7 @@
package com.android.server.accounts;
import android.annotation.NonNull;
+import android.app.ActivityManager;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -83,7 +84,7 @@
return null;
}
}
- return UserHandle.USER_SYSTEM;
+ return ActivityManager.getCurrentUser();
}
@Override
@@ -92,9 +93,11 @@
pw.println("Account manager service commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" set-bind-instant-service-allowed [--user <USER_ID>] true|false ");
+ pw.println(" set-bind-instant-service-allowed "
+ + "[--user <USER_ID> (current user if not specified)] true|false ");
pw.println(" Set whether binding to services provided by instant apps is allowed.");
- pw.println(" get-bind-instant-service-allowed [--user <USER_ID>]");
+ pw.println(" get-bind-instant-service-allowed "
+ + "[--user <USER_ID> (current user if not specified)]");
pw.println(" Get whether binding to services provided by instant apps is allowed.");
}
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index c45a314..7648636 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -680,6 +680,7 @@
@Override
public void onDisplayChanged(int displayId) {
updateDisplayModes(displayId);
+ mBrightnessObserver.onDisplayChanged(displayId);
}
private void updateDisplayModes(int displayId) {
@@ -734,8 +735,6 @@
private AmbientFilter mAmbientFilter;
private final Context mContext;
- private ScreenStateReceiver mScreenStateReceiver;
-
// Enable light sensor only when screen is on, peak refresh rate enabled and low power mode
// off. After initialization, these states will be updated from the same handler thread.
private boolean mScreenOn = false;
@@ -793,11 +792,7 @@
mSensorManager = sensorManager;
mLightSensor = lightSensor;
- // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
- if (mContext.getSystemService(PowerManager.class).isInteractive()) {
- onScreenOn(true);
- }
- mScreenStateReceiver = new ScreenStateReceiver(mContext);
+ onScreenOn(isDefaultDisplayOn());
}
}
@@ -822,6 +817,12 @@
}
}
+ public void onDisplayChanged(int displayId) {
+ if (displayId == Display.DEFAULT_DISPLAY) {
+ onScreenOn(isDefaultDisplayOn());
+ }
+ }
+
public void dumpLocked(PrintWriter pw) {
pw.println(" BrightnessObserver");
@@ -891,8 +892,6 @@
}
private void onScreenOn(boolean on) {
- // Not check mShouldObserveAmbientChange because Screen status receiver is registered
- // only when it is true.
if (mScreenOn != on) {
mScreenOn = on;
updateSensorStatus();
@@ -913,6 +912,13 @@
}
}
+ private boolean isDefaultDisplayOn() {
+ final Display display = mContext.getSystemService(DisplayManager.class)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+ return display.getState() != Display.STATE_OFF
+ && mContext.getSystemService(PowerManager.class).isInteractive();
+ }
+
private final class LightSensorEventListener implements SensorEventListener {
final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
private float mLastSensorData;
@@ -991,20 +997,5 @@
}
};
};
-
- private final class ScreenStateReceiver extends BroadcastReceiver {
- public ScreenStateReceiver(Context context) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- context.registerReceiver(this, filter, null, mHandler);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
- }
- }
}
}
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..d4b3138 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();
}
});
@@ -2256,7 +2266,7 @@
final int callingUid = Binder.getCallingUid();
final boolean isSystemToast = isCallerSystemOrPhone()
|| PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
- final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
+ final boolean isPackageSuspended = isPackagePaused(pkg);
final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
callingUid);
@@ -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)
@@ -4094,17 +4120,7 @@
Preconditions.checkNotNull(pkg);
checkCallerIsSameApp(pkg);
- boolean isPaused;
-
- final PackageManagerInternal pmi = LocalServices.getService(
- PackageManagerInternal.class);
- int flags = pmi.getDistractingPackageRestrictions(
- pkg, Binder.getCallingUserHandle().getIdentifier());
- isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
-
- isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
-
- return isPaused;
+ return isPackagePausedOrSuspended(pkg, Binder.getCallingUid());
}
private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
@@ -5326,11 +5342,18 @@
}
@GuardedBy("mNotificationLock")
- private boolean isPackageSuspendedLocked(NotificationRecord r) {
- final String pkg = r.sbn.getPackageName();
- final int callingUid = r.sbn.getUid();
+ boolean isPackagePausedOrSuspended(String pkg, int uid) {
+ boolean isPaused;
- return isPackageSuspendedForUser(pkg, callingUid);
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ int flags = pmi.getDistractingPackageRestrictions(
+ pkg, Binder.getCallingUserHandle().getIdentifier());
+ isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
+
+ isPaused |= isPackageSuspendedForUser(pkg, uid);
+
+ return isPaused;
}
protected class PostNotificationRunnable implements Runnable {
@@ -5363,7 +5386,8 @@
return;
}
- final boolean isPackageSuspended = isPackageSuspendedLocked(r);
+ final boolean isPackageSuspended =
+ isPackagePausedOrSuspended(r.sbn.getPackageName(), r.getUid());
r.setHidden(isPackageSuspended);
if (isPackageSuspended) {
mUsageStats.registerSuspendedByAdmin(r);
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 7c0118c..0bc0029 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2726,12 +2726,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
@@ -3494,6 +3502,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,