Merge "Add gravity center to layout params" into sc-dev
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 86fa06c..9572808 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -2603,7 +2603,7 @@
final int uid = mPackageManagerInternal.getPackageUid(packageName, 0, userId);
if (callingUid != uid && !UserHandle.isCore(callingUid)) {
throw new SecurityException("Uid " + callingUid
- + " cannot query hasScheduleExactAlarm for uid " + uid);
+ + " cannot query hasScheduleExactAlarm for package " + packageName);
}
return (uid > 0) ? hasScheduleExactAlarmInternal(packageName, uid) : false;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3915abe..dbaf275 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -369,11 +369,12 @@
@UnsupportedAppUsage(trackingBug = 176961850, maxTargetSdk = Build.VERSION_CODES.R,
publicAlternatives = "Use {@code Context#getResources()#getConfiguration()} instead.")
Configuration mConfiguration;
+ @GuardedBy("this")
+ private boolean mUpdateHttpProxyOnBind = false;
@UnsupportedAppUsage
Application mInitialApplication;
@UnsupportedAppUsage
- final ArrayList<Application> mAllApplications
- = new ArrayList<Application>();
+ final ArrayList<Application> mAllApplications = new ArrayList<>();
/**
* Bookkeeping of instantiated backup agents indexed first by user id, then by package name.
* Indexing by user id supports parallel backups across users on system packages as they run in
@@ -1187,8 +1188,18 @@
}
public void updateHttpProxy() {
- ActivityThread.updateHttpProxy(
- getApplication() != null ? getApplication() : getSystemContext());
+ final Application app;
+ synchronized (ActivityThread.this) {
+ app = getApplication();
+ if (null == app) {
+ // The app is not bound yet. Make a note to update the HTTP proxy when the
+ // app is bound.
+ mUpdateHttpProxyOnBind = true;
+ return;
+ }
+ }
+ // App is present, update the proxy inline.
+ ActivityThread.updateHttpProxy(app);
}
public void processInBackground() {
@@ -6685,6 +6696,15 @@
sendMessage(H.SET_CONTENT_CAPTURE_OPTIONS_CALLBACK, data.appInfo.packageName);
mInitialApplication = app;
+ final boolean updateHttpProxy;
+ synchronized (this) {
+ updateHttpProxy = mUpdateHttpProxyOnBind;
+ // This synchronized block ensures that any subsequent call to updateHttpProxy()
+ // will see a non-null mInitialApplication.
+ }
+ if (updateHttpProxy) {
+ ActivityThread.updateHttpProxy(app);
+ }
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9d149cf..4b054f4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6122,28 +6122,29 @@
// change the background bgColor
CharSequence title = action.title;
ColorStateList[] outResultColor = new ColorStateList[1];
- int background = getColors(p).getSecondaryAccentColor();
+ int buttonFillColor = getColors(p).getSecondaryAccentColor();
if (isLegacy()) {
title = ContrastColorUtil.clearColorSpans(title);
} else {
- title = ensureColorSpanContrast(title, background, outResultColor);
+ int notifBackgroundColor = getColors(p).getBackgroundColor();
+ title = ensureColorSpanContrast(title, notifBackgroundColor, outResultColor);
}
button.setTextViewText(R.id.action0, processTextSpans(title));
boolean hasColorOverride = outResultColor[0] != null;
if (hasColorOverride) {
// There's a span spanning the full text, let's take it and use it as the
// background color
- background = outResultColor[0].getDefaultColor();
+ buttonFillColor = outResultColor[0].getDefaultColor();
}
final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
- background, mInNightMode);
+ buttonFillColor, mInNightMode);
button.setTextColor(R.id.action0, textColor);
// We only want about 20% alpha for the ripple
final int rippleColor = (textColor & 0x00ffffff) | 0x33000000;
button.setColorStateList(R.id.action0, "setRippleColor",
ColorStateList.valueOf(rippleColor));
button.setColorStateList(R.id.action0, "setButtonBackground",
- ColorStateList.valueOf(background));
+ ColorStateList.valueOf(buttonFillColor));
if (p.mCallStyleActions) {
button.setImageViewIcon(R.id.action0, action.getIcon());
boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY);
@@ -6176,8 +6177,8 @@
* there exists a full length color span.
* @return the contrasted charSequence
*/
- private CharSequence ensureColorSpanContrast(CharSequence charSequence, int background,
- ColorStateList[] outResultColor) {
+ private static CharSequence ensureColorSpanContrast(CharSequence charSequence,
+ int background, ColorStateList[] outResultColor) {
if (charSequence instanceof Spanned) {
Spanned ss = (Spanned) charSequence;
Object[] spans = ss.getSpans(0, ss.length(), Object.class);
@@ -6197,8 +6198,9 @@
int[] colors = textColor.getColors();
int[] newColors = new int[colors.length];
for (int i = 0; i < newColors.length; i++) {
+ boolean isBgDark = isColorDark(background);
newColors[i] = ContrastColorUtil.ensureLargeTextContrast(
- colors[i], background, mInNightMode);
+ colors[i], background, isBgDark);
}
textColor = new ColorStateList(textColor.getStates().clone(),
newColors);
@@ -6217,8 +6219,9 @@
} else if (resultSpan instanceof ForegroundColorSpan) {
ForegroundColorSpan originalSpan = (ForegroundColorSpan) resultSpan;
int foregroundColor = originalSpan.getForegroundColor();
+ boolean isBgDark = isColorDark(background);
foregroundColor = ContrastColorUtil.ensureLargeTextContrast(
- foregroundColor, background, mInNightMode);
+ foregroundColor, background, isBgDark);
if (fullLength) {
outResultColor[0] = ColorStateList.valueOf(foregroundColor);
resultSpan = null;
@@ -6238,6 +6241,19 @@
}
/**
+ * Determines if the color is light or dark. Specifically, this is using the same metric as
+ * {@link ContrastColorUtil#resolvePrimaryColor(Context, int, boolean)} and peers so that
+ * the direction of color shift is consistent.
+ *
+ * @param color the color to check
+ * @return true if the color has higher contrast with white than black
+ */
+ private static boolean isColorDark(int color) {
+ // as per ContrastColorUtil.shouldUseDark, this uses the color contrast midpoint.
+ return ContrastColorUtil.calculateLuminance(color) <= 0.17912878474;
+ }
+
+ /**
* @return Whether we are currently building a notification from a legacy (an app that
* doesn't create material notifications by itself) app.
*/
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 65cdca9..1dd32fe 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -1025,6 +1025,10 @@
public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec,
int value) {
if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")");
+ if (value < 0) {
+ Log.e(TAG, "Trying to set audio buffer length to a negative value: " + value);
+ return false;
+ }
try {
final IBluetoothA2dp service = getService();
if (service != null && isEnabled()) {
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c78dd53..b55a1cb 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2318,6 +2318,51 @@
new Key<Float>("android.control.zoomRatio", float.class);
/**
+ * <p>Framework-only private key which informs camera fwk that the AF regions has been set
+ * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+ * set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#CONTROL_AF_REGIONS android.control.afRegions}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AF_REGIONS
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> CONTROL_AF_REGIONS_SET =
+ new Key<Boolean>("android.control.afRegionsSet", boolean.class);
+
+ /**
+ * <p>Framework-only private key which informs camera fwk that the AE regions has been set
+ * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+ * set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#CONTROL_AE_REGIONS android.control.aeRegions}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_REGIONS
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> CONTROL_AE_REGIONS_SET =
+ new Key<Boolean>("android.control.aeRegionsSet", boolean.class);
+
+ /**
+ * <p>Framework-only private key which informs camera fwk that the AF regions has been set
+ * by the client and those regions need not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is
+ * set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#CONTROL_AWB_REGIONS android.control.awbRegions}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#CONTROL_AWB_REGIONS
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> CONTROL_AWB_REGIONS_SET =
+ new Key<Boolean>("android.control.awbRegionsSet", boolean.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge enhancement improves sharpness and details in the captured image. OFF means
@@ -3057,6 +3102,21 @@
new Key<Integer>("android.scaler.rotateAndCrop", int.class);
/**
+ * <p>Framework-only private key which informs camera fwk that the scaler crop region
+ * ({@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}) has been set by the client and it need
+ * not be corrected when {@link CaptureRequest#SENSOR_PIXEL_MODE android.sensor.pixelMode} is set to MAXIMUM_RESOLUTION.</p>
+ * <p>This must be set to TRUE by the camera2 java fwk when the camera client sets
+ * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}.</p>
+ * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p>
+ *
+ * @see CaptureRequest#SCALER_CROP_REGION
+ * @see CaptureRequest#SENSOR_PIXEL_MODE
+ * @hide
+ */
+ public static final Key<Boolean> SCALER_CROP_REGION_SET =
+ new Key<Boolean>("android.scaler.cropRegionSet", boolean.class);
+
+ /**
* <p>Duration each pixel is exposed to
* light.</p>
* <p>If the sensor can't expose this exact duration, it will shorten the
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index bfc1f27..d5a35bc 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -446,10 +446,16 @@
}
}
+ @Override
+ protected void finalize() throws Throwable {
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ }
+ super.finalize();
+ }
+
public void release() {
synchronized (mInterfaceLock) {
- mHandlerThread.quitSafely();
-
if (mSessionProcessor != null) {
try {
mSessionProcessor.deInitSession();
@@ -812,6 +818,8 @@
Log.e(TAG,"Failed to parcel buffer fence!");
}
}
+ parcelImage.width = img.getWidth();
+ parcelImage.height = img.getHeight();
parcelImage.format = img.getFormat();
parcelImage.timestamp = img.getTimestamp();
parcelImage.transform = img.getTransform();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 11b137ca..0bf812e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -696,6 +696,16 @@
mCurrentSession.replaceSessionClose();
}
+ if (mCurrentExtensionSession != null) {
+ mCurrentExtensionSession.release();
+ mCurrentExtensionSession = null;
+ }
+
+ if (mCurrentAdvancedExtensionSession != null) {
+ mCurrentAdvancedExtensionSession.release();
+ mCurrentAdvancedExtensionSession = null;
+ }
+
// TODO: dont block for this
boolean configureSuccess = true;
CameraAccessException pendingException = null;
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 537b894..7d29a7d 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -49,8 +49,6 @@
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.annotation.NonNull;
@@ -265,13 +263,6 @@
} catch (ClassCastException e) {
throw new UnsupportedOperationException("Failed casting preview processor!");
}
- if (mClientRepeatingRequestSurface != null) {
- mPreviewRequestUpdateProcessor.onOutputSurface(mClientRepeatingRequestSurface,
- nativeGetSurfaceFormat(mClientRepeatingRequestSurface));
- mRepeatingRequestImageWriter = ImageWriter.newInstance(
- mClientRepeatingRequestSurface, PREVIEW_QUEUE_SIZE,
- CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
- }
mRepeatingRequestImageReader = ImageReader.newInstance(repeatingSurfaceInfo.mWidth,
repeatingSurfaceInfo.mHeight,
CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT,
@@ -285,11 +276,6 @@
mPreviewRequestUpdateProcessor.onImageFormatUpdate(
CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
} else {
- if (mClientRepeatingRequestSurface != null) {
- mRepeatingRequestImageWriter = ImageWriter.newInstance(
- mClientRepeatingRequestSurface, PREVIEW_QUEUE_SIZE,
- CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
- }
mRepeatingRequestImageReader = ImageReader.newInstance(repeatingSurfaceInfo.mWidth,
repeatingSurfaceInfo.mHeight,
CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT,
@@ -320,7 +306,6 @@
mBurstCaptureImageReader = ImageReader.newInstance(surfaceInfo.mWidth,
surfaceInfo.mHeight, CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
mImageExtender.getMaxCaptureStage());
- mImageProcessor.onOutputSurface(mClientCaptureSurface, surfaceInfo.mFormat);
} else {
// The client doesn't intend to trigger multi-frame capture, however the
// image extender still needs to get initialized and the camera still capture
@@ -367,6 +352,29 @@
}
}
+ private void finishPipelineInitialization() throws RemoteException {
+ if (mClientRepeatingRequestSurface != null) {
+ if (mPreviewProcessorType == IPreviewExtenderImpl.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY) {
+ mPreviewRequestUpdateProcessor.onOutputSurface(mClientRepeatingRequestSurface,
+ nativeGetSurfaceFormat(mClientRepeatingRequestSurface));
+ mRepeatingRequestImageWriter = ImageWriter.newInstance(
+ mClientRepeatingRequestSurface,
+ PREVIEW_QUEUE_SIZE,
+ CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
+ } else if (mPreviewProcessorType == IPreviewExtenderImpl.PROCESSOR_TYPE_NONE) {
+ mRepeatingRequestImageWriter = ImageWriter.newInstance(
+ mClientRepeatingRequestSurface,
+ PREVIEW_QUEUE_SIZE,
+ CameraExtensionCharacteristics.NON_PROCESSING_INPUT_FORMAT);
+ }
+ }
+ if ((mImageProcessor != null) && (mClientCaptureSurface != null)) {
+ CameraExtensionUtils.SurfaceInfo surfaceInfo = CameraExtensionUtils.querySurface(
+ mClientCaptureSurface);
+ mImageProcessor.onOutputSurface(mClientCaptureSurface, surfaceInfo.mFormat);
+ }
+ }
+
/**
* @hide
*/
@@ -622,11 +630,18 @@
new CameraExtensionUtils.HandlerExecutor(mHandler), requestHandler);
}
+ @Override
+ protected void finalize() throws Throwable {
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ }
+ super.finalize();
+ }
+
/** @hide */
public void release() {
synchronized (mInterfaceLock) {
mInternalRepeatingRequestEnabled = false;
- mHandlerThread.quitSafely();
try {
mPreviewExtender.onDeInit();
@@ -750,6 +765,7 @@
synchronized (mInterfaceLock) {
mCaptureSession = session;
try {
+ finishPipelineInitialization();
CameraExtensionCharacteristics.initializeSession(mInitializeHandler);
} catch (RemoteException e) {
Log.e(TAG, "Failed to initialize session! Extension service does"
@@ -1640,6 +1656,8 @@
Log.e(TAG,"Failed to parcel buffer fence!");
}
}
+ parcelImage.width = img.getWidth();
+ parcelImage.height = img.getHeight();
parcelImage.format = img.getFormat();
parcelImage.timestamp = img.getTimestamp();
parcelImage.transform = img.getTransform();
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
index 950d716b..9acf9bf 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionUtils.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
-import android.hardware.HardwareBuffer;
import android.hardware.camera2.CameraExtensionCharacteristics;
import android.hardware.camera2.params.OutputConfiguration;
import android.hardware.camera2.params.StreamConfigurationMap;
@@ -78,41 +77,20 @@
SurfaceInfo surfaceInfo = new SurfaceInfo();
int nativeFormat = SurfaceUtils.getSurfaceFormat(s);
int dataspace = SurfaceUtils.getSurfaceDataspace(s);
+ Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
+ surfaceInfo.mFormat = nativeFormat;
+ surfaceInfo.mWidth = surfaceSize.getWidth();
+ surfaceInfo.mHeight = surfaceSize.getHeight();
+ surfaceInfo.mUsage = SurfaceUtils.getSurfaceUsage(s);
// Jpeg surfaces cannot be queried for their usage and other parameters
// in the usual way below. A buffer can only be de-queued after the
// producer overrides the surface dimensions to (width*height) x 1.
if ((nativeFormat == StreamConfigurationMap.HAL_PIXEL_FORMAT_BLOB) &&
(dataspace == StreamConfigurationMap.HAL_DATASPACE_V0_JFIF)) {
surfaceInfo.mFormat = ImageFormat.JPEG;
- Size surfaceSize = SurfaceUtils.getSurfaceSize(s);
- surfaceInfo.mWidth = surfaceSize.getWidth();
- surfaceInfo.mHeight = surfaceSize.getHeight();
return surfaceInfo;
}
- HardwareBuffer buffer = null;
- try {
- writer = ImageWriter.newInstance(s, 1);
- img = writer.dequeueInputImage();
- buffer = img.getHardwareBuffer();
- surfaceInfo.mFormat = buffer.getFormat();
- surfaceInfo.mWidth = buffer.getWidth();
- surfaceInfo.mHeight = buffer.getHeight();
- surfaceInfo.mUsage = buffer.getUsage();
- } catch (Exception e) {
- Log.e(TAG, "Failed to query surface, returning defaults!");
- } finally {
- if (buffer != null) {
- buffer.close();
- }
- if (img != null) {
- img.close();
- }
- if (writer != null) {
- writer.close();
- }
- }
-
return surfaceInfo;
}
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 6cbe107..8fd9a6a 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -53,6 +53,7 @@
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.HighSpeedVideoConfiguration;
import android.hardware.camera2.params.LensShadingMap;
+import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.MandatoryStreamCombination;
import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap;
import android.hardware.camera2.params.OisSample;
@@ -1708,6 +1709,34 @@
metadata.setGpsLocation((Location) value);
}
});
+ sSetCommandMap.put(CaptureRequest.SCALER_CROP_REGION.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setScalerCropRegion((Rect) value);
+ }
+ });
+ sSetCommandMap.put(CaptureRequest.CONTROL_AWB_REGIONS.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setAWBRegions((MeteringRectangle[]) value);
+ }
+ });
+ sSetCommandMap.put(CaptureRequest.CONTROL_AF_REGIONS.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setAFRegions((MeteringRectangle[]) value);
+ }
+ });
+ sSetCommandMap.put(CaptureRequest.CONTROL_AE_REGIONS.getNativeKey(),
+ new SetCommand() {
+ @Override
+ public <T> void setValue(CameraMetadataNative metadata, T value) {
+ metadata.setAERegions((MeteringRectangle[]) value);
+ }
+ });
}
private boolean setAvailableFormats(int[] value) {
@@ -1777,6 +1806,42 @@
return true;
}
+ private <T> boolean setScalerCropRegion(Rect cropRegion) {
+ if (cropRegion == null) {
+ return false;
+ }
+ setBase(CaptureRequest.SCALER_CROP_REGION_SET, true);
+ setBase(CaptureRequest.SCALER_CROP_REGION, cropRegion);
+ return true;
+ }
+
+ private <T> boolean setAFRegions(MeteringRectangle[] afRegions) {
+ if (afRegions == null) {
+ return false;
+ }
+ setBase(CaptureRequest.CONTROL_AF_REGIONS_SET, true);
+ setBase(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
+ return true;
+ }
+
+ private <T> boolean setAERegions(MeteringRectangle[] aeRegions) {
+ if (aeRegions == null) {
+ return false;
+ }
+ setBase(CaptureRequest.CONTROL_AE_REGIONS_SET, true);
+ setBase(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
+ return true;
+ }
+
+ private <T> boolean setAWBRegions(MeteringRectangle[] awbRegions) {
+ if (awbRegions == null) {
+ return false;
+ }
+ setBase(CaptureRequest.CONTROL_AWB_REGIONS_SET, true);
+ setBase(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
+ return true;
+ }
+
private void updateNativeAllocation() {
long currentBufferSize = nativeGetBufferSize(mMetadataPtr);
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index 35b5c15..57d8ded 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -105,6 +105,20 @@
}
/**
+ * Get the surface usage bits.
+ *
+ * @param surface The surface to be queried for usage.
+ * @return the native object id of the surface, 0 if surface is not backed by a native object.
+ */
+ public static long getSurfaceUsage(Surface surface) {
+ checkNotNull(surface);
+ try {
+ return nativeDetectSurfaceUsageFlags(surface);
+ } catch (IllegalArgumentException e) {
+ return 0;
+ }
+ }
+ /**
* Get the Surface size.
*
* @param surface The surface to be queried for size.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a307369..95c24ad 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3507,7 +3507,7 @@
use by third party apps.
@hide -->
<permission android:name="android.permission.UPDATE_APP_OPS_STATS"
- android:protectionLevel="signature|privileged|installer" />
+ android:protectionLevel="signature|privileged|installer|role" />
<!-- @SystemApi Allows an application to update the user app op restrictions.
Not for use by third party apps.
diff --git a/core/res/res/values-night/colors.xml b/core/res/res/values-night/colors.xml
index 816ddd4..2e4578c 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -29,5 +29,8 @@
<color name="resolver_empty_state_text">#FFFFFF</color>
<color name="resolver_empty_state_icon">#FFFFFF</color>
+ <color name="call_notification_decline_color">#E66A5E</color>
+ <color name="call_notification_answer_color">#5DBA80</color>
+
<color name="personal_apps_suspension_notification_color">#8AB4F8</color>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3c3f1f4..e612fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -893,7 +893,8 @@
return;
}
- if (mView.getAnimationViewController() instanceof UdfpsKeyguardViewController) {
+ if (mView.getAnimationViewController() instanceof UdfpsKeyguardViewController
+ && !mStatusBarStateController.isDozing()) {
mKeyguardBypassController.setUserHasDeviceEntryIntent(true);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c7c2590..84cb12c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -399,6 +399,12 @@
private boolean mPendingLock;
/**
+ * When starting to go away, flag a need to show the PIN lock so the keyguard can be brought
+ * back.
+ */
+ private boolean mPendingPinLock = false;
+
+ /**
* Whether a power button gesture (such as double tap for camera) has been detected. This is
* delivered directly from {@link KeyguardService}, immediately upon the gesture being detected.
* This is used in {@link #onStartedWakingUp} to decide whether to execute the pending lock, or
@@ -472,6 +478,19 @@
KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
@Override
+ public void onKeyguardVisibilityChanged(boolean showing) {
+ synchronized (KeyguardViewMediator.this) {
+ if (!showing && mPendingPinLock) {
+ Log.i(TAG, "PIN lock requested, starting keyguard");
+
+ // Bring the keyguard back in order to show the PIN lock
+ mPendingPinLock = false;
+ doKeyguardLocked(null);
+ }
+ }
+ }
+
+ @Override
public void onUserSwitching(int userId) {
if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
// Note that the mLockPatternUtils user has already been updated from setCurrentUser.
@@ -591,6 +610,7 @@
+ "showing; need to show keyguard so user can enter sim pin");
doKeyguardLocked(null);
} else {
+ mPendingPinLock = true;
resetStateLocked();
}
}
@@ -739,6 +759,9 @@
@Override
public void onBouncerVisiblityChanged(boolean shown) {
synchronized (KeyguardViewMediator.this) {
+ if (shown) {
+ mPendingPinLock = false;
+ }
adjustStatusBarLocked(shown, false);
}
}
@@ -2783,7 +2806,7 @@
}
}
- private void setShowingLocked(boolean showing) {
+ void setShowingLocked(boolean showing) {
setShowingLocked(showing, false /* forceCallbacks */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index e9b19e5..59e5eb8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -28,13 +28,17 @@
import android.view.WindowInsets;
import android.widget.FrameLayout;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.qs.customize.QSCustomizer;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* Wrapper view with background which contains {@link QSPanel} and {@link QuickStatusBarHeader}
*/
-public class QSContainerImpl extends FrameLayout {
+public class QSContainerImpl extends FrameLayout implements Dumpable {
private final Point mSizePoint = new Point();
private int mFancyClippingTop;
@@ -296,4 +300,11 @@
mFancyClippingBottom, mFancyClippingRadii, Path.Direction.CW);
invalidate();
}
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(getClass().getSimpleName() + " updateClippingPath: top("
+ + mFancyClippingTop + ") bottom(" + mFancyClippingBottom + ") mClippingEnabled("
+ + mClippingEnabled + ")");
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 04f692d..c9230d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -36,8 +36,10 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
@@ -131,6 +133,8 @@
*/
private boolean mAnimateNextQsUpdate;
+ private DumpManager mDumpManager;
+
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
InjectionInflationController injectionInflater, QSTileHost qsTileHost,
@@ -139,7 +143,7 @@
@Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
KeyguardBypassController keyguardBypassController,
QSFragmentComponent.Factory qsComponentFactory, FeatureFlags featureFlags,
- FalsingManager falsingManager) {
+ FalsingManager falsingManager, DumpManager dumpManager) {
mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
mInjectionInflater = injectionInflater;
mCommandQueue = commandQueue;
@@ -153,6 +157,7 @@
mFalsingManager = falsingManager;
mBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
+ mDumpManager = dumpManager;
}
@Override
@@ -197,6 +202,7 @@
mQSContainerImplController = qsFragmentComponent.getQSContainerImplController();
mQSContainerImplController.init();
mContainer = mQSContainerImplController.getView();
+ mDumpManager.registerDumpable(mContainer.getClass().getName(), mContainer);
mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter, mFalsingManager);
mQSAnimator = qsFragmentComponent.getQSAnimator();
@@ -248,6 +254,7 @@
mQSCustomizerController.setQs(null);
mQsDetailDisplayer.setQsPanelController(null);
mScrollListener = null;
+ mDumpManager.unregisterDumpable(mContainer.getClass().getName());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index ad4d450..15e0716 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -631,6 +631,9 @@
private int mScreenCornerRadius;
private boolean mQSAnimatingHiddenFromCollapsed;
+ private int mQsClipTop;
+ private int mQsClipBottom;
+ private boolean mQsVisible;
private final ContentResolver mContentResolver;
private final Executor mUiExecutor;
@@ -2402,9 +2405,12 @@
mQsTranslationForFullShadeTransition = qsTranslation;
updateQsFrameTranslation();
float currentTranslation = mQsFrame.getTranslationY();
- mQs.setFancyClipping((
- int) (top - currentTranslation),
- (int) (bottom - currentTranslation),
+ mQsClipTop = (int) (top - currentTranslation);
+ mQsClipBottom = (int) (bottom - currentTranslation);
+ mQsVisible = qsVisible;
+ mQs.setFancyClipping(
+ mQsClipTop,
+ mQsClipBottom,
radius, qsVisible
&& !mShouldUseSplitNotificationShade);
}
@@ -3242,7 +3248,10 @@
switch (mBarState) {
case KEYGUARD:
if (!mDozingOnDown) {
- if (mKeyguardBypassController.getBypassEnabled()) {
+ if (mUpdateMonitor.isFaceEnrolled()
+ && !mUpdateMonitor.isFaceDetectionRunning()
+ && !mUpdateMonitor.getUserCanSkipBouncer(
+ KeyguardUpdateMonitor.getCurrentUser())) {
mUpdateMonitor.requestFaceAuth(true);
} else {
mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
@@ -3733,7 +3742,10 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
super.dump(fd, pw, args);
- pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect());
+ pw.println(" gestureExclusionRect: " + calculateGestureExclusionRect()
+ + " applyQSClippingImmediately: top(" + mQsClipTop + ") bottom(" + mQsClipBottom
+ + ") qsVisible(" + mQsVisible
+ );
if (mKeyguardStatusBar != null) {
mKeyguardStatusBar.dump(fd, pw, args);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 35da162..2120b0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -279,11 +279,35 @@
}
@Test
- public void onActionMove_onKeyguard_setDeviceEntryIntent() throws RemoteException {
- // GIVEN the current animation is UdfpsKeyguardViewController
+ public void onActionMove_dozing_setDeviceEntryIntent() throws RemoteException {
+ // GIVEN the current animation is UdfpsKeyguardViewController and device IS dozing
when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+ when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+ // GIVEN that the overlay is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ // WHEN ACTION_DOWN is received
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ moveEvent.recycle();
+
+ // THEN device entry intent is never to true b/c device was dozing on touch
+ verify(mKeyguardBypassController, never()).setUserHasDeviceEntryIntent(true);
+ }
+
+ @Test
+ public void onActionMove_onKeyguard_setDeviceEntryIntent() throws RemoteException {
+ // GIVEN the current animation is UdfpsKeyguardViewController and device isn't dozing
+ when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+ when(mUdfpsView.getAnimationViewController()).thenReturn(mUdfpsKeyguardViewController);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
// GIVEN that the overlay is showing
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 1dacc62..ad08780 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -23,6 +23,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -33,8 +34,9 @@
import android.app.trust.TrustManager;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
@@ -65,7 +67,7 @@
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class KeyguardViewMediatorTest extends SysuiTestCase {
private KeyguardViewMediator mViewMediator;
@@ -124,6 +126,7 @@
mUnlockedScreenOffAnimationController,
() -> mNotificationShadeDepthController);
mViewMediator.start();
+ mViewMediator.onSystemReady();
}
@Test
@@ -160,4 +163,27 @@
mViewMediator.onDozeAmountChanged(1f, 1f);
assertFalse(mViewMediator.isAnimatingScreenOff());
}
+
+ @Test
+ public void restoreBouncerWhenSimLockedAndKeyguardIsGoingAway() {
+ // When showing and provisioned
+ when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
+ mViewMediator.setShowingLocked(true);
+
+ // and a SIM becomes locked and requires a PIN
+ mViewMediator.mUpdateCallback.onSimStateChanged(
+ 1 /* subId */,
+ 0 /* slotId */,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED);
+
+ // and the keyguard goes away
+ mViewMediator.setShowingLocked(false);
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ mViewMediator.mUpdateCallback.onKeyguardVisibilityChanged(false);
+
+ TestableLooper.get(this).processAllMessages();
+
+ // then make sure it comes back
+ verify(mStatusBarKeyguardViewManager, atLeast(1)).show(null);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index c1a7bc5..3ee3e55 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -190,6 +190,7 @@
mBypassController,
mQsComponentFactory,
mFeatureFlags,
- mFalsingManager);
+ mFalsingManager,
+ mock(DumpManager.class));
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 85877dd3..df269d7 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -96,6 +96,7 @@
import android.util.SparseArray;
import android.util.TimeUtils;
import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -346,6 +347,8 @@
*/
private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
+ private final AccessibilityManager mAccessibilityManager;
+
void onSwitchInputMethodLocked() {
// One caveat is that for the case where the focus is on a field for which regular autofill
// returns null, and augmented autofill is triggered, and then the user switches the input
@@ -458,9 +461,14 @@
return;
}
- mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
- mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(),
- mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
+ // If a11y touch exploration is enabled, then we do not send an inline fill request
+ // to the regular af service, because dropdown UI is easier to use.
+ if (!mAccessibilityManager.isTouchExplorationEnabled()) {
+ mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+ mPendingFillRequest.getFillContexts(),
+ mPendingFillRequest.getClientState(),
+ mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
+ }
}
mRemoteFillService.onFillRequest(mPendingFillRequest);
@@ -889,6 +897,7 @@
mRemoteFillService = serviceComponentName == null ? null
: new RemoteFillService(context, serviceComponentName, userId, this,
bindInstantServiceAllowed);
+ mAccessibilityManager = AccessibilityManager.getInstance(context);
mActivityToken = activityToken;
mHasCallback = hasCallback;
mUiLatencyHistory = uiLatencyHistory;
diff --git a/services/core/java/com/android/server/am/PhantomProcessList.java b/services/core/java/com/android/server/am/PhantomProcessList.java
index ca31681..b07684c 100644
--- a/services/core/java/com/android/server/am/PhantomProcessList.java
+++ b/services/core/java/com/android/server/am/PhantomProcessList.java
@@ -365,6 +365,9 @@
private int onPhantomProcessFdEvent(FileDescriptor fd, int events) {
synchronized (mLock) {
final PhantomProcessRecord proc = mPhantomProcessesPidFds.get(fd.getInt$());
+ if (proc == null) {
+ return 0;
+ }
if ((events & EVENT_INPUT) != 0) {
proc.onProcDied(true);
} else {
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 7d06d6e..afd1889 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -3285,6 +3285,9 @@
synchronized (mSyncRoot) {
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
+ if (display == null) {
+ return null;
+ }
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
if (device == null) {
return null;
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 9fcc9a1..6fb9e58 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3230,7 +3230,7 @@
* Interface for the system to handle request from InputMonitors.
*/
private final class InputMonitorHost extends IInputMonitorHost.Stub {
- private final IBinder mToken;
+ private IBinder mToken;
InputMonitorHost(IBinder token) {
mToken = token;
@@ -3238,12 +3238,23 @@
@Override
public void pilferPointers() {
+ if (mToken == null) {
+ throw new IllegalStateException(
+ "Illegal call to pilferPointers after InputMonitorHost is disposed.");
+ }
nativePilferPointers(mPtr, mToken);
}
@Override
public void dispose() {
- nativeRemoveInputChannel(mPtr, mToken);
+ // We do not remove the input monitor here by calling nativeRemoveInputChannel because
+ // it causes a race in InputDispatcher between the removal of the InputChannel through
+ // that call and the InputChannel#dispose call (which causes an FD hangup) from the
+ // client (b/189135695).
+ //
+ // NOTE: This means the client is responsible for properly closing the InputMonitor by
+ // disposing the InputChannel and all its duplicates.
+ mToken = null;
}
}
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index 7627281..3101ca7 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -118,12 +118,19 @@
* @param progress Value between [0, 1].
*/
public void setProgress(float progress) {
+ final boolean oldLoadingState;
final boolean newLoadingState;
synchronized (mLock) {
- updateProgressLocked(progress);
+ oldLoadingState = mLoadingState.isLoading();
+ if (oldLoadingState) {
+ // Due to asynchronous progress reporting, incomplete progress might be received
+ // after the app is migrated off incremental. Ignore such progress updates.
+ updateProgressLocked(progress);
+ }
newLoadingState = mLoadingState.isLoading();
}
- if (!newLoadingState) {
+ if (oldLoadingState && !newLoadingState) {
+ // Only report the state change when loading state changes from true to false
onLoadingStateChanged();
}
}
diff --git a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
index 53b6b41..eab3f10 100644
--- a/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
+++ b/services/core/java/com/android/server/wm/FadeRotationAnimationController.java
@@ -66,10 +66,8 @@
} else {
mNavBarToken = null;
}
- // Do not fade notification shade when running fixed rotation (not frozen) because it may
- // need to animate with the launching app.
- final WindowState notificationShade = mFrozenTimeoutRunnable == null
- ? displayPolicy.getNotificationShade() : null;
+ // Collect the target windows to fade out. The display won't wait for them to unfreeze.
+ final WindowState notificationShade = displayPolicy.getNotificationShade();
displayContent.forAllWindows(w -> {
if (w.mActivityRecord == null && w.mHasSurface && !w.mForceSeamlesslyRotate
&& !w.mIsWallpaper && !w.mIsImWindow && w != navigationBar