summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt1
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/NotificationHistory.java20
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageImpl.java3
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java6
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java13
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java2
-rw-r--r--core/java/android/service/notification/NotificationListenerFilter.java14
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java23
-rw-r--r--core/java/android/text/method/TranslationTransformationMethod.java13
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/app/NotificationHistoryTest.java44
-rw-r--r--graphics/java/android/graphics/RecordingCanvas.java11
-rw-r--r--graphics/java/android/graphics/drawable/RippleAnimationSession.java6
-rw-r--r--graphics/java/android/graphics/drawable/RippleShader.java19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java4
-rw-r--r--media/java/android/media/IMediaRouterClient.aidl2
-rw-r--r--media/java/android/media/MediaRouter.java20
-rw-r--r--packages/Connectivity/framework/Android.bp1
-rw-r--r--packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl4
-rw-r--r--packages/SystemUI/res/layout/long_screenshot.xml6
-rw-r--r--packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java65
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java3
-rw-r--r--services/Android.bp1
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java30
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java57
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java10
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java17
-rw-r--r--services/core/java/com/android/server/camera/CameraServiceProxy.java7
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java16
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java59
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryDatabase.java48
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryManager.java16
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java46
-rw-r--r--services/core/java/com/android/server/pm/IncrementalStates.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java81
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/tests/PackageManagerServiceTests/host/Android.bp10
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/intent/verify/IntentFilterVerificationTest.kt413
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp37
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/AndroidManifest.xml38
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiver.kt62
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiverTest.kt164
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp57
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest1.xml94
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest2.xml34
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest3.xml32
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Base.xml33
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4NoAutoVerify.xml33
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Wildcard.xml34
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4WildcardNoAutoVerify.xml34
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java46
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java46
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java16
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java108
-rw-r--r--telephony/java/android/telephony/ims/SipMessage.java18
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java7
-rw-r--r--telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java9
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java72
75 files changed, 972 insertions, 1315 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index c6b4ea8e803e..3d00bda551bc 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -38532,6 +38532,7 @@ package android.service.notification {
method public final java.util.List<android.app.NotificationChannelGroup> getNotificationChannelGroups(@NonNull String, @NonNull android.os.UserHandle);
method public final java.util.List<android.app.NotificationChannel> getNotificationChannels(@NonNull String, @NonNull android.os.UserHandle);
method public final android.service.notification.StatusBarNotification[] getSnoozedNotifications();
+ method public final void migrateNotificationFilter(int, @Nullable java.util.List<java.lang.String>);
method public android.os.IBinder onBind(android.content.Intent);
method public void onInterruptionFilterChanged(int);
method public void onListenerConnected();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ea57e9863e6f..091b8e5d6e9a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -13591,7 +13591,7 @@ package android.telephony.ims {
method @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
- method @Nullable public String getViaBranchParameter();
+ method @NonNull public String getViaBranchParameter();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index d0e17f00e990..dab5aff5c9a8 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -228,6 +228,7 @@ interface INotificationManager
NotificationListenerFilter getListenerFilter(in ComponentName cn, int userId);
void setListenerFilter(in ComponentName cn, int userId, in NotificationListenerFilter nlf);
+ void migrateNotificationFilter(in INotificationListener token, int defaultTypes, in List<String> disallowedPkgs);
void setToastRateLimitingEnabled(boolean enable);
}
diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java
index 0c8188b9a51e..eb9ec869af12 100644
--- a/core/java/android/app/NotificationHistory.java
+++ b/core/java/android/app/NotificationHistory.java
@@ -404,6 +404,26 @@ public final class NotificationHistory implements Parcelable {
}
/**
+ * Removes all notifications from a channel and regenerates the string pool
+ */
+ public boolean removeChannelFromWrite(String packageName, String channelId) {
+ boolean removed = false;
+ for (int i = mNotificationsToWrite.size() - 1; i >= 0; i--) {
+ HistoricalNotification hn = mNotificationsToWrite.get(i);
+ if (packageName.equals(hn.getPackage())
+ && Objects.equals(channelId, hn.getChannelId())) {
+ removed = true;
+ mNotificationsToWrite.remove(i);
+ }
+ }
+ if (removed) {
+ poolStringsFromNotifications();
+ }
+
+ return removed;
+ }
+
+ /**
* Gets pooled strings in order to write them to disk
*/
public @NonNull String[] getPooledStringsToWrite() {
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index 72c9879c9360..97e1b543520e 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -72,7 +72,6 @@ import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap;
import com.android.internal.util.Parcelling.BuiltIn.ForStringSet;
import java.security.PublicKey;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -1346,7 +1345,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
this.gwpAsanMode = in.readInt();
this.minExtensionVersions = in.readSparseIntArray();
this.mBooleans = in.readLong();
- this.mProperties = in.createTypedArrayMap(Property.CREATOR);
+ this.mProperties = in.readHashMap(boot);
this.memtagMode = in.readInt();
this.nativeHeapZeroInitialized = in.readInt();
this.requestOptimizedExternalStorageAccess = sForBoolean.unparcel(in);
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 1e62a15772e9..c1009ffb3814 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1503,7 +1503,11 @@ public final class CameraManager {
*/
public boolean cameraIdHasConcurrentStreamsLocked(String cameraId) {
if (!mDeviceStatus.containsKey(cameraId)) {
- Log.e(TAG, "cameraIdHasConcurrentStreamsLocked called on non existing camera id");
+ // physical camera ids aren't advertised in concurrent camera id combinations.
+ if (DEBUG) {
+ Log.v(TAG, " physical camera id " + cameraId + " is hidden." +
+ " Available logical camera ids : " + mDeviceStatus.toString());
+ }
return false;
}
for (Set<String> comb : mConcurrentCameraIdCombinations) {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java b/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java
index 8eb1dccdf65e..bf4593260a70 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionForwardProcessor.java
@@ -25,6 +25,7 @@ import android.media.Image;
import android.media.ImageReader;
import android.media.ImageWriter;
import android.annotation.NonNull;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.util.Size;
@@ -39,6 +40,7 @@ public class CameraExtensionForwardProcessor {
private final IPreviewImageProcessorImpl mProcessor;
private final long mOutputSurfaceUsage;
private final int mOutputSurfaceFormat;
+ private final Handler mHandler;
private ImageReader mIntermediateReader = null;
private Surface mIntermediateSurface = null;
@@ -48,10 +50,11 @@ public class CameraExtensionForwardProcessor {
private boolean mOutputAbandoned = false;
public CameraExtensionForwardProcessor(@NonNull IPreviewImageProcessorImpl processor,
- int format, long surfaceUsage) {
+ int format, long surfaceUsage, @NonNull Handler handler) {
mProcessor = processor;
mOutputSurfaceUsage = surfaceUsage;
mOutputSurfaceFormat = format;
+ mHandler = handler;
}
public void close() {
@@ -98,7 +101,7 @@ public class CameraExtensionForwardProcessor {
mResolution.getHeight(), CameraExtensionCharacteristics.PROCESSING_INPUT_FORMAT,
FORWARD_QUEUE_SIZE, mOutputSurfaceUsage);
mIntermediateSurface = mIntermediateReader.getSurface();
- mIntermediateReader.setOnImageAvailableListener(new ForwardCallback(), null);
+ mIntermediateReader.setOnImageAvailableListener(new ForwardCallback(), mHandler);
mProcessor.onOutputSurface(mIntermediateSurface, mOutputSurfaceFormat);
// PreviewImageProcessorImpl always expect the extension processing format as input
@@ -124,11 +127,15 @@ public class CameraExtensionForwardProcessor {
@Override public void onImageAvailable(ImageReader reader) {
Image processedImage = null;
try {
- processedImage = mIntermediateReader.acquireNextImage();
+ processedImage = reader.acquireNextImage();
} catch (IllegalStateException e) {
Log.e(TAG, "Failed to acquire processed image!");
return;
}
+ if (processedImage == null) {
+ Log.e(TAG, "Invalid image");
+ return;
+ }
if (mOutputSurface != null && mOutputSurface.isValid() && !mOutputAbandoned) {
if (mOutputWriter == null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 1f5098f80735..3d771c01e8ac 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -352,7 +352,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
try {
mPreviewImageProcessor = new CameraExtensionForwardProcessor(
mPreviewExtender.getPreviewImageProcessor(), repeatingSurfaceInfo.mFormat,
- repeatingSurfaceInfo.mUsage);
+ repeatingSurfaceInfo.mUsage, mHandler);
} catch (ClassCastException e) {
throw new UnsupportedOperationException("Failed casting preview processor!");
}
diff --git a/core/java/android/service/notification/NotificationListenerFilter.java b/core/java/android/service/notification/NotificationListenerFilter.java
index 9de75cac159a..a69d33c17e9d 100644
--- a/core/java/android/service/notification/NotificationListenerFilter.java
+++ b/core/java/android/service/notification/NotificationListenerFilter.java
@@ -31,15 +31,17 @@ import android.util.ArraySet;
* @hide
*/
public class NotificationListenerFilter implements Parcelable {
+
+ private static final int DEFAULT_TYPES = FLAG_FILTER_TYPE_CONVERSATIONS
+ | FLAG_FILTER_TYPE_ALERTING
+ | FLAG_FILTER_TYPE_SILENT
+ | FLAG_FILTER_TYPE_ONGOING;
private int mAllowedNotificationTypes;
// VersionedPackage is holding the pkg name and pkg uid
private ArraySet<VersionedPackage> mDisallowedPackages;
public NotificationListenerFilter() {
- mAllowedNotificationTypes = FLAG_FILTER_TYPE_CONVERSATIONS
- | FLAG_FILTER_TYPE_ALERTING
- | FLAG_FILTER_TYPE_SILENT
- | FLAG_FILTER_TYPE_ONGOING;
+ mAllowedNotificationTypes = DEFAULT_TYPES;
mDisallowedPackages = new ArraySet<>();
}
@@ -80,6 +82,10 @@ public class NotificationListenerFilter implements Parcelable {
return (mAllowedNotificationTypes & type) != 0;
}
+ public boolean areAllTypesAllowed() {
+ return DEFAULT_TYPES == mAllowedNotificationTypes;
+ }
+
public boolean isPackageAllowed(VersionedPackage pkg) {
return !mDisallowedPackages.contains(pkg);
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 09c3b2effcb0..6c775852fcee 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -792,6 +792,29 @@ public abstract class NotificationListenerService extends Service {
}
}
+ /**
+ * Lets an app migrate notification filters from its app into the OS.
+ *
+ * <p>This call will be ignored if the app has already migrated these settings or the user
+ * has set filters in the UI. This method is intended for user specific settings; if an app has
+ * already specified defaults types in its manifest with
+ * {@link #META_DATA_DEFAULT_FILTER_TYPES}, the defaultTypes option will be ignored.</p>
+ * @param defaultTypes A value representing the types of notifications that this listener should
+ * receive by default
+ * @param disallowedPkgs A list of package names whose notifications should not be seen by this
+ * listener, by default, because the listener does not process or display them, or because a
+ * user had previously disallowed these packages in the listener app's UI
+ */
+ public final void migrateNotificationFilter(@NotificationFilterTypes int defaultTypes,
+ @Nullable List<String> disallowedPkgs) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().migrateNotificationFilter(
+ mWrapper, defaultTypes, disallowedPkgs);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
/**
* Inform the notification manager that these notifications have been viewed by the
diff --git a/core/java/android/text/method/TranslationTransformationMethod.java b/core/java/android/text/method/TranslationTransformationMethod.java
index 54c0ffcdbb65..7db999a89fbe 100644
--- a/core/java/android/text/method/TranslationTransformationMethod.java
+++ b/core/java/android/text/method/TranslationTransformationMethod.java
@@ -78,11 +78,24 @@ public class TranslationTransformationMethod implements TransformationMethod2 {
if (TextUtils.isEmpty(translatedText) || isWhitespace(translatedText.toString())) {
return source;
} else {
+ // TODO(b/179693024): Remove this once we have the fix to pad the view text instead.
+ translatedText = ellipsize(translatedText, ((TextView) view).getText().length());
// TODO(b/174283799): apply the spans to the text
return translatedText;
}
}
+ private static CharSequence ellipsize(CharSequence text, int newLength) {
+ if (text.length() <= newLength) {
+ return text;
+ }
+ String ellipsis = String.valueOf('\u2026');
+ if (newLength == 1) {
+ return ellipsis;
+ }
+ return TextUtils.concat(TextUtils.trimToSize(text, newLength - 1), ellipsis);
+ }
+
@Override
public void onFocusChanged(View view, CharSequence sourceText,
boolean focused, int direction,
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index af595a43e0d1..180fc124f92e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4428,6 +4428,9 @@
-->
</integer-array>
+ <!-- Indicates whether device has a power button fingerprint sensor. -->
+ <bool name="config_is_powerbutton_fps" translatable="false" >false</bool>
+
<!-- Messages that should not be shown to the user during face auth enrollment. This should be
used to hide messages that may be too chatty or messages that the user can't do much about.
Entries are defined in android.hardware.biometrics.face@1.0 types.hal -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ba9e4543abb3..eb1fe1dd367d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2558,6 +2558,7 @@
<java-symbol type="array" name="config_biometric_sensors" />
<java-symbol type="bool" name="allow_test_udfps" />
<java-symbol type="array" name="config_udfps_sensor_props" />
+ <java-symbol type="bool" name="config_is_powerbutton_fps" />
<java-symbol type="array" name="config_face_acquire_enroll_ignorelist" />
<java-symbol type="array" name="config_face_acquire_vendor_enroll_ignorelist" />
diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
index 3df0a6871639..bd493f41d25b 100644
--- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java
+++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
@@ -29,6 +29,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -327,6 +329,48 @@ public class NotificationHistoryTest {
}
@Test
+ public void testRemoveChannelFromWrite() {
+ NotificationHistory history = new NotificationHistory();
+
+ List<HistoricalNotification> postRemoveExpectedEntries = new ArrayList<>();
+ Set<String> postRemoveExpectedStrings = new HashSet<>();
+ for (int i = 1; i <= 10; i++) {
+ HistoricalNotification n = getHistoricalNotification("pkg", i);
+
+ // Remove channel numbers 5 and 6
+ if (i != 5 && i != 6) {
+ postRemoveExpectedStrings.add(n.getPackage());
+ postRemoveExpectedStrings.add(n.getChannelName());
+ postRemoveExpectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ postRemoveExpectedStrings.add(n.getConversationId());
+ }
+ postRemoveExpectedEntries.add(n);
+ }
+
+ history.addNotificationToWrite(n);
+ }
+ // add second notification with the same channel id that will also be removed
+ history.addNotificationToWrite(getHistoricalNotification("pkg", 6));
+
+ history.poolStringsFromNotifications();
+
+ assertThat(history.getNotificationsToWrite().size()).isEqualTo(11);
+ // 1 package name and 20 unique channel names and ids and 5 conversation ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(26);
+
+ history.removeChannelFromWrite("pkg", "channelId5");
+ history.removeChannelFromWrite("pkg", "channelId6");
+
+ // 1 package names and 8 * 2 unique channel names and ids and 4 conversation ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(21);
+ assertThat(Arrays.asList(history.getPooledStringsToWrite()))
+ .containsExactlyElementsIn(postRemoveExpectedStrings);
+ assertThat(history.getNotificationsToWrite())
+ .containsExactlyElementsIn(postRemoveExpectedEntries);
+ }
+
+ @Test
public void testParceling() {
NotificationHistory history = new NotificationHistory();
diff --git a/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index 8dd7f317c842..6c03ddc4a12d 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -17,6 +17,7 @@
package android.graphics;
import android.annotation.NonNull;
+import android.os.SystemProperties;
import android.util.Pools.SynchronizedPool;
import dalvik.annotation.optimization.CriticalNative;
@@ -36,7 +37,15 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
// view hierarchy because display lists are generated recursively.
private static final int POOL_LIMIT = 25;
- private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
+ /** @hide */
+ private static int getPanelFrameSize() {
+ final int DefaultSize = 100 * 1024 * 1024; // 100 MB;
+ return Math.max(SystemProperties.getInt("ro.hwui.max_texture_allocation_size", DefaultSize),
+ DefaultSize);
+ }
+
+ /** @hide */
+ public static final int MAX_BITMAP_SIZE = getPanelFrameSize();
private static final SynchronizedPool<RecordingCanvas> sPool =
new SynchronizedPool<>(POOL_LIMIT);
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index fb089741dfb2..9ee1ef1cadd3 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -41,8 +41,8 @@ public final class RippleAnimationSession {
private static final int ENTER_ANIM_DURATION = 450;
private static final int EXIT_ANIM_DURATION = 300;
private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
- private static final Interpolator FAST_OUT_LINEAR_IN =
- new PathInterpolator(0.4f, 0f, 1f, 1f);
+ private static final Interpolator FAST_OUT_SLOW_IN =
+ new PathInterpolator(0.4f, 0f, 0.2f, 1f);
private Consumer<RippleAnimationSession> mOnSessionEnd;
private final AnimationProperties<Float, Paint> mProperties;
private AnimationProperties<CanvasProperty<Float>, CanvasProperty<Paint>> mCanvasProperties;
@@ -173,7 +173,7 @@ public final class RippleAnimationSession {
private void startAnimation(Animator expand) {
expand.setDuration(ENTER_ANIM_DURATION);
expand.addListener(new AnimatorListener(this));
- expand.setInterpolator(FAST_OUT_LINEAR_IN);
+ expand.setInterpolator(FAST_OUT_SLOW_IN);
expand.start();
mAnimateSparkle = true;
}
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index 6b2b9599facb..aaab3bd0f673 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -48,7 +48,7 @@ final class RippleShader extends RuntimeShader {
+ " float s = 0.0;\n"
+ " for (float i = 0; i < 4; i += 1) {\n"
+ " float l = i * 0.01;\n"
- + " float h = l + 0.1;\n"
+ + " float h = l + 0.2;\n"
+ " float o = smoothstep(n - l, h, n);\n"
+ " o *= abs(sin(PI * o * (t + 0.55 * i)));\n"
+ " s += o;\n"
@@ -62,7 +62,7 @@ final class RippleShader extends RuntimeShader {
+ " return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n"
+ "}\n"
+ "float softRing(vec2 uv, vec2 xy, float radius, float progress, float blur) {\n"
- + " float thickness = 0.2 * radius;\n"
+ + " float thickness = 0.3 * radius;\n"
+ " float currentRadius = radius * progress;\n"
+ " float circle_outer = softCircle(uv, xy, currentRadius + thickness, blur);\n"
+ " float circle_inner = softCircle(uv, xy, currentRadius - thickness, blur);\n"
@@ -73,18 +73,19 @@ final class RippleShader extends RuntimeShader {
+ " return (sub - start) / (end - start); \n"
+ "}\n";
private static final String SHADER_MAIN = "vec4 main(vec2 p) {\n"
- + " float fadeIn = subProgress(0., 0.175, in_progress);\n"
- + " float fadeOutNoise = subProgress(0.375, 1., in_progress);\n"
- + " float fadeOutRipple = subProgress(0.375, 0.75, in_progress);\n"
+ + " float fadeIn = subProgress(0., 0.1, in_progress);\n"
+ + " float scaleIn = subProgress(0., 0.45, in_progress);\n"
+ + " float fadeOutNoise = subProgress(0.5, 1., in_progress);\n"
+ + " float fadeOutRipple = subProgress(0.5, 0.75, in_progress);\n"
+ " vec2 center = mix(in_touch, in_origin, fadeIn);\n"
- + " float ring = softRing(p, center, in_maxRadius, fadeIn, 0.45);\n"
- + " float alpha = 1. - fadeOutNoise;\n"
+ + " float ring = softRing(p, center, in_maxRadius, scaleIn, 0.45);\n"
+ + " float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
+ " vec2 uv = p * in_resolutionScale;\n"
+ " vec2 densityUv = uv - mod(uv, in_noiseScale);\n"
+ " float sparkle = sparkles(densityUv, in_noisePhase) * ring * alpha;\n"
+ " float fade = min(fadeIn, 1. - fadeOutRipple);\n"
+ " vec4 circle = in_color * (softCircle(p, center, in_maxRadius "
- + " * fadeIn, 0.2) * fade);\n"
+ + " * scaleIn, 0.2) * fade);\n"
+ " float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n"
+ " return mix(circle, vec4(sparkle), sparkle) * mask;\n"
+ "}";
@@ -134,7 +135,7 @@ final class RippleShader extends RuntimeShader {
}
public void setResolution(float w, float h, int density) {
- float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE * 1.25f;
setUniform("in_resolutionScale", new float[] {1f / w, 1f / h});
setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 65f3d3a92476..4cf8ab476865 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -526,6 +526,10 @@ public class PhonePipMenuController implements PipMenuController {
* Handles a pointer event sent from pip input consumer.
*/
void handlePointerEvent(MotionEvent ev) {
+ if (mPipMenuView == null) {
+ return;
+ }
+
if (ev.isTouchEvent()) {
mPipMenuView.dispatchTouchEvent(ev);
} else {
diff --git a/media/java/android/media/IMediaRouterClient.aidl b/media/java/android/media/IMediaRouterClient.aidl
index 53122bb990d6..6b754e157cfb 100644
--- a/media/java/android/media/IMediaRouterClient.aidl
+++ b/media/java/android/media/IMediaRouterClient.aidl
@@ -22,6 +22,6 @@ package android.media;
oneway interface IMediaRouterClient {
void onStateChanged();
void onRestoreRoute();
- void onSelectedRouteChanged(String routeId);
+ void onGroupRouteSelected(String routeId);
void onGlobalA2dpChanged(boolean a2dpOn);
}
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index dc43ad342725..480e2eaaf40f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -122,6 +122,8 @@ public class MediaRouter {
mIsBluetoothA2dpOn = mAudioService.isBluetoothA2dpOn();
} catch (RemoteException e) {
Log.e(TAG, "Error querying Bluetooth A2DP state", e);
+ //TODO: When we reach here, mIsBluetoothA2dpOn may not be synced with
+ // mBluetoothA2dpRoute.
}
mHandler.post(new Runnable() {
@Override public void run() {
@@ -403,18 +405,18 @@ public class MediaRouter {
}
}
- void updateSelectedRouteForId(String routeId) {
- RouteInfo selectedRoute = isBluetoothA2dpOn()
+ void handleGroupRouteSelected(String routeId) {
+ RouteInfo routeToSelect = isBluetoothA2dpOn()
? mBluetoothA2dpRoute : mDefaultAudioVideo;
final int count = mRoutes.size();
for (int i = 0; i < count; i++) {
final RouteInfo route = mRoutes.get(i);
if (TextUtils.equals(route.mGlobalRouteId, routeId)) {
- selectedRoute = route;
+ routeToSelect = route;
}
}
- if (selectedRoute != mSelectedRoute) {
- selectRouteStatic(selectedRoute.mSupportedTypes, selectedRoute, false);
+ if (routeToSelect != mSelectedRoute) {
+ selectRouteStatic(routeToSelect.mSupportedTypes, routeToSelect, /*explicit=*/false);
}
}
@@ -675,10 +677,10 @@ public class MediaRouter {
}
@Override
- public void onSelectedRouteChanged(String routeId) {
+ public void onGroupRouteSelected(String groupRouteId) {
mHandler.post(() -> {
if (Client.this == mClient) {
- updateSelectedRouteForId(routeId);
+ handleGroupRouteSelected(groupRouteId);
}
});
}
@@ -689,9 +691,9 @@ public class MediaRouter {
public void onGlobalA2dpChanged(boolean a2dpOn) {
mHandler.post(() -> {
if (mSelectedRoute == mDefaultAudioVideo && a2dpOn) {
- setSelectedRoute(mBluetoothA2dpRoute, false);
+ setSelectedRoute(mBluetoothA2dpRoute, /*explicit=*/false);
} else if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpOn) {
- setSelectedRoute(mDefaultAudioVideo, false);
+ setSelectedRoute(mDefaultAudioVideo, /*explicit=*/false);
}
});
}
diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp
index 4185a42c60f0..5f5ebf410f21 100644
--- a/packages/Connectivity/framework/Android.bp
+++ b/packages/Connectivity/framework/Android.bp
@@ -108,6 +108,7 @@ java_sdk_library {
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
"//packages/modules/Connectivity/tests:__subpackages__",
"//packages/modules/NetworkStack/tests:__subpackages__",
+ "//packages/modules/Wifi/service/tests/wifitests",
],
apex_available: [
"com.android.tethering",
diff --git a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
index 0d70f2a1ed2c..3495efc1f1d0 100644
--- a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
+++ b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
@@ -18,5 +18,5 @@
package android.net;
// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
-// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
-@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
+// build rule).
+@JavaOnlyStableParcelable parcelable IpPrefix;
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 8b2d4e0a44b9..e775de2d8e06 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -52,8 +52,9 @@
android:id="@+id/preview"
android:layout_width="0px"
android:layout_height="0px"
- android:layout_marginBottom="42dp"
android:paddingHorizontal="48dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="42dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@id/save"
@@ -68,7 +69,8 @@
android:id="@+id/crop_view"
android:layout_width="0px"
android:layout_height="0px"
- android:layout_marginBottom="42dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="42dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toTopOf="@id/preview"
diff --git a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
index ed465de0e766..15312ad9dfd1 100644
--- a/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
+++ b/packages/SystemUI/src/com/android/keyguard/DisabledUdfpsController.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.hardware.biometrics.BiometricSourceType;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -73,7 +74,7 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
@NonNull KeyguardStateController keyguardStateController
) {
super(view);
- mView.setOnClickListener(mOnClickListener);
+ mView.setOnTouchListener(mOnTouchListener);
mView.setSensorProperties(authController.getUdfpsProps().get(0));
mStatusBarStateController = statusBarStateController;
@@ -153,11 +154,11 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
}
- private final View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
@Override
- public void onClick(View v) {
- // if the device is locked, shows bouncer, else goes to launcher
+ public boolean onTouch(View v, MotionEvent event) {
mKeyguardViewController.showBouncer(/* scrim */ true);
+ return true;
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index 60fdbab8482c..5647e4366075 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -32,9 +32,10 @@ import android.widget.FrameLayout;
* - optionally can override dozeTimeTick to adjust views for burn-in mitigation
*/
abstract class UdfpsAnimationView extends FrameLayout {
-
+ // mAlpha takes into consideration the status bar expansion amount to fade out icon when
+ // the status bar is expanded
private int mAlpha;
- private boolean mPauseAuth;
+ boolean mPauseAuth;
public UdfpsAnimationView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -75,7 +76,7 @@ abstract class UdfpsAnimationView extends FrameLayout {
getDrawable().setAlpha(calculateAlpha());
}
- protected final int calculateAlpha() {
+ int calculateAlpha() {
return mPauseAuth ? mAlpha : 255;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
index 2f025f63034e..f4993f46bf1d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.java
@@ -16,10 +16,6 @@
package com.android.systemui.biometrics;
-import static com.android.systemui.statusbar.StatusBarState.FULLSCREEN_USER_SWITCHER;
-import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
-import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
-
import android.annotation.NonNull;
import android.graphics.PointF;
import android.graphics.RectF;
@@ -68,18 +64,13 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
@Override
protected void onViewAttached() {
- mStatusBarStateController.addCallback(mStateListener);
- mStateListener.onStateChanged(mStatusBarStateController.getState());
mStatusBar.addExpansionChangedListener(mStatusBarExpansionChangedListener);
-
mDumpManger.registerDumpable(getDumpTag(), this);
}
@Override
protected void onViewDetached() {
- mStatusBarStateController.removeCallback(mStateListener);
mStatusBar.removeExpansionChangedListener(mStatusBarExpansionChangedListener);
-
mDumpManger.unregisterDumpable(getDumpTag());
}
@@ -106,9 +97,7 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
* authentication.
*/
boolean shouldPauseAuth() {
- return (mNotificationShadeExpanded && mStatusBarState != KEYGUARD)
- || mStatusBarState == SHADE_LOCKED
- || mStatusBarState == FULLSCREEN_USER_SWITCHER;
+ return mNotificationShadeExpanded;
}
/**
@@ -188,13 +177,4 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
updatePauseAuth();
}
};
-
- private final StatusBarStateController.StateListener mStateListener =
- new StatusBarStateController.StateListener() {
- @Override
- public void onStateChanged(int newState) {
- mStatusBarState = newState;
- updatePauseAuth();
- }
- };
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 7b5d7cb5a525..2bdbf518e203 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -52,6 +52,7 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeReceiver;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -90,6 +91,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull private final DumpManager mDumpManager;
@NonNull private final AuthRippleController mAuthRippleController;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @NonNull private final KeyguardViewMediator mKeyguardViewMediator;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -310,7 +312,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@NonNull DumpManager dumpManager,
@NonNull AuthRippleController authRippleController,
- @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor) {
+ @NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
+ @NonNull KeyguardViewMediator keyguardViewMediator) {
mContext = context;
mInflater = inflater;
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
@@ -324,6 +327,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
mDumpManager = dumpManager;
mAuthRippleController = authRippleController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mKeyguardViewMediator = keyguardViewMediator;
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -491,7 +495,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
mKeyguardViewManager,
mKeyguardUpdateMonitor,
mFgExecutor,
- mDumpManager
+ mDumpManager,
+ mKeyguardViewMediator
);
case IUdfpsOverlayController.REASON_AUTH_BP:
// note: empty controller, currently shows no visual affordance
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 4590182ac870..fc906f2137f2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -97,6 +97,11 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
}
}
+ @Override
+ int calculateAlpha() {
+ return mPauseAuth ? 0 : 255;
+ }
+
void onDozeAmountChanged(float linear, float eased) {
mFingerprintDrawable.onDozeAmountChanged(linear, eased);
}
@@ -153,6 +158,10 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
return mStatusBarState == StatusBarState.SHADE_LOCKED;
}
+ boolean isHome() {
+ return mStatusBarState == StatusBarState.SHADE;
+ }
+
/**
* Animates out the bg protection circle behind the fp icon to unhighlight the icon.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 9d846fa54e5b..dc0c685bf01e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+
import android.annotation.NonNull;
import android.hardware.biometrics.BiometricSourceType;
@@ -24,7 +26,9 @@ import androidx.annotation.Nullable;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -45,12 +49,15 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@NonNull private final DelayableExecutor mExecutor;
+ @NonNull private final KeyguardViewMediator mKeyguardViewMediator;
@Nullable private Runnable mCancelRunnable;
private boolean mShowBouncer;
private boolean mQsExpanded;
private boolean mFaceDetectRunning;
private boolean mHintShown;
+ private boolean mTransitioningFromHome;
+ private int mStatusBarState;
protected UdfpsKeyguardViewController(
@NonNull UdfpsKeyguardView view,
@@ -59,11 +66,13 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@NonNull DelayableExecutor mainDelayableExecutor,
- @NonNull DumpManager dumpManager) {
+ @NonNull DumpManager dumpManager,
+ @NonNull KeyguardViewMediator keyguardViewMediator) {
super(view, statusBarStateController, statusBar, dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mExecutor = mainDelayableExecutor;
+ mKeyguardViewMediator = keyguardViewMediator;
}
@Override
@@ -94,6 +103,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mStatusBarStateController.removeCallback(mStateListener);
mAlternateAuthInterceptor.hideAlternateAuthBouncer();
mKeyguardViewManager.setAlternateAuthInterceptor(null);
+ mTransitioningFromHome = false;
if (mCancelRunnable != null) {
mCancelRunnable.run();
@@ -106,17 +116,18 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
super.dump(fd, pw, args);
pw.println("mShowBouncer=" + mShowBouncer);
pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
+ pw.println("mTransitioningFromHomeToKeyguard=" + mTransitioningFromHome);
}
/**
* Overrides non-bouncer show logic in shouldPauseAuth to still auth.
*/
- private void showBouncer(boolean forceShow) {
- if (mShowBouncer == forceShow) {
+ private void showBouncer(boolean show) {
+ if (mShowBouncer == show) {
return;
}
- mShowBouncer = forceShow;
+ mShowBouncer = show;
updatePauseAuth();
if (mShowBouncer) {
mView.animateUdfpsBouncer();
@@ -128,18 +139,26 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
/**
* Returns true if the fingerprint manager is running but we want to temporarily pause
* authentication. On the keyguard, we may want to show udfps when the shade
- * is expanded, so this can be overridden with the forceShow method.
+ * is expanded, so this can be overridden with the showBouncer method.
*/
public boolean shouldPauseAuth() {
if (mShowBouncer) {
return false;
}
+ if (mStatusBarState != KEYGUARD) {
+ return true;
+ }
+
+ if (mTransitioningFromHome && mKeyguardViewMediator.isAnimatingScreenOff()) {
+ return true;
+ }
+
if (mQsExpanded) {
return true;
}
- return super.shouldPauseAuth();
+ return false;
}
private void cancelDelayedHint() {
@@ -176,12 +195,25 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
new StatusBarStateController.StateListener() {
@Override
public void onDozeAmountChanged(float linear, float eased) {
- mView.onDozeAmountChanged(linear, eased);
if (linear != 0) showBouncer(false);
+ mView.onDozeAmountChanged(linear, eased);
+ if (linear == 1f) {
+ // transition has finished
+ mTransitioningFromHome = false;
+ }
+ updatePauseAuth();
+ }
+
+ @Override
+ public void onStatePreChange(int oldState, int newState) {
+ mTransitioningFromHome = oldState == StatusBarState.SHADE
+ && newState == StatusBarState.KEYGUARD;
+ updatePauseAuth();
}
@Override
public void onStateChanged(int statusBarState) {
+ mStatusBarState = statusBarState;
mView.setStatusBarState(statusBarState);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index c7ed89ba49b1..3d5a709a5fdd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -43,7 +43,7 @@ public class QSTileView extends QSTileBaseView {
protected TextView mLabel;
protected TextView mSecondLine;
private ImageView mPadLock;
- private int mState;
+ protected int mState;
protected ViewGroup mLabelContainer;
private View mExpandIndicator;
private View mExpandSpace;
@@ -133,14 +133,7 @@ public class QSTileView extends QSTileBaseView {
protected void handleStateChanged(QSTile.State state) {
super.handleStateChanged(state);
if (!Objects.equals(mLabel.getText(), state.label) || mState != state.state) {
- ColorStateList labelColor;
- if (state.state == Tile.STATE_ACTIVE) {
- labelColor = mColorLabelActive;
- } else if (state.state == Tile.STATE_INACTIVE) {
- labelColor = mColorLabelInactive;
- } else {
- labelColor = mColorLabelUnavailable;
- }
+ ColorStateList labelColor = getLabelColor(state.state);
changeLabelColor(labelColor);
mState = state.state;
mLabel.setText(state.label);
@@ -163,6 +156,15 @@ public class QSTileView extends QSTileBaseView {
mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
}
+ protected final ColorStateList getLabelColor(int state) {
+ if (state == Tile.STATE_ACTIVE) {
+ return mColorLabelActive;
+ } else if (state == Tile.STATE_INACTIVE) {
+ return mColorLabelInactive;
+ }
+ return mColorLabelUnavailable;
+ }
+
protected void changeLabelColor(ColorStateList color) {
mLabel.setTextColor(color);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index 188e89edd89a..ea6876f5999b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -57,6 +57,7 @@ open class QSTileViewHorizontal(
addView(mIcon, 0, LayoutParams(iconSize, iconSize))
mColorLabelActive = ColorStateList.valueOf(getColorForState(getContext(), STATE_ACTIVE))
+ changeLabelColor(getLabelColor(mState)) // Matches the default state of the tile
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
@@ -121,13 +122,11 @@ open class QSTileViewHorizontal(
if (allowAnimations) {
animateBackground(newColor)
} else {
- if (newColor != paintColor) {
- clearBackgroundAnimator()
- colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))?.also {
- paintColor = newColor
- }
+ clearBackgroundAnimator()
+ colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))?.also {
paintColor = newColor
}
+ paintColor = newColor
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index 04d199645b24..9ce0eebfd441 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -411,19 +411,22 @@ public class LongScreenshotActivity extends Activity {
float imageRatio = bounds.width() / (float) bounds.height();
int previewWidth = mPreview.getWidth() - mPreview.getPaddingLeft()
- mPreview.getPaddingRight();
- float viewRatio = previewWidth / (float) mPreview.getHeight();
+ int previewHeight = mPreview.getHeight() - mPreview.getPaddingTop()
+ - mPreview.getPaddingBottom();
+ float viewRatio = previewWidth / (float) previewHeight;
if (imageRatio > viewRatio) {
// Image is full width and height is constrained, compute extra padding to inform
// CropView
- float imageHeight = mPreview.getHeight() * viewRatio / imageRatio;
- int extraPadding = (int) (mPreview.getHeight() - imageHeight) / 2;
- mCropView.setExtraPadding(extraPadding, extraPadding);
+ float imageHeight = previewHeight * viewRatio / imageRatio;
+ int extraPadding = (int) (previewHeight - imageHeight) / 2;
+ mCropView.setExtraPadding(extraPadding + mPreview.getPaddingTop(),
+ extraPadding + mPreview.getPaddingBottom());
mCropView.setImageWidth(previewWidth);
} else {
// Image is full height
- mCropView.setExtraPadding(0, 0);
- mCropView.setImageWidth((int) (mPreview.getHeight() * imageRatio));
+ mCropView.setExtraPadding(mPreview.getPaddingTop(), mPreview.getPaddingBottom());
+ mCropView.setImageWidth((int) (previewHeight * imageRatio));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 91a4f94eea43..50cbbd5d4852 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -393,11 +393,6 @@ class NotificationWakeUpCoordinator @Inject constructor(
override fun onDozingChanged(isDozing: Boolean) {
if (isDozing) {
setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
- } else {
- // We only unset the flag once we fully went asleep. If the user interrupts the
- // animation in the middle, we have to abort the animation as well to make sure
- // the notifications are visible again.
- animatingScreenOff = false
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index aa0be8a39716..8ed9cd66aed1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -239,6 +239,7 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.tuner.TunerService;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
@@ -791,6 +792,7 @@ public class StatusBar extends SystemUI implements DemoMode,
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
OngoingCallController ongoingCallController,
+ TunerService tunerService,
FeatureFlags featureFlags) {
super(context);
mNotificationsController = notificationsController;
@@ -873,6 +875,15 @@ public class StatusBar extends SystemUI implements DemoMode,
mOngoingCallController = ongoingCallController;
mFeatureFlags = featureFlags;
+ tunerService.addTunable(
+ (key, newValue) -> {
+ if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) {
+ updateLightRevealScrimVisibility();
+ }
+ },
+ Settings.Secure.DOZE_ALWAYS_ON
+ );
+
mExpansionChangedListeners = new ArrayList<>();
mBubbleExpandListener =
@@ -1216,15 +1227,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
mChargingRippleAnimationController.setViewHost(mNotificationShadeWindowView);
-
-
- if (mFeatureFlags.useNewLockscreenAnimations()
- && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
- mLightRevealScrim.setVisibility(View.VISIBLE);
- mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
- } else {
- mLightRevealScrim.setVisibility(View.GONE);
- }
+ updateLightRevealScrimVisibility();
mNotificationPanelViewController.initDependencies(
this,
@@ -4654,4 +4657,19 @@ public class StatusBar extends SystemUI implements DemoMode,
public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
mExpansionChangedListeners.remove(listener);
}
+
+ private void updateLightRevealScrimVisibility() {
+ if (mLightRevealScrim == null) {
+ // status bar may not be inflated yet
+ return;
+ }
+
+ if (mFeatureFlags.useNewLockscreenAnimations()
+ && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
+ mLightRevealScrim.setVisibility(View.VISIBLE);
+ mLightRevealScrim.setRevealEffect(LiftReveal.INSTANCE);
+ } else {
+ mLightRevealScrim.setVisibility(View.GONE);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 785d98ccd8dc..2c2779e53e16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -100,6 +100,7 @@ import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.tuner.TunerService;
import com.android.systemui.volume.VolumeComponent;
import com.android.systemui.wmshell.BubblesManager;
import com.android.wm.shell.bubbles.Bubbles;
@@ -208,6 +209,7 @@ public interface StatusBarPhoneModule {
BrightnessSlider.Factory brightnessSliderFactory,
WiredChargingRippleController chargingRippleAnimationController,
OngoingCallController ongoingCallController,
+ TunerService tunerService,
FeatureFlags featureFlags) {
return new StatusBar(
context,
@@ -291,6 +293,7 @@ public interface StatusBarPhoneModule {
brightnessSliderFactory,
chargingRippleAnimationController,
ongoingCallController,
+ tunerService,
featureFlags);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 1026a5ca1be5..a8a3d79c67cf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -301,11 +301,13 @@ public class VolumeDialogImpl implements VolumeDialog,
// the volume dialog container itself, so this is fine.
for (int i = 0; i < mDialogView.getChildCount(); i++) {
final View view = mDialogView.getChildAt(i);
+ final int[] locInWindow = new int[2];
+ view.getLocationInWindow(locInWindow);
mTouchableRegion.op(
- view.getLeft(),
- view.getTop(),
- view.getRight(),
- view.getBottom(),
+ locInWindow[0],
+ locInWindow[1],
+ locInWindow[0] + view.getWidth(),
+ locInWindow[1] + view.getHeight(),
Region.Op.UNION);
}
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 beca96549fb9..9504970af19c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -47,6 +47,7 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -103,6 +104,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
+ private KeyguardViewMediator mKeyguardViewMediator;
+ @Mock
private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback;
private FakeExecutor mFgExecutor;
@@ -155,7 +158,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
mStatusBarKeyguardViewManager,
mDumpManager,
mAuthRippleController,
- mKeyguardUpdateMonitor);
+ mKeyguardUpdateMonitor,
+ mKeyguardViewMediator);
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
mOverlayController = mOverlayCaptor.getValue();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 879cdbfb775f..2383c7b985c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -18,7 +18,7 @@ package com.android.systemui.biometrics;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -30,6 +30,7 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -44,7 +45,6 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -65,12 +65,13 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
private DelayableExecutor mExecutor;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private KeyguardViewMediator mKeyguardViewMediator;
private UdfpsKeyguardViewController mController;
// Capture listeners so that they can be used to send events
@Captor private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerCaptor;
- private StatusBarStateController.StateListener mParentStatusBarStateListener;
private StatusBarStateController.StateListener mStatusBarStateListener;
@Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
@@ -83,6 +84,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(false);
mController = new UdfpsKeyguardViewController(
mView,
mStatusBarStateController,
@@ -90,7 +92,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mStatusBarKeyguardViewManager,
mKeyguardUpdateMonitor,
mExecutor,
- mDumpManager);
+ mDumpManager,
+ mKeyguardViewMediator);
}
@Test
@@ -108,7 +111,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
@Test
public void testViewControllerQueriesSBStateOnAttached() {
mController.onViewAttached();
- verify(mStatusBarStateController, times(2)).getState();
+ verify(mStatusBarStateController).getState();
verify(mStatusBarStateController).getDozeAmount();
final float dozeAmount = .88f;
@@ -117,7 +120,7 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
captureStatusBarStateListeners();
mController.onViewAttached();
- verify(mView).setPauseAuth(true);
+ verify(mView, atLeast(1)).setPauseAuth(true);
verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount);
}
@@ -128,7 +131,6 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
captureExpansionListener();
mController.onViewDetached();
- verify(mStatusBarStateController).removeCallback(mParentStatusBarStateListener);
verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
verify(mStatusBar).removeExpansionChangedListener(mExpansionListener);
}
@@ -168,6 +170,47 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
}
@Test
+ public void testShouldPauseAuthOnShade() {
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+ captureExpansionListener();
+
+ // WHEN not on keyguard yet (shade = home)
+ sendStatusBarStateChanged(StatusBarState.SHADE);
+
+ // THEN pause auth
+ assertTrue(mController.shouldPauseAuth());
+ }
+
+ @Test
+ public void testShouldPauseAuthAnimatingScreenOffFromShade() {
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+ captureExpansionListener();
+
+ // WHEN transitioning from home/shade => keyguard + animating screen off
+ mStatusBarStateListener.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD);
+ when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(true);
+
+ // THEN pause auth
+ assertTrue(mController.shouldPauseAuth());
+ }
+
+ @Test
+ public void testDoNotPauseAuthAnimatingScreenOffFromLS() {
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+ captureExpansionListener();
+
+ // WHEN animating screen off transition from LS => AOD
+ sendStatusBarStateChanged(StatusBarState.KEYGUARD);
+ when(mKeyguardViewMediator.isAnimatingScreenOff()).thenReturn(true);
+
+ // THEN don't pause auth
+ assertFalse(mController.shouldPauseAuth());
+ }
+
+ @Test
public void testOverrideShouldPauseAuthOnShadeLocked() {
mController.onViewAttached();
captureStatusBarStateListeners();
@@ -203,15 +246,11 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
private void sendStatusBarStateChanged(int statusBarState) {
mStatusBarStateListener.onStateChanged(statusBarState);
- mParentStatusBarStateListener.onStateChanged(statusBarState);
}
private void captureStatusBarStateListeners() {
- verify(mStatusBarStateController, times(2)).addCallback(mStateListenerCaptor.capture());
- List<StatusBarStateController.StateListener> stateListeners =
- mStateListenerCaptor.getAllValues();
- mParentStatusBarStateListener = stateListeners.get(0);
- mStatusBarStateListener = stateListeners.get(1);
+ verify(mStatusBarStateController).addCallback(mStateListenerCaptor.capture());
+ mStatusBarStateListener = mStateListenerCaptor.getValue();
}
private void captureExpansionListener() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 39f0db5228bc..98a44875fbd7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -143,6 +143,7 @@ import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
@@ -265,6 +266,7 @@ public class StatusBarTest extends SysuiTestCase {
@Mock private BrightnessSlider.Factory mBrightnessSliderFactory;
@Mock private WiredChargingRippleController mWiredChargingRippleController;
@Mock private OngoingCallController mOngoingCallController;
+ @Mock private TunerService mTunerService;
@Mock private FeatureFlags mFeatureFlags;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -430,6 +432,7 @@ public class StatusBarTest extends SysuiTestCase {
mBrightnessSliderFactory,
mWiredChargingRippleController,
mOngoingCallController,
+ mTunerService,
mFeatureFlags);
when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
diff --git a/services/Android.bp b/services/Android.bp
index 81bb579fdabc..25b270ea1a79 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -123,6 +123,7 @@ java_library {
libs: [
"android.hidl.manager-V1.0-java",
"framework-tethering.stubs.module_lib",
+ "service-art.stubs.system_server",
],
// Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 153152e0aca6..239058984b99 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4056,7 +4056,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
}
- decrementRequestCount(nri);
+ nri.decrementRequestCount();
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (null != nri.getActiveRequest()) {
@@ -4167,14 +4167,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
? mSystemNetworkRequestCounter : mNetworkRequestCounter;
}
- private void incrementRequestCountOrThrow(NetworkRequestInfo nri) {
- getRequestCounter(nri).incrementCountOrThrow(nri.mUid);
- }
-
- private void decrementRequestCount(NetworkRequestInfo nri) {
- getRequestCounter(nri).decrementCount(nri.mUid);
- }
-
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -5462,6 +5454,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Nullable
final String mCallingAttributionTag;
+ // Counter keeping track of this NRI.
+ final PerUidCounter mPerUidCounter;
+
// Effective UID of this request. This is different from mUid when a privileged process
// files a request on behalf of another UID. This UID is used to determine blocked status,
// UID matching, and so on. mUid above is used for permission checks and to enforce the
@@ -5512,7 +5507,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mAsUid = asUid;
- incrementRequestCountOrThrow(this);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
/**
* Location sensitive data not included in pending intent. Only included in
* {@link NetworkCallback}.
@@ -5544,7 +5540,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUid = mDeps.getCallingUid();
mAsUid = asUid;
mPendingIntent = null;
- incrementRequestCountOrThrow(this);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
linkDeathRecipient();
@@ -5582,7 +5579,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUid = nri.mUid;
mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
- incrementRequestCountOrThrow(this);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
linkDeathRecipient();
@@ -5614,6 +5612,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
return Collections.unmodifiableList(tempRequests);
}
+ void decrementRequestCount() {
+ mPerUidCounter.decrementCount(mUid);
+ }
+
void linkDeathRecipient() {
if (null != mBinder) {
try {
@@ -8883,7 +8885,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementRequestCount(nri);
+ nri.decrementRequestCount();
return;
}
@@ -8949,7 +8951,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementRequestCount(nri);
+ nri.decrementRequestCount();
iCb.unlinkToDeath(cbInfo, 0);
}
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index ed579f2df4fc..c792c542088d 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -35,7 +37,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.vcn.IVcnManagementService;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -161,6 +165,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull private final VcnContext mVcnContext;
@NonNull private final BroadcastReceiver mPkgChangeReceiver;
+ @NonNull
+ private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback();
+
/** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
@Nullable private LocationPermissionChecker mLocationPermissionChecker;
@@ -356,6 +363,10 @@ public class VcnManagementService extends IVcnManagementService.Stub {
public void systemReady() {
mContext.getSystemService(ConnectivityManager.class)
.registerNetworkProvider(mNetworkProvider);
+ mContext.getSystemService(ConnectivityManager.class)
+ .registerNetworkCallback(
+ new NetworkRequest.Builder().clearCapabilities().build(),
+ mTrackingNetworkCallback);
mTelephonySubscriptionTracker.register();
mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext());
}
@@ -791,8 +802,9 @@ public class VcnManagementService extends IVcnManagementService.Stub {
NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
+ final NetworkCapabilities result = ncBuilder.build();
return new VcnUnderlyingNetworkPolicy(
- false /* isTearDownRequested */, ncBuilder.build());
+ mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
});
}
@@ -939,6 +951,49 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@Nullable String exceptionMessage);
}
+ /**
+ * TrackingNetworkCallback tracks all active networks
+ *
+ * <p>This is used to ensure that no underlying networks have immutable capabilities changed
+ * without requiring a Network restart.
+ */
+ private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback {
+ private final Map<Network, NetworkCapabilities> mCaps = new ArrayMap<>();
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) {
+ synchronized (mCaps) {
+ mCaps.put(network, caps);
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ synchronized (mCaps) {
+ mCaps.remove(network);
+ }
+ }
+
+ private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
+ if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) {
+ return false;
+ }
+
+ synchronized (mCaps) {
+ for (NetworkCapabilities existing : mCaps.values()) {
+ if (existing.hasTransport(TRANSPORT_WIFI)
+ && caps.getSubIds().equals(existing.getSubIds())) {
+ // Restart if any immutable capabilities have changed
+ return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+
/** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
private class VcnCallbackImpl implements VcnCallback {
@NonNull private final ParcelUuid mSubGroup;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 8ad11d161cdc..7c5936720feb 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1864,6 +1864,7 @@ public final class OomAdjuster {
}
int capabilityFromFGS = 0; // capability from foreground service.
+ boolean scheduleLikeTopApp = false;
for (int is = psr.numberOfRunningServices() - 1;
is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
|| schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
@@ -1975,6 +1976,8 @@ public final class OomAdjuster {
int clientAdj = cstate.getCurRawAdj();
int clientProcState = cstate.getCurRawProcState();
+ final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
+
// pass client's mAllowStartFgs to the app if client is not persistent process.
if (cstate.getAllowedStartFgs() != REASON_DENIED
&& cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) {
@@ -2170,8 +2173,10 @@ public final class OomAdjuster {
}
if (schedGroup < ProcessList.SCHED_GROUP_TOP_APP
- && (cr.flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0) {
+ && (cr.flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0
+ && clientIsSystem) {
schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ scheduleLikeTopApp = true;
}
if (!trackedProcState) {
@@ -2438,7 +2443,8 @@ public final class OomAdjuster {
// Put bound foreground services in a special sched group for additional
// restrictions on screen off
if (procState >= PROCESS_STATE_BOUND_FOREGROUND_SERVICE
- && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE) {
+ && mService.mWakefulness.get() != PowerManagerInternal.WAKEFULNESS_AWAKE
+ && !scheduleLikeTopApp) {
if (schedGroup > ProcessList.SCHED_GROUP_RESTRICTED) {
schedGroup = ProcessList.SCHED_GROUP_RESTRICTED;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index e149ca9428dd..243cc7cd9b00 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -119,6 +119,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
private int mCurrentUserId = UserHandle.USER_NULL;
private final boolean mIsUdfps;
private final int mSensorId;
+ private boolean mIsPowerbuttonFps;
private final class BiometricTaskStackListener extends TaskStackListener {
@Override
@@ -345,9 +346,18 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mIsUdfps = !ArrayUtils.isEmpty(
mContext.getResources().getIntArray(R.array.config_udfps_sensor_props));
- final @FingerprintSensorProperties.SensorType int sensorType =
- mIsUdfps ? FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
- : FingerprintSensorProperties.TYPE_REAR;
+ // config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor.
+ mIsPowerbuttonFps = mContext.getResources().getBoolean(R.bool.config_is_powerbutton_fps);
+
+ final @FingerprintSensorProperties.SensorType int sensorType;
+ if (mIsUdfps) {
+ sensorType = FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
+ } else if (mIsPowerbuttonFps) {
+ sensorType = FingerprintSensorProperties.TYPE_POWER_BUTTON;
+ } else {
+ sensorType = FingerprintSensorProperties.TYPE_REAR;
+ }
+
// IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
// cannot be checked
final boolean resetLockoutRequiresHardwareAuthToken = false;
@@ -835,6 +845,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
try {
dump.put("service", TAG);
dump.put("isUdfps", mIsUdfps);
+ dump.put("isPowerbuttonFps", mIsPowerbuttonFps);
JSONArray sets = new JSONArray();
for (UserInfo user : UserManager.get(mContext).getUsers()) {
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index cd2457635932..1bbcedeb0494 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -528,8 +528,13 @@ public class CameraServiceProxy extends SystemService
} catch (RemoteException e) {
Log.e(TAG, "Failed to register task stack listener!");
}
+ }
- CameraStatsJobService.schedule(mContext);
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ CameraStatsJobService.schedule(mContext);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index b85cea7a637d..3d19b70ca95f 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -728,7 +728,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
clientRecord.mGroupId = groupId;
if (groupId != null) {
userRecord.addToGroup(groupId, clientRecord);
- userRecord.mHandler.obtainMessage(UserHandler.MSG_UPDATE_SELECTED_ROUTE, groupId)
+ userRecord.mHandler.obtainMessage(UserHandler.MSG_NOTIFY_GROUP_ROUTE_SELECTED, groupId)
.sendToTarget();
}
}
@@ -809,7 +809,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
if (group != null) {
group.mSelectedRouteId = routeId;
clientRecord.mUserRecord.mHandler.obtainMessage(
- UserHandler.MSG_UPDATE_SELECTED_ROUTE, clientRecord.mGroupId)
+ UserHandler.MSG_NOTIFY_GROUP_ROUTE_SELECTED, clientRecord.mGroupId)
.sendToTarget();
}
}
@@ -1079,7 +1079,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
public static final int MSG_REQUEST_UPDATE_VOLUME = 7;
private static final int MSG_UPDATE_CLIENT_STATE = 8;
private static final int MSG_CONNECTION_TIMED_OUT = 9;
- private static final int MSG_UPDATE_SELECTED_ROUTE = 10;
+ private static final int MSG_NOTIFY_GROUP_ROUTE_SELECTED = 10;
private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1;
private static final int TIMEOUT_REASON_CONNECTION_LOST = 2;
@@ -1156,8 +1156,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
connectionTimedOut();
break;
}
- case MSG_UPDATE_SELECTED_ROUTE: {
- updateSelectedRoute((String) msg.obj);
+ case MSG_NOTIFY_GROUP_ROUTE_SELECTED: {
+ notifyGroupRouteSelected((String) msg.obj);
break;
}
}
@@ -1483,9 +1483,9 @@ public final class MediaRouterService extends IMediaRouterService.Stub
}
}
- private void updateSelectedRoute(String groupId) {
+ private void notifyGroupRouteSelected(String groupId) {
try {
- String selectedRouteId = null;
+ String selectedRouteId;
synchronized (mService.mLock) {
ClientGroup group = mUserRecord.mClientGroupMap.get(groupId);
if (group == null) {
@@ -1504,7 +1504,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub
final int count = mTempClients.size();
for (int i = 0; i < count; i++) {
try {
- mTempClients.get(i).onSelectedRouteChanged(selectedRouteId);
+ mTempClients.get(i).onGroupRouteSelected(selectedRouteId);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to call onSelectedRouteChanged. Client probably died.");
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 7bd3ee2b33e3..4aa1691efc58 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -643,6 +643,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mUidRulesFirstLock")
private final SparseBooleanArray mInternetPermissionMap = new SparseBooleanArray();
+ /**
+ * Map of uid -> UidStateCallbackInfo objects holding the data received from
+ * {@link IUidObserver#onUidStateChanged(int, int, long, int)} callbacks. In order to avoid
+ * creating a new object for every callback received, we hold onto the object created for each
+ * uid and reuse it.
+ *
+ * Note that the lock used for accessing this object should not be used for anything else and we
+ * should not be acquiring new locks or doing any heavy work while this lock is held since this
+ * will be used in the callback from ActivityManagerService.
+ */
+ @GuardedBy("mUidStateCallbackInfos")
+ private final SparseArray<UidStateCallbackInfo> mUidStateCallbackInfos =
+ new SparseArray<>();
+
private RestrictedModeObserver mRestrictedModeObserver;
// TODO: keep allowlist of system-critical services that should never have
@@ -1022,11 +1036,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final private IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
@ProcessCapability int capability) {
- // TODO: Avoid creating a new UidStateCallbackInfo object every time
- // we get a callback for an uid
- mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED,
- new UidStateCallbackInfo(uid, procState, procStateSeq, capability))
+ synchronized (mUidStateCallbackInfos) {
+ UidStateCallbackInfo callbackInfo = mUidStateCallbackInfos.get(uid);
+ if (callbackInfo == null) {
+ callbackInfo = new UidStateCallbackInfo();
+ mUidStateCallbackInfos.put(uid, callbackInfo);
+ }
+ callbackInfo.update(uid, procState, procStateSeq, capability);
+ if (!callbackInfo.isPending) {
+ mUidEventHandler.obtainMessage(UID_MSG_STATE_CHANGED, callbackInfo)
.sendToTarget();
+ }
+ }
}
@Override public void onUidGone(int uid, boolean disabled) {
@@ -1044,14 +1065,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
};
private static final class UidStateCallbackInfo {
- public final int uid;
- public final int procState;
- public final long procStateSeq;
+ public int uid;
+ public int procState;
+ public long procStateSeq;
@ProcessCapability
- public final int capability;
+ public int capability;
+ public boolean isPending;
- UidStateCallbackInfo(int uid, int procState, long procStateSeq,
- @ProcessCapability int capability) {
+ public void update(int uid, int procState, long procStateSeq, int capability) {
this.uid = uid;
this.procState = procState;
this.procStateSeq = procStateSeq;
@@ -4495,6 +4516,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mPowerSaveTempWhitelistAppIds.delete(uid);
mAppIdleTempWhitelistAppIds.delete(uid);
mUidFirewallRestrictedModeRules.delete(uid);
+ synchronized (mUidStateCallbackInfos) {
+ mUidStateCallbackInfos.remove(uid);
+ }
// ...then update iptables asynchronously.
mHandler.obtainMessage(MSG_RESET_FIREWALL_RULES_BY_UID, uid, 0).sendToTarget();
@@ -5128,10 +5152,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
case UID_MSG_STATE_CHANGED: {
final UidStateCallbackInfo uidStateCallbackInfo =
(UidStateCallbackInfo) msg.obj;
- final int uid = uidStateCallbackInfo.uid;
- final int procState = uidStateCallbackInfo.procState;
- final long procStateSeq = uidStateCallbackInfo.procStateSeq;
- final int capability = uidStateCallbackInfo.capability;
+ final int uid;
+ final int procState;
+ final long procStateSeq;
+ final int capability;
+ synchronized (mUidStateCallbackInfos) {
+ uid = uidStateCallbackInfo.uid;
+ procState = uidStateCallbackInfo.procState;
+ procStateSeq = uidStateCallbackInfo.procStateSeq;
+ capability = uidStateCallbackInfo.capability;
+ uidStateCallbackInfo.isPending = false;
+ }
handleUidChanged(uid, procState, procStateSeq, capability);
return true;
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index b9984a5c24ee..8bd3b1e0b6ac 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -175,6 +175,11 @@ public class NotificationHistoryDatabase {
mFileWriteHandler.post(rcr);
}
+ public void deleteNotificationChannel(String pkg, String channelId) {
+ RemoveChannelRunnable rcr = new RemoveChannelRunnable(pkg, channelId);
+ mFileWriteHandler.post(rcr);
+ }
+
public void addNotification(final HistoricalNotification notification) {
synchronized (mLock) {
mBuffer.addNewNotificationToWrite(notification);
@@ -505,4 +510,47 @@ public class NotificationHistoryDatabase {
}
}
}
+
+ final class RemoveChannelRunnable implements Runnable {
+ private String mPkg;
+ private String mChannelId;
+ private NotificationHistory mNotificationHistory;
+
+ RemoveChannelRunnable(String pkg, String channelId) {
+ mPkg = pkg;
+ mChannelId = channelId;
+ }
+
+ @VisibleForTesting
+ void setNotificationHistory(NotificationHistory nh) {
+ mNotificationHistory = nh;
+ }
+
+ @Override
+ public void run() {
+ if (DEBUG) Slog.d(TAG, "RemoveChannelRunnable");
+ synchronized (mLock) {
+ // Remove from pending history
+ mBuffer.removeChannelFromWrite(mPkg, mChannelId);
+
+ Iterator<AtomicFile> historyFileItr = mHistoryFiles.iterator();
+ while (historyFileItr.hasNext()) {
+ final AtomicFile af = historyFileItr.next();
+ try {
+ NotificationHistory notificationHistory = mNotificationHistory != null
+ ? mNotificationHistory
+ : new NotificationHistory();
+ readLocked(af, notificationHistory,
+ new NotificationHistoryFilter.Builder().build());
+ if (notificationHistory.removeChannelFromWrite(mPkg, mChannelId)) {
+ writeLocked(af, notificationHistory);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Cannot clean up file on channel removal "
+ + af.getBaseFile().getName(), e);
+ }
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index cf3530bfe7fc..6da898acdafe 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -183,6 +183,22 @@ public class NotificationHistoryManager {
}
}
+ public void deleteNotificationChannel(String pkg, int uid, String channelId) {
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(uid);
+ final NotificationHistoryDatabase userHistory =
+ getUserHistoryAndInitializeIfNeededLocked(userId);
+ // TODO: it shouldn't be possible to delete a notification entry while the user is
+ // locked but we should handle it
+ if (userHistory == null) {
+ Slog.w(TAG, "Attempted to remove channel for locked/gone/disabled user "
+ + userId);
+ return;
+ }
+ userHistory.deleteNotificationChannel(pkg, channelId);
+ }
+ }
+
public void triggerWriteToDisk() {
synchronized (mLock) {
final int userCount = mUserState.size();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4ee90d6e0956..02809ff5678c 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3623,6 +3623,7 @@ public class NotificationManagerService extends SystemService {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
callingUser, REASON_CHANNEL_REMOVED, null);
mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
+ mHistoryManager.deleteNotificationChannel(pkg, callingUid, channelId);
mListeners.notifyNotificationChannelChanged(pkg,
UserHandle.getUserHandleForUid(callingUid),
mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
@@ -4342,6 +4343,49 @@ public class NotificationManagerService extends SystemService {
}
/**
+ * Allows an app to set an initial notification listener filter
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public void migrateNotificationFilter(INotificationListener token, int defaultTypes,
+ List<String> disallowedApps) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mNotificationLock) {
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+
+ Pair key = Pair.create(info.component, info.userid);
+
+ NotificationListenerFilter nlf = mListeners.getNotificationListenerFilter(key);
+ if (nlf == null) {
+ nlf = new NotificationListenerFilter();
+ }
+ if (nlf.getDisallowedPackages().isEmpty() && disallowedApps != null) {
+ for (String pkg : disallowedApps) {
+ // block the current user's version and any work profile versions
+ for (int userId : mUm.getProfileIds(info.userid, false)) {
+ try {
+ int uid = getUidForPackageAndUser(pkg, UserHandle.of(userId));
+ VersionedPackage vp = new VersionedPackage(pkg, uid);
+ nlf.addPackage(vp);
+ } catch (Exception e) {
+ // pkg doesn't exist on that user; skip
+ }
+ }
+ }
+ }
+ if (nlf.areAllTypesAllowed()) {
+ nlf.setTypes(defaultTypes);
+ }
+ mListeners.setNotificationListenerFilter(key, nlf);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Allow an INotificationListener to simulate clearing (dismissing) a single notification.
*
* {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
@@ -5239,7 +5283,7 @@ public class NotificationManagerService extends SystemService {
}
private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
- int uid = 0;
+ int uid = INVALID_UID;
final long identity = Binder.clearCallingIdentity();
try {
uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index ecafdfdbd6f1..4fd360bcd453 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -293,11 +293,11 @@ public final class IncrementalStates {
Slog.i(TAG, "received progress update: " + progress);
}
mLoadingState.setProgress(progress);
- if (1 - progress < 0.001) {
+ if (Math.abs(1.0f - progress) < 0.00000001f) {
if (DEBUG) {
Slog.i(TAG, "package is fully loaded");
}
- mLoadingState.setProgress(1);
+ mLoadingState.setProgress(1.0f);
if (mLoadingState.isLoading()) {
mLoadingState.adoptNewLoadingStateLocked(false);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7b71be98834c..4eafe5143c8f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -309,23 +309,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private final String mOriginalInstallerPackageName;
/** Uid of the owner of the installer session */
- @GuardedBy("mLock")
- private int mInstallerUid;
+ private volatile int mInstallerUid;
/** Where this install request came from */
@GuardedBy("mLock")
private InstallSource mInstallSource;
- @GuardedBy("mLock")
+ private final Object mProgressLock = new Object();
+
+ @GuardedBy("mProgressLock")
private float mClientProgress = 0;
- @GuardedBy("mLock")
+ @GuardedBy("mProgressLock")
private float mInternalProgress = 0;
- @GuardedBy("mLock")
+ @GuardedBy("mProgressLock")
private float mProgress = 0;
- @GuardedBy("mLock")
+ @GuardedBy("mProgressLock")
private float mReportedProgress = -1;
- @GuardedBy("mLock")
+ @GuardedBy("mProgressLock")
private float mIncrementalProgress = 0;
/** State of the session. */
@@ -571,7 +572,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
*/
@Override
public void installSession(IntentSender statusReceiver) {
- assertCallerIsOwnerOrRootOrSystemLocked();
+ assertCallerIsOwnerOrRootOrSystem();
assertNotChildLocked("StagedSession#installSession");
Preconditions.checkArgument(isCommitted() && isSessionReady());
@@ -670,7 +671,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final Runnable r;
synchronized (mLock) {
assertNotChildLocked("StagedSession#abandon");
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
if (isInTerminalState()) {
// We keep the session in the database if it's in a finalized state. It will be
// removed by PackageInstallerService when the last update time is old enough.
@@ -744,7 +745,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
*/
@Override
public void verifySession() {
- assertCallerIsOwnerOrRootOrSystemLocked();
+ assertCallerIsOwnerOrRootOrSystem();
Preconditions.checkArgument(isCommitted());
Preconditions.checkArgument(!mSessionApplied && !mSessionFailed);
verify();
@@ -1229,7 +1230,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- @GuardedBy("mLock")
+ @GuardedBy("mProgressLock")
private void setClientProgressLocked(float progress) {
// Always publish first staging movement
final boolean forcePublish = (mClientProgress == 0);
@@ -1239,21 +1240,21 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public void setClientProgress(float progress) {
- synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
+ synchronized (mProgressLock) {
setClientProgressLocked(progress);
}
}
@Override
public void addClientProgress(float progress) {
- synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
+ synchronized (mProgressLock) {
setClientProgressLocked(mClientProgress + progress);
}
}
- @GuardedBy("mLock")
+ @GuardedBy("mProgressLock")
private void computeProgressLocked(boolean forcePublish) {
if (!mCommitted) {
mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
@@ -1278,8 +1279,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public String[] getNames() {
+ assertCallerIsOwnerOrRoot();
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
return getNamesLocked();
@@ -1362,8 +1363,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ assertCallerIsOwnerOrRoot();
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums");
if (mChecksums.containsKey(name)) {
@@ -1384,8 +1385,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new IllegalStateException("Must specify package name to remove a split");
}
+ assertCallerIsOwnerOrRoot();
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotCommittedOrDestroyedLocked("removeSplit");
try {
@@ -1431,8 +1432,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new IllegalStateException(
"Cannot write regular files in a data loader installation session.");
}
+ assertCallerIsOwnerOrRoot();
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotSealedLocked("assertCanWrite");
}
if (reverseMode) {
@@ -1605,8 +1606,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
throw new IllegalStateException(
"Cannot read regular files in a data loader installation session.");
}
+ assertCallerIsOwnerOrRoot();
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotCommittedOrDestroyedLocked("openRead");
try {
return openReadInternalLocked(name);
@@ -1634,8 +1635,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
* Check if the caller is the owner of this session. Otherwise throw a
* {@link SecurityException}.
*/
- @GuardedBy("mLock")
- private void assertCallerIsOwnerOrRootLocked() {
+ private void assertCallerIsOwnerOrRoot() {
final int callingUid = Binder.getCallingUid();
if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
throw new SecurityException("Session does not belong to uid " + callingUid);
@@ -1646,8 +1646,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
* Check if the caller is the owner of this session. Otherwise throw a
* {@link SecurityException}.
*/
- @GuardedBy("mLock")
- private void assertCallerIsOwnerOrRootOrSystemLocked() {
+ private void assertCallerIsOwnerOrRootOrSystem() {
final int callingUid = Binder.getCallingUid();
if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid
&& callingUid != Process.SYSTEM_UID) {
@@ -1929,9 +1928,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
*/
private boolean markAsSealed(@NonNull IntentSender statusReceiver, boolean forTransfer) {
Objects.requireNonNull(statusReceiver);
+ assertCallerIsOwnerOrRoot();
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotDestroyedLocked("commit of session " + sessionId);
assertNoWriteFileTransfersOpenLocked();
@@ -2004,9 +2003,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"Session destroyed");
}
if (!isIncrementalInstallation()) {
- // For non-incremental installs, client staging is fully done at this point
- mClientProgress = 1f;
- computeProgressLocked(true);
+ synchronized (mProgressLock) {
+ // For non-incremental installs, client staging is fully done at this point
+ mClientProgress = 1f;
+ computeProgressLocked(true);
+ }
}
// This ongoing commit should keep session active, even though client
@@ -2191,7 +2192,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
assertPreparedAndNotSealedLocked("transfer");
try {
@@ -2376,8 +2377,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
PackageLite result = parseApkLite();
if (result != null) {
mPackageLite = result;
- mInternalProgress = 0.5f;
- computeProgressLocked(true);
+ synchronized (mProgressLock) {
+ mInternalProgress = 0.5f;
+ computeProgressLocked(true);
+ }
extractNativeLibraries(
mPackageLite, stageDir, params.abiOverride, mayInheritNativeLibs());
@@ -3554,7 +3557,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
int activeCount;
synchronized (mLock) {
if (checkCaller) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
}
activeCount = mActiveCount.decrementAndGet();
@@ -3593,7 +3596,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private void abandonNonStaged() {
synchronized (mLock) {
assertNotChildLocked("abandonNonStaged");
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
if (mRelinquished) {
if (LOGD) Slog.d(TAG, "Ignoring abandon after commit relinquished control");
return;
@@ -3659,7 +3662,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
assertPreparedAndNotSealedLocked("addFile");
if (!mFiles.add(new FileEntry(mFiles.size(),
@@ -3680,7 +3683,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
assertPreparedAndNotSealedLocked("removeFile");
if (!mFiles.add(new FileEntry(mFiles.size(),
@@ -3893,7 +3896,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
new IPackageLoadingProgressCallback.Stub() {
@Override
public void onPackageLoadingProgressChanged(float progress) {
- synchronized (mLock) {
+ synchronized (mProgressLock) {
mIncrementalProgress = progress;
computeProgressLocked(true);
}
@@ -3993,7 +3996,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
+ " as it is in an invalid state.");
}
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
assertPreparedAndNotSealedLocked("addChildSessionId");
final int indexOfSession = mChildSessions.indexOfKey(childSessionId);
@@ -4012,7 +4015,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public void removeChildSessionId(int sessionId) {
synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
+ assertCallerIsOwnerOrRoot();
assertPreparedAndNotSealedLocked("removeChildSessionId");
final int indexOfSession = mChildSessions.indexOfKey(sessionId);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6f71e991bb96..fbf677dd0967 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -103,6 +103,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.ILockSettings;
import com.android.server.am.ActivityManagerService;
import com.android.server.appbinding.AppBindingService;
+import com.android.server.art.ArtManagerLocal;
import com.android.server.attention.AttentionManagerService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.AuthService;
@@ -2610,6 +2611,10 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(GAME_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ t.traceBegin("ArtManagerLocal");
+ LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
+ t.traceEnd();
+
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 06313da58da1..b136d00fccac 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -46,15 +46,7 @@ java_test_host {
":PackageManagerTestAppVersion4",
":PackageManagerTestAppOriginalOverride",
":PackageManagerServiceDeviceSideTests",
- ":PackageManagerTestIntentVerifier",
- ":PackageManagerTestIntentVerifierTarget1",
- ":PackageManagerTestIntentVerifierTarget2",
- ":PackageManagerTestIntentVerifierTarget3",
- ":PackageManagerTestIntentVerifierTarget4Base",
- ":PackageManagerTestIntentVerifierTarget4NoAutoVerify",
- ":PackageManagerTestIntentVerifierTarget4Wildcard",
- ":PackageManagerTestIntentVerifierTarget4WildcardNoAutoVerify",
- ]
+ ],
}
genrule {
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/intent/verify/IntentFilterVerificationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/intent/verify/IntentFilterVerificationTest.kt
deleted file mode 100644
index fffda8ebd36c..000000000000
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/intent/verify/IntentFilterVerificationTest.kt
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm.test.intent.verify
-
-import com.android.internal.util.test.SystemPreparer
-import com.android.server.pm.test.Partition
-import com.android.server.pm.test.deleteApkFolders
-import com.android.server.pm.test.installJavaResourceApk
-import com.android.server.pm.test.pushApk
-import com.android.server.pm.test.uninstallPackages
-import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
-import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.ClassRule
-import org.junit.Rule
-import org.junit.Test
-import org.junit.rules.RuleChain
-import org.junit.rules.TemporaryFolder
-import org.junit.runner.RunWith
-import java.io.File
-import java.util.concurrent.TimeUnit
-
-@RunWith(DeviceJUnit4ClassRunner::class)
-class IntentFilterVerificationTest : BaseHostJUnit4Test() {
-
- companion object {
- private const val VERIFIER = "PackageManagerTestIntentVerifier.apk"
- private const val VERIFIER_PKG_NAME = "com.android.server.pm.test.intent.verifier"
- private const val TARGET_PKG_PREFIX = "$VERIFIER_PKG_NAME.target"
- private const val TARGET_APK_PREFIX = "PackageManagerTestIntentVerifierTarget"
- private const val TARGET_ONE = "${TARGET_APK_PREFIX}1.apk"
- private const val TARGET_ONE_PKG_NAME = "$TARGET_PKG_PREFIX.one"
- private const val TARGET_TWO = "${TARGET_APK_PREFIX}2.apk"
- private const val TARGET_TWO_PKG_NAME = "$TARGET_PKG_PREFIX.two"
- private const val TARGET_THREE = "${TARGET_APK_PREFIX}3.apk"
- private const val TARGET_THREE_PKG_NAME = "$TARGET_PKG_PREFIX.three"
- private const val TARGET_FOUR_BASE = "${TARGET_APK_PREFIX}4Base.apk"
- private const val TARGET_FOUR_PKG_NAME = "$TARGET_PKG_PREFIX.four"
- private const val TARGET_FOUR_NO_AUTO_VERIFY = "${TARGET_APK_PREFIX}4NoAutoVerify.apk"
- private const val TARGET_FOUR_WILDCARD = "${TARGET_APK_PREFIX}4Wildcard.apk"
- private const val TARGET_FOUR_WILDCARD_NO_AUTO_VERIFY =
- "${TARGET_APK_PREFIX}4WildcardNoAutoVerify.apk"
-
- @get:ClassRule
- val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
- }
-
- private val tempFolder = TemporaryFolder()
- private val preparer: SystemPreparer = SystemPreparer(tempFolder,
- SystemPreparer.RebootStrategy.FULL, deviceRebootRule) { this.device }
-
- @Rule
- @JvmField
- val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
-
- private val permissionsFile = File("/system/etc/permissions" +
- "/privapp-PackageManagerIntentFilterVerificationTest-permissions.xml")
-
- @Before
- fun cleanupAndPushPermissionsFile() {
- // In order for the test app to be the verification agent, it needs a permission file
- // which can be pushed onto the system and removed afterwards.
- val file = tempFolder.newFile().apply {
- """
- <permissions>
- <privapp-permissions package="$VERIFIER_PKG_NAME">
- <permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
- </privapp-permissions>
- </permissions>
- """
- .trimIndent()
- .let { writeText(it) }
- }
- device.uninstallPackages(TARGET_ONE_PKG_NAME, TARGET_TWO_PKG_NAME, TARGET_THREE_PKG_NAME,
- TARGET_FOUR_PKG_NAME)
- preparer.pushApk(VERIFIER, Partition.SYSTEM_PRIVILEGED)
- .pushFile(file, permissionsFile.toString())
- .reboot()
- runTest("clearResponse")
- }
-
- @After
- fun cleanupAndDeletePermissionsFile() {
- device.uninstallPackages(TARGET_ONE_PKG_NAME, TARGET_TWO_PKG_NAME, TARGET_THREE_PKG_NAME,
- TARGET_FOUR_PKG_NAME)
- preparer.deleteApkFolders(Partition.SYSTEM_PRIVILEGED, VERIFIER)
- .deleteFile(permissionsFile.toString())
- device.reboot()
- }
-
- @Test
- fun verifyOne() {
- installPackage(TARGET_ONE)
-
- assertReceivedRequests(true, VerifyRequest(
- scheme = "https",
- hosts = listOf(
- "https_only.pm.server.android.com",
- "other_activity.pm.server.android.com",
- "http_only.pm.server.android.com",
- "verify.pm.server.android.com",
- "https_plus_non_web_scheme.pm.server.android.com",
- "multiple.pm.server.android.com",
- // TODO(b/159952358): the following domain should not be
- // verified, this is because the verifier tries to verify all web domains,
- // even in intent filters not marked for auto verify
- "no_verify.pm.server.android.com"
- ),
- packageName = TARGET_ONE_PKG_NAME
- ))
-
- runTest(StartActivityParams(
- uri = "https://https_only.pm.server.android.com",
- expected = "$TARGET_ONE_PKG_NAME.TargetActivity"
- ))
- }
-
- @Test
- fun nonWebScheme() {
- installPackage(TARGET_TWO)
- assertReceivedRequests(null)
- }
-
- @Test
- fun verifyHttpNonSecureOnly() {
- installPackage(TARGET_THREE)
- assertReceivedRequests(true, VerifyRequest(
- scheme = "https",
- hosts = listOf(
- "multiple.pm.server.android.com"
- ),
- packageName = TARGET_THREE_PKG_NAME
- ))
-
- runTest(StartActivityParams(
- uri = "http://multiple.pm.server.android.com",
- expected = "$TARGET_THREE_PKG_NAME.TargetActivity"
- ))
- }
-
- @Test
- fun multipleResults() {
- installPackage(TARGET_ONE)
- installPackage(TARGET_THREE)
- assertReceivedRequests(true, VerifyRequest(
- scheme = "https",
- hosts = listOf(
- "https_only.pm.server.android.com",
- "other_activity.pm.server.android.com",
- "http_only.pm.server.android.com",
- "verify.pm.server.android.com",
- "https_plus_non_web_scheme.pm.server.android.com",
- "multiple.pm.server.android.com",
- // TODO(b/159952358): the following domain should not be
- // verified, this is because the verifier tries to verify all web domains,
- // even in intent filters not marked for auto verify
- "no_verify.pm.server.android.com"
- ),
- packageName = TARGET_ONE_PKG_NAME
- ), VerifyRequest(
- scheme = "https",
- hosts = listOf(
- "multiple.pm.server.android.com"
- ),
- packageName = TARGET_THREE_PKG_NAME
- ))
-
- // Target3 declares http non-s, so it should be included in the set here
- runTest(StartActivityParams(
- uri = "http://multiple.pm.server.android.com",
- expected = listOf(
- "$TARGET_ONE_PKG_NAME.TargetActivity2",
- "$TARGET_THREE_PKG_NAME.TargetActivity"
- )
- ))
-
- // But it excludes https, so it shouldn't resolve here
- runTest(StartActivityParams(
- uri = "https://multiple.pm.server.android.com",
- expected = "$TARGET_ONE_PKG_NAME.TargetActivity2"
- ))
-
- // Remove Target3 and return to single verified Target1 app for http non-s
- device.uninstallPackage(TARGET_THREE_PKG_NAME)
- runTest(StartActivityParams(
- uri = "http://multiple.pm.server.android.com",
- expected = "$TARGET_ONE_PKG_NAME.TargetActivity2"
- ))
- }
-
- @Test
- fun demoteAlways() {
- installPackage(TARGET_FOUR_BASE)
- assertReceivedRequests(false, VerifyRequest(
- scheme = "https",
- host = "failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME
- ))
-
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
- withBrowsers = true
- ))
- runTest(SetActivityAsAlwaysParams(
- uri = "https://failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME,
- activityName = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
-
- // Re-installing with same host/verify set will maintain always setting
- installPackage(TARGET_FOUR_BASE)
- assertReceivedRequests(null)
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
-
- // Installing with new wildcard host will downgrade out of always, re-including browsers
- installPackage(TARGET_FOUR_WILDCARD)
-
- // TODO(b/159952358): The first request without the wildcard should not be sent. This is
- // caused by the request being queued even if it should be dropped from the previous
- // install case since the host set didn't change.
- assertReceivedRequests(false, VerifyRequest(
- scheme = "https",
- hosts = listOf("failing.pm.server.android.com"),
- packageName = TARGET_FOUR_PKG_NAME
- ), VerifyRequest(
- scheme = "https",
- hosts = listOf("failing.pm.server.android.com", "wildcard.tld"),
- packageName = TARGET_FOUR_PKG_NAME
- ))
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
- withBrowsers = true
- ))
- }
-
- @Test
- fun unverifiedReinstallResendRequest() {
- installPackage(TARGET_FOUR_BASE)
- assertReceivedRequests(false, VerifyRequest(
- scheme = "https",
- host = "failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME
- ))
-
- installPackage(TARGET_FOUR_BASE)
-
- assertReceivedRequests(false, VerifyRequest(
- scheme = "https",
- host = "failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME
- ))
- }
-
- @Test
- fun unverifiedUpdateRemovingDomainNoRequestDemoteAlways() {
- installPackage(TARGET_FOUR_WILDCARD)
- assertReceivedRequests(false, VerifyRequest(
- scheme = "https",
- hosts = listOf("failing.pm.server.android.com", "wildcard.tld"),
- packageName = TARGET_FOUR_PKG_NAME
- ))
-
- runTest(SetActivityAsAlwaysParams(
- uri = "https://failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME,
- activityName = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
-
- // Re-installing with a smaller host/verify set will not request re-verification
- installPackage(TARGET_FOUR_BASE)
- assertReceivedRequests(null)
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
-
- // Re-installing with a (now) larger host/verify set will re-request and demote
- installPackage(TARGET_FOUR_WILDCARD)
- // TODO(b/159952358): The first request should not be sent. This is caused by the request
- // being queued even if it should be dropped from the previous install case.
- assertReceivedRequests(false, VerifyRequest(
- scheme = "https",
- host = "failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME
- ), VerifyRequest(
- scheme = "https",
- hosts = listOf("failing.pm.server.android.com", "wildcard.tld"),
- packageName = TARGET_FOUR_PKG_NAME
- ))
-
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
- withBrowsers = true
- ))
- }
-
- // TODO(b/159952358): I would expect this to demote
- // TODO(b/32810168)
- @Test
- fun verifiedUpdateRemovingAutoVerifyMaintainsAlways() {
- installPackage(TARGET_FOUR_BASE)
- assertReceivedRequests(true, VerifyRequest(
- scheme = "https",
- host = "failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME
- ))
-
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
-
- installPackage(TARGET_FOUR_NO_AUTO_VERIFY)
- assertReceivedRequests(null)
-
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
- }
-
- @Test
- fun verifiedUpdateRemovingAutoVerifyAddingDomainDemotesAlways() {
- installPackage(TARGET_FOUR_BASE)
-
- assertReceivedRequests(true, VerifyRequest(
- scheme = "https",
- host = "failing.pm.server.android.com",
- packageName = TARGET_FOUR_PKG_NAME
- ))
-
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity"
- ))
-
- installPackage(TARGET_FOUR_WILDCARD_NO_AUTO_VERIFY)
- assertReceivedRequests(null)
-
- runTest(StartActivityParams(
- uri = "https://failing.pm.server.android.com",
- expected = "$TARGET_FOUR_PKG_NAME.TargetActivity",
- withBrowsers = true
- ))
- }
-
- private fun installPackage(javaResourceName: String) {
- // Need to pass --user as verification is not currently run for all user installs
- assertThat(device.installJavaResourceApk(tempFolder, javaResourceName,
- extraArgs = arrayOf("--user", device.currentUser.toString()))).isNull()
- }
-
- private fun assertReceivedRequests(success: Boolean?, vararg expected: VerifyRequest?) {
- // TODO(b/159952358): This can probably be less than 10
- // Because tests have to assert that multiple broadcasts aren't received, there's no real
- // better way to await for a value than sleeping for a long enough time.
- TimeUnit.SECONDS.sleep(10)
-
- val params = mutableMapOf<String, String>()
- if (expected.any { it != null }) {
- params["expected"] = expected.filterNotNull()
- .joinToString(separator = "") { it.serializeToString() }
- }
- runTest("compareLastReceived", params)
-
- if (success != null) {
- if (success) {
- runTest("verifyPreviousReceivedSuccess")
- } else {
- runTest("verifyPreviousReceivedFailure")
- }
- runTest("clearResponse")
- }
- }
-
- private fun runTest(params: IntentVerifyTestParams) =
- runTest(params.methodName, params.toArgsMap())
-
- private fun runTest(testName: String, args: Map<String, String> = emptyMap()) {
- val escapedArgs = args.mapValues {
- // Need to escape strings so that args are passed properly through the shell command
- "\"${it.value.trim('"')}\""
- }
- runDeviceTests(device, null, VERIFIER_PKG_NAME, "$VERIFIER_PKG_NAME.VerifyReceiverTest",
- testName, null, 10 * 60 * 1000L, 10 * 60 * 1000L, 0L, true, false, escapedArgs)
- }
-}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
deleted file mode 100644
index 4f3f2eb1b58e..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/Android.bp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifier",
- srcs: [ "src/**/*.kt" ],
- static_libs: [
- "androidx.test.core",
- "androidx.test.espresso.core",
- "androidx.test.runner",
- "compatibility-device-util-axt",
- "junit",
- "truth-prebuilt",
- "PackageManagerServiceHostTestsIntentVerifyUtils",
- ],
- platform_apis: true,
-}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/AndroidManifest.xml
deleted file mode 100644
index 17b50b0ec949..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/AndroidManifest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier"
- >
-
- <uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT" />
- <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
- <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
-
- <instrumentation
- android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.server.pm.test.intent.verifier"
- />
-
- <application>
- <receiver android:name=".VerifyReceiver" android:exported="true">
- <intent-filter android:priority="999">
- <action android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION"/>
- <data android:mimeType="application/vnd.android.package-archive"/>
- </intent-filter>
- </receiver>
- </application>
-
-</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiver.kt b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiver.kt
deleted file mode 100644
index 073c2be75424..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiver.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm.test.intent.verifier
-
-import android.content.BroadcastReceiver
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.content.pm.PackageManager
-import com.android.server.pm.test.intent.verify.VerifyRequest
-
-class VerifyReceiver : BroadcastReceiver() {
-
- override fun onReceive(context: Context, intent: Intent) {
- if (intent.action != Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION) return
- val params = intent.toVerifyParams()
-
- // If the receiver is called for a normal request, proxy it to the real verifier on device
- if (params.hosts.none { it.contains("pm.server.android.com") }) {
- sendToRealVerifier(context, Intent(intent))
- return
- }
-
- // When the receiver is invoked for a test install, there is no direct connection to host,
- // so store the result in a file to read and assert on later. Append is intentional so that
- // amount of invocations and clean up can be verified.
- context.filesDir.resolve("test.txt")
- .appendText(params.serializeToString())
- }
-
- private fun sendToRealVerifier(context: Context, intent: Intent) {
- context.packageManager.queryBroadcastReceivers(intent, 0)
- .first { it.activityInfo?.packageName != context.packageName }
- .let { it.activityInfo!! }
- .let { intent.setComponent(ComponentName(it.packageName, it.name)) }
- .run { context.sendBroadcast(intent) }
- }
-
- private fun Intent.toVerifyParams() = VerifyRequest(
- id = getIntExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID, -1),
- scheme = getStringExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME)!!,
- hosts = getStringExtra(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS)!!
- .split(' '),
- packageName = getStringExtra(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME)!!
-
- )
-}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiverTest.kt b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiverTest.kt
deleted file mode 100644
index 23ed278e04ef..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifier/src/com/android/server/pm/test/intent/verifier/VerifyReceiverTest.kt
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm.test.intent.verifier
-
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.content.pm.PackageManager
-import android.net.Uri
-import android.os.Bundle
-import android.os.UserHandle
-import androidx.test.InstrumentationRegistry
-import androidx.test.runner.AndroidJUnit4
-import com.android.compatibility.common.util.ShellIdentityUtils
-import com.android.server.pm.test.intent.verify.SetActivityAsAlwaysParams
-import com.android.server.pm.test.intent.verify.StartActivityParams
-import com.android.server.pm.test.intent.verify.VerifyRequest
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import java.io.File
-
-@RunWith(AndroidJUnit4::class)
-class VerifyReceiverTest {
-
- val args: Bundle = InstrumentationRegistry.getArguments()
- val context: Context = InstrumentationRegistry.getContext()
-
- private val file = context.filesDir.resolve("test.txt")
-
- @Test
- fun clearResponse() {
- file.delete()
- }
-
- @Test
- fun compareLastReceived() {
- val lastReceivedText = file.readTextIfExists()
- val expectedText = args.getString("expected")
- if (expectedText.isNullOrEmpty()) {
- assertThat(lastReceivedText).isEmpty()
- return
- }
-
- val expectedParams = expectedText.parseParams()
- val lastReceivedParams = lastReceivedText.parseParams()
-
- assertThat(lastReceivedParams).hasSize(expectedParams.size)
-
- lastReceivedParams.zip(expectedParams).forEach { (actual, expected) ->
- assertThat(actual.hosts).containsExactlyElementsIn(expected.hosts)
- assertThat(actual.packageName).isEqualTo(expected.packageName)
- assertThat(actual.scheme).isEqualTo(expected.scheme)
- }
- }
-
- @Test
- fun setActivityAsAlways() {
- val params = SetActivityAsAlwaysParams.fromArgs(
- args.keySet().associateWith { args.getString(it)!! })
- val uri = Uri.parse(params.uri)
- val filter = IntentFilter().apply {
- addAction(Intent.ACTION_VIEW)
- addCategory(Intent.CATEGORY_DEFAULT)
- addCategory(Intent.CATEGORY_BROWSABLE)
- addDataScheme(uri.scheme)
- addDataAuthority(uri.authority, null)
- }
-
- val intent = Intent(Intent.ACTION_VIEW, uri).apply {
- addCategory(Intent.CATEGORY_DEFAULT)
- addCategory(Intent.CATEGORY_BROWSABLE)
- }
- val allResults = context.packageManager.queryIntentActivities(intent, 0)
- val allComponents = allResults
- .map { ComponentName(it.activityInfo.packageName, it.activityInfo.name) }
- .toTypedArray()
- val matchingInfo = allResults.first {
- it.activityInfo.packageName == params.packageName &&
- it.activityInfo.name == params.activityName
- }
-
- ShellIdentityUtils.invokeMethodWithShellPermissions(context.packageManager,
- ShellIdentityUtils.ShellPermissionMethodHelper<Unit, PackageManager> {
- it.addUniquePreferredActivity(filter, matchingInfo.match, allComponents,
- ComponentName(matchingInfo.activityInfo.packageName,
- matchingInfo.activityInfo.name))
- it.updateIntentVerificationStatusAsUser(params.packageName,
- PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
- UserHandle.myUserId())
- }, "android.permission.SET_PREFERRED_APPLICATIONS")
- }
-
- @Test
- fun verifyPreviousReceivedSuccess() {
- file.readTextIfExists()
- .parseParams()
- .forEach {
- context.packageManager.verifyIntentFilter(it.id,
- PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS, emptyList())
- }
- }
-
- @Test
- fun verifyPreviousReceivedFailure() {
- file.readTextIfExists()
- .parseParams()
- .forEach {
- context.packageManager.verifyIntentFilter(it.id,
- PackageManager.INTENT_FILTER_VERIFICATION_FAILURE, it.hosts)
- }
- }
-
- @Test
- fun verifyActivityStart() {
- val params = StartActivityParams
- .fromArgs(args.keySet().associateWith { args.getString(it)!! })
- val uri = Uri.parse(params.uri)
- val intent = Intent(Intent.ACTION_VIEW).apply {
- data = uri
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- addCategory(Intent.CATEGORY_DEFAULT)
- addCategory(Intent.CATEGORY_BROWSABLE)
- }
-
- val expectedActivities = params.expected.toMutableList()
-
- if (params.withBrowsers) {
- // Since the host doesn't know what browsers the device has, query here and add it to
- // set if it's expected that browser are returned
- val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
- expectedActivities += context.packageManager.queryIntentActivities(browserIntent, 0)
- .map { it.activityInfo.name }
- }
-
- val infos = context.packageManager.queryIntentActivities(intent, 0)
- .map { it.activityInfo.name }
- assertThat(infos).containsExactlyElementsIn(expectedActivities)
- }
-
- private fun File.readTextIfExists() = if (exists()) readText() else ""
-
- // Rudimentary list deserialization by splitting text block into 4 line sections
- private fun String.parseParams() = trim()
- .lines()
- .windowed(4, 4)
- .map { it.joinToString(separator = "\n") }
- .map { VerifyRequest.deserialize(it) }
-}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
deleted file mode 100644
index 9f9ed24c63bc..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/Android.bp
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifierTarget1",
- manifest: "AndroidManifest1.xml",
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifierTarget2",
- manifest: "AndroidManifest2.xml",
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifierTarget3",
- manifest: "AndroidManifest3.xml",
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifierTarget4Base",
- manifest: "AndroidManifest4Base.xml",
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifierTarget4NoAutoVerify",
- manifest: "AndroidManifest4NoAutoVerify.xml",
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifierTarget4Wildcard",
- manifest: "AndroidManifest4Wildcard.xml",
-}
-
-android_test_helper_app {
- name: "PackageManagerTestIntentVerifierTarget4WildcardNoAutoVerify",
- manifest: "AndroidManifest4WildcardNoAutoVerify.xml",
-}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest1.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest1.xml
deleted file mode 100644
index 6cf5c7619a30..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest1.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier.target.one" android:versionCode="1">
-
- <application>
- <activity android:name=".TargetActivity" android:exported="true">
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="verify.pm.server.android.com" />
- </intent-filter>
-
- <intent-filter android:autoVerify="false">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="no_verify.pm.server.android.com" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:host="http_only.pm.server.android.com" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="https" />
- <data android:host="https_only.pm.server.android.com" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="htttps" />
- <data android:host="non_http.pm.server.android.com" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="https" />
- <data android:scheme="non_web_scheme" />
- <data android:host="https_plus_non_web_scheme.pm.server.android.com" />
- </intent-filter>
- </activity>
-
- <activity android:name=".TargetActivity2" android:exported="true">
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="other_activity.pm.server.android.com" />
- </intent-filter>
-
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="multiple.pm.server.android.com" />
- </intent-filter>
- </activity>
- </application>
-
-</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest2.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest2.xml
deleted file mode 100644
index 087ef70595f9..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest2.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier.target.two"
- android:versionCode="1">
-
- <application>
- <activity android:name=".TargetActivity" android:exported="true">
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:scheme="non_web_scheme" />
- <data android:host="only_https_plus_non_web_scheme.pm.server.android.com" />
- </intent-filter>
- </activity>
- </application>
-
-</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest3.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest3.xml
deleted file mode 100644
index eb75b5e53bc8..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest3.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier.target.three"
- android:versionCode="1">
-
- <application>
- <activity android:name=".TargetActivity" android:exported="true">
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:host="multiple.pm.server.android.com" />
- </intent-filter>
- </activity>
- </application>
-
-</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Base.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Base.xml
deleted file mode 100644
index 7eacb8bc8fb7..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Base.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier.target.four"
- android:versionCode="1">
-
- <application>
- <activity android:name=".TargetActivity" android:exported="true">
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="failing.pm.server.android.com" />
- </intent-filter>
- </activity>
- </application>
-
-</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4NoAutoVerify.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4NoAutoVerify.xml
deleted file mode 100644
index ecfee55b9c4a..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4NoAutoVerify.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier.target.four"
- android:versionCode="1">
-
- <application>
- <activity android:name=".TargetActivity" android:exported="true">
- <intent-filter android:autoVerify="false">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="failing.pm.server.android.com" />
- </intent-filter>
- </activity>
- </application>
-
-</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Wildcard.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Wildcard.xml
deleted file mode 100644
index 0f0f53ba07e9..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4Wildcard.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier.target.four"
- android:versionCode="1">
-
- <application>
- <activity android:name=".TargetActivity" android:exported="true">
- <intent-filter android:autoVerify="true">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="failing.pm.server.android.com" />
- <data android:host="*.wildcard.tld" />
- </intent-filter>
- </activity>
- </application>
-
-</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4WildcardNoAutoVerify.xml b/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4WildcardNoAutoVerify.xml
deleted file mode 100644
index d5652e1b924d..000000000000
--- a/services/tests/PackageManagerServiceTests/host/test-apps/IntentVerifierTarget/AndroidManifest4WildcardNoAutoVerify.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2020 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.
- -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.intent.verifier.target.four"
- android:versionCode="1">
-
- <application>
- <activity android:name=".TargetActivity" android:exported="true">
- <intent-filter android:autoVerify="false">
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:host="failing.pm.server.android.com" />
- <data android:host="*.wildcard.tld" />
- </intent-filter>
- </activity>
- </application>
-
-</manifest>
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 1c45203bb3c9..3404aff976d0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -1361,6 +1361,52 @@ public class MockingOomAdjusterTests {
@SuppressWarnings("GuardedBy")
@Test
+ public void testUpdateOomAdj_DoOne_ScheduleLikeTop() {
+ final ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+ MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
+ final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+ MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+ final ProcessRecord client1 = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID,
+ MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false));
+ final ProcessRecord client2 = spy(makeDefaultProcessRecord(MOCKAPP4_PID, MOCKAPP4_UID,
+ MOCKAPP4_PROCESSNAME, MOCKAPP4_PACKAGENAME, false));
+ bindService(app1, client1, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+ mock(IBinder.class));
+ bindService(app2, client2, null, Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+ mock(IBinder.class));
+ client1.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
+ client2.mServices.setHasForegroundServices(true, 0);
+
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+ sService.mOomAdjuster.updateOomAdjLocked(app1, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+ sService.mOomAdjuster.updateOomAdjLocked(app2, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+ assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+ assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+
+ bindService(app1, client1, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
+ bindService(app2, client2, null, Context.BIND_SCHEDULE_LIKE_TOP_APP, mock(IBinder.class));
+ sService.mOomAdjuster.updateOomAdjLocked(app1, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+ sService.mOomAdjuster.updateOomAdjLocked(app2, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+ assertProcStates(app1, PROCESS_STATE_BOUND_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
+ SCHED_GROUP_TOP_APP);
+ assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+
+ sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_ASLEEP);
+ sService.mOomAdjuster.updateOomAdjLocked(app1, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+ sService.mOomAdjuster.updateOomAdjLocked(app2, false, OomAdjuster.OOM_ADJ_REASON_NONE);
+ assertProcStates(app1, PROCESS_STATE_IMPORTANT_FOREGROUND, VISIBLE_APP_ADJ,
+ SCHED_GROUP_TOP_APP);
+ assertProcStates(app2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ SCHED_GROUP_DEFAULT);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Test
public void testUpdateOomAdj_UidIdle_StopService() {
final ProcessRecord app1 = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index f6d6624d7e1c..809b6d561362 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -350,6 +350,52 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
}
@Test
+ public void testRemoveChannelRunnable() throws Exception {
+ NotificationHistory nh = mock(NotificationHistory.class);
+ NotificationHistoryDatabase.RemoveChannelRunnable rcr =
+ mDataBase.new RemoveChannelRunnable("pkg", "channel");
+ rcr.setNotificationHistory(nh);
+
+ AtomicFile af = mock(AtomicFile.class);
+ when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
+ mDataBase.mHistoryFiles.addLast(af);
+
+ when(nh.removeChannelFromWrite("pkg", "channel")).thenReturn(true);
+
+ mDataBase.mBuffer = mock(NotificationHistory.class);
+
+ rcr.run();
+
+ verify(mDataBase.mBuffer).removeChannelFromWrite("pkg", "channel");
+ verify(af).openRead();
+ verify(nh).removeChannelFromWrite("pkg", "channel");
+ verify(af).startWrite();
+ }
+
+ @Test
+ public void testRemoveChannelRunnable_noChanges() throws Exception {
+ NotificationHistory nh = mock(NotificationHistory.class);
+ NotificationHistoryDatabase.RemoveChannelRunnable rcr =
+ mDataBase.new RemoveChannelRunnable("pkg", "channel");
+ rcr.setNotificationHistory(nh);
+
+ AtomicFile af = mock(AtomicFile.class);
+ when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
+ mDataBase.mHistoryFiles.addLast(af);
+
+ when(nh.removeChannelFromWrite("pkg", "channel")).thenReturn(false);
+
+ mDataBase.mBuffer = mock(NotificationHistory.class);
+
+ rcr.run();
+
+ verify(mDataBase.mBuffer).removeChannelFromWrite("pkg", "channel");
+ verify(af).openRead();
+ verify(nh).removeChannelFromWrite("pkg", "channel");
+ verify(af, never()).startWrite();
+ }
+
+ @Test
public void testWriteBufferRunnable() throws Exception {
NotificationHistory nh = mock(NotificationHistory.class);
when(nh.getPooledStringsToWrite()).thenReturn(new String[]{});
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
index a0293b7ad12a..5892793fdb72 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
@@ -366,7 +366,7 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
@Test
public void testDeleteConversation_userUnlocked() {
String pkg = "pkg";
- Set<String> convos = Set.of("convo", "another");
+ Set<String> convos = Set.of("convo", "another");
NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class);
mHistoryManager.onUserUnlocked(USER_SYSTEM);
@@ -378,6 +378,20 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
}
@Test
+ public void testDeleteNotificationChannel_userUnlocked() {
+ String pkg = "pkg";
+ String channelId = "channelId";
+ NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class);
+
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistory);
+
+ mHistoryManager.deleteNotificationChannel(pkg, 1, channelId);
+
+ verify(userHistory, times(1)).deleteNotificationChannel(pkg, channelId);
+ }
+
+ @Test
public void testTriggerWriteToDisk() {
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
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 9a63782a4079..c8c8c8288bd5 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -56,6 +56,9 @@ import static android.os.UserHandle.USER_SYSTEM;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING;
+import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_SILENT;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
@@ -124,6 +127,7 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.UserInfo;
+import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Icon;
@@ -189,6 +193,8 @@ import com.android.server.utils.quota.MultiRateLimiter;
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.WindowManagerInternal;
+import com.google.common.collect.ImmutableList;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -7585,4 +7591,106 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(),
r.getSbn().getTag(), r,false);
}
+
+ @Test
+ public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception {
+ int uid = 9000;
+ int[] userIds = new int[] {UserHandle.getUserId(mUid), 1000};
+ when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
+ List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries");
+ for (int userId : userIds) {
+ for (String pkg : disallowedApps) {
+ when(mPackageManager.getPackageUid(pkg, 0, userId)).thenReturn(uid++);
+ }
+ }
+
+ when(mListeners.getNotificationListenerFilter(any())).thenReturn(
+ new NotificationListenerFilter());
+
+ mBinderService.migrateNotificationFilter(null,
+ FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
+ disallowedApps);
+
+ ArgumentCaptor<NotificationListenerFilter> captor =
+ ArgumentCaptor.forClass(NotificationListenerFilter.class);
+ verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
+
+ assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING,
+ captor.getValue().getTypes());
+ assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9000)));
+ assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9002)));
+ assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9003)));
+
+ // hypothetical other user untouched
+ assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 10000)));
+ }
+
+ @Test
+ public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception {
+ int[] userIds = new int[] {UserHandle.getUserId(mUid)};
+ when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
+ List<String> disallowedApps = ImmutableList.of("apples");
+ when(mPackageManager.getPackageUid("apples", 0, UserHandle.getUserId(mUid)))
+ .thenReturn(1001);
+
+ when(mListeners.getNotificationListenerFilter(any())).thenReturn(null);
+
+ mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
+ disallowedApps);
+
+ ArgumentCaptor<NotificationListenerFilter> captor =
+ ArgumentCaptor.forClass(NotificationListenerFilter.class);
+ verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
+
+ assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
+ assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
+ }
+
+ @Test
+ public void testMigrateNotificationFilter_existingTypeFilter() throws Exception {
+ int[] userIds = new int[] {UserHandle.getUserId(mUid)};
+ when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
+ List<String> disallowedApps = ImmutableList.of("apples");
+ when(mPackageManager.getPackageUid("apples", 0, UserHandle.getUserId(mUid)))
+ .thenReturn(1001);
+
+ when(mListeners.getNotificationListenerFilter(any())).thenReturn(
+ new NotificationListenerFilter(FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>()));
+
+ mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
+ disallowedApps);
+
+ ArgumentCaptor<NotificationListenerFilter> captor =
+ ArgumentCaptor.forClass(NotificationListenerFilter.class);
+ verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
+
+ // type isn't saved but pkg list is
+ assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, captor.getValue().getTypes());
+ assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
+ }
+
+ @Test
+ public void testMigrateNotificationFilter_existingPkgFilter() throws Exception {
+ int[] userIds = new int[] {UserHandle.getUserId(mUid)};
+ when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds);
+ List<String> disallowedApps = ImmutableList.of("apples");
+ when(mPackageManager.getPackageUid("apples", 0, UserHandle.getUserId(mUid)))
+ .thenReturn(1001);
+
+ NotificationListenerFilter preexisting = new NotificationListenerFilter();
+ preexisting.addPackage(new VersionedPackage("test", 1002));
+ when(mListeners.getNotificationListenerFilter(any())).thenReturn(preexisting);
+
+ mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING,
+ disallowedApps);
+
+ ArgumentCaptor<NotificationListenerFilter> captor =
+ ArgumentCaptor.forClass(NotificationListenerFilter.class);
+ verify(mListeners).setNotificationListenerFilter(any(), captor.capture());
+
+ // type is saved but pkg list isn't
+ assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes());
+ assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001)));
+ assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002)));
+ }
}
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index ad6d73c39962..b5295637d4dd 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -24,6 +24,7 @@ import android.annotation.SystemApi;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import com.android.internal.telephony.SipMessageParsingUtils;
@@ -60,14 +61,19 @@ public final class SipMessage implements Parcelable {
*/
public SipMessage(@NonNull String startLine, @NonNull String headerSection,
@NonNull byte[] content) {
- if (startLine == null || headerSection == null || content == null) {
- throw new IllegalArgumentException("One or more null parameters entered");
- }
+ Objects.requireNonNull(startLine, "Required parameter is null: startLine");
+ Objects.requireNonNull(headerSection, "Required parameter is null: headerSection");
+ Objects.requireNonNull(content, "Required parameter is null: content");
+
mStartLine = startLine;
mHeaderSection = headerSection;
mContent = content;
mViaBranchParam = SipMessageParsingUtils.getTransactionId(mHeaderSection);
+ if (TextUtils.isEmpty(mViaBranchParam)) {
+ throw new IllegalArgumentException("header section MUST contain a branch parameter "
+ + "inside of the Via header.");
+ }
mCallIdParam = SipMessageParsingUtils.getCallId(mHeaderSection);
}
@@ -107,11 +113,9 @@ public final class SipMessage implements Parcelable {
/**
* @return the branch parameter enclosed in the Via header key's value. See RFC 3261 section
- * 20.42 for more information on the Via header. If {@code null}, then there was either no
- * Via parameter found in this SIP message's headers or no branch parameter found in the
- * Via header.
+ * 20.42 for more information on the Via header.
*/
- public @Nullable String getViaBranchParameter() {
+ public @NonNull String getViaBranchParameter() {
return mViaBranchParam;
}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 739946be2e5b..5c9ec53d713b 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -28,8 +28,6 @@ import android.telephony.ims.SipDelegateImsConfiguration;
import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
-import android.util.Log;
import java.util.ArrayList;
import java.util.Set;
@@ -187,11 +185,6 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe
private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
String transactionId = m.getViaBranchParameter();
- if (TextUtils.isEmpty(transactionId)) {
- Log.w(LOG_TAG, "failure to parse SipMessage.");
- throw new IllegalArgumentException("Malformed SipMessage, can not determine "
- + "transaction ID.");
- }
SipDelegate d = mDelegate;
if (d != null) {
mExecutor.execute(() -> d.notifyMessageReceiveError(transactionId, reason));
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index 3cd27264295c..ad02fe55902f 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -28,7 +28,6 @@ import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -267,12 +266,6 @@ public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection,
private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
String transactionId = m.getViaBranchParameter();
- if (TextUtils.isEmpty(transactionId)) {
- Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a "
- + "transaction ID.");
- throw new IllegalArgumentException("Could not send SipMessage due to malformed header");
- }
- mExecutor.execute(() ->
- mMessageCallback.onMessageSendFailure(transactionId, reason));
+ mExecutor.execute(() -> mMessageCallback.onMessageSendFailure(transactionId, reason));
}
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 4ad7136aabb2..4ffbf3147ee6 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
@@ -55,8 +57,10 @@ import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkCapabilities.Transport;
+import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -258,6 +262,10 @@ public class VcnManagementServiceTest {
verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
verify(mSubscriptionTracker).register();
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ any(NetworkCallback.class));
}
@Test
@@ -706,10 +714,8 @@ public class VcnManagementServiceTest {
.checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any());
}
- private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
- int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
- setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
-
+ private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport(
+ int subId, int transport) {
final NetworkCapabilities.Builder ncBuilder =
new NetworkCapabilities.Builder()
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
@@ -718,7 +724,16 @@ public class VcnManagementServiceTest {
ncBuilder.setSubIds(Collections.singleton(subId));
}
- return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties());
+ return ncBuilder;
+ }
+
+ private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
+ int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
+ setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
+
+ return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(subId, transport).build(),
+ new LinkProperties());
}
@Test
@@ -780,6 +795,53 @@ public class VcnManagementServiceTest {
true /* isRestricted */);
}
+ private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
+ mVcnMgmtSvc.systemReady();
+
+ final ArgumentCaptor<NetworkCallback> captor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ captor.capture());
+ captor.getValue().onCapabilitiesChanged(new Network(0), caps);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
+ // immutable capability
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build(),
+ new LinkProperties());
+ assertTrue(policy.isTeardownRequested());
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
+
+ assertTrue(policy.isTeardownRequested());
+ }
+
@Test
public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);