diff options
205 files changed, 3271 insertions, 1762 deletions
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java index f6af09c853ca..02df5e2b6c31 100644 --- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java +++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java @@ -15,6 +15,7 @@ */ package com.android.perftests.blob; +import android.app.blob.BlobHandle; import android.app.blob.BlobStoreManager; import android.content.Context; import android.perftests.utils.ManualBenchmarkState; @@ -30,7 +31,6 @@ import com.android.utils.blob.DummyBlobData; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,6 +39,7 @@ import org.junit.runners.Parameterized; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -90,7 +91,6 @@ public class BlobStorePerfTests { runShellCommand("cmd jobscheduler run -f android 191934935"); } - @Ignore @Test public void testComputeDigest() throws Exception { mAtraceUtils.startTrace(ATRACE_CATEGORY_SYSTEM_SERVER); @@ -104,7 +104,8 @@ public class BlobStorePerfTests { durations.clear(); collectDigestDurationsFromTrace(parser, durations); - // TODO: get and delete blobId before next iteration. + + deleteBlob(blobData.getBlobHandle()); } } finally { mAtraceUtils.stopTrace(); @@ -137,6 +138,16 @@ public class BlobStorePerfTests { } } + private void deleteBlob(BlobHandle blobHandle) throws Exception { + runShellCommand(String.format( + "cmd blob_store delete-blob --algo %s --digest %s --label %s --expiry %d --tag %s", + blobHandle.algorithm, + Base64.getEncoder().encode(blobHandle.digest), + blobHandle.label, + blobHandle.expiryTimeMillis, + blobHandle.tag)); + } + private String runShellCommand(String cmd) { try { return UiDevice.getInstance( diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java index 9c3bd812f298..bcef8ceaa941 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java @@ -43,7 +43,8 @@ import java.util.Objects; */ // TODO: use datagen tool? public final class BlobHandle implements Parcelable { - private static final String ALGO_SHA_256 = "SHA-256"; + /** @hide */ + public static final String ALGO_SHA_256 = "SHA-256"; private static final String[] SUPPORTED_ALGOS = { ALGO_SHA_256 diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index 1efdbda97fe5..d4ceabda8acc 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -874,6 +874,20 @@ public class BlobStoreManagerService extends SystemService { } } + void deleteBlob(@NonNull BlobHandle blobHandle, @UserIdInt int userId) { + synchronized (mBlobsLock) { + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId); + final BlobMetadata blobMetadata = userBlobs.get(blobHandle); + if (blobMetadata == null) { + return; + } + blobMetadata.getBlobFile().delete(); + userBlobs.remove(blobHandle); + mKnownBlobIds.remove(blobMetadata.getBlobId()); + writeBlobsInfoAsync(); + } + } + @GuardedBy("mBlobsLock") private void dumpSessionsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) { for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) { diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java index 3ac30f8fff6c..d58294b8b941 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java @@ -15,10 +15,13 @@ */ package com.android.server.blob; +import android.app.ActivityManager; +import android.app.blob.BlobHandle; import android.os.ShellCommand; import android.os.UserHandle; import java.io.PrintWriter; +import java.util.Base64; class BlobStoreManagerShellCommand extends ShellCommand { @@ -39,6 +42,8 @@ class BlobStoreManagerShellCommand extends ShellCommand { return runClearAllSessions(pw); case "clear-all-blobs": return runClearAllBlobs(pw); + case "delete-blob": + return runDeleteBlob(pw); default: return handleDefaultCommands(cmd); } @@ -68,6 +73,17 @@ class BlobStoreManagerShellCommand extends ShellCommand { return 0; } + private int runDeleteBlob(PrintWriter pw) { + final ParsedArgs args = new ParsedArgs(); + + if (parseOptions(pw, args) < 0) { + return -1; + } + + mService.deleteBlob(args.getBlobHandle(), args.userId); + return 0; + } + @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); @@ -78,14 +94,24 @@ class BlobStoreManagerShellCommand extends ShellCommand { pw.println("clear-all-sessions [-u | --user USER_ID]"); pw.println(" Remove all sessions."); pw.println(" Options:"); - pw.println(" -u or --user: specify which user's sessions to be removed;"); + pw.println(" -u or --user: specify which user's sessions to be removed."); pw.println(" If not specified, sessions in all users are removed."); pw.println(); pw.println("clear-all-blobs [-u | --user USER_ID]"); pw.println(" Remove all blobs."); pw.println(" Options:"); + pw.println(" -u or --user: specify which user's blobs to be removed."); + pw.println(" If not specified, blobs in all users are removed."); + pw.println("delete-blob [-u | --user USER_ID] [--digest DIGEST] [--expiry EXPIRY_TIME] " + + "[--label LABEL] [--tag TAG]"); + pw.println(" Delete a blob."); + pw.println(" Options:"); pw.println(" -u or --user: specify which user's blobs to be removed;"); pw.println(" If not specified, blobs in all users are removed."); + pw.println(" --digest: Base64 encoded digest of the blob to delete."); + pw.println(" --expiry: Expiry time of the blob to delete, in milliseconds."); + pw.println(" --label: Label of the blob to delete."); + pw.println(" --tag: Tag of the blob to delete."); pw.println(); } @@ -97,15 +123,43 @@ class BlobStoreManagerShellCommand extends ShellCommand { case "--user": args.userId = Integer.parseInt(getNextArgRequired()); break; + case "--algo": + args.algorithm = getNextArgRequired(); + break; + case "--digest": + args.digest = Base64.getDecoder().decode(getNextArgRequired()); + break; + case "--label": + args.label = getNextArgRequired(); + break; + case "--expiry": + args.expiryTimeMillis = Long.parseLong(getNextArgRequired()); + break; + case "--tag": + args.tag = getNextArgRequired(); + break; default: pw.println("Error: unknown option '" + opt + "'"); return -1; } } + if (args.userId == UserHandle.USER_CURRENT) { + args.userId = ActivityManager.getCurrentUser(); + } return 0; } private static class ParsedArgs { - public int userId; + public int userId = UserHandle.USER_CURRENT; + + public String algorithm = BlobHandle.ALGO_SHA_256; + public byte[] digest; + public long expiryTimeMillis; + public CharSequence label; + public String tag; + + public BlobHandle getBlobHandle() { + return BlobHandle.create(algorithm, digest, label, expiryTimeMillis, tag); + } } } diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp index c8aa526254b8..0e9311034ee0 100644 --- a/apex/statsd/Android.bp +++ b/apex/statsd/Android.bp @@ -27,6 +27,7 @@ apex_defaults { "framework-statsd", "service-statsd", ], + compile_multilib: "both", // prebuilts: ["my_prebuilt"], name: "com.android.os.statsd-defaults", key: "com.android.os.statsd.key", @@ -72,4 +73,4 @@ cc_library_shared { "com.android.os.statsd", "test_com.android.os.statsd", ], -}
\ No newline at end of file +} diff --git a/api/current.txt b/api/current.txt index 24478f4d06d2..140b6ae51a80 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4351,7 +4351,7 @@ package android.app { public class AppOpsManager { method @Deprecated public int checkOp(@NonNull String, int, @NonNull String); method @Deprecated public int checkOpNoThrow(@NonNull String, int, @NonNull String); - method public void checkPackage(int, @NonNull String); + method @Deprecated public void checkPackage(int, @NonNull String); method @Deprecated public void finishOp(@NonNull String, int, @NonNull String); method public void finishOp(@NonNull String, int, @NonNull String, @Nullable String); method public boolean isOpActive(@NonNull String, int, @NonNull String); @@ -4364,7 +4364,7 @@ package android.app { method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @NonNull String); method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int); method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String, @Nullable String); - method public static String permissionToOp(String); + method @Nullable public static String permissionToOp(@NonNull String); method public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector); method @Deprecated public int startOp(@NonNull String, int, @NonNull String); method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String); @@ -11560,7 +11560,7 @@ package android.content.pm { method @NonNull public android.graphics.drawable.Drawable getProfileSwitchingIconDrawable(@NonNull android.os.UserHandle); method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle); method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles(); - method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle); + method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity); method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle); field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED"; } @@ -24377,10 +24377,8 @@ package android.media { public final class AudioPlaybackCaptureConfiguration { method @NonNull public int[] getExcludeUids(); method @NonNull public int[] getExcludeUsages(); - method @NonNull public int[] getExcludeUserIds(); method @NonNull public int[] getMatchingUids(); method @NonNull public int[] getMatchingUsages(); - method @NonNull public int[] getMatchingUserIds(); method @NonNull public android.media.projection.MediaProjection getMediaProjection(); } @@ -24388,11 +24386,9 @@ package android.media { ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection); method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int); method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(int); - method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUserId(int); method @NonNull public android.media.AudioPlaybackCaptureConfiguration build(); method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int); method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(int); - method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUserId(int); } public final class AudioPlaybackConfiguration implements android.os.Parcelable { @@ -24793,11 +24789,15 @@ package android.media { public abstract class DrmInitData { method public abstract android.media.DrmInitData.SchemeInitData get(java.util.UUID); + method @NonNull public android.media.DrmInitData.SchemeInitData getSchemeInitDataAt(int); + method public int getSchemeInitDataCount(); } public static final class DrmInitData.SchemeInitData { + field @NonNull public static final java.util.UUID UUID_NIL; field public final byte[] data; field public final String mimeType; + field @NonNull public final java.util.UUID uuid; } public class ExifInterface { @@ -43541,7 +43541,6 @@ package android.service.controls.templates { method public abstract int getTemplateType(); field @NonNull public static final android.service.controls.templates.ControlTemplate ERROR_TEMPLATE; field @NonNull public static final android.service.controls.templates.ControlTemplate NO_TEMPLATE; - field public static final int TYPE_DISCRETE_TOGGLE = 4; // 0x4 field public static final int TYPE_ERROR = -1; // 0xffffffff field public static final int TYPE_NONE = 0; // 0x0 field public static final int TYPE_RANGE = 2; // 0x2 @@ -43552,30 +43551,6 @@ package android.service.controls.templates { field public static final int TYPE_TOGGLE_RANGE = 6; // 0x6 } - public final class CoordinatedRangeTemplate extends android.service.controls.templates.ControlTemplate { - ctor public CoordinatedRangeTemplate(@NonNull String, float, @NonNull android.service.controls.templates.RangeTemplate, @NonNull android.service.controls.templates.RangeTemplate); - ctor public CoordinatedRangeTemplate(@NonNull String, float, float, float, float, float, float, float, float, @Nullable CharSequence); - method public float getCurrentValueHigh(); - method public float getCurrentValueLow(); - method @NonNull public CharSequence getFormatString(); - method public float getMaxValueHigh(); - method public float getMaxValueLow(); - method public float getMinGap(); - method public float getMinValueHigh(); - method public float getMinValueLow(); - method @NonNull public android.service.controls.templates.RangeTemplate getRangeHigh(); - method @NonNull public android.service.controls.templates.RangeTemplate getRangeLow(); - method public float getStepValue(); - method public int getTemplateType(); - } - - public final class DiscreteToggleTemplate extends android.service.controls.templates.ControlTemplate { - ctor public DiscreteToggleTemplate(@NonNull String, @NonNull android.service.controls.templates.ControlButton, @NonNull android.service.controls.templates.ControlButton); - method @NonNull public android.service.controls.templates.ControlButton getNegativeButton(); - method @NonNull public android.service.controls.templates.ControlButton getPositiveButton(); - method public int getTemplateType(); - } - public final class RangeTemplate extends android.service.controls.templates.ControlTemplate { ctor public RangeTemplate(@NonNull String, float, float, float, float, @Nullable CharSequence); method public float getCurrentValue(); @@ -72118,6 +72093,7 @@ package java.time.chrono { method public static java.time.chrono.JapaneseEra[] values(); field public static final java.time.chrono.JapaneseEra HEISEI; field public static final java.time.chrono.JapaneseEra MEIJI; + field public static final java.time.chrono.JapaneseEra REIWA; field public static final java.time.chrono.JapaneseEra SHOWA; field public static final java.time.chrono.JapaneseEra TAISHO; } diff --git a/api/lint-baseline.txt b/api/lint-baseline.txt index 2a8f04fe54b6..569e838ea177 100644 --- a/api/lint-baseline.txt +++ b/api/lint-baseline.txt @@ -561,6 +561,9 @@ MissingNullability: android.media.MediaMetadataRetriever#getFrameAtTime(long, in MissingNullability: android.media.MediaMetadataRetriever#getScaledFrameAtTime(long, int, int, int, android.media.MediaMetadataRetriever.BitmapParams): + +MissingNullability: java.time.chrono.JapaneseEra#REIWA: + Missing nullability on field `REIWA` in class `class java.time.chrono.JapaneseEra` RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler): diff --git a/api/system-current.txt b/api/system-current.txt index 5b6bd21acede..79a9b2196295 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -371,8 +371,8 @@ package android.app { method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[]); method public static int opToDefaultMode(@NonNull String); method @Nullable public static String opToPermission(@NonNull String); - method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(String, int, String, int); - method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int); + method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int); + method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int); field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover"; field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications"; @@ -8163,94 +8163,7 @@ package android.net.wifi.hotspot2 { } -package android.net.wifi.p2p { - - public final class WifiP2pGroupList implements android.os.Parcelable { - method public int describeContents(); - method @NonNull public java.util.List<android.net.wifi.p2p.WifiP2pGroup> getGroupList(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroupList> CREATOR; - } - - public class WifiP2pManager { - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void deletePersistentGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); - method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public void requestPersistentGroupInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener); - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); - method @RequiresPermission(allOf={android.Manifest.permission.CONNECTIVITY_INTERNAL, android.Manifest.permission.CONFIGURE_WIFI_DISPLAY}) public void setMiracastMode(int); - method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); - method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); - method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); - method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void stopListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); - field public static final String ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED = "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED"; - field public static final int MIRACAST_DISABLED = 0; // 0x0 - field public static final int MIRACAST_SINK = 2; // 0x2 - field public static final int MIRACAST_SOURCE = 1; // 0x1 - } - - public static interface WifiP2pManager.PersistentGroupInfoListener { - method public void onPersistentGroupInfoAvailable(@NonNull android.net.wifi.p2p.WifiP2pGroupList); - } - -} - -package android.net.wifi.rtt { - - public static final class RangingRequest.Builder { - method public android.net.wifi.rtt.RangingRequest.Builder addResponder(@NonNull android.net.wifi.rtt.ResponderConfig); - } - - public final class RangingResult implements android.os.Parcelable { - method @NonNull public byte[] getLci(); - method @NonNull public byte[] getLcr(); - } - - public final class ResponderConfig implements android.os.Parcelable { - ctor public ResponderConfig(@NonNull android.net.MacAddress, int, boolean, int, int, int, int, int); - ctor public ResponderConfig(@NonNull android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int); - method public int describeContents(); - method public static android.net.wifi.rtt.ResponderConfig fromScanResult(android.net.wifi.ScanResult); - method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerHandleWithDefaults(android.net.wifi.aware.PeerHandle); - method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(android.net.MacAddress); - method public void writeToParcel(android.os.Parcel, int); - field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3 - field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0 - field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1 - field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2 - field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4 - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.ResponderConfig> CREATOR; - field public static final int PREAMBLE_HE = 3; // 0x3 - field public static final int PREAMBLE_HT = 1; // 0x1 - field public static final int PREAMBLE_LEGACY = 0; // 0x0 - field public static final int PREAMBLE_VHT = 2; // 0x2 - field public static final int RESPONDER_AP = 0; // 0x0 - field public static final int RESPONDER_AWARE = 4; // 0x4 - field public static final int RESPONDER_P2P_CLIENT = 3; // 0x3 - field public static final int RESPONDER_P2P_GO = 2; // 0x2 - field public static final int RESPONDER_STA = 1; // 0x1 - field public final int centerFreq0; - field public final int centerFreq1; - field public final int channelWidth; - field public final int frequency; - field public final android.net.MacAddress macAddress; - field public final android.net.wifi.aware.PeerHandle peerHandle; - field public final int preamble; - field public final int responderType; - field public final boolean supports80211mc; - } - - public final class ResponderLocation implements android.os.Parcelable { - method public boolean getExtraInfoOnAssociationIndication(); - } - - public class WifiRttManager { - method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE}) public void cancelRanging(@Nullable android.os.WorkSource); - method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_WIFI_STATE}) public void startRanging(@Nullable android.os.WorkSource, @NonNull android.net.wifi.rtt.RangingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.rtt.RangingResultCallback); - } - -} - -package android.net.wifi.wificond { +package android.net.wifi.nl80211 { public final class DeviceWiphyCapabilities implements android.os.Parcelable { ctor public DeviceWiphyCapabilities(); @@ -8264,7 +8177,7 @@ package android.net.wifi.wificond { method public void setMaxNumberTxSpatialStreams(int); method public void setWifiStandardSupport(int, boolean); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.DeviceWiphyCapabilities> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.DeviceWiphyCapabilities> CREATOR; } public final class NativeScanResult implements android.os.Parcelable { @@ -8274,7 +8187,7 @@ package android.net.wifi.wificond { method public int getCapabilities(); method public int getFrequencyMhz(); method @NonNull public byte[] getInformationElements(); - method @NonNull public java.util.List<android.net.wifi.wificond.RadioChainInfo> getRadioChainInfos(); + method @NonNull public java.util.List<android.net.wifi.nl80211.RadioChainInfo> getRadioChainInfos(); method public int getSignalMbm(); method @NonNull public byte[] getSsid(); method public long getTsf(); @@ -8296,7 +8209,7 @@ package android.net.wifi.wificond { field public static final int BSS_CAPABILITY_SHORT_PREAMBLE = 32; // 0x20 field public static final int BSS_CAPABILITY_SHORT_SLOT_TIME = 1024; // 0x400 field public static final int BSS_CAPABILITY_SPECTRUM_MANAGEMENT = 256; // 0x100 - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.NativeScanResult> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.NativeScanResult> CREATOR; } public final class NativeWifiClient implements android.os.Parcelable { @@ -8304,7 +8217,7 @@ package android.net.wifi.wificond { method public int describeContents(); method @Nullable public android.net.MacAddress getMacAddress(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.NativeWifiClient> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.NativeWifiClient> CREATOR; } public final class PnoNetwork implements android.os.Parcelable { @@ -8317,7 +8230,7 @@ package android.net.wifi.wificond { method public void setHidden(boolean); method public void setSsid(@NonNull byte[]); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.PnoNetwork> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.PnoNetwork> CREATOR; } public final class PnoSettings implements android.os.Parcelable { @@ -8327,14 +8240,14 @@ package android.net.wifi.wificond { method public int getMin2gRssiDbm(); method public int getMin5gRssiDbm(); method public int getMin6gRssiDbm(); - method @NonNull public java.util.List<android.net.wifi.wificond.PnoNetwork> getPnoNetworks(); + method @NonNull public java.util.List<android.net.wifi.nl80211.PnoNetwork> getPnoNetworks(); method public void setIntervalMillis(long); method public void setMin2gRssiDbm(int); method public void setMin5gRssiDbm(int); method public void setMin6gRssiDbm(int); - method public void setPnoNetworks(@NonNull java.util.List<android.net.wifi.wificond.PnoNetwork>); + method public void setPnoNetworks(@NonNull java.util.List<android.net.wifi.nl80211.PnoNetwork>); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.PnoSettings> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.PnoSettings> CREATOR; } public final class RadioChainInfo implements android.os.Parcelable { @@ -8343,24 +8256,24 @@ package android.net.wifi.wificond { method public int getChainId(); method public int getLevelDbm(); method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.RadioChainInfo> CREATOR; + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.RadioChainInfo> CREATOR; } public class WifiNl80211Manager { method public void abortScan(@NonNull String); method public void enableVerboseLogging(boolean); method @NonNull public int[] getChannelsMhzForBand(int); - method @Nullable public android.net.wifi.wificond.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String); - method @NonNull public java.util.List<android.net.wifi.wificond.NativeScanResult> getScanResults(@NonNull String, int); - method @Nullable public android.net.wifi.wificond.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String); - method @Nullable public static android.net.wifi.wificond.WifiNl80211Manager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]); - method public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.SoftApCallback); - method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.SendMgmtFrameCallback); + method @Nullable public android.net.wifi.nl80211.DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String); + method @NonNull public java.util.List<android.net.wifi.nl80211.NativeScanResult> getScanResults(@NonNull String, int); + method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.TxPacketCounters getTxPacketCounters(@NonNull String); + method @Nullable public static android.net.wifi.nl80211.WifiNl80211Manager.OemSecurityType parseOemSecurityTypeElement(int, int, @NonNull byte[]); + method public boolean registerApCallback(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.SoftApCallback); + method public void sendMgmtFrame(@NonNull String, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.SendMgmtFrameCallback); method public void setOnServiceDeadCallback(@NonNull Runnable); - method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.ScanEventCallback, @NonNull android.net.wifi.wificond.WifiNl80211Manager.ScanEventCallback); + method public boolean setupInterfaceForClientMode(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.ScanEventCallback, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.ScanEventCallback); method public boolean setupInterfaceForSoftApMode(@NonNull String); - method @Nullable public android.net.wifi.wificond.WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String); - method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.wificond.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.wificond.WifiNl80211Manager.PnoScanRequestCallback); + method @Nullable public android.net.wifi.nl80211.WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String); + method public boolean startPnoScan(@NonNull String, @NonNull android.net.wifi.nl80211.PnoSettings, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.PnoScanRequestCallback); method public boolean startScan(@NonNull String, int, @Nullable java.util.Set<java.lang.Integer>, @Nullable java.util.List<byte[]>); method public boolean stopPnoScan(@NonNull String); method public boolean tearDownClientInterface(@NonNull String); @@ -8406,7 +8319,7 @@ package android.net.wifi.wificond { } public static interface WifiNl80211Manager.SoftApCallback { - method public void onConnectedClientsChanged(@NonNull android.net.wifi.wificond.NativeWifiClient, boolean); + method public void onConnectedClientsChanged(@NonNull android.net.wifi.nl80211.NativeWifiClient, boolean); method public void onFailure(); method public void onSoftApChannelSwitched(int, int); } @@ -8418,6 +8331,93 @@ package android.net.wifi.wificond { } +package android.net.wifi.p2p { + + public final class WifiP2pGroupList implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<android.net.wifi.p2p.WifiP2pGroup> getGroupList(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroupList> CREATOR; + } + + public class WifiP2pManager { + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void deletePersistentGroup(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public void requestPersistentGroupInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @RequiresPermission(allOf={android.Manifest.permission.CONNECTIVITY_INTERNAL, android.Manifest.permission.CONFIGURE_WIFI_DISPLAY}) public void setMiracastMode(int); + method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void stopListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener); + field public static final String ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED = "android.net.wifi.p2p.action.WIFI_P2P_PERSISTENT_GROUPS_CHANGED"; + field public static final int MIRACAST_DISABLED = 0; // 0x0 + field public static final int MIRACAST_SINK = 2; // 0x2 + field public static final int MIRACAST_SOURCE = 1; // 0x1 + } + + public static interface WifiP2pManager.PersistentGroupInfoListener { + method public void onPersistentGroupInfoAvailable(@NonNull android.net.wifi.p2p.WifiP2pGroupList); + } + +} + +package android.net.wifi.rtt { + + public static final class RangingRequest.Builder { + method public android.net.wifi.rtt.RangingRequest.Builder addResponder(@NonNull android.net.wifi.rtt.ResponderConfig); + } + + public final class RangingResult implements android.os.Parcelable { + method @NonNull public byte[] getLci(); + method @NonNull public byte[] getLcr(); + } + + public final class ResponderConfig implements android.os.Parcelable { + ctor public ResponderConfig(@NonNull android.net.MacAddress, int, boolean, int, int, int, int, int); + ctor public ResponderConfig(@NonNull android.net.wifi.aware.PeerHandle, int, boolean, int, int, int, int, int); + method public int describeContents(); + method public static android.net.wifi.rtt.ResponderConfig fromScanResult(android.net.wifi.ScanResult); + method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerHandleWithDefaults(android.net.wifi.aware.PeerHandle); + method public static android.net.wifi.rtt.ResponderConfig fromWifiAwarePeerMacAddressWithDefaults(android.net.MacAddress); + method public void writeToParcel(android.os.Parcel, int); + field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3 + field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0 + field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1 + field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2 + field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4 + field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.rtt.ResponderConfig> CREATOR; + field public static final int PREAMBLE_HE = 3; // 0x3 + field public static final int PREAMBLE_HT = 1; // 0x1 + field public static final int PREAMBLE_LEGACY = 0; // 0x0 + field public static final int PREAMBLE_VHT = 2; // 0x2 + field public static final int RESPONDER_AP = 0; // 0x0 + field public static final int RESPONDER_AWARE = 4; // 0x4 + field public static final int RESPONDER_P2P_CLIENT = 3; // 0x3 + field public static final int RESPONDER_P2P_GO = 2; // 0x2 + field public static final int RESPONDER_STA = 1; // 0x1 + field public final int centerFreq0; + field public final int centerFreq1; + field public final int channelWidth; + field public final int frequency; + field public final android.net.MacAddress macAddress; + field public final android.net.wifi.aware.PeerHandle peerHandle; + field public final int preamble; + field public final int responderType; + field public final boolean supports80211mc; + } + + public final class ResponderLocation implements android.os.Parcelable { + method public boolean getExtraInfoOnAssociationIndication(); + } + + public class WifiRttManager { + method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE}) public void cancelRanging(@Nullable android.os.WorkSource); + method @RequiresPermission(allOf={android.Manifest.permission.LOCATION_HARDWARE, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_WIFI_STATE}) public void startRanging(@Nullable android.os.WorkSource, @NonNull android.net.wifi.rtt.RangingRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.rtt.RangingResultCallback); + } + +} + package android.nfc { public final class NfcAdapter { diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt index f4403811d7d2..55333cf06ffc 100644 --- a/api/system-lint-baseline.txt +++ b/api/system-lint-baseline.txt @@ -234,7 +234,7 @@ OnNameExpected: android.content.ContentProvider#checkUriPermission(android.net.U If implemented by developer, should follow the on<Something> style; otherwise consider marking final -PairedRegistration: android.net.wifi.wificond.WifiNl80211Manager#registerApCallback(String, java.util.concurrent.Executor, android.net.wifi.wificond.WifiNl80211Manager.SoftApCallback): +PairedRegistration: android.net.wifi.nl80211.WifiNl80211Manager#registerApCallback(String, java.util.concurrent.Executor, android.net.wifi.nl80211.WifiNl80211Manager.SoftApCallback): diff --git a/api/test-current.txt b/api/test-current.txt index 79d29f6e906f..957794cac057 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -180,8 +180,8 @@ package android.app { method @RequiresPermission("android.permission.MANAGE_APPOPS") public void resetHistoryParameters(); method @RequiresPermission("android.permission.MANAGE_APPOPS") public void setHistoryParameters(int, long, int); method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(int, int, String, int); - method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(String, int, String, int); - method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int); + method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(@NonNull String, int, @Nullable String, int); + method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int); method public static int strOpToOp(@NonNull String); field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0 field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1 diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 27c4f4ec3711..bf6afe7f2c0f 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -678,17 +678,32 @@ message CachedKillReported { * frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiDataStall.java */ message WifiHealthStatReported { + enum Band { + UNKNOWN = 0; + // All of 2.4GHz band + BAND_2G = 1; + // Frequencies in the range of [5150, 5250) GHz + BAND_5G_LOW = 2; + // Frequencies in the range of [5250, 5725) GHz + BAND_5G_MIDDLE = 3; + // Frequencies in the range of [5725, 5850) GHz + BAND_5G_HIGH = 4; + // Frequencies in the range of [5925, 6425) GHz + BAND_6G_LOW = 5; + // Frequencies in the range of [6425, 6875) GHz + BAND_6G_MIDDLE = 6; + // Frequencies in the range of [6875, 7125) GHz + BAND_6G_HIGH = 7; + } // duration this stat is obtained over in milliseconds optional int32 duration_millis = 1; // whether wifi is classified as sufficient for the user's data traffic, determined // by whether the calculated throughput exceeds the average demand within |duration_millis| optional bool is_sufficient = 2; - // whether the calculated throughput is exceeds the minimum required for typical usage - optional bool is_throughput_good = 3; // whether cellular data is available - optional bool is_cell_data_available = 4; - // the WLAN channel the connected network is on (ie. 2412) - optional int32 frequency = 5; + optional bool is_cell_data_available = 3; + // the Band bucket the connected network is on + optional Band band = 4; } /** diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index f6bbc6824e71..9ed479840750 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -97,15 +97,77 @@ import java.util.function.Consumer; import java.util.function.Supplier; /** - * AppOps are mappings of [package/uid, op-name] -> [mode]. The list of existing appops is defined - * by the system and cannot be amended by apps. Only system apps can change appop-modes. + * App-ops are used for two purposes: Access control and tracking. * - * <p>Beside a mode the system tracks when an op was {@link #noteOp noted}. The tracked data can - * only be read by system components. + * <p>App-ops cover a wide variety of functionality from helping with runtime permissions access + * control and tracking to battery consumption tracking. * - * <p>Installed apps can usually only listen to changes and events on their own ops. E.g. - * {@link AppOpsCollector} allows to get a callback each time an app called {@link #noteOp} or - * {@link #startOp} for an op belonging to the app. + * <h2>Access control</h2> + * + * <p>App-ops can either be controlled for each uid or for each package. Which one is used depends + * on the API provider maintaining this app-op. For any security or privacy related app-op the + * provider needs to control the app-op for per uid as all security and privacy is based on uid in + * Android. + * + * <p>To control access the app-op can be set to a mode to: + * <dl> + * <dt>{@link #MODE_DEFAULT} + * <dd>Default behavior, might differ from app-op or app-op + * <dt>{@link #MODE_ALLOWED} + * <dd>Allow the access + * <dt>{@link #MODE_IGNORED} + * <dd>Don't allow the access, i.e. don't perform the requested action or return no or dummy + * data + * <dt>{@link #MODE_ERRORED} + * <dd>Throw a {@link SecurityException} on access. This can be suppressed by using a + * {@code ...noThrow} method to check the mode + * </dl> + * + * <p>API providers need to check the mode returned by {@link #noteOp} if they are are allowing + * access to operations gated by the app-op. {@link #unsafeCheckOp} should be used to check the + * mode if no access is granted. E.g. this can be used for displaying app-op state in the UI or + * when checking the state before later calling {@link #noteOp} anyway. + * + * <p>If an operation refers to a time span (e.g. a audio-recording session) the API provider + * should use {@link #startOp} and {@link #finishOp} instead of {@link #noteOp}. + * + * <h3>Runtime permissions and app-ops</h3> + * + * <p>Each platform defined runtime permission (beside background modifiers) has an associated app + * op which is used for tracking but also to allow for silent failures. I.e. if the runtime + * permission is denied the caller gets a {@link SecurityException}, but if the permission is + * granted and the app-op is {@link #MODE_IGNORED} then the callers gets dummy behavior, e.g. + * location callbacks would not happen. + * + * <h3>App-op permissions</h3> + * + * <p>App-ops permissions are platform defined permissions that can be overridden. The security + * check for app-op permissions should by {@link #MODE_DEFAULT default} check the permission grant + * state. If the app-op state is set to {@link #MODE_ALLOWED} or {@link #MODE_IGNORED} the app-op + * state should be checked instead of the permission grant state. + * + * <p>This functionality allows to grant access by default to apps fulfilling the requirements for + * a certain permission level. Still the behavior can be overridden when needed. + * + * <h2>Tracking</h2> + * + * <p>App-ops track many important events, including all accesses to runtime permission protected + * APIs. This is done by tracking when an app-op was {@link #noteOp noted} or + * {@link #startOp started}. The tracked data can only be read by system components. + * + * <p><b>Only {@link #noteOp}/{@link #startOp} are tracked; {@link #unsafeCheckOp} is not tracked. + * Hence it is important to eventually call {@link #noteOp} or {@link #startOp} when providing + * access to protected operations or data.</b> + * + * <p>Some apps are forwarding access to other apps. E.g. an app might get the location from the + * system's location provider and then send the location further to a 3rd app. In this case the + * app passing on the data needs to call {@link #noteProxyOp} to signal the access proxying. This + * might also make sense inside of a single app if the access is forwarded between two features of + * the app. + * + * <p>An app can register an {@link AppOpsCollector} to get informed about what accesses the + * system is tracking for it. As each runtime permission has an associated app-op this API is + * particularly useful for an app that want to find unexpected private data accesses. */ @SystemService(Context.APP_OPS_SERVICE) public class AppOpsManager { @@ -121,28 +183,6 @@ public class AppOpsManager { @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) public static final long CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE = 148180766L; - /** - * <p>App ops allows callers to:</p> - * - * <ul> - * <li> Note when operations are happening, and find out if they are allowed for the current - * caller.</li> - * <li> Disallow specific apps from doing specific operations.</li> - * <li> Collect all of the current information about operations that have been executed or - * are not being allowed.</li> - * <li> Monitor for changes in whether an operation is allowed.</li> - * </ul> - * - * <p>Each operation is identified by a single integer; these integers are a fixed set of - * operations, enumerated by the OP_* constants. - * - * <p></p>When checking operations, the result is a "mode" integer indicating the current - * setting for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute - * the operation but fake its behavior enough so that the caller doesn't crash), - * MODE_ERRORED (throw a SecurityException back to the caller; the normal operation calls - * will do this for you). - */ - final Context mContext; @UnsupportedAppUsage @@ -1093,7 +1133,7 @@ public class AppOpsManager { /** Required to draw on top of other apps. */ public static final String OPSTR_SYSTEM_ALERT_WINDOW = "android:system_alert_window"; - /** Required to write/modify/update system settingss. */ + /** Required to write/modify/update system settings. */ public static final String OPSTR_WRITE_SETTINGS = "android:write_settings"; /** @hide Get device accounts. */ @@ -6115,7 +6155,7 @@ public class AppOpsManager { */ public interface OnOpActiveChangedListener { /** - * Called when the active state of an app op changes. + * Called when the active state of an app-op changes. * * @param op The operation that changed. * @param packageName The package performing the operation. @@ -6406,7 +6446,7 @@ public class AppOpsManager { @SystemApi @TestApi @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) - public void setUidMode(String appOp, int uid, @Mode int mode) { + public void setUidMode(@NonNull String appOp, int uid, @Mode int mode) { try { mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode); } catch (RemoteException e) { @@ -6461,7 +6501,8 @@ public class AppOpsManager { @TestApi @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES) - public void setMode(String op, int uid, String packageName, @Mode int mode) { + public void setMode(@NonNull String op, int uid, @Nullable String packageName, + @Mode int mode) { try { mService.setMode(strOpToOp(op), uid, packageName, mode); } catch (RemoteException e) { @@ -6504,16 +6545,17 @@ public class AppOpsManager { } /** - * Gets the app op name associated with a given permission. - * The app op name is one of the public constants defined + * Gets the app-op name associated with a given permission. + * + * <p>The app-op name is one of the public constants defined * in this class such as {@link #OPSTR_COARSE_LOCATION}. * This API is intended to be used for mapping runtime - * permissions to the corresponding app op. + * permissions to the corresponding app-op. * * @param permission The permission. - * @return The app op associated with the permission or null. + * @return The app-op associated with the permission or {@code null}. */ - public static String permissionToOp(String permission) { + public static @Nullable String permissionToOp(@NonNull String permission) { final Integer opCode = sPermToOp.get(permission); if (opCode == null) { return null; @@ -6631,7 +6673,7 @@ public class AppOpsManager { } /** - * Start watching for changes to the active state of app ops. An app op may be + * Start watching for changes to the active state of app-ops. An app-op may be * long running and it has a clear start and stop delimiters. If an op is being * started or stopped by any package you will get a callback. To change the * watched ops for a registered callback you need to unregister and register it @@ -6690,7 +6732,7 @@ public class AppOpsManager { } /** - * Stop watching for changes to the active state of an app op. An app op may be + * Stop watching for changes to the active state of an app-op. An app-op may be * long running and it has a clear start and stop delimiters. Unregistering a * non-registered callback has no effect. * @@ -6921,7 +6963,8 @@ public class AppOpsManager { * @param op The operation to note. One of the OPSTR_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. - * @param featureId The feature in the app or {@code null} for default feature + * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code + * null} for default feature * @param message A message describing the reason the op was noted * * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or @@ -6996,6 +7039,8 @@ public class AppOpsManager { * @param op The operation to note. One of the OPSTR_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. + * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code + * null} for default feature * @param message A message describing the reason the op was noted * * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or @@ -7003,8 +7048,8 @@ public class AppOpsManager { * causing the app to crash). */ public int noteOpNoThrow(@NonNull String op, int uid, @NonNull String packageName, - @Nullable String feature, @Nullable String message) { - return noteOpNoThrow(strOpToOp(op), uid, packageName, feature, message); + @Nullable String featureId, @Nullable String message) { + return noteOpNoThrow(strOpToOp(op), uid, packageName, featureId, message); } /** @@ -7273,11 +7318,9 @@ public class AppOpsManager { } /** - * Do a quick check to validate if a package name belongs to a UID. - * - * @throws SecurityException if the package name doesn't belong to the given - * UID, or if ownership cannot be verified. + * @deprecated Use {@link PackageManager#getPackageUid} instead */ + @Deprecated public void checkPackage(int uid, @NonNull String packageName) { try { if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) { @@ -7396,7 +7439,8 @@ public class AppOpsManager { * @param op The operation to start. One of the OPSTR_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. - * @param featureId The feature in the app or {@code null} for default feature + * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code + * null} for default feature * @param message Description why op was started * * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or @@ -7587,7 +7631,8 @@ public class AppOpsManager { } /** - * Checks whether the given op for a package is active. + * Checks whether the given op for a package is active, i.e. did someone call {@link #startOp} + * without {@link #finishOp} yet. * <p> * If you don't hold the {@code android.Manifest.permission#WATCH_APPOPS} * permission you can query only for your UID. @@ -7917,18 +7962,19 @@ public class AppOpsManager { } /** - * Callback an app can choose to {@link #setNotedAppOpsCollector register} to monitor it's noted - * appops. I.e. each time any app calls {@link #noteOp} or {@link #startOp} one of the callback - * methods of this object is called. + * Callback an app can {@link #setNotedAppOpsCollector register} to monitor the app-ops the + * system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp} + * one of the callback methods of this object is called. * - * <p><b>Only appops related to dangerous permissions are collected.</b> + * <p><b>There will be a callback for all app-ops related to runtime permissions, but not + * necessarily for all other app-ops. * * <pre> * setNotedAppOpsCollector(new AppOpsCollector() { * ArraySet<Pair<String, String>> opsNotedForThisProcess = new ArraySet<>(); * * private synchronized void addAccess(String op, String accessLocation) { - * // Ops are often noted when permission protected APIs were called. + * // Ops are often noted when runtime permission protected APIs were called. * // In this case permissionToOp() allows to resolve the permission<->op * opsNotedForThisProcess.add(new Pair(accessType, accessLocation)); * } @@ -7970,20 +8016,21 @@ public class AppOpsManager { } /** - * Called when an app-op was noted for this package inside of a two-way binder-call. + * Called when an app-op was {@link #noteOp noted} for this package inside of a synchronous + * API call, i.e. a API call that returned data or waited until the action was performed. * - * <p>Called on the calling thread just after executing the binder-call. This allows - * the app to e.g. collect stack traces to figure out where the access came from. + * <p>Called on the calling thread before the API returns. This allows the app to e.g. + * collect stack traces to figure out where the access came from. * * @param op The op noted */ public abstract void onNoted(@NonNull SyncNotedAppOp op); /** - * Called when this app noted an app-op for its own package. + * Called when this app noted an app-op for its own package, * - * <p>Called on the thread the noted the op. This allows the app to e.g. collect stack - * traces to figure out where the access came from. + * <p>This is very similar to {@link #onNoted} only that the tracking was not caused by the + * API provider in a separate process, but by one in the app's own process. * * @param op The op noted */ diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index c13c5a5ab9c4..309e91f1e4ff 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -94,14 +94,16 @@ public abstract class AppOpsManagerInternal { boolean visible); /** - * Like {@link AppOpsManager#setUidMode}, but allows ignoring a certain callback. + * Like {@link AppOpsManager#setUidMode}, but allows ignoring our own callback and not updating + * the REVOKED_COMPAT flag. */ - public abstract void setUidModeIgnoringCallback(int code, int uid, int mode, - @Nullable IAppOpsCallback callbackToIgnore); + public abstract void setUidModeFromPermissionPolicy(int code, int uid, int mode, + @Nullable IAppOpsCallback callback); /** - * Like {@link AppOpsManager#setMode}, but allows ignoring a certain callback. + * Like {@link AppOpsManager#setMode}, but allows ignoring our own callback and not updating the + * REVOKED_COMPAT flag. */ - public abstract void setModeIgnoringCallback(int code, int uid, @NonNull String packageName, - int mode, @Nullable IAppOpsCallback callbackToIgnore); + public abstract void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName, + int mode, @Nullable IAppOpsCallback callback); } diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java index d16120dedd24..8c2cc9492e39 100644 --- a/core/java/android/app/NotificationHistory.java +++ b/core/java/android/app/NotificationHistory.java @@ -384,6 +384,26 @@ public final class NotificationHistory implements Parcelable { } /** + * Removes all notifications from a conversation and regenerates the string pool + */ + public boolean removeConversationFromWrite(String packageName, String conversationId) { + boolean removed = false; + for (int i = mNotificationsToWrite.size() - 1; i >= 0; i--) { + HistoricalNotification hn = mNotificationsToWrite.get(i); + if (packageName.equals(hn.getPackage()) + && conversationId.equals(hn.getConversationId())) { + 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/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 9b7306089dca..655dd9b41c34 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -109,8 +109,8 @@ import android.media.session.MediaSessionManager; import android.media.soundtrigger.SoundTriggerManager; import android.media.tv.ITvInputManager; import android.media.tv.TvInputManager; -import android.media.tv.tuner.ITunerResourceManager; -import android.media.tv.tuner.TunerResourceManager; +import android.media.tv.tunerresourcemanager.ITunerResourceManager; +import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityManager; import android.net.ConnectivityThread; @@ -132,7 +132,7 @@ import android.net.lowpan.LowpanManager; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.wifi.WifiFrameworkInitializer; -import android.net.wifi.wificond.WifiNl80211Manager; +import android.net.wifi.nl80211.WifiNl80211Manager; import android.nfc.NfcManager; import android.os.BatteryManager; import android.os.BatteryStats; diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index d9b9c56ae757..d08dbc609332 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4741,7 +4741,8 @@ public class DevicePolicyManager { * @hide */ public static final int ORG_OWNED_PROFILE_KEYGUARD_FEATURES_PARENT_ONLY = - KEYGUARD_DISABLE_SECURE_CAMERA; + DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA + | DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS; /** * Keyguard features that when set on a normal or organization-owned managed profile, have @@ -6146,14 +6147,17 @@ public class DevicePolicyManager { * <ul> * <li>{@link #KEYGUARD_DISABLE_SECURE_CAMERA} which affects the parent user when called on the * parent profile. + * <li>{@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} which affects the parent user when called + * on the parent profile. * </ul> * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}, {@link #KEYGUARD_DISABLE_FINGERPRINT}, - * {@link #KEYGUARD_DISABLE_FACE}, {@link #KEYGUARD_DISABLE_IRIS} and - * {@link #KEYGUARD_DISABLE_SECURE_CAMERA} can also be set on the {@link DevicePolicyManager} - * instance returned by {@link #getParentProfileInstance(ComponentName)} in order to set - * restrictions on the parent profile. {@link #KEYGUARD_DISABLE_SECURE_CAMERA} can only be set - * on the parent profile instance if the calling device admin is the profile owner of an - * organization-owned managed profile. + * {@link #KEYGUARD_DISABLE_FACE}, {@link #KEYGUARD_DISABLE_IRIS}, + * {@link #KEYGUARD_DISABLE_SECURE_CAMERA} and {@link #KEYGUARD_DISABLE_SECURE_NOTIFICATIONS} + * can also be set on the {@link DevicePolicyManager} instance returned by + * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent + * profile. {@link #KEYGUARD_DISABLE_SECURE_CAMERA} can only be set on the parent profile + * instance if the calling device admin is the profile owner of an organization-owned + * managed profile. * <p> * Requests to disable other features on a managed profile will be ignored. * <p> diff --git a/core/java/android/companion/IFindDeviceCallback.aidl b/core/java/android/companion/IFindDeviceCallback.aidl index 4e9fa19e5ce5..405277b50f5b 100644 --- a/core/java/android/companion/IFindDeviceCallback.aidl +++ b/core/java/android/companion/IFindDeviceCallback.aidl @@ -21,6 +21,6 @@ import android.app.PendingIntent; /** @hide */ interface IFindDeviceCallback { @UnsupportedAppUsage - void onSuccess(in PendingIntent launcher); - void onFailure(in CharSequence reason); + oneway void onSuccess(in PendingIntent launcher); + oneway void onFailure(in CharSequence reason); } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index f32a4ab43357..0e0161ff4e9f 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -700,6 +700,27 @@ public abstract class ContentResolver implements ContentInterface { /** @hide */ public static final String REMOTE_CALLBACK_RESULT = "result"; + /** + * How long we wait for an attached process to publish its content providers + * before we decide it must be hung. + * @hide + */ + public static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS = 10 * 1000; + + /** + * How long we wait for an provider to be published. Should be longer than + * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}. + * @hide + */ + public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS = + CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000; + + // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how + // long ActivityManagerService is giving a content provider to get published if a new process + // needs to be started for that. + private static final int GET_TYPE_TIMEOUT_MILLIS = + CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000; + public ContentResolver(@Nullable Context context) { this(context, null); } @@ -849,8 +870,6 @@ public abstract class ContentResolver implements ContentInterface { } } - private static final int GET_TYPE_TIMEOUT_MILLIS = 3000; - private static class GetTypeResultListener implements RemoteCallback.OnResultListener { @GuardedBy("this") public boolean done; diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java index eb1da67972fd..3261cb124e00 100644 --- a/core/java/android/content/pm/CrossProfileApps.java +++ b/core/java/android/content/pm/CrossProfileApps.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.app.Activity; import android.app.AppOpsManager.Mode; import android.content.ComponentName; import android.content.Context; @@ -116,18 +117,25 @@ public class CrossProfileApps { * @param targetUser The {@link UserHandle} of the profile; must be one of the users returned by * {@link #getTargetUserProfiles()} if different to the calling user, otherwise a * {@link SecurityException} will be thrown. + * @param callingActivity The activity to start the new activity from for the purposes of + * deciding which task the new activity should belong to. If {@code null}, the activity + * will always be started in a new task. */ @RequiresPermission(anyOf = { android.Manifest.permission.INTERACT_ACROSS_PROFILES, android.Manifest.permission.INTERACT_ACROSS_USERS}) - public void startActivity(@NonNull Intent intent, @NonNull UserHandle targetUser) { + public void startActivity( + @NonNull Intent intent, + @NonNull UserHandle targetUser, + @Nullable Activity callingActivity) { try { mService.startActivityAsUserByIntent( mContext.getIApplicationThread(), mContext.getPackageName(), mContext.getFeatureId(), intent, - targetUser.getIdentifier()); + targetUser.getIdentifier(), + callingActivity != null ? callingActivity.getActivityToken() : null); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } diff --git a/core/java/android/content/pm/CrossProfileAppsInternal.java b/core/java/android/content/pm/CrossProfileAppsInternal.java index 9ff441741bed..16a749fa360a 100644 --- a/core/java/android/content/pm/CrossProfileAppsInternal.java +++ b/core/java/android/content/pm/CrossProfileAppsInternal.java @@ -17,6 +17,9 @@ package android.content.pm; import android.annotation.UserIdInt; +import android.os.UserHandle; + +import java.util.List; /** * Exposes internal methods from {@link com.android.server.pm.CrossProfileAppsServiceImpl} to other @@ -52,4 +55,11 @@ public abstract class CrossProfileAppsInternal { */ public abstract boolean verifyUidHasInteractAcrossProfilePermission(String packageName, int uid); + + /** + * Returns the list of target user profiles for the given package on the given user. See {@link + * CrossProfileApps#getTargetUserProfiles()}. + */ + public abstract List<UserHandle> getTargetUserProfiles( + String packageName, @UserIdInt int userId); } diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl index 98bf2ddd0e1b..5a6e008608f3 100644 --- a/core/java/android/content/pm/ICrossProfileApps.aidl +++ b/core/java/android/content/pm/ICrossProfileApps.aidl @@ -31,7 +31,7 @@ interface ICrossProfileApps { in String callingFeatureId, in ComponentName component, int userId, boolean launchMainActivity); void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage, - in String callingFeatureId, in Intent intent, int userId); + in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity); List<UserHandle> getTargetUserProfiles(in String callingPackage); boolean canInteractAcrossProfiles(in String callingPackage); boolean canRequestInteractAcrossProfiles(in String callingPackage); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 03ed373b91c1..5a56b0e50853 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3023,6 +3023,18 @@ public abstract class PackageManager { public static final String FEATURE_TUNER = "android.hardware.tv.tuner"; /** + * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has + * the necessary changes to support app enumeration. + * + * @hide + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration"; + + /** @hide */ + public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true; + + /** * Extra field name for the URI to a verification file. Passed to a package * verifier. * diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java index f19ba0f5ef51..2041cfb22ea8 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -126,7 +126,11 @@ public class VpnManager { return getIntentForConfirmation(); } - /** Delete the VPN profile configuration that was provisioned by the calling app */ + /** + * Delete the VPN profile configuration that was provisioned by the calling app + * + * @throws SecurityException if this would violate user settings + */ public void deleteProvisionedVpnProfile() { try { mService.deleteVpnProfile(mContext.getOpPackageName()); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 267613f0af83..a8fa6db232a2 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -26,6 +26,7 @@ import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.app.PropertyInvalidatedCache; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.service.dreams.Sandman; @@ -877,6 +878,39 @@ public final class PowerManager { } } + private static final String CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY = + "cache_key.is_power_save_mode"; + + private static final String CACHE_KEY_IS_INTERACTIVE_PROPERTY = "cache_key.is_interactive"; + + private static final int MAX_CACHE_ENTRIES = 1; + + private PropertyInvalidatedCache<Void, Boolean> mPowerSaveModeCache = + new PropertyInvalidatedCache<Void, Boolean>(MAX_CACHE_ENTRIES, + CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY) { + @Override + protected Boolean recompute(Void query) { + try { + return mService.isPowerSaveMode(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + }; + + private PropertyInvalidatedCache<Void, Boolean> mInteractiveCache = + new PropertyInvalidatedCache<Void, Boolean>(MAX_CACHE_ENTRIES, + CACHE_KEY_IS_INTERACTIVE_PROPERTY) { + @Override + protected Boolean recompute(Void query) { + try { + return mService.isInteractive(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + }; + final Context mContext; @UnsupportedAppUsage final IPowerManager mService; @@ -1440,11 +1474,7 @@ public final class PowerManager { * @see android.content.Intent#ACTION_SCREEN_OFF */ public boolean isInteractive() { - try { - return mService.isInteractive(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mInteractiveCache.query(null); } /** @@ -1504,11 +1534,7 @@ public final class PowerManager { * @return Returns true if currently in low power mode, else false. */ public boolean isPowerSaveMode() { - try { - return mService.isPowerSaveMode(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return mPowerSaveModeCache.query(null); } /** @@ -2508,4 +2534,18 @@ public final class PowerManager { }; } } + + /** + * @hide + */ + public static void invalidatePowerSaveModeCaches() { + PropertyInvalidatedCache.invalidateCache(CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY); + } + + /** + * @hide + */ + public static void invalidateIsInteractiveCaches() { + PropertyInvalidatedCache.invalidateCache(CACHE_KEY_IS_INTERACTIVE_PROPERTY); + } } diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java index d2c0f76907e6..a5156e36f2ce 100644 --- a/core/java/android/service/controls/templates/ControlTemplate.java +++ b/core/java/android/service/controls/templates/ControlTemplate.java @@ -74,8 +74,6 @@ public abstract class ControlTemplate { TYPE_TOGGLE, TYPE_RANGE, TYPE_THUMBNAIL, - TYPE_DISCRETE_TOGGLE, - TYPE_COORD_RANGE, TYPE_TOGGLE_RANGE, TYPE_TEMPERATURE, TYPE_STATELESS @@ -104,16 +102,6 @@ public abstract class ControlTemplate { */ public static final @TemplateType int TYPE_THUMBNAIL = 3; - /** - * Type identifier of {@link DiscreteToggleTemplate}. - */ - public static final @TemplateType int TYPE_DISCRETE_TOGGLE = 4; - - /** - * @hide - */ - public static final @TemplateType int TYPE_COORD_RANGE = 5; - public static final @TemplateType int TYPE_TOGGLE_RANGE = 6; public static final @TemplateType int TYPE_TEMPERATURE = 7; @@ -190,10 +178,6 @@ public abstract class ControlTemplate { return new RangeTemplate(bundle); case TYPE_THUMBNAIL: return new ThumbnailTemplate(bundle); - case TYPE_DISCRETE_TOGGLE: - return new DiscreteToggleTemplate(bundle); - case TYPE_COORD_RANGE: - return new CoordinatedRangeTemplate(bundle); case TYPE_TOGGLE_RANGE: return new ToggleRangeTemplate(bundle); case TYPE_TEMPERATURE: diff --git a/core/java/android/service/controls/templates/CoordinatedRangeTemplate.java b/core/java/android/service/controls/templates/CoordinatedRangeTemplate.java deleted file mode 100644 index 6aa5480f0611..000000000000 --- a/core/java/android/service/controls/templates/CoordinatedRangeTemplate.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.service.controls.templates; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Bundle; -import android.util.Log; - -public final class CoordinatedRangeTemplate extends ControlTemplate { - - private static final String TAG = "CoordinatedRangeTemplate"; - - private static final @TemplateType int TYPE = TYPE_COORD_RANGE; - private static final String KEY_RANGE_LOW = "key_range_low"; - private static final String KEY_RANGE_HIGH = "key_range_high"; - private static final String KEY_MIN_GAP = "key_min_gap"; - - private final @NonNull RangeTemplate mRangeLow; - private final @NonNull RangeTemplate mRangeHigh; - private final float mMinGap; - - public CoordinatedRangeTemplate( - @NonNull String templateId, - float minGap, - @NonNull RangeTemplate rangeLow, - @NonNull RangeTemplate rangeHigh) { - super(templateId); - mRangeLow = rangeLow; - mRangeHigh = rangeHigh; - if (minGap < 0) { - Log.e(TAG, "minGap must be non-negative. Setting to 0"); - mMinGap = 0; - } else { - mMinGap = minGap; - } - validateRanges(); - } - - public CoordinatedRangeTemplate( - @NonNull String templateId, - float minGap, - float minValueLow, - float maxValueLow, - float currentValueLow, - float minValueHigh, - float maxValueHigh, - float currentValueHigh, - float stepValue, - @Nullable CharSequence formatString) { - this(templateId, - minGap, - new RangeTemplate("", - minValueLow, maxValueLow, currentValueLow, stepValue, formatString), - new RangeTemplate("", - minValueHigh, maxValueHigh, currentValueHigh, stepValue, formatString)); - } - - /** - * @param b - * @hide - */ - CoordinatedRangeTemplate(Bundle b) { - super(b); - mRangeLow = new RangeTemplate(b.getBundle(KEY_RANGE_LOW)); - mRangeHigh = new RangeTemplate(b.getBundle(KEY_RANGE_HIGH)); - mMinGap = b.getFloat(KEY_MIN_GAP); - validateRanges(); - } - - @NonNull - public RangeTemplate getRangeLow() { - return mRangeLow; - } - - @NonNull - public RangeTemplate getRangeHigh() { - return mRangeHigh; - } - - public float getMinValueLow() { - return mRangeLow.getMinValue(); - } - - public float getMaxValueLow() { - return mRangeLow.getMaxValue(); - } - - public float getCurrentValueLow() { - return mRangeLow.getCurrentValue(); - } - - public float getMinValueHigh() { - return mRangeHigh.getMinValue(); - } - - public float getMaxValueHigh() { - return mRangeHigh.getMaxValue(); - } - - public float getCurrentValueHigh() { - return mRangeHigh.getCurrentValue(); - } - - public float getStepValue() { - return mRangeLow.getStepValue(); - } - - public float getMinGap() { - return mMinGap; - } - - @NonNull - public CharSequence getFormatString() { - return mRangeLow.getFormatString(); - } - - @Override - public int getTemplateType() { - return TYPE; - } - - /** - * @return - * @hide - */ - @Override - @NonNull - Bundle getDataBundle() { - Bundle b = super.getDataBundle(); - b.putBundle(KEY_RANGE_LOW, mRangeLow.getDataBundle()); - b.putBundle(KEY_RANGE_HIGH, mRangeHigh.getDataBundle()); - return b; - } - - private void validateRanges() { - if (Float.compare(mRangeLow.getStepValue(), mRangeHigh.getStepValue()) != 0) { - throw new IllegalArgumentException( - String.format("lowStepValue=%f != highStepValue=%f", - mRangeLow.getStepValue(), mRangeHigh.getStepValue())); - } - if (!mRangeLow.getFormatString().equals(mRangeHigh.getFormatString())) { - throw new IllegalArgumentException( - String.format("lowFormatString=%s != highFormatString=%s", - mRangeLow.getFormatString(), mRangeHigh.getFormatString())); - } - if (mMinGap > mRangeHigh.getCurrentValue() - mRangeLow.getCurrentValue()) { - throw new IllegalArgumentException( - String.format("Minimum gap (%f) > Current gap (%f)", mMinGap, - mRangeHigh.getCurrentValue() - mRangeLow.getCurrentValue())); - } - } - -} diff --git a/core/java/android/service/controls/templates/DiscreteToggleTemplate.java b/core/java/android/service/controls/templates/DiscreteToggleTemplate.java deleted file mode 100644 index 7a1331a35ed4..000000000000 --- a/core/java/android/service/controls/templates/DiscreteToggleTemplate.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.service.controls.templates; - -import android.annotation.NonNull; -import android.os.Bundle; -import android.service.controls.Control; -import android.service.controls.actions.BooleanAction; - -import com.android.internal.util.Preconditions; - -/** - * A template for a {@link Control} with two discrete inputs. - * - * The two inputs represent a <i>Negative</i> input and a <i>Positive</i> input. - * <p> - * When one of the buttons is actioned, a {@link BooleanAction} will be sent. - * {@link BooleanAction#getNewState} will be {@code false} if the button was - * {@link DiscreteToggleTemplate#getNegativeButton} and {@code true} if the button was - * {@link DiscreteToggleTemplate#getPositiveButton}. - */ -public final class DiscreteToggleTemplate extends ControlTemplate { - - private static final @TemplateType int TYPE = TYPE_DISCRETE_TOGGLE; - private static final String KEY_NEGATIVE_BUTTON = "key_negative_button"; - private static final String KEY_POSITIVE_BUTTON = "key_positive_button"; - - private final @NonNull ControlButton mPositiveButton; - private final @NonNull ControlButton mNegativeButton; - - /** - * @param templateId the identifier for this template object - * @param negativeButton a {@link ControlButton} for the <i>Negative</i> input - * @param positiveButton a {@link ControlButton} for the <i>Positive</i> input - */ - public DiscreteToggleTemplate(@NonNull String templateId, - @NonNull ControlButton negativeButton, - @NonNull ControlButton positiveButton) { - super(templateId); - Preconditions.checkNotNull(negativeButton); - Preconditions.checkNotNull(positiveButton); - mNegativeButton = negativeButton; - mPositiveButton = positiveButton; - } - - /** - * @param b - * @hide - */ - DiscreteToggleTemplate(Bundle b) { - super(b); - mNegativeButton = b.getParcelable(KEY_NEGATIVE_BUTTON); - mPositiveButton = b.getParcelable(KEY_POSITIVE_BUTTON); - } - - /** - * The {@link ControlButton} associated with the <i>Negative</i> action. - */ - @NonNull - public ControlButton getNegativeButton() { - return mNegativeButton; - } - - /** - * The {@link ControlButton} associated with the <i>Positive</i> action. - */ - @NonNull - public ControlButton getPositiveButton() { - return mPositiveButton; - } - - /** - * @return {@link ControlTemplate#TYPE_DISCRETE_TOGGLE} - */ - @Override - public int getTemplateType() { - return TYPE; - } - - /** - * @return - * @hide - */ - @Override - @NonNull - Bundle getDataBundle() { - Bundle b = super.getDataBundle(); - b.putParcelable(KEY_NEGATIVE_BUTTON, mNegativeButton); - b.putParcelable(KEY_POSITIVE_BUTTON, mPositiveButton); - return b; - } - -} diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 44ab596b93ee..330e6c137f8b 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -9566,7 +9566,10 @@ public final class ViewRootImpl implements ViewParent, return mRtBLASTSyncTransaction; } - SurfaceControl getRenderSurfaceControl() { + /** + * @hide + */ + public SurfaceControl getRenderSurfaceControl() { if (mUseBLASTAdapter) { return mBlastSurfaceControl; } else { diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index a6a5ec55b972..47ea1cbade93 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -1257,7 +1257,8 @@ public final class Magnifier { return; } // Show or move the window at the content draw frame. - mTransaction.deferTransactionUntilSurface(mSurfaceControl, mSurface, frame); + mTransaction.deferTransactionUntil(mSurfaceControl, mSurfaceControl, + frame); if (updateWindowPosition) { mTransaction.setPosition(mSurfaceControl, pendingX, pendingY); } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 578c0cc23a74..3378c073eace 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -1160,6 +1160,10 @@ public class SystemConfig { addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0); } + if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) { + addFeature(PackageManager.FEATURE_APP_ENUMERATION, 0); + } + for (String featureName : mUnavailableFeatures) { removeFeature(featureName); } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index ce9a048f8006..3f81b112d9f1 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -236,7 +236,6 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj, static void nativeRelease(JNIEnv* env, jclass clazz, jlong nativeObject) { sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject)); - ctrl->release(); ctrl->decStrong((void *)nativeCreate); } diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 0aaf41e6c497..030483bc4c33 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -2627,4 +2627,10 @@ enum PageId { // CATEGORY: SETTINGS // OS: R PANEL_MEDIA_OUTPUT_GROUP = 1835; + + // OPEN: Settings > Developer Options > Wireless debugging + // > Click on paired device + // CATEGORY: SETTINGS + // OS: R + ADB_WIRELESS_DEVICE_DETAILS = 1836; } diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto index a4e2193115a2..782b2694c453 100644 --- a/core/proto/android/stats/devicepolicy/device_policy_enums.proto +++ b/core/proto/android/stats/devicepolicy/device_policy_enums.proto @@ -176,4 +176,7 @@ enum EventId { IS_MANAGED_PROFILE = 149; START_ACTIVITY_BY_INTENT = 150; BIND_CROSS_PROFILE_SERVICE = 151; + PROVISIONING_DPC_SETUP_STARTED = 152; + PROVISIONING_DPC_SETUP_COMPLETED = 153; + PROVISIONING_ORGANIZATION_OWNED_MANAGED_PROFILE = 154; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 6530036f940c..488698a8f461 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4953,6 +4953,16 @@ <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS" android:protectionLevel="signature|appPredictor" /> + <!-- Feature Id for Country Detector. --> + <feature android:featureId="CountryDetector" android:label="@string/country_detector"/> + <!-- Feature Id for Location service. --> + <feature android:featureId="LocationService" android:label="@string/location_service"/> + <!-- Feature Id for Sensor Notification service. --> + <feature android:featureId="SensorNotificationService" + android:label="@string/sensor_notification_service"/> + <!-- Feature Id for Twilight service. --> + <feature android:featureId="TwilightService" android:label="@string/twilight_service"/> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/core/res/res/drawable/ic_work_apps_off.xml b/core/res/res/drawable/ic_work_apps_off.xml index e91806f199df..f62eb2769bef 100644 --- a/core/res/res/drawable/ic_work_apps_off.xml +++ b/core/res/res/drawable/ic_work_apps_off.xml @@ -1,4 +1,4 @@ -<vector android:height="32dp" android:viewportHeight="24" - android:viewportWidth="24" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android"> - <path android:fillColor="@color/resolver_empty_state_icon" android:pathData="M22,7.95c0.05,-1.11 -0.84,-2 -1.95,-1.95L16,6L16,3.95c0,-1.11 -0.84,-2 -1.95,-1.95h-4C8.94,1.95 8,2.84 8,3.95v0.32l14,14L22,7.95zM14,6h-4L10,4h4v2zM21.54,20.28l-7.56,-7.56v0.01l-1.7,-1.7h0.01L7.21,5.95 3.25,1.99 1.99,3.27 4.69,6h-0.64c-1.11,0 -1.99,0.86 -1.99,1.97l-0.01,11.02c0,1.11 0.89,2.01 2,2.01h15.64l2.05,2.02L23,21.75l-1.46,-1.47z"/> -</vector> +<vector android:height="32dp" android:viewportHeight="24.0" + android:viewportWidth="24.0" android:width="32dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@color/resolver_empty_state_icon" android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v1.17L10.83,8L20,8v9.17l1.98,1.98c0,-0.05 0.02,-0.1 0.02,-0.16L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2zM19,19L8,8 6,6 2.81,2.81 1.39,4.22 3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19c0,1.11 0.89,2 2,2h14.17l1.61,1.61 1.41,-1.41 -0.37,-0.37L19,19zM4,19L4,8h1.17l11,11L4,19z"/> +</vector>
\ No newline at end of file diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index e6a93e550a5f..e7ad8eba3188 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -421,6 +421,14 @@ [CHAR LIMIT=NONE] --> <string name="location_changed_notification_text">Tap to see your location settings.</string> + <!-- Feature Id for Country Detector. [CHAR LIMIT=NONE]--> + <string name="country_detector">Country Detector</string> + <!-- Feature Id for Location service. [CHAR LIMIT=NONE]--> + <string name="location_service">Location Service</string> + <!-- Feature Id for Sensor Notification service. [CHAR LIMIT=NONE]--> + <string name="sensor_notification_service">Sensor Notification Service</string> + <!-- Feature Id for Twilight service. [CHAR LIMIT=NONE]--> + <string name="twilight_service">Twilight Service</string> <!-- Factory reset warning dialog strings--> <skip /> <!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] --> diff --git a/core/res/res/values/vendor_allowed_personal_apps_org_owned_device.xml b/core/res/res/values/vendor_allowed_personal_apps_org_owned_device.xml new file mode 100644 index 000000000000..0435c301a2da --- /dev/null +++ b/core/res/res/values/vendor_allowed_personal_apps_org_owned_device.xml @@ -0,0 +1,23 @@ +<?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. + */ +--> +<resources> + <!-- A list of apps to be allowed in the personal profile of an organization-owned device. --> + <string-array translatable="false" name="vendor_allowed_personal_apps_org_owned_device"> + </string-array> +</resources> diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 59335a595334..718ca46a4f18 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1330,6 +1330,12 @@ android:process=":FakeProvider"> </provider> + <provider + android:name="android.content.SlowProvider" + android:authorities="android.content.SlowProvider" + android:process=":SlowProvider"> + </provider> + <!-- Application components used for os tests --> <service android:name="android.os.MessengerService" diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java index 8d8acb75ae03..0443d3a9e73f 100644 --- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java +++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java @@ -289,6 +289,44 @@ public class NotificationHistoryTest { } @Test + public void testRemoveConversationNotificationFromWrite() { + NotificationHistory history = new NotificationHistory(); + + List<HistoricalNotification> postRemoveExpectedEntries = new ArrayList<>(); + List<String> postRemoveExpectedStrings = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + HistoricalNotification n = getHistoricalNotification("pkg", i); + + if (i != 2) { + 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 conversation id that will be removed + history.addNotificationToWrite(getHistoricalNotification("pkg", 2)); + + 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.removeConversationFromWrite("pkg", "convo2"); + + // 1 package names and 9 * 2 unique channel names and ids and 4 conversation ids + assertThat(history.getPooledStringsToWrite().length).isEqualTo(23); + assertThat(history.getNotificationsToWrite()) + .containsExactlyElementsIn(postRemoveExpectedEntries); + } + + @Test public void testParceling() { NotificationHistory history = new NotificationHistory(); diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java index 9dcce1e51e0b..78c4420b9496 100644 --- a/core/tests/coretests/src/android/content/ContentResolverTest.java +++ b/core/tests/coretests/src/android/content/ContentResolverTest.java @@ -16,6 +16,8 @@ package android.content; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -31,6 +33,7 @@ import android.graphics.Paint; import android.net.Uri; import android.os.MemoryFile; import android.os.ParcelFileDescriptor; +import android.os.SystemClock; import android.util.Size; import androidx.test.InstrumentationRegistry; @@ -209,4 +212,26 @@ public class ContentResolverTest { String type = mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote")); assertEquals("fake/remote", type); } + + @Test + public void testGetType_slowProvider() { + // This provider is running in a different process and is intentionally slow to start. + // We are trying to confirm that it does not cause an ANR + long start = SystemClock.uptimeMillis(); + String type = mResolver.getType(Uri.parse("content://android.content.SlowProvider")); + long end = SystemClock.uptimeMillis(); + assertEquals("slow", type); + assertThat(end).isLessThan(start + 5000); + } + + @Test + public void testGetType_unknownProvider() { + // This provider does not exist. + // We are trying to confirm that getType returns null and does not cause an ANR + long start = SystemClock.uptimeMillis(); + String type = mResolver.getType(Uri.parse("content://android.content.NonexistentProvider")); + long end = SystemClock.uptimeMillis(); + assertThat(type).isNull(); + assertThat(end).isLessThan(start + 5000); + } } diff --git a/core/tests/coretests/src/android/content/SlowProvider.java b/core/tests/coretests/src/android/content/SlowProvider.java new file mode 100644 index 000000000000..aba32e836e80 --- /dev/null +++ b/core/tests/coretests/src/android/content/SlowProvider.java @@ -0,0 +1,65 @@ +/* + * 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 android.content; + +import android.database.Cursor; +import android.net.Uri; + +/** + * A dummy content provider for tests. This provider runs in a different process from the test and + * is intentionally slow. + */ +public class SlowProvider extends ContentProvider { + + private static final int ON_CREATE_LATENCY_MILLIS = 3000; + + @Override + public boolean onCreate() { + try { + Thread.sleep(ON_CREATE_LATENCY_MILLIS); + } catch (InterruptedException e) { + // Ignore + } + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, + String sortOrder) { + return null; + } + + @Override + public String getType(Uri uri) { + return "slow"; + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + return null; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + return 0; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + return 0; + } +} diff --git a/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java b/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java index c9b5eecdcd21..292ac0928f1d 100644 --- a/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java +++ b/core/tests/coretests/src/android/service/controls/templates/ControlTemplateTest.java @@ -113,54 +113,6 @@ public class ControlTemplateTest { } @Test - public void testUnparcelingCorrectClass_discreteToggle() { - ControlTemplate toParcel = - new DiscreteToggleTemplate(TEST_ID, mControlButton, mControlButton); - - ControlTemplate fromParcel = parcelAndUnparcel(toParcel); - - assertEquals(ControlTemplate.TYPE_DISCRETE_TOGGLE, fromParcel.getTemplateType()); - assertTrue(fromParcel instanceof DiscreteToggleTemplate); - } - - @Test - public void testUnparcelingCorrectClass_coordRange() { - ControlTemplate toParcel = - new CoordinatedRangeTemplate(TEST_ID, 0.1f, 0, 1, 0.5f, 1, 2, 1.5f, 0.1f, "%f"); - ControlTemplate fromParcel = parcelAndUnparcel(toParcel); - assertEquals(ControlTemplate.TYPE_COORD_RANGE, fromParcel.getTemplateType()); - assertTrue(fromParcel instanceof CoordinatedRangeTemplate); - } - - @Test - public void testCoordRangeParameters_negativeMinGap() { - CoordinatedRangeTemplate template = - new CoordinatedRangeTemplate(TEST_ID, -0.1f, 0, 1, 0.5f, 1, 2, 1.5f, 0.1f, "%f"); - assertEquals(0, template.getMinGap(), 0); - } - - @Test(expected = IllegalArgumentException.class) - public void testCoordRangeParameters_differentStep() { - RangeTemplate rangeLow = new RangeTemplate(TEST_ID, 0, 1, 0.5f, 0.1f, "%f"); - RangeTemplate rangeHigh = new RangeTemplate(TEST_ID, 0, 1, 0.75f, 0.2f, "%f"); - new CoordinatedRangeTemplate(TEST_ID, 0.1f, rangeLow, rangeHigh); - } - - @Test(expected = IllegalArgumentException.class) - public void testCoordRangeParameters_differentFormat() { - RangeTemplate rangeLow = new RangeTemplate(TEST_ID, 0, 1, 0.5f, 0.1f, "%f"); - RangeTemplate rangeHigh = new RangeTemplate(TEST_ID, 0, 1, 0.75f, 0.1f, "%.1f"); - new CoordinatedRangeTemplate(TEST_ID, 0.1f, rangeLow, rangeHigh); - } - - @Test(expected = IllegalArgumentException.class) - public void testCoordRangeParameters_LargeMinGap() { - RangeTemplate rangeLow = new RangeTemplate(TEST_ID, 0, 1, 0.5f, 0.1f, "%f"); - RangeTemplate rangeHigh = new RangeTemplate(TEST_ID, 0, 1, 0.75f, 0.1f, "%f"); - new CoordinatedRangeTemplate(TEST_ID, 0.5f, rangeLow, rangeHigh); - } - - @Test public void testUnparcelingCorrectClass_toggleRange() { ControlTemplate toParcel = new ToggleRangeTemplate(TEST_ID, mControlButton, new RangeTemplate(TEST_ID, 0, 2, 1, 1, "%f")); diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java index 65f2f1789491..453704eea398 100644 --- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java +++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java @@ -102,12 +102,6 @@ public final class AudioPlaybackCaptureConfiguration { criterion -> criterion.getIntProp()); } - /** @return the userId's passed to {@link Builder#addMatchingUserId(int)}. */ - public @NonNull int[] getMatchingUserIds() { - return getIntPredicates(AudioMixingRule.RULE_MATCH_USERID, - criterion -> criterion.getIntProp()); - } - /** @return the usages passed to {@link Builder#excludeUsage(int)}. */ @AttributeUsage public @NonNull int[] getExcludeUsages() { @@ -121,12 +115,6 @@ public final class AudioPlaybackCaptureConfiguration { criterion -> criterion.getIntProp()); } - /** @return the userId's passed to {@link Builder#excludeUserId(int)}. */ - public @NonNull int[] getExcludeUserIds() { - return getIntPredicates(AudioMixingRule.RULE_EXCLUDE_USERID, - criterion -> criterion.getIntProp()); - } - private int[] getIntPredicates(int rule, ToIntFunction<AudioMixMatchCriterion> getPredicate) { return mAudioMixingRule.getCriteria().stream() @@ -165,7 +153,6 @@ public final class AudioPlaybackCaptureConfiguration { private final MediaProjection mProjection; private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED; private int mUidMatchType = MATCH_TYPE_UNSPECIFIED; - private int mUserIdMatchType = MATCH_TYPE_UNSPECIFIED; /** @param projection A MediaProjection that supports audio projection. */ public Builder(@NonNull MediaProjection projection) { @@ -215,23 +202,6 @@ public final class AudioPlaybackCaptureConfiguration { } /** - * Only capture audio output by app with the matching {@code userId}. - * - * <p>If called multiple times, will capture audio output by apps whose userId is any of the - * given userId's. - * - * @throws IllegalStateException if called in conjunction with {@link #excludeUserId(int)}. - */ - public @NonNull Builder addMatchingUserId(int userId) { - Preconditions.checkState( - mUserIdMatchType != MATCH_TYPE_EXCLUSIVE, - ERROR_MESSAGE_MISMATCHED_RULES); - mAudioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_USERID, userId); - mUserIdMatchType = MATCH_TYPE_INCLUSIVE; - return this; - } - - /** * Only capture audio output that does not match the given {@link AudioAttributes}. * * <p>If called multiple times, will capture audio output that does not match any of the @@ -268,24 +238,6 @@ public final class AudioPlaybackCaptureConfiguration { } /** - * Only capture audio output by apps that do not have the matching {@code userId}. - * - * <p>If called multiple times, will capture audio output by apps whose userId is not any of - * the given userId's. - * - * @throws IllegalStateException if called in conjunction with - * {@link #addMatchingUserId(int)}. - */ - public @NonNull Builder excludeUserId(int userId) { - Preconditions.checkState( - mUserIdMatchType != MATCH_TYPE_INCLUSIVE, - ERROR_MESSAGE_MISMATCHED_RULES); - mAudioMixingRuleBuilder.excludeMixRule(AudioMixingRule.RULE_MATCH_USERID, userId); - mUserIdMatchType = MATCH_TYPE_EXCLUSIVE; - return this; - } - - /** * Builds the configuration instance. * * @throws UnsupportedOperationException if the parameters set are incompatible. diff --git a/media/java/android/media/DrmInitData.java b/media/java/android/media/DrmInitData.java index 170d9de9d50a..cc35f140dd7e 100644 --- a/media/java/android/media/DrmInitData.java +++ b/media/java/android/media/DrmInitData.java @@ -15,11 +15,10 @@ */ package android.media; +import android.annotation.NonNull; import android.media.MediaDrm; import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; /** @@ -42,11 +41,41 @@ public abstract class DrmInitData { public abstract SchemeInitData get(UUID schemeUuid); /** + * Returns the number of {@link SchemeInitData} elements available through {@link + * #getSchemeInitDataAt}. + */ + public int getSchemeInitDataCount() { + return 0; + } + + /** + * Returns the {@link SchemeInitData} with the given {@code index}. + * + * @param index The index of the {@link SchemeInitData} to return. + * @return The {@link SchemeInitData} associated with the given {@code index}. + * @throws IndexOutOfBoundsException If the given {@code index} is negative or greater than + * {@link #getSchemeInitDataCount}{@code - 1}. + */ + @NonNull public SchemeInitData getSchemeInitDataAt(int index) { + throw new IndexOutOfBoundsException(); + } + + /** * Scheme initialization data. */ public static final class SchemeInitData { /** + * The Nil UUID, as defined in RFC 4122, section 4.1.7. + */ + @NonNull public static final UUID UUID_NIL = new UUID(0, 0); + + /** + * The UUID associated with this scheme initialization data. May be {@link #UUID_NIL} if + * unknown or not applicable. + */ + @NonNull public final UUID uuid; + /** * The mimeType of {@link #data}. */ public final String mimeType; @@ -56,12 +85,14 @@ public abstract class DrmInitData { public final byte[] data; /** + * @param uuid The UUID associated with this scheme initialization data. * @param mimeType The mimeType of the initialization data. * @param data The initialization data. * * @hide */ - public SchemeInitData(String mimeType, byte[] data) { + public SchemeInitData(UUID uuid, String mimeType, byte[] data) { + this.uuid = uuid; this.mimeType = mimeType; this.data = data; } @@ -76,12 +107,14 @@ public abstract class DrmInitData { } SchemeInitData other = (SchemeInitData) obj; - return mimeType.equals(other.mimeType) && Arrays.equals(data, other.data); + return uuid.equals(other.uuid) + && mimeType.equals(other.mimeType) + && Arrays.equals(data, other.data); } @Override public int hashCode() { - return mimeType.hashCode() + 31 * Arrays.hashCode(data); + return uuid.hashCode() + 31 * (mimeType.hashCode() + 31 * Arrays.hashCode(data)); } } diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java index 7785900a7c6e..6ef871383a58 100644 --- a/media/java/android/media/MediaExtractor.java +++ b/media/java/android/media/MediaExtractor.java @@ -40,10 +40,12 @@ import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; /** * MediaExtractor facilitates extraction of demuxed, typically encoded, media data @@ -393,17 +395,28 @@ final public class MediaExtractor { } if (formatMap.containsKey("pssh")) { Map<UUID, byte[]> psshMap = getPsshInfo(); + DrmInitData.SchemeInitData[] schemeInitDatas = + psshMap.entrySet().stream().map( + entry -> new DrmInitData.SchemeInitData( + entry.getKey(), /* mimeType= */ "cenc", entry.getValue())) + .toArray(DrmInitData.SchemeInitData[]::new); final Map<UUID, DrmInitData.SchemeInitData> initDataMap = - new HashMap<UUID, DrmInitData.SchemeInitData>(); - for (Map.Entry<UUID, byte[]> e: psshMap.entrySet()) { - UUID uuid = e.getKey(); - byte[] data = e.getValue(); - initDataMap.put(uuid, new DrmInitData.SchemeInitData("cenc", data)); - } + Arrays.stream(schemeInitDatas).collect( + Collectors.toMap(initData -> initData.uuid, initData -> initData)); return new DrmInitData() { public SchemeInitData get(UUID schemeUuid) { return initDataMap.get(schemeUuid); } + + @Override + public int getSchemeInitDataCount() { + return schemeInitDatas.length; + } + + @Override + public SchemeInitData getSchemeInitDataAt(int index) { + return schemeInitDatas[index]; + } }; } else { int numTracks = getTrackCount(); @@ -416,9 +429,23 @@ final public class MediaExtractor { buf.rewind(); final byte[] data = new byte[buf.remaining()]; buf.get(data); + // Webm scheme init data is not uuid-specific. + DrmInitData.SchemeInitData webmSchemeInitData = + new DrmInitData.SchemeInitData( + DrmInitData.SchemeInitData.UUID_NIL, "webm", data); return new DrmInitData() { public SchemeInitData get(UUID schemeUuid) { - return new DrmInitData.SchemeInitData("webm", data); + return webmSchemeInitData; + } + + @Override + public int getSchemeInitDataCount() { + return 1; + } + + @Override + public SchemeInitData getSchemeInitDataAt(int index) { + return webmSchemeInitData; } }; } diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index b57182e03675..5832fc172498 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -656,16 +656,20 @@ public final class MediaFormat { public static final String KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT = "aac-max-output-channel_count"; /** - * A key describing a gain to be applied so that the output loudness matches the - * Target Reference Level. This is typically used to normalize loudness across program items. - * The gain is derived as the difference between the Target Reference Level and the - * Program Reference Level. The latter can be given in the bitstream and indicates the actual - * loudness value of the program item. + * A key describing the Target Reference Level (Target Loudness). + * <p>For normalizing loudness across program items, a gain is applied to the audio output so + * that the output loudness matches the Target Reference Level. The gain is derived as the + * difference between the Target Reference Level and the Program Reference Level (Program + * Loudness). The latter can be given in the bitstream and indicates the actual loudness value + * of the program item.</p> * <p>The Target Reference Level controls loudness normalization for both MPEG-4 DRC and * MPEG-D DRC. * <p>The value is given as an integer value between * 40 and 127, and is calculated as -4 * Target Reference Level in LKFS. * Therefore, it represents the range of -10 to -31.75 LKFS. + * <p>For MPEG-4 DRC, a value of -1 switches off loudness normalization and DRC processing.</p> + * <p>For MPEG-D DRC, a value of -1 switches off loudness normalization only. For DRC processing + * options of MPEG-D DRC, see {@link #KEY_AAC_DRC_EFFECT_TYPE}</p> * <p>The default value on mobile devices is 64 (-16 LKFS). * <p>This key is only used during decoding. */ @@ -686,7 +690,7 @@ public final class MediaFormat { * <tr><th>6</th><th>General compression</th></tr> * </table> * <p>The value -1 (Off) disables DRC processing, while loudness normalization may still be - * active and dependent on KEY_AAC_DRC_TARGET_REFERENCE_LEVEL.<br> + * active and dependent on {@link #KEY_AAC_DRC_TARGET_REFERENCE_LEVEL}.<br> * The value 0 (None) automatically enables DRC processing if necessary to prevent signal * clipping<br> * The value 6 (General compression) can be used for enabling MPEG-D DRC without particular @@ -703,8 +707,8 @@ public final class MediaFormat { * 0 and 127, which is calculated as -4 * Encoded Target Level in LKFS. * If the Encoded Target Level is unknown, the value can be set to -1. * <p>The default value is -1 (unknown). - * <p>The value is ignored when heavy compression is used (see - * {@link #KEY_AAC_DRC_HEAVY_COMPRESSION}). + * <p>The value is ignored when heavy compression (see {@link #KEY_AAC_DRC_HEAVY_COMPRESSION}) + * or MPEG-D DRC is used. * <p>This key is only used during decoding. */ public static final String KEY_AAC_ENCODED_TARGET_LEVEL = "aac-encoded-target-level"; @@ -745,17 +749,17 @@ public final class MediaFormat { public static final String KEY_AAC_DRC_ATTENUATION_FACTOR = "aac-drc-cut-level"; /** - * A key describing the selection of the heavy compression profile for DRC. - * Two separate DRC gain sequences can be transmitted in one bitstream: MPEG-4 DRC light - * compression, and DVB-specific heavy compression. When selecting the application of the heavy - * compression, one of the sequences is selected: + * A key describing the selection of the heavy compression profile for MPEG-4 DRC. + * <p>Two separate DRC gain sequences can be transmitted in one bitstream: light compression + * and heavy compression. When selecting the application of the heavy compression, one of + * the sequences is selected: * <ul> * <li>0 enables light compression,</li> * <li>1 enables heavy compression instead. * </ul> - * Note that only light compression offers the features of scaling of DRC gains + * Note that heavy compression doesn't offer the features of scaling of DRC gains * (see {@link #KEY_AAC_DRC_BOOST_FACTOR} and {@link #KEY_AAC_DRC_ATTENUATION_FACTOR} for the - * boost and attenuation factors, and frequency-selective (multiband) DRC. + * boost and attenuation factors), and frequency-selective (multiband) DRC. * Light compression usually contains clipping prevention for stereo downmixing while heavy * compression, if additionally provided in the bitstream, is usually stronger, and contains * clipping prevention for stereo and mono downmixing. diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index 32a4a4f70192..d3e9c7e91056 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.content.Context; import android.content.pm.PackageManager; @@ -481,12 +482,13 @@ public class AudioPolicy { * @hide * Removes audio device affinity previously set by * {@link #setUserIdDeviceAffinity(int, java.util.List)}. - * @param userId userId of the application affected. + * @param userId userId of the application affected, as obtained via + * {@link UserHandle#getIdentifier}. Not to be confused with application uid. * @return true if the change was successful, false otherwise. */ @TestApi @SystemApi - public boolean removeUserIdDeviceAffinity(int userId) { + public boolean removeUserIdDeviceAffinity(@UserIdInt int userId) { synchronized (mLock) { if (mStatus != POLICY_STATUS_REGISTERED) { throw new IllegalStateException("Cannot use unregistered AudioPolicy"); @@ -512,13 +514,15 @@ public class AudioPolicy { * multiple devices in the list doesn't imply the signals will be duplicated on the different * audio devices, final routing will depend on the {@link AudioAttributes} of the sounds being * played. - * @param userId Android user id to affect. + * @param userId userId of the application affected, as obtained via + * {@link UserHandle#getIdentifier}. Not to be confused with application uid. * @param devices list of devices to which the audio stream of the application may be routed. * @return true if the change was successful, false otherwise. */ @TestApi @SystemApi - public boolean setUserIdDeviceAffinity(int userId, @NonNull List<AudioDeviceInfo> devices) { + public boolean setUserIdDeviceAffinity(@UserIdInt int userId, + @NonNull List<AudioDeviceInfo> devices) { Objects.requireNonNull(devices, "Illegal null list of audio devices"); synchronized (mLock) { if (mStatus != POLICY_STATUS_REGISTERED) { diff --git a/media/java/android/media/tv/tunerresourcemanager/Android.bp b/media/java/android/media/tv/tunerresourcemanager/Android.bp new file mode 100644 index 000000000000..c65d25a03813 --- /dev/null +++ b/media/java/android/media/tv/tunerresourcemanager/Android.bp @@ -0,0 +1,17 @@ +filegroup { + name: "framework-media-tv-tunerresourcemanager-sources", + srcs: [ + "*.java", + "*.aidl", + ], + path: ".", +} + +java_library { + name: "framework-media-tv-trm-sources", + srcs: [":framework-media-tv-tunerresourcemanager-sources"], + installable: true, + visibility: [ + "//frameworks/base", + ], +}
\ No newline at end of file diff --git a/media/java/android/media/tv/tuner/CasSessionRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/CasSessionRequest.aidl index 3dbf3d836ff3..c918d88b479a 100644 --- a/media/java/android/media/tv/tuner/CasSessionRequest.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/CasSessionRequest.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; /** * A wrapper of a cas session requests that contains all the request info of the client. diff --git a/media/java/android/media/tv/tuner/CasSessionRequest.java b/media/java/android/media/tv/tunerresourcemanager/CasSessionRequest.java index 0f6a885dec61..59802ff8c3f8 100644 --- a/media/java/android/media/tv/tuner/CasSessionRequest.java +++ b/media/java/android/media/tv/tunerresourcemanager/CasSessionRequest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; import android.annotation.NonNull; import android.os.Parcel; diff --git a/media/java/android/media/tv/tuner/ITunerResourceManagerListener.aidl b/media/java/android/media/tv/tunerresourcemanager/IResourcesReclaimListener.aidl index 557032ca8d6d..1a4eb2946b8c 100644 --- a/media/java/android/media/tv/tuner/ITunerResourceManagerListener.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/IResourcesReclaimListener.aidl @@ -14,20 +14,20 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; /** * Interface to receive callbacks from ITunerResourceManager. * * @hide */ -oneway interface ITunerResourceManagerListener { +oneway interface IResourcesReclaimListener { /* * TRM invokes this method when the client's resources need to be reclaimed. * * <p>This method is implemented in Tuner Framework to take the reclaiming - * actions. It's a synchonized call. TRM would wait on the call to finish + * actions. It's a synchronous call. TRM would wait on the call to finish * then grant the resource. */ - void onResourcesReclaim(); + void onReclaimResources(); }
\ No newline at end of file diff --git a/media/java/android/media/tv/tuner/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl index 758c68949b65..20efaa1e0833 100644 --- a/media/java/android/media/tv/tuner/ITunerResourceManager.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl @@ -14,14 +14,14 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; -import android.media.tv.tuner.CasSessionRequest; -import android.media.tv.tuner.ITunerResourceManagerListener; -import android.media.tv.tuner.ResourceClientProfile; -import android.media.tv.tuner.TunerFrontendInfo; -import android.media.tv.tuner.TunerFrontendRequest; -import android.media.tv.tuner.TunerLnbRequest; +import android.media.tv.tunerresourcemanager.CasSessionRequest; +import android.media.tv.tunerresourcemanager.IResourcesReclaimListener; +import android.media.tv.tunerresourcemanager.ResourceClientProfile; +import android.media.tv.tunerresourcemanager.TunerFrontendInfo; +import android.media.tv.tunerresourcemanager.TunerFrontendRequest; +import android.media.tv.tunerresourcemanager.TunerLnbRequest; /** * Interface of the Tuner Resource Manager. It manages resources used by TV Tuners. @@ -37,10 +37,10 @@ import android.media.tv.tuner.TunerLnbRequest; * <ul> * <li>Tuner Java/MediaCas/TIF update resources of the current device with TRM. * <li>Client registers its profile through {@link #registerClientProfile(ResourceClientProfile, - * ITunerResourceManagerListener, int[])}. + * IResourcesReclaimListener, int[])}. * <li>Client requests resources through request APIs. * <li>If the resource needs to be handed to a higher priority client from a lower priority - * one, TRM calls ITunerResourceManagerListener registered by the lower priority client to release + * one, TRM calls IResourcesReclaimListener registered by the lower priority client to release * the resource. * <ul> * @@ -53,13 +53,13 @@ interface ITunerResourceManager { * <p>The profile contains information that can show the base priority score of the client. * * @param profile {@link ResourceClientProfile} profile of the current client - * @param listener {@link ITunerResourceManagerListener} a callback to + * @param listener {@link IResourcesReclaimListener} a callback to * reclaim clients' resources when needed. * @param clientId returns a clientId from the resource manager when the * the client registers its profile. */ void registerClientProfile(in ResourceClientProfile profile, - ITunerResourceManagerListener listener, out int[] clientId); + IResourcesReclaimListener listener, out int[] clientId); /* * This API is used by the client to unregister their profile with the Tuner Resource manager. @@ -119,7 +119,7 @@ interface ITunerResourceManager { * * <li>If no Frontend is available but the current request info can show higher priority than * other uses of Frontend, the API will send - * {@link ITunerResourceManagerListener#onResourcesReclaim()} to the {@link Tuner}. Tuner would + * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would * handle the resource reclaim on the holder of lower priority and notify the holder of its * resource loss. * @@ -157,7 +157,7 @@ interface ITunerResourceManager { * * <li>If no Cas session is available but the current request info can show higher priority than * other uses of the sessions under the requested CAS system, the API will send - * {@link ITunerResourceManagerCallback#onResourcesReclaim()} to the {@link Tuner}. Tuner would + * {@link ITunerResourceManagerCallback#onReclaimResources()} to the {@link Tuner}. Tuner would * handle the resource reclaim on the holder of lower priority and notify the holder of its * resource loss. * @@ -181,7 +181,7 @@ interface ITunerResourceManager { * <li>If there is Lnb available, the API would send the id back. * * <li>If no Lnb is available but the current request has a higher priority than other uses of - * lnbs, the API will send {@link ITunerResourceManagerCallback#onResourcesReclaim()} to the + * lnbs, the API will send {@link ITunerResourceManagerCallback#onReclaimResources()} to the * {@link Tuner}. Tuner would handle the resource reclaim on the holder of lower priority and * notify the holder of its resource loss. * diff --git a/media/java/android/media/tv/tunerresourcemanager/OWNER b/media/java/android/media/tv/tunerresourcemanager/OWNER new file mode 100644 index 000000000000..76b84d98046a --- /dev/null +++ b/media/java/android/media/tv/tunerresourcemanager/OWNER @@ -0,0 +1,4 @@ +amyjojo@google.com +nchalko@google.com +quxiangfang@google.com +shubang@google.com
\ No newline at end of file diff --git a/media/java/android/media/tv/tuner/ResourceClientProfile.aidl b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.aidl index da3c5c4f15f9..ed90c1dc3996 100644 --- a/media/java/android/media/tv/tuner/ResourceClientProfile.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; /** * A profile of a resource client. This profile is used to register the client info diff --git a/media/java/android/media/tv/tuner/ResourceClientProfile.java b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java index e2031353b27a..68372444cb83 100644 --- a/media/java/android/media/tv/tuner/ResourceClientProfile.java +++ b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; import android.annotation.NonNull; import android.os.Parcel; diff --git a/media/java/android/media/tv/tuner/TunerFrontendInfo.aidl b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl index 012e051d8598..e649c2aa3fd6 100644 --- a/media/java/android/media/tv/tuner/TunerFrontendInfo.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; /** * Simple container of the FrontendInfo struct defined in the TunerHAL 1.0 interface. diff --git a/media/java/android/media/tv/tuner/TunerFrontendInfo.java b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendInfo.java index a62ecb3893ea..8957c3791e64 100644 --- a/media/java/android/media/tv/tuner/TunerFrontendInfo.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; import android.annotation.NonNull; import android.media.tv.tuner.frontend.FrontendSettings.Type; diff --git a/media/java/android/media/tv/tuner/TunerFrontendRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendRequest.aidl index 25c298f0f65b..5e48adc075b8 100644 --- a/media/java/android/media/tv/tuner/TunerFrontendRequest.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendRequest.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; /** * Information required to request a Tuner Frontend. diff --git a/media/java/android/media/tv/tuner/TunerFrontendRequest.java b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendRequest.java index 01a0a091877f..12f8032ab99b 100644 --- a/media/java/android/media/tv/tuner/TunerFrontendRequest.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerFrontendRequest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; import android.annotation.NonNull; import android.media.tv.tuner.frontend.FrontendSettings.Type; diff --git a/media/java/android/media/tv/tuner/TunerLnbRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/TunerLnbRequest.aidl index b811e3922252..0e6fcde51642 100644 --- a/media/java/android/media/tv/tuner/TunerLnbRequest.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/TunerLnbRequest.aidl @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; /** * Information required to request a Tuner Lnb. diff --git a/media/java/android/media/tv/tuner/TunerLnbRequest.java b/media/java/android/media/tv/tunerresourcemanager/TunerLnbRequest.java index 60cd7903b176..5ed7f3f546f4 100644 --- a/media/java/android/media/tv/tuner/TunerLnbRequest.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerLnbRequest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; import android.annotation.NonNull; import android.os.Parcel; diff --git a/media/java/android/media/tv/tuner/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java index 68ca5722ecad..7c11ed485ced 100644 --- a/media/java/android/media/tv/tuner/TunerResourceManager.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.media.tv.tuner; +package android.media.tv.tunerresourcemanager; import android.annotation.CallbackExecutor; import android.annotation.NonNull; @@ -42,10 +42,10 @@ import java.util.concurrent.Executor; * <ul> * <li>Tuner Java/MediaCas/TIF update resources of the current device with TRM. * <li>Client registers its profile through {@link #registerClientProfile(ResourceClientProfile, - * Executor, ResourceListener, int[])}. + * Executor, ResourcesReclaimListener, int[])}. * <li>Client requests resources through request APIs. * <li>If the resource needs to be handed to a higher priority client from a lower priority - * one, TRM calls ITunerResourceManagerListener registered by the lower priority client to release + * one, TRM calls IResourcesReclaimListener registered by the lower priority client to release * the resource. * <ul> * @@ -85,25 +85,26 @@ public class TunerResourceManager { * @param profile {@link ResourceClientProfile} profile of the current client. Undefined use * case would cause IllegalArgumentException. * @param executor the executor on which the listener would be invoked. - * @param listener {@link ResourceListener} callback to reclaim clients' resources when needed. + * @param listener {@link ResourcesReclaimListener} callback to reclaim clients' resources when + * needed. * @param clientId returned a clientId from the resource manager when the * the client registeres. * @throws IllegalArgumentException when {@code profile} contains undefined use case. */ public void registerClientProfile(@NonNull ResourceClientProfile profile, @NonNull @CallbackExecutor Executor executor, - @NonNull ResourceListener listener, + @NonNull ResourcesReclaimListener listener, @NonNull int[] clientId) { // TODO: throw new IllegalArgumentException("Unknown client use case") // when the use case is not defined. try { mService.registerClientProfile(profile, - new ITunerResourceManagerListener.Stub() { + new IResourcesReclaimListener.Stub() { @Override - public void onResourcesReclaim() { + public void onReclaimResources() { final long identity = Binder.clearCallingIdentity(); try { - executor.execute(() -> listener.onResourcesReclaim()); + executor.execute(() -> listener.onReclaimResources()); } finally { Binder.restoreCallingIdentity(identity); } @@ -214,7 +215,7 @@ public class TunerResourceManager { * * <li>If no Frontend is available but the current request info can show higher priority than * other uses of Frontend, the API will send - * {@link ITunerResourceManagerListener#onResourcesReclaim()} to the {@link Tuner}. Tuner would + * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would * handle the resource reclaim on the holder of lower priority and notify the holder of its * resource loss. * @@ -267,7 +268,7 @@ public class TunerResourceManager { * * <li>If no Cas system is available but the current request info can show higher priority than * other uses of the cas sessions under the requested cas system, the API will send - * {@link ITunerResourceManagerListener#onResourcesReclaim()} to the {@link Tuner}. Tuner would + * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would * handle the resource reclaim on the holder of lower priority and notify the holder of its * resource loss. * @@ -300,7 +301,7 @@ public class TunerResourceManager { * <li>If there is Lnb available, the API would send the id back. * * <li>If no Lnb is available but the current request has a higher priority than other uses of - * lnbs, the API will send {@link ITunerResourceManagerListener#onResourcesReclaim()} to the + * lnbs, the API will send {@link IResourcesReclaimListener#onReclaimResources()} to the * {@link Tuner}. Tuner would handle the resource reclaim on the holder of lower priority and * notify the holder of its resource loss. * @@ -398,10 +399,10 @@ public class TunerResourceManager { /** * Interface used to receive events from TunerResourceManager. */ - public abstract static class ResourceListener { + public abstract static class ResourcesReclaimListener { /* * To reclaim all the resources of the callack owner. */ - public abstract void onResourcesReclaim(); + public abstract void onReclaimResources(); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java index 51b263ebdb4e..7d544c9a9bd7 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java @@ -21,6 +21,7 @@ import com.android.systemui.dagger.DependencyProvider; import com.android.systemui.dagger.SystemServicesModule; import com.android.systemui.dagger.SystemUIModule; import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.pip.phone.dagger.PipModule; import javax.inject.Singleton; @@ -32,6 +33,7 @@ import dagger.Component; CarComponentBinder.class, DependencyProvider.class, DependencyBinder.class, + PipModule.class, SystemUIFactory.ContextHolder.class, SystemServicesModule.class, SystemUIModule.class, diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index fbca2bc9f0b7..a4eada4ebe0b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -919,7 +919,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt Dependency.get(KeyguardUpdateMonitor.class).dump(fd, pw, args); } - Dependency.get(FalsingManager.class).dump(pw); FalsingLog.dump(pw); pw.println("SharedPreferences:"); diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml index 0dd3352b2df0..fb38e1c6dc6b 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml +++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml @@ -29,7 +29,8 @@ android:background="@drawable/ripple_drawable" android:clipChildren="false" android:clipToPadding="false" - sysui:activatedFontFamily="sans-serif-medium"> + sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" + sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> <TextView android:id="@+id/user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml index c7bfaef8bbe8..5c03e3099522 100644 --- a/packages/SystemUI/res/layout/qs_user_detail_item.xml +++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml @@ -30,7 +30,8 @@ android:clipToPadding="false" android:focusable="true" android:background="@drawable/ripple_drawable" - systemui:activatedFontFamily="sans-serif-medium"> + systemui:regularTextAppearance="@style/TextAppearance.QS.UserSwitcher" + systemui:activatedTextAppearance="@style/TextAppearance.QS.UserSwitcher.Activated"> <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" @@ -52,8 +53,6 @@ android:id="@+id/user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textSize="@dimen/qs_detail_item_secondary_text_size" - android:textColor="?android:attr/textColorSecondary" android:gravity="center_horizontal" /> <ImageView android:id="@+id/restricted_padlock" diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index bb4999453d4f..90ea5e203429 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -21,8 +21,9 @@ for different hardware and product builds. --> <resources> <!-- SystemUIFactory component --> - <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.tv.TvSystemUIFactory</string> - + <string name="config_systemUIFactoryComponent" translatable="false"> + com.android.systemui.tv.TvSystemUIFactory + </string> <!-- SystemUI Services: The classes of the stuff to start. --> <string-array name="config_systemUIServiceComponents" translatable="false"> <item>com.android.systemui.util.NotificationChannels</item> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 79629e4c6d7e..d3256ef34bd7 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -63,8 +63,8 @@ <attr name="badgeMargin" format="dimension" /> </declare-styleable> <declare-styleable name="UserDetailItemView"> - <attr name="regularFontFamily" format="string" /> - <attr name="activatedFontFamily" format="string" /> + <attr name="regularTextAppearance" format="string" /> + <attr name="activatedTextAppearance" format="string" /> </declare-styleable> <declare-styleable name="DateView"> <attr name="datePattern" format="string" /> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index ef9e705d0a81..5e9feff566e5 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1784,7 +1784,7 @@ <string name="bubble_overflow_empty_title">No recent bubbles</string> <!-- [CHAR LIMIT=NONE] Empty overflow subtitle --> - <string name="bubble_overflow_empty_subtitle">Recently dismissed bubbles will appear here for easy retrieval.</string> + <string name="bubble_overflow_empty_subtitle">Recent bubbles and dismissed bubbles will appear here.</string> <!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. --> <string name="notification_unblockable_desc">These notifications can\'t be modified.</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index fecb75cdf9b3..557e2d65202b 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -134,6 +134,11 @@ <item name="android:textColor">?android:attr/textColorSecondary</item> </style> + <style name="TextAppearance.StatusBar.Expanded.UserSwitcher.Activated"> + <item name="android:fontWeight">700</item> + <item name="android:textStyle">bold</item> + </style> + <style name="TextAppearance" /> <style name="TextAppearance.QS"> @@ -216,6 +221,16 @@ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> + <style name="TextAppearance.QS.UserSwitcher"> + <item name="android:textSize">@dimen/qs_detail_item_secondary_text_size</item> + <item name="android:textColor">?android:attr/textColorSecondary</item> + </style> + + <style name="TextAppearance.QS.UserSwitcher.Activated"> + <item name="android:fontWeight">700</item> + <item name="android:textStyle">bold</item> + </style> + <!-- This is hard coded to be sans-serif-condensed to match the icons --> <style name="TextAppearance.RATBadge" parent="@style/TextAppearance.QS.TileLabel.Secondary"> <item name="android:fontFamily">sans-serif-condensed</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java index e80b43739557..7dcf4b0c11ae 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java @@ -24,6 +24,7 @@ import android.os.Handler.Callback; import android.os.Message; import android.os.Trace; import android.view.Surface; +import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; @@ -39,7 +40,7 @@ public class SyncRtSurfaceTransactionApplierCompat { private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0; - private final Surface mTargetSurface; + private final SurfaceControl mBarrierSurfaceControl; private final ViewRootImpl mTargetViewRootImpl; private final Handler mApplyHandler; @@ -52,7 +53,8 @@ public class SyncRtSurfaceTransactionApplierCompat { */ public SyncRtSurfaceTransactionApplierCompat(View targetView) { mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null; - mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null; + mBarrierSurfaceControl = mTargetViewRootImpl != null + ? mTargetViewRootImpl.getRenderSurfaceControl() : null; mApplyHandler = new Handler(new Callback() { @Override @@ -91,7 +93,7 @@ public class SyncRtSurfaceTransactionApplierCompat { mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() { @Override public void onFrameDraw(long frame) { - if (mTargetSurface == null || !mTargetSurface.isValid()) { + if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) { Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0) .sendToTarget(); return; @@ -102,7 +104,7 @@ public class SyncRtSurfaceTransactionApplierCompat { SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams = params[i]; SurfaceControlCompat surface = surfaceParams.surface; - t.deferTransactionUntil(surface, mTargetSurface, frame); + t.deferTransactionUntil(surface, mBarrierSurfaceControl, frame); applyParams(t, surfaceParams); } t.setEarlyWakeup(); diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java index 073688b0bf8c..8f4926fe14a3 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java @@ -20,6 +20,7 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.view.Surface; import android.view.SurfaceControl.Transaction; +import android.view.SurfaceControl; public class TransactionCompat { @@ -87,8 +88,8 @@ public class TransactionCompat { } public TransactionCompat deferTransactionUntil(SurfaceControlCompat surfaceControl, - Surface barrier, long frameNumber) { - mTransaction.deferTransactionUntilSurface(surfaceControl.mSurfaceControl, barrier, + SurfaceControl barrier, long frameNumber) { + mTransaction.deferTransactionUntil(surfaceControl.mSurfaceControl, barrier, frameNumber); return this; } @@ -102,4 +103,4 @@ public class TransactionCompat { mTransaction.setColor(surfaceControl.mSurfaceControl, color); return this; } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index e5f6d3c90eb7..9ba3860f4fb8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -95,6 +95,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.util.Assert; import com.google.android.collect.Lists; @@ -341,7 +342,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onTrustChanged(boolean enabled, int userId, int flags) { - checkIsHandlerThread(); + Assert.isMainThread(); mUserHasTrust.put(userId, enabled); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -360,7 +361,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleSimSubscriptionInfoChanged() { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG_SIM_STATES) { Log.v(TAG, "onSubscriptionInfoChanged()"); List<SubscriptionInfo> sil = mSubscriptionManager @@ -403,7 +404,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void callbacksRefreshCarrierInfo() { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -466,7 +467,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onTrustManagedChanged(boolean managed, int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); mUserTrustIsManaged.put(userId, managed); mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); for (int i = 0; i < mCallbacks.size(); i++) { @@ -523,7 +524,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @VisibleForTesting protected void onFingerprintAuthenticated(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); Trace.beginSection("KeyGuardUpdateMonitor#onFingerPrintAuthenticated"); mUserFingerprintAuthenticated.put(userId, true); // Update/refresh trust state only if user can skip bouncer @@ -549,7 +550,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFingerprintAuthFailed() { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -561,7 +562,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFingerprintAcquired(int acquireInfo) { - checkIsHandlerThread(); + Assert.isMainThread(); if (acquireInfo != FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) { return; } @@ -599,7 +600,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFingerprintHelp(int msgId, String helpString) { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -618,7 +619,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab }; private void handleFingerprintError(int msgId, String errString) { - checkIsHandlerThread(); + Assert.isMainThread(); if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED && mHandler.hasCallbacks( mCancelNotReceived)) { mHandler.removeCallbacks(mCancelNotReceived); @@ -671,7 +672,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void notifyFingerprintRunningStateChanged() { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -684,7 +685,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @VisibleForTesting protected void onFaceAuthenticated(int userId) { Trace.beginSection("KeyGuardUpdateMonitor#onFaceAuthenticated"); - checkIsHandlerThread(); + Assert.isMainThread(); mUserFaceAuthenticated.put(userId, true); // Update/refresh trust state only if user can skip bouncer if (getUserCanSkipBouncer(userId)) { @@ -710,7 +711,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFaceAuthFailed() { - checkIsHandlerThread(); + Assert.isMainThread(); setFaceRunningState(BIOMETRIC_STATE_STOPPED); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -723,7 +724,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFaceAcquired(int acquireInfo) { - checkIsHandlerThread(); + Assert.isMainThread(); if (acquireInfo != FaceManager.FACE_ACQUIRED_GOOD) { return; } @@ -767,7 +768,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFaceHelp(int msgId, String helpString) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG_FACE) Log.d(TAG, "Face help received: " + helpString); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -787,7 +788,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab }; private void handleFaceError(int msgId, String errString) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG_FACE) Log.d(TAG, "Face error received: " + errString); if (msgId == FaceManager.FACE_ERROR_CANCELED && mHandler.hasCallbacks(mCancelNotReceived)) { mHandler.removeCallbacks(mCancelNotReceived); @@ -842,7 +843,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void notifyFaceRunningStateChanged() { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -853,7 +854,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleFaceUnlockStateChanged(boolean running, int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); mUserFaceUnlockRunning.put(userId, running); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -965,7 +966,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Cached version of {@link TrustManager#isTrustUsuallyManaged(int)}. */ public boolean isTrustUsuallyManaged(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); return mUserTrustIsUsuallyManaged.get(userId); } @@ -996,7 +997,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void notifyStrongAuthStateChanged(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1010,7 +1011,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void dispatchErrorMessage(CharSequence message) { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1323,7 +1324,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab protected void handleStartedWakingUp() { Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp"); - checkIsHandlerThread(); + Assert.isMainThread(); updateBiometricListeningState(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1335,7 +1336,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } protected void handleStartedGoingToSleep(int arg1) { - checkIsHandlerThread(); + Assert.isMainThread(); mLockIconPressed = false; clearBiometricRecognized(); for (int i = 0; i < mCallbacks.size(); i++) { @@ -1349,7 +1350,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } protected void handleFinishedGoingToSleep(int arg1) { - checkIsHandlerThread(); + Assert.isMainThread(); mGoingToSleep = false; for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1361,7 +1362,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleScreenTurnedOn() { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1373,7 +1374,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private void handleScreenTurnedOff() { final String tag = "KeyguardUpdateMonitor#handleScreenTurnedOff"; DejankUtils.startDetectingBlockingIpcs(tag); - checkIsHandlerThread(); + Assert.isMainThread(); mHardwareFingerprintUnavailableRetryCount = 0; mHardwareFaceUnavailableRetryCount = 0; for (int i = 0; i < mCallbacks.size(); i++) { @@ -1386,7 +1387,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleDreamingStateChanged(int dreamStart) { - checkIsHandlerThread(); + Assert.isMainThread(); mIsDreaming = dreamStart == 1; for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -1398,7 +1399,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleUserInfoChanged(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -1408,7 +1409,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleUserUnlocked(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); mUserIsUnlocked.put(userId, true); mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition(); for (int i = 0; i < mCallbacks.size(); i++) { @@ -1420,20 +1421,22 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void handleUserStopped(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); mUserIsUnlocked.put(userId, mUserManager.isUserUnlocked(userId)); } @VisibleForTesting void handleUserRemoved(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); mUserIsUnlocked.delete(userId); mUserTrustIsUsuallyManaged.delete(userId); } @VisibleForTesting @Inject - protected KeyguardUpdateMonitor(Context context, @Main Looper mainLooper, + protected KeyguardUpdateMonitor( + Context context, + @Main Looper mainLooper, BroadcastDispatcher broadcastDispatcher, DumpController dumpController) { mContext = context; @@ -1962,7 +1965,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @param hasLockscreenWallpaper Whether Keyguard has a lockscreen wallpaper. */ public void setHasLockscreenWallpaper(boolean hasLockscreenWallpaper) { - checkIsHandlerThread(); + Assert.isMainThread(); if (hasLockscreenWallpaper != mHasLockscreenWallpaper) { mHasLockscreenWallpaper = hasLockscreenWallpaper; for (int i = 0; i < mCallbacks.size(); i++) { @@ -1985,7 +1988,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_DPM_STATE_CHANGED} */ private void handleDevicePolicyManagerStateChanged(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); updateFingerprintListeningState(); updateSecondaryLockscreenRequirement(userId); for (int i = 0; i < mCallbacks.size(); i++) { @@ -2000,7 +2003,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_USER_SWITCHING} */ private void handleUserSwitching(int userId, IRemoteCallback reply) { - checkIsHandlerThread(); + Assert.isMainThread(); mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -2018,7 +2021,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_USER_SWITCH_COMPLETE} */ private void handleUserSwitchComplete(int userId) { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -2031,7 +2034,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_DEVICE_PROVISIONED} */ private void handleDeviceProvisioned() { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -2049,7 +2052,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_PHONE_STATE_CHANGED} */ private void handlePhoneStateChanged(String newState) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) Log.d(TAG, "handlePhoneStateChanged(" + newState + ")"); if (TelephonyManager.EXTRA_STATE_IDLE.equals(newState)) { mPhoneState = TelephonyManager.CALL_STATE_IDLE; @@ -2070,7 +2073,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_RINGER_MODE_CHANGED} */ private void handleRingerModeChange(int mode) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) Log.d(TAG, "handleRingerModeChange(" + mode + ")"); mRingMode = mode; for (int i = 0; i < mCallbacks.size(); i++) { @@ -2085,7 +2088,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_TIME_UPDATE} */ private void handleTimeUpdate() { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) Log.d(TAG, "handleTimeUpdate"); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -2099,7 +2102,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle (@line #MSG_TIMEZONE_UPDATE} */ private void handleTimeZoneUpdate(String timeZone) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) Log.d(TAG, "handleTimeZoneUpdate"); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); @@ -2115,7 +2118,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_BATTERY_UPDATE} */ private void handleBatteryUpdate(BatteryStatus status) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) Log.d(TAG, "handleBatteryUpdate"); final boolean batteryUpdateInteresting = isBatteryUpdateInteresting(mBatteryStatus, status); mBatteryStatus = status; @@ -2134,7 +2137,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab */ @VisibleForTesting void updateTelephonyCapable(boolean capable) { - checkIsHandlerThread(); + Assert.isMainThread(); if (capable == mTelephonyCapable) { return; } @@ -2152,7 +2155,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab */ @VisibleForTesting void handleSimStateChange(int subId, int slotId, int state) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG_SIM_STATES) { Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId=" + slotId + ", state=" + state + ")"); @@ -2236,7 +2239,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * <p>Needs to be called from the main thread. */ public void onKeyguardVisibilityChanged(boolean showing) { - checkIsHandlerThread(); + Assert.isMainThread(); Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")"); mKeyguardIsVisible = showing; @@ -2279,7 +2282,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @see #sendKeyguardBouncerChanged(boolean) */ private void handleKeyguardBouncerChanged(int bouncer) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) Log.d(TAG, "handleKeyguardBouncerChanged(" + bouncer + ")"); boolean isBouncer = (bouncer == 1); mBouncer = isBouncer; @@ -2305,7 +2308,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * Handle {@link #MSG_REPORT_EMERGENCY_CALL_ACTION} */ private void handleReportEmergencyCallAction() { - checkIsHandlerThread(); + Assert.isMainThread(); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); if (cb != null) { @@ -2344,7 +2347,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @param callback The callback to remove */ public void removeCallback(KeyguardUpdateMonitorCallback callback) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) { Log.v(TAG, "*** unregister callback for " + callback); } @@ -2359,7 +2362,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab * @param callback The callback to register */ public void registerCallback(KeyguardUpdateMonitorCallback callback) { - checkIsHandlerThread(); + Assert.isMainThread(); if (DEBUG) Log.v(TAG, "*** register callback for " + callback); // Prevent adding duplicate callbacks @@ -2448,7 +2451,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (!bypassHandler) { mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget(); } else { - checkIsHandlerThread(); + Assert.isMainThread(); handleReportEmergencyCallAction(); } } @@ -2466,7 +2469,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } public void clearBiometricRecognized() { - checkIsHandlerThread(); + Assert.isMainThread(); mUserFingerprintAuthenticated.clear(); mUserFaceAuthenticated.clear(); mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT); @@ -2653,7 +2656,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } private void updateLogoutEnabled() { - checkIsHandlerThread(); + Assert.isMainThread(); boolean logoutEnabled = mDevicePolicyManager.isLogoutEnabled(); if (mLogoutEnabled != logoutEnabled) { mLogoutEnabled = logoutEnabled; @@ -2667,13 +2670,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } } - private void checkIsHandlerThread() { - if (!mHandler.getLooper().isCurrentThread()) { - Log.wtfStack(TAG, "must call on mHandler's thread " - + mHandler.getLooper().getThread() + ", not " + Thread.currentThread()); - } - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("KeyguardUpdateMonitor state:"); diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 27fe37ef4e69..d317b7ebd8e7 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -48,7 +48,6 @@ import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; -import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.PluginDependencyProvider; import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -315,7 +314,6 @@ public class Dependency { @Inject Lazy<DockManager> mDockManager; @Inject Lazy<ChannelEditorDialogController> mChannelEditorDialogController; @Inject Lazy<INotificationManager> mINotificationManager; - @Inject Lazy<FalsingManager> mFalsingManager; @Inject Lazy<SysUiState> mSysUiStateFlagsContainer; @Inject Lazy<AlarmManager> mAlarmManager; @Inject Lazy<KeyguardSecurityModel> mKeyguardSecurityModel; @@ -509,7 +507,6 @@ public class Dependency { mProviders.put(DockManager.class, mDockManager::get); mProviders.put(ChannelEditorDialogController.class, mChannelEditorDialogController::get); mProviders.put(INotificationManager.class, mINotificationManager::get); - mProviders.put(FalsingManager.class, mFalsingManager::get); mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get); mProviders.put(AlarmManager.class, mAlarmManager::get); mProviders.put(KeyguardSecurityModel.class, mKeyguardSecurityModel::get); diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 03bc738c8ab9..4473b010cbda 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -168,12 +168,13 @@ public class ImageWallpaper extends WallpaperService { @Override public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { + if (mWorker == null) return; mWorker.getThreadHandler().post(() -> mRenderer.updateOffsets(xOffset, yOffset)); } @Override public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) { - if (!mNeedTransition) return; + if (mWorker == null || !mNeedTransition) return; final long duration = mShouldStopTransition ? 0 : animationDuration; if (DEBUG) { Log.d(TAG, "onAmbientModeChanged: inAmbient=" + inAmbientMode @@ -223,6 +224,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceCreated(SurfaceHolder holder) { mShouldStopTransition = checkIfShouldStopTransition(); + if (mWorker == null) return; mWorker.getThreadHandler().post(() -> { mEglHelper.init(holder, needSupportWideColorGamut()); mRenderer.onSurfaceCreated(); @@ -231,6 +233,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { + if (mWorker == null) return; mWorker.getThreadHandler().post(() -> { mRenderer.onSurfaceChanged(width, height); mNeedRedraw = true; @@ -239,6 +242,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onSurfaceRedrawNeeded(SurfaceHolder holder) { + if (mWorker == null) return; if (DEBUG) { Log.d(TAG, "onSurfaceRedrawNeeded: mNeedRedraw=" + mNeedRedraw); } @@ -267,7 +271,7 @@ public class ImageWallpaper extends WallpaperService { @Override public void onStatePostChange() { // When back to home, we try to release EGL, which is preserved in lock screen or aod. - if (mController.getState() == StatusBarState.SHADE) { + if (mWorker != null && mController.getState() == StatusBarState.SHADE) { mWorker.getThreadHandler().post(this::scheduleFinishRendering); } } @@ -356,10 +360,12 @@ public class ImageWallpaper extends WallpaperService { } private void cancelFinishRenderingTask() { + if (mWorker == null) return; mWorker.getThreadHandler().removeCallbacks(mFinishRenderingTask); } private void scheduleFinishRendering() { + if (mWorker == null) return; cancelFinishRenderingTask(); mWorker.getThreadHandler().postDelayed(mFinishRenderingTask, DELAY_FINISH_RENDERING); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 1f94dbd5e59a..de707b9527bb 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -94,6 +94,7 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.FloatingContentCoordinator; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -140,6 +141,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer; private final NotificationGroupManager mNotificationGroupManager; private final ShadeController mShadeController; + private final FloatingContentCoordinator mFloatingContentCoordinator; private BubbleData mBubbleData; @Nullable private BubbleStackView mStackView; @@ -284,11 +286,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi NotificationEntryManager entryManager, NotifPipeline notifPipeline, FeatureFlags featureFlags, - DumpController dumpController) { + DumpController dumpController, + FloatingContentCoordinator floatingContentCoordinator) { this(context, notificationShadeWindowController, statusBarStateController, shadeController, data, null /* synchronizer */, configurationController, interruptionStateProvider, zenModeController, notifUserManager, groupManager, entryManager, - notifPipeline, featureFlags, dumpController); + notifPipeline, featureFlags, dumpController, floatingContentCoordinator); } /** @@ -308,13 +311,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi NotificationEntryManager entryManager, NotifPipeline notifPipeline, FeatureFlags featureFlags, - DumpController dumpController) { + DumpController dumpController, + FloatingContentCoordinator floatingContentCoordinator) { dumpController.registerDumpable(TAG, this); mContext = context; mShadeController = shadeController; mNotificationInterruptionStateProvider = interruptionStateProvider; mNotifUserManager = notifUserManager; mZenModeController = zenModeController; + mFloatingContentCoordinator = floatingContentCoordinator; mZenModeController.addCallback(new ZenModeController.Callback() { @Override public void onZenChanged(int zen) { @@ -584,7 +589,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi */ private void ensureStackViewCreated() { if (mStackView == null) { - mStackView = new BubbleStackView(mContext, mBubbleData, mSurfaceSynchronizer); + mStackView = new BubbleStackView( + mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator); ViewGroup nsv = mNotificationShadeWindowController.getNotificationShadeView(); int bubbleScrimIndex = nsv.indexOfChild(nsv.findViewById(R.id.scrim_for_bubble)); int stackIndex = bubbleScrimIndex + 1; // Show stack above bubble scrim. diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 9a6295a80c1c..3d9865c05222 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -72,6 +72,7 @@ import com.android.systemui.bubbles.animation.ExpandedAnimationController; import com.android.systemui.bubbles.animation.PhysicsAnimationLayout; import com.android.systemui.bubbles.animation.StackAnimationController; import com.android.systemui.shared.system.SysUiStatsLog; +import com.android.systemui.util.FloatingContentCoordinator; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -319,7 +320,8 @@ public class BubbleStackView extends FrameLayout { private BubbleOverflow mBubbleOverflow; public BubbleStackView(Context context, BubbleData data, - @Nullable SurfaceSynchronizer synchronizer) { + @Nullable SurfaceSynchronizer synchronizer, + FloatingContentCoordinator floatingContentCoordinator) { super(context); mBubbleData = data; @@ -353,7 +355,7 @@ public class BubbleStackView extends FrameLayout { mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding); int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation); - mStackAnimationController = new StackAnimationController(); + mStackAnimationController = new StackAnimationController(floatingContentCoordinator); mExpandedAnimationController = new ExpandedAnimationController( mDisplaySize, mExpandedViewPadding, res.getConfiguration().orientation); @@ -620,16 +622,16 @@ public class BubbleStackView extends FrameLayout { mBubbleData.setExpanded(true); return true; } else if (action == R.id.action_move_top_left) { - mStackAnimationController.springStack(stackBounds.left, stackBounds.top); + mStackAnimationController.springStackAfterFling(stackBounds.left, stackBounds.top); return true; } else if (action == R.id.action_move_top_right) { - mStackAnimationController.springStack(stackBounds.right, stackBounds.top); + mStackAnimationController.springStackAfterFling(stackBounds.right, stackBounds.top); return true; } else if (action == R.id.action_move_bottom_left) { - mStackAnimationController.springStack(stackBounds.left, stackBounds.bottom); + mStackAnimationController.springStackAfterFling(stackBounds.left, stackBounds.bottom); return true; } else if (action == R.id.action_move_bottom_right) { - mStackAnimationController.springStack(stackBounds.right, stackBounds.bottom); + mStackAnimationController.springStackAfterFling(stackBounds.right, stackBounds.bottom); return true; } return false; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index 793f8b9bc05b..60c8c4e10cf0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -16,8 +16,10 @@ package com.android.systemui.bubbles.animation; +import android.annotation.NonNull; import android.content.res.Resources; import android.graphics.PointF; +import android.graphics.Rect; import android.graphics.RectF; import android.util.Log; import android.view.View; @@ -31,6 +33,8 @@ import androidx.dynamicanimation.animation.SpringAnimation; import androidx.dynamicanimation.animation.SpringForce; import com.android.systemui.R; +import com.android.systemui.util.FloatingContentCoordinator; +import com.android.systemui.util.animation.PhysicsAnimator; import com.google.android.collect.Sets; @@ -95,6 +99,12 @@ public class StackAnimationController extends */ private PointF mStackPosition = new PointF(-1, -1); + /** + * The area that Bubbles will occupy after all animations end. This is used to move other + * floating content out of the way proactively. + */ + private Rect mAnimatingToBounds = new Rect(); + /** Whether or not the stack's start position has been set. */ private boolean mStackMovedToStartPosition = false; @@ -163,11 +173,70 @@ public class StackAnimationController extends /** Height of the status bar. */ private float mStatusBarHeight; + /** FloatingContentCoordinator instance for resolving floating content conflicts. */ + private FloatingContentCoordinator mFloatingContentCoordinator; + + /** + * FloatingContent instance that returns the stack's location on the screen, and moves it when + * requested. + */ + private final FloatingContentCoordinator.FloatingContent mStackFloatingContent = + new FloatingContentCoordinator.FloatingContent() { + + private final Rect mFloatingBoundsOnScreen = new Rect(); + + @Override + public void moveToBounds(@NonNull Rect bounds) { + springStack(bounds.left, bounds.top, SpringForce.STIFFNESS_LOW); + } + + @NonNull + @Override + public Rect getAllowedFloatingBoundsRegion() { + final Rect floatingBounds = getFloatingBoundsOnScreen(); + final Rect allowableStackArea = new Rect(); + getAllowableStackPositionRegion().roundOut(allowableStackArea); + allowableStackArea.right += floatingBounds.width(); + allowableStackArea.bottom += floatingBounds.height(); + return allowableStackArea; + } + + @NonNull + @Override + public Rect getFloatingBoundsOnScreen() { + if (!mAnimatingToBounds.isEmpty()) { + return mAnimatingToBounds; + } + + if (mLayout.getChildCount() > 0) { + // Calculate the bounds using stack position + bubble size so that we don't need to + // wait for the bubble views to lay out. + mFloatingBoundsOnScreen.set( + (int) mStackPosition.x, + (int) mStackPosition.y, + (int) mStackPosition.x + mBubbleSize, + (int) mStackPosition.y + mBubbleSize + mBubblePaddingTop); + } else { + mFloatingBoundsOnScreen.setEmpty(); + } + + return mFloatingBoundsOnScreen; + } + }; + + public StackAnimationController( + FloatingContentCoordinator floatingContentCoordinator) { + mFloatingContentCoordinator = floatingContentCoordinator; + } + /** * Instantly move the first bubble to the given point, and animate the rest of the stack behind * it with the 'following' effect. */ public void moveFirstBubbleWithStackFollowing(float x, float y) { + // If we're moving the bubble around, we're not animating to any bounds. + mAnimatingToBounds.setEmpty(); + // If we manually move the bubbles with the IME open, clear the return point since we don't // want the stack to snap away from the new position. mPreImeY = Float.MIN_VALUE; @@ -204,23 +273,33 @@ public class StackAnimationController extends * Note that we need new SpringForce instances per animation despite identical configs because * SpringAnimation uses SpringForce's internal (changing) velocity while the animation runs. */ - public void springStack(float destinationX, float destinationY) { + public void springStack(float destinationX, float destinationY, float stiffness) { + notifyFloatingCoordinatorStackAnimatingTo(destinationX, destinationY); + springFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_X, new SpringForce() - .setStiffness(SPRING_AFTER_FLING_STIFFNESS) + .setStiffness(stiffness) .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO), 0 /* startXVelocity */, destinationX); springFirstBubbleWithStackFollowing(DynamicAnimation.TRANSLATION_Y, new SpringForce() - .setStiffness(SPRING_AFTER_FLING_STIFFNESS) + .setStiffness(stiffness) .setDampingRatio(SPRING_AFTER_FLING_DAMPING_RATIO), 0 /* startYVelocity */, destinationY); } /** + * Springs the stack to the specified x/y coordinates, with the stiffness used for springs after + * flings. + */ + public void springStackAfterFling(float destinationX, float destinationY) { + springStack(destinationX, destinationY, SPRING_AFTER_FLING_STIFFNESS); + } + + /** * Flings the stack starting with the given velocities, springing it to the nearest edge * afterward. * @@ -253,6 +332,13 @@ public class StackAnimationController extends final float minimumVelocityToReachEdge = (destinationRelativeX - x) * (FLING_FRICTION_X * 4.2f); + final float estimatedY = PhysicsAnimator.estimateFlingEndValue( + mStackPosition.y, velY, + new PhysicsAnimator.FlingConfig( + FLING_FRICTION_Y, stackBounds.top, stackBounds.bottom)); + + notifyFloatingCoordinatorStackAnimatingTo(destinationRelativeX, estimatedY); + // Use the touch event's velocity if it's sufficient, otherwise use the minimum velocity so // that it'll make it all the way to the side of the screen. final float startXVelocity = stackShouldFlingLeft @@ -426,14 +512,28 @@ public class StackAnimationController extends .setStiffness(SpringForce.STIFFNESS_LOW), /* startVel */ 0f, destinationY); + + notifyFloatingCoordinatorStackAnimatingTo(mStackPosition.x, destinationY); } } /** - * Returns the region within which the stack is allowed to rest. This goes slightly off the left + * Notifies the floating coordinator that we're moving, and sets {@link #mAnimatingToBounds} so + * we return these bounds from + * {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}. + */ + private void notifyFloatingCoordinatorStackAnimatingTo(float x, float y) { + final Rect floatingBounds = mStackFloatingContent.getFloatingBoundsOnScreen(); + floatingBounds.offsetTo((int) x, (int) y); + mAnimatingToBounds = floatingBounds; + mFloatingContentCoordinator.onContentMoved(mStackFloatingContent); + } + + /** + * Returns the region that the stack position must stay within. This goes slightly off the left * and right sides of the screen, below the status bar/cutout and above the navigation bar. - * While the stack is not allowed to rest outside of these bounds, it can temporarily be - * animated or dragged beyond them. + * While the stack position is not allowed to rest outside of these bounds, it can temporarily + * be animated or dragged beyond them. */ public RectF getAllowableStackPositionRegion() { final WindowInsets insets = mLayout.getRootWindowInsets(); @@ -690,6 +790,10 @@ public class StackAnimationController extends setStackPosition(mRestingStackPosition == null ? getDefaultStartPosition() : mRestingStackPosition); + + // Remove the stack from the coordinator since we don't have any bubbles and aren't + // visible. + mFloatingContentCoordinator.onContentRemoved(mStackFloatingContent); } } @@ -741,6 +845,10 @@ public class StackAnimationController extends // Animate in the top bubble now that we're visible. if (mLayout.getChildCount() > 0) { + // Add the stack to the floating content coordinator now that we have a bubble and + // are visible. + mFloatingContentCoordinator.onContentAdded(mStackFloatingContent); + animateInBubble(mLayout.getChildAt(0), 0 /* index */); } }); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java index 0337ee37bd37..f057d0b65294 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java @@ -32,6 +32,7 @@ import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.FloatingContentCoordinator; import javax.inject.Singleton; @@ -60,7 +61,8 @@ public interface BubbleModule { NotificationEntryManager entryManager, NotifPipeline notifPipeline, FeatureFlags featureFlags, - DumpController dumpController) { + DumpController dumpController, + FloatingContentCoordinator floatingContentCoordinator) { return new BubbleController( context, notificationShadeWindowController, @@ -76,6 +78,7 @@ public interface BubbleModule { entryManager, notifPipeline, featureFlags, - dumpController); + dumpController, + floatingContentCoordinator); } } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java index 3bf5ad759267..12b9be11817a 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java @@ -27,6 +27,7 @@ import com.android.systemui.SystemUIAppComponentFactory; import com.android.systemui.SystemUIFactory; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardSliceProvider; +import com.android.systemui.pip.phone.dagger.PipModule; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.util.InjectionInflationController; @@ -43,6 +44,7 @@ import dagger.Component; DefaultComponentBinder.class, DependencyProvider.class, DependencyBinder.class, + PipModule.class, SystemServicesModule.class, SystemUIFactory.ContextHolder.class, SystemUIBinder.class, diff --git a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java index 92aa02050d28..adee7f23e709 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java @@ -16,17 +16,12 @@ package com.android.systemui.pip; -import android.content.Context; import android.content.res.Configuration; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.wm.DisplayController; - import java.io.PrintWriter; + public interface BasePipManager { - void initialize(Context context, BroadcastDispatcher broadcastDispatcher, - DisplayController displayController); void showPictureInPictureMenu(); default void expandPip() {} default void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) {} diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java index cecdc9cbb4f3..599c845ba39a 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipUI.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipUI.java @@ -16,7 +16,6 @@ package com.android.systemui.pip; -import static android.content.pm.PackageManager.FEATURE_LEANBACK_ONLY; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import android.content.Context; @@ -26,9 +25,7 @@ import android.os.UserHandle; import android.os.UserManager; import com.android.systemui.SystemUI; -import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.wm.DisplayController; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -44,25 +41,20 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks { private final CommandQueue mCommandQueue; private BasePipManager mPipManager; - private final BroadcastDispatcher mBroadcastDispatcher; - private final DisplayController mDisplayController; - private boolean mSupportsPip; @Inject public PipUI(Context context, CommandQueue commandQueue, - BroadcastDispatcher broadcastDispatcher, - DisplayController displayController) { + BasePipManager pipManager) { super(context); - mBroadcastDispatcher = broadcastDispatcher; mCommandQueue = commandQueue; - mDisplayController = displayController; + mPipManager = pipManager; } @Override public void start() { PackageManager pm = mContext.getPackageManager(); - mSupportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE); - if (!mSupportsPip) { + boolean supportsPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE); + if (!supportsPip) { return; } @@ -72,11 +64,6 @@ public class PipUI extends SystemUI implements CommandQueue.Callbacks { throw new IllegalStateException("Non-primary Pip component not currently supported."); } - mPipManager = pm.hasSystemFeature(FEATURE_LEANBACK_ONLY) - ? com.android.systemui.pip.tv.PipManager.getInstance() - : com.android.systemui.pip.phone.PipManager.getInstance(); - mPipManager.initialize(mContext, mBroadcastDispatcher, mDisplayController); - mCommandQueue.addCallback(this); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 239ef3638ff6..cb94e28e3467 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -46,19 +46,22 @@ import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; +import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.wm.DisplayChangeController; import com.android.systemui.wm.DisplayController; import java.io.PrintWriter; +import javax.inject.Inject; +import javax.inject.Singleton; + /** * Manages the picture-in-picture (PIP) UI and states for Phones. */ +@Singleton public class PipManager implements BasePipManager { private static final String TAG = "PipManager"; - private static PipManager sPipController; - private Context mContext; private IActivityManager mActivityManager; private IActivityTaskManager mActivityTaskManager; @@ -225,13 +228,10 @@ public class PipManager implements BasePipManager { } } - private PipManager() {} - - /** - * Initializes {@link PipManager}. - */ - public void initialize(Context context, BroadcastDispatcher broadcastDispatcher, - DisplayController displayController) { + @Inject + public PipManager(Context context, BroadcastDispatcher broadcastDispatcher, + DisplayController displayController, + FloatingContentCoordinator floatingContentCoordinator) { mContext = context; mActivityManager = ActivityManager.getService(); mActivityTaskManager = ActivityTaskManager.getService(); @@ -249,7 +249,8 @@ public class PipManager implements BasePipManager { mMenuController = new PipMenuActivityController(context, mActivityManager, mMediaController, mInputConsumerController); mTouchHandler = new PipTouchHandler(context, mActivityManager, mActivityTaskManager, - mMenuController, mInputConsumerController, mPipBoundsHandler); + mMenuController, mInputConsumerController, mPipBoundsHandler, + floatingContentCoordinator); mAppOpsListener = new PipAppOpsListener(context, mActivityManager, mTouchHandler.getMotionHelper()); displayController.addDisplayChangingController(mRotationController); @@ -329,16 +330,6 @@ public class PipManager implements BasePipManager { mTmpDisplayInfo.rotation); } - /** - * Gets an instance of {@link PipManager}. - */ - public static PipManager getInstance() { - if (sPipController == null) { - sPipController = new PipManager(); - } - return sPipController; - } - public void dump(PrintWriter pw) { final String innerPrefix = " "; pw.println(TAG); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index 3ae627d27def..c6e28522ccbd 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -19,6 +19,7 @@ package com.android.systemui.pip.phone; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager.StackInfo; import android.app.IActivityManager; @@ -41,6 +42,7 @@ import com.android.internal.os.SomeArgs; import com.android.systemui.pip.PipSnapAlgorithm; import com.android.systemui.shared.system.WindowManagerWrapper; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.animation.FloatProperties; import com.android.systemui.util.animation.PhysicsAnimator; @@ -49,7 +51,8 @@ import java.io.PrintWriter; /** * A helper to animate and manipulate the PiP. */ -public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback { +public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Callback, + FloatingContentCoordinator.FloatingContent { private static final String TAG = "PipMotionHelper"; private static final boolean DEBUG = false; @@ -85,6 +88,12 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** PIP's current bounds on the screen. */ private final Rect mBounds = new Rect(); + /** The bounds within which PIP's top-left coordinate is allowed to move. */ + private Rect mMovementBounds = new Rect(); + + /** The region that all of PIP must stay within. */ + private Rect mFloatingAllowedArea = new Rect(); + private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider = new SfVsyncFrameCallbackProvider(); @@ -93,6 +102,12 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call */ private final Rect mAnimatedBounds = new Rect(); + /** The destination bounds to which PIP is animating. */ + private Rect mAnimatingToBounds = new Rect(); + + /** Coordinator instance for resolving conflicts with other floating content. */ + private FloatingContentCoordinator mFloatingContentCoordinator; + /** * PhysicsAnimator instance for animating {@link #mAnimatedBounds} using physics animations. */ @@ -119,9 +134,15 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call new PhysicsAnimator.SpringConfig( SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + /** SpringConfig to use for springing PIP away from conflicting floating content. */ + private final PhysicsAnimator.SpringConfig mConflictResolutionSpringConfig = + new PhysicsAnimator.SpringConfig( + SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY); + public PipMotionHelper(Context context, IActivityManager activityManager, IActivityTaskManager activityTaskManager, PipMenuActivityController menuController, - PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) { + PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils, + FloatingContentCoordinator floatingContentCoordinator) { mContext = context; mHandler = new Handler(ForegroundThread.get().getLooper(), this); mActivityManager = activityManager; @@ -129,9 +150,27 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call mMenuController = menuController; mSnapAlgorithm = snapAlgorithm; mFlingAnimationUtils = flingAnimationUtils; + mFloatingContentCoordinator = floatingContentCoordinator; onConfigurationChanged(); } + @NonNull + @Override + public Rect getFloatingBoundsOnScreen() { + return !mAnimatingToBounds.isEmpty() ? mAnimatingToBounds : mBounds; + } + + @NonNull + @Override + public Rect getAllowedFloatingBoundsRegion() { + return mFloatingAllowedArea; + } + + @Override + public void moveToBounds(@NonNull Rect bounds) { + animateToBounds(bounds, mConflictResolutionSpringConfig); + } + /** * Updates whenever the configuration changes. */ @@ -157,9 +196,24 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call } /** - * Tries to the move the pinned stack to the given {@param bounds}. + * Tries to move the pinned stack to the given {@param bounds}. */ void movePip(Rect toBounds) { + movePip(toBounds, false /* isDragging */); + } + + /** + * Tries to move the pinned stack to the given {@param bounds}. + * + * @param isDragging Whether this movement is the result of a drag touch gesture. If so, we + * won't notify the floating content coordinator of this move, since that will + * happen when the gesture ends. + */ + void movePip(Rect toBounds, boolean isDragging) { + if (!isDragging) { + mFloatingContentCoordinator.onContentMoved(this); + } + cancelAnimations(); resizePipUnchecked(toBounds); mBounds.set(toBounds); @@ -211,6 +265,18 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call }); } + /** Sets the movement bounds to use to constrain PIP position animations. */ + void setCurrentMovementBounds(Rect movementBounds) { + mMovementBounds.set(movementBounds); + rebuildFlingConfigs(); + + // The movement bounds represent the area within which we can move PIP's top-left position. + // The allowed area for all of PIP is those bounds plus PIP's width and height. + mFloatingAllowedArea.set(mMovementBounds); + mFloatingAllowedArea.right += mBounds.width(); + mFloatingAllowedArea.bottom += mBounds.height(); + } + /** * @return the PiP bounds. */ @@ -221,11 +287,11 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** * @return the closest minimized PiP bounds. */ - Rect getClosestMinimizedBounds(Rect stackBounds, Rect movementBounds) { + Rect getClosestMinimizedBounds(Rect stackBounds) { Point displaySize = new Point(); mContext.getDisplay().getRealSize(displaySize); - Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, stackBounds); - mSnapAlgorithm.applyMinimizedOffset(toBounds, movementBounds, displaySize, mStableInsets); + Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(mMovementBounds, stackBounds); + mSnapAlgorithm.applyMinimizedOffset(toBounds, mMovementBounds, displaySize, mStableInsets); return toBounds; } @@ -264,11 +330,10 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call /** * Animates the PiP to the minimized state, slightly offscreen. */ - void animateToClosestMinimizedState(Rect movementBounds, @Nullable Runnable updateAction) { - final Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds); - - prepareForBoundsAnimation(movementBounds); + void animateToClosestMinimizedState(@Nullable Runnable updateAction) { + final Rect toBounds = getClosestMinimizedBounds(mBounds); + mAnimatedBounds.set(mBounds); mAnimatedBoundsPhysicsAnimator .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig) .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig); @@ -285,10 +350,8 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call * Flings the PiP to the closest snap target. */ void flingToSnapTarget( - float velocityX, float velocityY, Rect movementBounds, Runnable updateAction, - @Nullable Runnable endAction) { - prepareForBoundsAnimation(movementBounds); - + float velocityX, float velocityY, Runnable updateAction, @Nullable Runnable endAction) { + mAnimatedBounds.set(mBounds); mAnimatedBoundsPhysicsAnimator .flingThenSpring( FloatProperties.RECT_X, velocityX, mFlingConfigX, mSpringConfig, @@ -298,21 +361,39 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call .addUpdateListener((target, values) -> updateAction.run()) .withEndActions(endAction); + final float xEndValue = velocityX < 0 ? mMovementBounds.left : mMovementBounds.right; + final float estimatedFlingYEndValue = + PhysicsAnimator.estimateFlingEndValue(mBounds.top, velocityY, mFlingConfigY); + + setAnimatingToBounds(new Rect( + (int) xEndValue, + (int) estimatedFlingYEndValue, + (int) xEndValue + mBounds.width(), + (int) estimatedFlingYEndValue + mBounds.height())); + startBoundsAnimation(); } /** * Animates the PiP to the closest snap target. */ - void animateToClosestSnapTarget(Rect movementBounds) { - prepareForBoundsAnimation(movementBounds); + void animateToClosestSnapTarget() { + final Rect newBounds = mSnapAlgorithm.findClosestSnapBounds(mMovementBounds, mBounds); + animateToBounds(newBounds, mSpringConfig); + } - final Rect toBounds = mSnapAlgorithm.findClosestSnapBounds(movementBounds, mBounds); + /** + * Animates PIP to the provided bounds, using physics animations and the given spring + * configuration + */ + void animateToBounds(Rect bounds, PhysicsAnimator.SpringConfig springConfig) { + mAnimatedBounds.set(mBounds); mAnimatedBoundsPhysicsAnimator - .spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig) - .spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig); - + .spring(FloatProperties.RECT_X, bounds.left, springConfig) + .spring(FloatProperties.RECT_Y, bounds.top, springConfig); startBoundsAnimation(); + + setAnimatingToBounds(bounds); } /** @@ -323,9 +404,6 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond(); final Point dismissEndPoint = getDismissEndPoint(mBounds, velocityX, velocityY, isFling); - // Set the animated bounds to start at the current bounds. We don't need to rebuild the - // fling configs here via prepareForBoundsAnimation, since animateDismiss isn't provided - // with new movement bounds. mAnimatedBounds.set(mBounds); // Animate to the dismiss end point, and then dismiss PIP. @@ -366,9 +444,11 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call currentMovementBounds); } mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction); + if (minimized) { - normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds); + normalBounds = getClosestMinimizedBounds(normalBounds); } + if (immediate) { movePip(normalBounds); } else { @@ -400,19 +480,15 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call */ private void cancelAnimations() { mAnimatedBoundsPhysicsAnimator.cancel(); + mAnimatingToBounds.setEmpty(); } - /** - * Set new fling configs whose min/max values respect the given movement bounds, and set the - * animated bounds to PIP's current 'real' bounds. - */ - private void prepareForBoundsAnimation(Rect movementBounds) { + /** Set new fling configs whose min/max values respect the given movement bounds. */ + private void rebuildFlingConfigs() { mFlingConfigX = new PhysicsAnimator.FlingConfig( - DEFAULT_FRICTION, movementBounds.left, movementBounds.right); + DEFAULT_FRICTION, mMovementBounds.left, mMovementBounds.right); mFlingConfigY = new PhysicsAnimator.FlingConfig( - DEFAULT_FRICTION, movementBounds.top, movementBounds.bottom); - - mAnimatedBounds.set(mBounds); + DEFAULT_FRICTION, mMovementBounds.top, mMovementBounds.bottom); } /** @@ -432,6 +508,16 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call } /** + * Notifies the floating coordinator that we're moving, and sets {@link #mAnimatingToBounds} so + * we return these bounds from + * {@link FloatingContentCoordinator.FloatingContent#getFloatingBoundsOnScreen()}. + */ + private void setAnimatingToBounds(Rect bounds) { + mAnimatingToBounds = bounds; + mFloatingContentCoordinator.onContentMoved(this); + } + + /** * Directly resizes the PiP to the given {@param bounds}. */ private void resizePipUnchecked(Rect toBounds) { @@ -459,6 +545,7 @@ public class PipMotionHelper implements Handler.Callback, PipAppOpsListener.Call args.arg1 = toBounds; args.argi1 = duration; mHandler.sendMessage(mHandler.obtainMessage(MSG_RESIZE_ANIMATE, args)); + setAnimatingToBounds(toBounds); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 924edb6fe312..8e588e67861c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -47,6 +47,7 @@ import com.android.systemui.pip.PipBoundsHandler; import com.android.systemui.pip.PipSnapAlgorithm; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.statusbar.FlingAnimationUtils; +import com.android.systemui.util.FloatingContentCoordinator; import java.io.PrintWriter; @@ -127,6 +128,7 @@ public class PipTouchHandler { // Touch state private final PipTouchState mTouchState; private final FlingAnimationUtils mFlingAnimationUtils; + private final FloatingContentCoordinator mFloatingContentCoordinator; private final PipMotionHelper mMotionHelper; private PipTouchGesture mGesture; @@ -152,7 +154,7 @@ public class PipTouchHandler { @Override public void onPipMinimize() { setMinimizedStateInternal(true); - mMotionHelper.animateToClosestMinimizedState(mMovementBounds, null /* updateAction */); + mMotionHelper.animateToClosestMinimizedState(null /* updateAction */); } @Override @@ -172,7 +174,8 @@ public class PipTouchHandler { public PipTouchHandler(Context context, IActivityManager activityManager, IActivityTaskManager activityTaskManager, PipMenuActivityController menuController, InputConsumerController inputConsumerController, - PipBoundsHandler pipBoundsHandler) { + PipBoundsHandler pipBoundsHandler, + FloatingContentCoordinator floatingContentCoordinator) { // Initialize the Pip input consumer mContext = context; @@ -188,7 +191,7 @@ public class PipTouchHandler { 2.5f); mGesture = new DefaultPipTouchGesture(); mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mActivityTaskManager, - mMenuController, mSnapAlgorithm, mFlingAnimationUtils); + mMenuController, mSnapAlgorithm, mFlingAnimationUtils, floatingContentCoordinator); mPipResizeGestureHandler = new PipResizeGestureHandler(context, pipBoundsHandler, this, mMotionHelper); mTouchState = new PipTouchState(mViewConfig, mHandler, @@ -207,6 +210,7 @@ public class PipTouchHandler { inputConsumerController.setRegistrationListener(this::onRegistrationChanged); mPipBoundsHandler = pipBoundsHandler; + mFloatingContentCoordinator = floatingContentCoordinator; mConnection = new PipAccessibilityInteractionConnection(mMotionHelper, this::onAccessibilityShowMenu, mHandler); } @@ -228,15 +232,18 @@ public class PipTouchHandler { } public void onActivityPinned() { - cleanUp(); + cleanUpDismissTarget(); mShowPipMenuOnAnimationEnd = true; mPipResizeGestureHandler.onActivityPinned(); + mFloatingContentCoordinator.onContentAdded(mMotionHelper); } public void onActivityUnpinned(ComponentName topPipActivity) { if (topPipActivity == null) { // Clean up state after the last PiP activity is removed - cleanUp(); + cleanUpDismissTarget(); + + mFloatingContentCoordinator.onContentRemoved(mMotionHelper); } mPipResizeGestureHandler.onActivityUnpinned(); } @@ -501,8 +508,7 @@ public class PipTouchHandler { if (fromController) { if (isMinimized) { // Move the PiP to the new bounds immediately if minimized - mMotionHelper.movePip(mMotionHelper.getClosestMinimizedBounds(mNormalBounds, - mMovementBounds)); + mMotionHelper.movePip(mMotionHelper.getClosestMinimizedBounds(mNormalBounds)); } } else if (mPinnedStackController != null) { try { @@ -654,7 +660,7 @@ public class PipTouchHandler { mTmpBounds.set(mMotionHelper.getBounds()); mTmpBounds.offsetTo((int) left, (int) top); - mMotionHelper.movePip(mTmpBounds); + mMotionHelper.movePip(mTmpBounds, true /* isDragging */); if (mEnableDimissDragToEdge) { updateDismissFraction(); @@ -724,7 +730,6 @@ public class PipTouchHandler { mMenuController.hideMenu(); } else { mMotionHelper.animateToClosestMinimizedState( - mMovementBounds, PipTouchHandler.this::updateDismissFraction /* updateAction */); } return true; @@ -748,16 +753,15 @@ public class PipTouchHandler { } if (isFling) { - mMotionHelper.flingToSnapTarget( - vel.x, vel.y, mMovementBounds, + mMotionHelper.flingToSnapTarget(vel.x, vel.y, PipTouchHandler.this::updateDismissFraction /* updateAction */, endAction /* endAction */); } else { - mMotionHelper.animateToClosestSnapTarget(mMovementBounds); + mMotionHelper.animateToClosestSnapTarget(); } } else if (mIsMinimized) { // This was a tap, so no longer minimized - mMotionHelper.animateToClosestSnapTarget(mMovementBounds); + mMotionHelper.animateToClosestSnapTarget(); setMinimizedStateInternal(false); } else if (mTouchState.isDoubleTap()) { // Expand to fullscreen if this is a double tap @@ -789,6 +793,7 @@ public class PipTouchHandler { : mNormalMovementBounds; mPipBoundsHandler.setMinEdgeSize( isMenuExpanded ? mExpandedShortestEdgeSize : 0); + mMotionHelper.setCurrentMovementBounds(mMovementBounds); } /** @@ -800,16 +805,6 @@ public class PipTouchHandler { } /** - * Resets some states related to the touch handling. - */ - private void cleanUp() { - if (mIsMinimized) { - setMinimizedStateInternal(false); - } - cleanUpDismissTarget(); - } - - /** * @return whether the menu will resize as a part of showing the full menu. */ private boolean willResizeMenu() { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java new file mode 100644 index 000000000000..c8b6982a2eba --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/dagger/PipModule.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.pip.phone.dagger; + +import com.android.systemui.pip.BasePipManager; +import com.android.systemui.pip.phone.PipManager; + +import dagger.Binds; +import dagger.Module; + +/** + * Dagger Module for Phone PIP. + */ +@Module +public abstract class PipModule { + + /** Binds PipManager as the default BasePipManager. */ + @Binds + public abstract BasePipManager providePipManager(PipManager pipManager); +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java index a40b72b30f22..9c175bc2b756 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsView.java @@ -16,286 +16,38 @@ package com.android.systemui.pip.tv; -import android.app.PendingIntent.CanceledException; -import android.app.RemoteAction; import android.content.Context; -import android.graphics.Color; -import android.media.session.MediaController; -import android.media.session.PlaybackState; -import android.os.Handler; import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; -import android.view.View; import android.widget.LinearLayout; import com.android.systemui.R; -import java.util.ArrayList; -import java.util.List; - /** * A view containing PIP controls including fullscreen, close, and media controls. */ public class PipControlsView extends LinearLayout { - private static final String TAG = PipControlsView.class.getSimpleName(); - - private static final float DISABLED_ACTION_ALPHA = 0.54f; - - /** - * An interface to listen user action. - */ - public abstract static interface Listener { - /** - * Called when an user clicks close PIP button. - */ - public abstract void onClosed(); - }; - - private MediaController mMediaController; - - private final PipManager mPipManager = PipManager.getInstance(); - private final LayoutInflater mLayoutInflater; - private final Handler mHandler; - private Listener mListener; - - private PipControlButtonView mFullButtonView; - private PipControlButtonView mCloseButtonView; - private PipControlButtonView mPlayPauseButtonView; - private ArrayList<PipControlButtonView> mCustomButtonViews = new ArrayList<>(); - private List<RemoteAction> mCustomActions = new ArrayList<>(); - - private PipControlButtonView mFocusedChild; - - private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { - @Override - public void onPlaybackStateChanged(PlaybackState state) { - updateUserActions(); - } - }; - - private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() { - @Override - public void onMediaControllerChanged() { - updateMediaController(); - } - }; - - private final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() { - @Override - public void onFocusChange(View view, boolean hasFocus) { - if (hasFocus) { - mFocusedChild = (PipControlButtonView) view; - } else if (mFocusedChild == view) { - mFocusedChild = null; - } - } - }; - - public PipControlsView(Context context) { - this(context, null, 0, 0); - } - - public PipControlsView(Context context, AttributeSet attrs) { - this(context, attrs, 0, 0); - } - - public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - public PipControlsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mLayoutInflater = (LayoutInflater) getContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mLayoutInflater.inflate(R.layout.tv_pip_controls, this); - mHandler = new Handler(); - + LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + layoutInflater.inflate(R.layout.tv_pip_controls, this); setOrientation(LinearLayout.HORIZONTAL); setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); } - @Override - public void onFinishInflate() { - super.onFinishInflate(); - - mFullButtonView = findViewById(R.id.full_button); - mFullButtonView.setOnFocusChangeListener(mFocusChangeListener); - mFullButtonView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mPipManager.movePipToFullscreen(); - } - }); - - mCloseButtonView = findViewById(R.id.close_button); - mCloseButtonView.setOnFocusChangeListener(mFocusChangeListener); - mCloseButtonView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - mPipManager.closePip(); - if (mListener != null) { - mListener.onClosed(); - } - } - }); - - mPlayPauseButtonView = findViewById(R.id.play_pause_button); - mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener); - mPlayPauseButtonView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (mMediaController == null || mMediaController.getPlaybackState() == null) { - return; - } - long actions = mMediaController.getPlaybackState().getActions(); - int state = mMediaController.getPlaybackState().getState(); - if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PAUSED) { - mMediaController.getTransportControls().play(); - } else if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PLAYING) { - mMediaController.getTransportControls().pause(); - } - // View will be updated later in {@link mMediaControllerCallback} - } - }); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - updateMediaController(); - mPipManager.addMediaListener(mPipMediaListener); - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mPipManager.removeMediaListener(mPipMediaListener); - if (mMediaController != null) { - mMediaController.unregisterCallback(mMediaControllerCallback); - } - } - - private void updateMediaController() { - MediaController newController = mPipManager.getMediaController(); - if (mMediaController == newController) { - return; - } - if (mMediaController != null) { - mMediaController.unregisterCallback(mMediaControllerCallback); - } - mMediaController = newController; - if (mMediaController != null) { - mMediaController.registerCallback(mMediaControllerCallback); - } - updateUserActions(); - } - - /** - * Updates the actions for the PIP. If there are no custom actions, then the media session - * actions are shown. - */ - private void updateUserActions() { - if (!mCustomActions.isEmpty()) { - // Ensure we have as many buttons as actions - while (mCustomButtonViews.size() < mCustomActions.size()) { - PipControlButtonView buttonView = (PipControlButtonView) mLayoutInflater.inflate( - R.layout.tv_pip_custom_control, this, false); - addView(buttonView); - mCustomButtonViews.add(buttonView); - } - - // Update the visibility of all views - for (int i = 0; i < mCustomButtonViews.size(); i++) { - mCustomButtonViews.get(i).setVisibility(i < mCustomActions.size() - ? View.VISIBLE - : View.GONE); - } - - // Update the state and visibility of the action buttons, and hide the rest - for (int i = 0; i < mCustomActions.size(); i++) { - final RemoteAction action = mCustomActions.get(i); - PipControlButtonView actionView = mCustomButtonViews.get(i); - - // TODO: Check if the action drawable has changed before we reload it - action.getIcon().loadDrawableAsync(getContext(), d -> { - d.setTint(Color.WHITE); - actionView.setImageDrawable(d); - }, mHandler); - actionView.setText(action.getContentDescription()); - if (action.isEnabled()) { - actionView.setOnClickListener(v -> { - try { - action.getActionIntent().send(); - } catch (CanceledException e) { - Log.w(TAG, "Failed to send action", e); - } - }); - } - actionView.setEnabled(action.isEnabled()); - actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA); - } - - // Hide the media session buttons - mPlayPauseButtonView.setVisibility(View.GONE); - } else { - int state = mPipManager.getPlaybackState(); - if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) { - mPlayPauseButtonView.setVisibility(View.GONE); - } else { - mPlayPauseButtonView.setVisibility(View.VISIBLE); - if (state == PipManager.PLAYBACK_STATE_PLAYING) { - mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white); - mPlayPauseButtonView.setText(R.string.pip_pause); - } else { - mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white); - mPlayPauseButtonView.setText(R.string.pip_play); - } - } - - // Hide all the custom action buttons - for (int i = 0; i < mCustomButtonViews.size(); i++) { - mCustomButtonViews.get(i).setVisibility(View.GONE); - } - } - } - - /** - * Resets to initial state. - */ - public void reset() { - mFullButtonView.reset(); - mCloseButtonView.reset(); - mPlayPauseButtonView.reset(); - mFullButtonView.requestFocus(); - for (int i = 0; i < mCustomButtonViews.size(); i++) { - mCustomButtonViews.get(i).reset(); - } - } - - /** - * Sets the {@link Listener} to listen user actions. - */ - public void setListener(Listener listener) { - mListener = listener; + PipControlButtonView getFullButtonView() { + return findViewById(R.id.full_button); } - /** - * Updates the set of activity-defined actions. - */ - public void setActions(List<RemoteAction> actions) { - mCustomActions.clear(); - mCustomActions.addAll(actions); - updateUserActions(); + PipControlButtonView getCloseButtonView() { + return findViewById(R.id.close_button); } - /** - * Returns the focused control button view to animate focused button. - */ - PipControlButtonView getFocusedButton() { - return mFocusedChild; + PipControlButtonView getPlayPauseButtonView() { + return findViewById(R.id.play_pause_button); } } diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java new file mode 100644 index 000000000000..1fe531b372c6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipControlsViewController.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.pip.tv; + +import android.app.PendingIntent; +import android.app.RemoteAction; +import android.graphics.Color; +import android.media.session.MediaController; +import android.media.session.PlaybackState; +import android.os.Handler; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Main; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +/** + * Controller for {@link PipControlsView}. + */ +public class PipControlsViewController { + private static final String TAG = PipControlsViewController.class.getSimpleName(); + + private static final float DISABLED_ACTION_ALPHA = 0.54f; + + private final PipControlsView mView; + private final PipManager mPipManager; + private final LayoutInflater mLayoutInflater; + private final Handler mHandler; + private final PipControlButtonView mPlayPauseButtonView; + private MediaController mMediaController; + private PipControlButtonView mFocusedChild; + private Listener mListener; + private ArrayList<PipControlButtonView> mCustomButtonViews = new ArrayList<>(); + private List<RemoteAction> mCustomActions = new ArrayList<>(); + + public PipControlsView getView() { + return mView; + } + + /** + * An interface to listen user action. + */ + public interface Listener { + /** + * Called when a user clicks close PIP button. + */ + void onClosed(); + } + + private View.OnAttachStateChangeListener + mOnAttachStateChangeListener = + new View.OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View v) { + updateMediaController(); + mPipManager.addMediaListener(mPipMediaListener); + } + + @Override + public void onViewDetachedFromWindow(View v) { + mPipManager.removeMediaListener(mPipMediaListener); + } + }; + + private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { + @Override + public void onPlaybackStateChanged(PlaybackState state) { + updateUserActions(); + } + }; + + private final PipManager.MediaListener mPipMediaListener = this::updateMediaController; + + private final View.OnFocusChangeListener + mFocusChangeListener = + new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View view, boolean hasFocus) { + if (hasFocus) { + mFocusedChild = (PipControlButtonView) view; + } else if (mFocusedChild == view) { + mFocusedChild = null; + } + } + }; + + + @Inject + public PipControlsViewController(PipControlsView view, PipManager pipManager, + LayoutInflater layoutInflater, @Main Handler handler) { + super(); + mView = view; + mPipManager = pipManager; + mLayoutInflater = layoutInflater; + mHandler = handler; + + mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); + if (mView.isAttachedToWindow()) { + mOnAttachStateChangeListener.onViewAttachedToWindow(mView); + } + + View fullButtonView = mView.getFullButtonView(); + fullButtonView.setOnFocusChangeListener(mFocusChangeListener); + fullButtonView.setOnClickListener(v -> mPipManager.movePipToFullscreen()); + + View closeButtonView = mView.getCloseButtonView(); + closeButtonView.setOnFocusChangeListener(mFocusChangeListener); + closeButtonView.setOnClickListener(v -> { + mPipManager.closePip(); + if (mListener != null) { + mListener.onClosed(); + } + }); + + + mPlayPauseButtonView = mView.getPlayPauseButtonView(); + mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener); + mPlayPauseButtonView.setOnClickListener(v -> { + if (mMediaController == null || mMediaController.getPlaybackState() == null) { + return; + } + if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PAUSED) { + mMediaController.getTransportControls().play(); + } else if (mPipManager.getPlaybackState() == PipManager.PLAYBACK_STATE_PLAYING) { + mMediaController.getTransportControls().pause(); + } + // View will be updated later in {@link mMediaControllerCallback} + }); + } + + private void updateMediaController() { + MediaController newController = mPipManager.getMediaController(); + if (mMediaController == newController) { + return; + } + if (mMediaController != null) { + mMediaController.unregisterCallback(mMediaControllerCallback); + } + mMediaController = newController; + if (mMediaController != null) { + mMediaController.registerCallback(mMediaControllerCallback); + } + updateUserActions(); + } + + /** + * Updates the actions for the PIP. If there are no custom actions, then the media session + * actions are shown. + */ + private void updateUserActions() { + if (!mCustomActions.isEmpty()) { + // Ensure we have as many buttons as actions + while (mCustomButtonViews.size() < mCustomActions.size()) { + PipControlButtonView buttonView = (PipControlButtonView) mLayoutInflater.inflate( + R.layout.tv_pip_custom_control, mView, false); + mView.addView(buttonView); + mCustomButtonViews.add(buttonView); + } + + // Update the visibility of all views + for (int i = 0; i < mCustomButtonViews.size(); i++) { + mCustomButtonViews.get(i).setVisibility( + i < mCustomActions.size() ? View.VISIBLE : View.GONE); + } + + // Update the state and visibility of the action buttons, and hide the rest + for (int i = 0; i < mCustomActions.size(); i++) { + final RemoteAction action = mCustomActions.get(i); + PipControlButtonView actionView = mCustomButtonViews.get(i); + + // TODO: Check if the action drawable has changed before we reload it + action.getIcon().loadDrawableAsync(mView.getContext(), d -> { + d.setTint(Color.WHITE); + actionView.setImageDrawable(d); + }, mHandler); + actionView.setText(action.getContentDescription()); + if (action.isEnabled()) { + actionView.setOnClickListener(v -> { + try { + action.getActionIntent().send(); + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, "Failed to send action", e); + } + }); + } + actionView.setEnabled(action.isEnabled()); + actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA); + } + + // Hide the media session buttons + mPlayPauseButtonView.setVisibility(View.GONE); + } else { + int state = mPipManager.getPlaybackState(); + if (state == PipManager.PLAYBACK_STATE_UNAVAILABLE) { + mPlayPauseButtonView.setVisibility(View.GONE); + } else { + mPlayPauseButtonView.setVisibility(View.VISIBLE); + if (state == PipManager.PLAYBACK_STATE_PLAYING) { + mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white); + mPlayPauseButtonView.setText(R.string.pip_pause); + } else { + mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white); + mPlayPauseButtonView.setText(R.string.pip_play); + } + } + + // Hide all the custom action buttons + for (int i = 0; i < mCustomButtonViews.size(); i++) { + mCustomButtonViews.get(i).setVisibility(View.GONE); + } + } + } + + + /** + * Sets the {@link Listener} to listen user actions. + */ + public void setListener(Listener listener) { + mListener = listener; + } + + + /** + * Updates the set of activity-defined actions. + */ + public void setActions(List<RemoteAction> actions) { + mCustomActions.clear(); + mCustomActions.addAll(actions); + updateUserActions(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 7532f9f11296..487c2533b0bb 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -55,21 +55,23 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.PinnedStackListenerForwarder.PinnedStackListener; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.WindowManagerWrapper; -import com.android.systemui.wm.DisplayController; import java.util.ArrayList; import java.util.List; +import javax.inject.Inject; +import javax.inject.Singleton; + /** * Manages the picture-in-picture (PIP) UI and states. */ +@Singleton public class PipManager implements BasePipManager { private static final String TAG = "PipManager"; static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String SETTINGS_PACKAGE_AND_CLASS_DELIMITER = "/"; - private static PipManager sPipManager; private static List<Pair<String, String>> sSettingsPackageAndClassNamePairList; /** @@ -224,13 +226,8 @@ public class PipManager implements BasePipManager { } } - private PipManager() { } - - /** - * Initializes {@link PipManager}. - */ - public void initialize(Context context, BroadcastDispatcher broadcastDispatcher, - DisplayController displayController) { + @Inject + public PipManager(Context context, BroadcastDispatcher broadcastDispatcher) { if (mInitialized) { return; } @@ -289,7 +286,7 @@ public class PipManager implements BasePipManager { Log.e(TAG, "Failed to register pinned stack listener", e); } - mPipNotification = new PipNotification(context, broadcastDispatcher); + mPipNotification = new PipNotification(context, broadcastDispatcher, this); } private void loadConfigurationsAndApply(Configuration newConfig) { @@ -739,16 +736,6 @@ public class PipManager implements BasePipManager { void onMediaControllerChanged(); } - /** - * Gets an instance of {@link PipManager}. - */ - public static PipManager getInstance() { - if (sPipManager == null) { - sPipManager = new PipManager(); - } - return sPipManager; - } - private void updatePipVisibility(final boolean visible) { Dependency.get(UiOffloadThread.class).execute(() -> { WindowManagerWrapper.getInstance().setPipVisibility(visible); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java index 3a5fa2253057..f43f8e795fe6 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipMenuActivity.java @@ -24,8 +24,12 @@ import android.content.pm.ParceledListSlice; import android.os.Bundle; import com.android.systemui.R; +import com.android.systemui.pip.tv.dagger.TvPipComponent; import java.util.Collections; + +import javax.inject.Inject; + /** * Activity to show the PIP menu to control PIP. */ @@ -34,12 +38,22 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { static final String EXTRA_CUSTOM_ACTIONS = "custom_actions"; - private final PipManager mPipManager = PipManager.getInstance(); + private final TvPipComponent.Builder mPipComponentBuilder; + private TvPipComponent mTvPipComponent; + private final PipManager mPipManager; private Animator mFadeInAnimation; private Animator mFadeOutAnimation; - private PipControlsView mPipControlsView; private boolean mRestorePipSizeWhenClose; + private PipControlsViewController mPipControlsViewController; + + + @Inject + public PipMenuActivity(TvPipComponent.Builder pipComponentBuilder, PipManager pipManager) { + super(); + mPipComponentBuilder = pipComponentBuilder; + mPipManager = pipManager; + } @Override protected void onCreate(Bundle bundle) { @@ -48,16 +62,19 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { finish(); } setContentView(R.layout.tv_pip_menu); + mTvPipComponent = mPipComponentBuilder.pipControlsView( + findViewById(R.id.pip_controls)).build(); + mPipControlsViewController = mTvPipComponent.getPipControlsViewController(); + mPipManager.addListener(this); mRestorePipSizeWhenClose = true; - mPipControlsView = findViewById(R.id.pip_controls); mFadeInAnimation = AnimatorInflater.loadAnimator( this, R.anim.tv_pip_menu_fade_in_animation); - mFadeInAnimation.setTarget(mPipControlsView); + mFadeInAnimation.setTarget(mPipControlsViewController.getView()); mFadeOutAnimation = AnimatorInflater.loadAnimator( this, R.anim.tv_pip_menu_fade_out_animation); - mFadeOutAnimation.setTarget(mPipControlsView); + mFadeOutAnimation.setTarget(mPipControlsViewController.getView()); onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS)); } @@ -114,7 +131,8 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { @Override public void onPipMenuActionsChanged(ParceledListSlice actions) { boolean hasCustomActions = actions != null && !actions.getList().isEmpty(); - mPipControlsView.setActions(hasCustomActions ? actions.getList() : Collections.EMPTY_LIST); + mPipControlsViewController.setActions( + hasCustomActions ? actions.getList() : Collections.EMPTY_LIST); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java index ca1513128e56..b01c2f4eb5fb 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java @@ -50,7 +50,7 @@ public class PipNotification { private static final String ACTION_MENU = "PipNotification.menu"; private static final String ACTION_CLOSE = "PipNotification.close"; - private final PipManager mPipManager = PipManager.getInstance(); + private final PipManager mPipManager; private final NotificationManager mNotificationManager; private final Notification.Builder mNotificationBuilder; @@ -144,7 +144,8 @@ public class PipNotification { } }; - public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher) { + public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher, + PipManager pipManager) { mNotificationManager = (NotificationManager) context.getSystemService( Context.NOTIFICATION_SERVICE); @@ -156,6 +157,7 @@ public class PipNotification { .setContentIntent(createPendingIntent(context, ACTION_MENU)) .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE))); + mPipManager = pipManager; mPipManager.addListener(mPipListener); mPipManager.addMediaListener(mPipMediaListener); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java new file mode 100644 index 000000000000..52b38a91a58f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/PipModule.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.pip.tv.dagger; + +import android.app.Activity; + +import com.android.systemui.pip.BasePipManager; +import com.android.systemui.pip.tv.PipManager; +import com.android.systemui.pip.tv.PipMenuActivity; + +import dagger.Binds; +import dagger.Module; +import dagger.multibindings.ClassKey; +import dagger.multibindings.IntoMap; + +/** + * Dagger module for TV Pip. + */ +@Module(subcomponents = {TvPipComponent.class}) +public abstract class PipModule { + + /** Binds PipManager as the default BasePipManager. */ + @Binds + public abstract BasePipManager providePipManager(PipManager pipManager); + + + /** Inject into PipMenuActivity. */ + @Binds + @IntoMap + @ClassKey(PipMenuActivity.class) + public abstract Activity providePipMenuActivity(PipMenuActivity activity); +} diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipComponent.java b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipComponent.java new file mode 100644 index 000000000000..8e8b7f37b8d6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/dagger/TvPipComponent.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.pip.tv.dagger; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.android.systemui.pip.tv.PipControlsView; +import com.android.systemui.pip.tv.PipControlsViewController; +import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import javax.inject.Scope; + +import dagger.BindsInstance; +import dagger.Subcomponent; + +/** + * Component for injecting into Pip related classes. + */ +@Subcomponent +public interface TvPipComponent { + /** + * Builder for {@link StatusBarComponent}. + */ + @Subcomponent.Builder + interface Builder { + @BindsInstance + TvPipComponent.Builder pipControlsView(PipControlsView pipControlsView); + TvPipComponent build(); + } + + /** + * Scope annotation for singleton items within the PipComponent. + */ + @Documented + @Retention(RUNTIME) + @Scope + @interface PipScope {} + + /** + * Creates a StatusBarWindowViewController. + */ + @TvPipComponent.PipScope + PipControlsViewController getPipControlsViewController(); +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java index 7d4343c9b583..6249f82ace9e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Bitmap; -import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -43,8 +42,8 @@ public class UserDetailItemView extends LinearLayout { private UserAvatarView mAvatar; private TextView mName; - private Typeface mRegularTypeface; - private Typeface mActivatedTypeface; + private int mActivatedStyle; + private int mRegularStyle; private View mRestrictedPadlock; public UserDetailItemView(Context context) { @@ -68,10 +67,10 @@ public class UserDetailItemView extends LinearLayout { final int N = a.getIndexCount(); for (int i = 0; i < N; i++) { int attr = a.getIndex(i); - if (attr == R.styleable.UserDetailItemView_regularFontFamily) { - mRegularTypeface = Typeface.create(a.getString(attr), 0 /* style */); - } else if (attr == R.styleable.UserDetailItemView_activatedFontFamily) { - mActivatedTypeface = Typeface.create(a.getString(attr), 0 /* style */); + if (attr == R.styleable.UserDetailItemView_regularTextAppearance) { + mRegularStyle = a.getResourceId(attr, 0); + } else if (attr == R.styleable.UserDetailItemView_activatedTextAppearance) { + mActivatedStyle = a.getResourceId(attr, 0); } } a.recycle(); @@ -115,13 +114,16 @@ public class UserDetailItemView extends LinearLayout { protected void onFinishInflate() { mAvatar = findViewById(R.id.user_picture); mName = findViewById(R.id.user_name); - if (mRegularTypeface == null) { - mRegularTypeface = mName.getTypeface(); + + if (mRegularStyle == 0) { + mRegularStyle = mName.getExplicitStyle(); } - if (mActivatedTypeface == null) { - mActivatedTypeface = mName.getTypeface(); + + if (mActivatedStyle == 0) { + mActivatedStyle = mName.getExplicitStyle(); } - updateTypeface(); + + updateTextStyle(); mRestrictedPadlock = findViewById(R.id.restricted_padlock); } @@ -134,12 +136,12 @@ public class UserDetailItemView extends LinearLayout { @Override protected void drawableStateChanged() { super.drawableStateChanged(); - updateTypeface(); + updateTextStyle(); } - private void updateTypeface() { + private void updateTextStyle() { boolean activated = ArrayUtils.contains(getDrawableState(), android.R.attr.state_activated); - mName.setTypeface(activated ? mActivatedTypeface : mRegularTypeface); + mName.setTextAppearance(activated ? mActivatedStyle : mRegularStyle); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 3eac229af3f6..b03ba3c2a110 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -336,6 +336,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView return false; } + boolean superPerformClick() { + return super.performClick(); + } + /** * Cancels the hotspot and makes the notification inactive. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java index 8465658079f1..2643ec975023 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java @@ -72,7 +72,8 @@ public class ActivatableNotificationViewController { } else { mView.makeInactive(true /* animate */); } - }, mView::performClick, mView::handleSlideBack, mFalsingManager::onNotificationDoubleTap); + }, mView::superPerformClick, mView::handleSlideBack, + mFalsingManager::onNotificationDoubleTap); mView.setOnTouchListener(mTouchHandler); mView.setTouchHandler(mTouchHandler); mView.setOnDimmedListener(dimmed -> { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index 923c348c2359..248e5feba703 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -513,7 +513,11 @@ public class NotificationConversationInfo extends LinearLayout implements @Override public boolean shouldBeSaved() { - return mSelectedAction > -1; + // Toggle actions are already saved by the time the guts are closed; save for any other + // taps + return mSelectedAction > -1 + && mSelectedAction != ACTION_FAVORITE + && mSelectedAction != ACTION_MUTE; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java index 264ddc026781..be30a4a4c72e 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java @@ -17,11 +17,12 @@ package com.android.systemui.tv; import com.android.systemui.dagger.SystemUIRootComponent; +import com.android.systemui.pip.tv.dagger.PipModule; import dagger.Binds; import dagger.Module; -@Module +@Module(includes = {PipModule.class}) interface TvSystemUIBinder { @Binds SystemUIRootComponent bindSystemUIRootComponent(TvSystemUIRootComponent systemUIRootComponent); diff --git a/packages/SystemUI/src/com/android/systemui/util/Assert.java b/packages/SystemUI/src/com/android/systemui/util/Assert.java index f6e921e628ba..3f05657ed09e 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Assert.java +++ b/packages/SystemUI/src/com/android/systemui/util/Assert.java @@ -24,12 +24,17 @@ import androidx.annotation.VisibleForTesting; * Helper providing common assertions. */ public class Assert { + private static final Looper sMainLooper = Looper.getMainLooper(); + private static Looper sTestLooper = null; @VisibleForTesting - public static Looper sMainLooper = Looper.getMainLooper(); + public static void setTestableLooper(Looper testLooper) { + sTestLooper = testLooper; + } public static void isMainThread() { - if (!sMainLooper.isCurrentThread()) { + if (!sMainLooper.isCurrentThread() + && (sTestLooper == null || !sTestLooper.isCurrentThread())) { throw new IllegalStateException("should be called from the main thread." + " sMainLooper.threadName=" + sMainLooper.getThread().getName() + " Thread.currentThread()=" + Thread.currentThread().getName()); @@ -37,7 +42,8 @@ public class Assert { } public static void isNotMainThread() { - if (sMainLooper.isCurrentThread()) { + if (sMainLooper.isCurrentThread() + && (sTestLooper == null || sTestLooper.isCurrentThread())) { throw new IllegalStateException("should not be called from the main thread."); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index 082782d3092a..b6ca8d8e4afb 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -37,7 +37,7 @@ public class KeyguardPresentationTest extends SysuiTestCase { @Test public void testInflation_doesntCrash() { mDependency.injectMockDependency(KeyguardUpdateMonitor.class); - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); InjectionInflationController inflationController = new InjectionInflationController( SystemUIFactory.getInstance().getRootComponent()); Context context = getContext(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java index 116f8fc7d3eb..462b0421e1ed 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java @@ -19,7 +19,6 @@ import android.graphics.Color; import android.net.Uri; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; @@ -51,7 +50,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); InjectionInflationController inflationController = new InjectionInflationController( SystemUIFactory.getInstance().getRootComponent()); LayoutInflater layoutInflater = inflationController diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java index e4b83ccc5125..bc3c3d995ce6 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java @@ -20,14 +20,12 @@ import static org.mockito.Mockito.verify; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import com.android.systemui.R; import com.android.systemui.SystemUIFactory; import com.android.systemui.SysuiTestCase; -import com.android.systemui.util.Assert; import com.android.systemui.util.InjectionInflationController; import org.junit.Before; @@ -50,7 +48,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase { @Before public void setUp() { - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); InjectionInflationController inflationController = new InjectionInflationController( SystemUIFactory.getInstance().getRootComponent()); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 7e4ba92301aa..befe3e12b64e 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -147,6 +147,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { context.addMockSystemService(SubscriptionManager.class, mSubscriptionManager); mTestableLooper = TestableLooper.get(this); + allowTestableLooperAsMainThread(); mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(context); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java index ffe8c285b4f1..471149c936e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ExpandHelperTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.when; import android.animation.ObjectAnimator; import android.content.Context; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import androidx.test.annotation.UiThreadTest; @@ -33,7 +32,6 @@ import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.statusbar.NotificationMediaManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.util.Assert; import org.junit.Before; import org.junit.Test; @@ -52,7 +50,7 @@ public class ExpandHelperTest extends SysuiTestCase { public void setUp() throws Exception { mDependency.injectMockDependency(KeyguardUpdateMonitor.class); mDependency.injectMockDependency(NotificationMediaManager.class); - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); Context context = getContext(); mRow = new NotificationTestHelper(context, mDependency).createRow(); mCallback = mock(ExpandHelper.Callback.class); diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 8d11b54dacb2..c912b678ac09 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -35,7 +35,6 @@ import android.app.Notification; import android.app.NotificationManager; import android.os.Bundle; import android.os.Handler; -import android.os.Looper; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; @@ -75,8 +74,8 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { @Before public void setUp() throws Exception { - // assume the TestLooper is the main looper for these tests - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + // allow the TestLooper to be asserted as the main thread these tests + allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler); @@ -93,7 +92,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { public void testAppOpsChangedCalledFromBgThread() { try { // WHEN onAppOpChanged is called from a different thread than the MainLooper - com.android.systemui.util.Assert.sMainLooper = Looper.getMainLooper(); + disallowTestableLooperAsMainThread(); NotificationEntry entry = createFgEntry(); mFsc.onAppOpChanged( AppOpsManager.OP_CAMERA, diff --git a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java index fc331d6adccc..689eed9e2a61 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ImageWallpaperTest.java @@ -77,7 +77,7 @@ public class ImageWallpaperTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); mEventCountdown = new CountDownLatch(1); diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index c85d600e8447..7ac5443d67d0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -25,6 +25,7 @@ import android.os.MessageQueue; import android.os.ParcelFileDescriptor; import android.testing.DexmakerShareClassLoaderRule; import android.testing.LeakCheck; +import android.testing.TestableLooper; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -32,7 +33,6 @@ import androidx.test.InstrumentationRegistry; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.FalsingManager; -import com.android.systemui.util.Assert; import org.junit.After; import org.junit.Before; @@ -86,11 +86,24 @@ public abstract class SysuiTestCase { public void SysuiTeardown() { InstrumentationRegistry.registerInstance(mRealInstrumentation, InstrumentationRegistry.getArguments()); - // Reset the assert's main looper. - Assert.sMainLooper = Looper.getMainLooper(); + // Reset the assert's testable looper to null. + disallowTestableLooperAsMainThread(); SystemUIFactory.cleanup(); } + /** + * Tests are run on the TestableLooper; however, there are parts of SystemUI that assert that + * the code is run from the main looper. Therefore, we allow the TestableLooper to pass these + * assertions since in a test, the TestableLooper is essentially the MainLooper. + */ + protected void allowTestableLooperAsMainThread() { + com.android.systemui.util.Assert.setTestableLooper(TestableLooper.get(this).getLooper()); + } + + protected void disallowTestableLooperAsMainThread() { + com.android.systemui.util.Assert.setTestableLooper(null); + } + protected LeakCheck getLeakCheck() { return null; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index fc79fcb9dc66..daea7a7a8dc9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -84,6 +84,7 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.InjectionInflationController; import org.junit.Before; @@ -129,6 +130,8 @@ public class BubbleControllerTest extends SysuiTestCase { private SysuiStatusBarStateController mStatusBarStateController; @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock + private FloatingContentCoordinator mFloatingContentCoordinator; @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor; @@ -243,7 +246,8 @@ public class BubbleControllerTest extends SysuiTestCase { mNotificationEntryManager, mNotifPipeline, mFeatureFlagsOldPipeline, - mDumpController); + mDumpController, + mFloatingContentCoordinator); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 24f8a7b52f91..b412ca5b47c4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -79,6 +79,7 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.FloatingContentCoordinator; import com.android.systemui.util.InjectionInflationController; import org.junit.Before; @@ -126,6 +127,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { private SysuiStatusBarStateController mStatusBarStateController; @Mock private KeyguardBypassController mKeyguardBypassController; + @Mock + private FloatingContentCoordinator mFloatingContentCoordinator; @Captor private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor; @@ -232,7 +235,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mNotificationEntryManager, mNotifPipeline, mFeatureFlagsNewPipeline, - mDumpController); + mDumpController, + mFloatingContentCoordinator); mBubbleController.addNotifCallback(mNotifCallback); mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener); mBubbleController.setExpandListener(mBubbleExpandListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java index 338abf59c918..f9849f46d24d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java @@ -30,6 +30,7 @@ import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ZenModeController; +import com.android.systemui.util.FloatingContentCoordinator; /** * Testable BubbleController subclass that immediately synchronizes surfaces. @@ -50,12 +51,13 @@ public class TestableBubbleController extends BubbleController { NotificationEntryManager entryManager, NotifPipeline notifPipeline, FeatureFlags featureFlags, - DumpController dumpController) { + DumpController dumpController, + FloatingContentCoordinator floatingContentCoordinator) { super(context, notificationShadeWindowController, statusBarStateController, shadeController, data, Runnable::run, configurationController, interruptionStateProvider, zenModeController, lockscreenUserManager, groupManager, entryManager, - notifPipeline, featureFlags, dumpController); + notifPipeline, featureFlags, dumpController, floatingContentCoordinator); setInflateSynchronously(true); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java index d79128ca5c78..9cc034996687 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/StackAnimationControllerTest.java @@ -18,6 +18,10 @@ package com.android.systemui.bubbles.animation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.graphics.PointF; @@ -30,13 +34,14 @@ import androidx.dynamicanimation.animation.SpringForce; import androidx.test.filters.SmallTest; import com.android.systemui.R; +import com.android.systemui.util.FloatingContentCoordinator; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.Spy; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -45,8 +50,10 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidTestingRunner.class) public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase { - @Spy - private TestableStackController mStackController = new TestableStackController(); + @Mock + private FloatingContentCoordinator mFloatingContentCoordinator; + + private TestableStackController mStackController; private int mStackOffset; private Runnable mCheckStartPosSet; @@ -54,6 +61,7 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase @Before public void setUp() throws Exception { super.setUp(); + mStackController = spy(new TestableStackController(mFloatingContentCoordinator)); mLayout.setActiveController(mStackController); addOneMoreThanBubbleLimitBubbles(); mStackOffset = mLayout.getResources().getDimensionPixelSize(R.dimen.bubble_stack_offset); @@ -288,6 +296,21 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase assertEquals(30, mStackController.getStackPosition().y, 1f); } + @Test + public void testFloatingCoordinator() { + // We should have called onContentAdded only once while adding all of the bubbles in + // setup(). + verify(mFloatingContentCoordinator, times(1)).onContentAdded(any()); + verify(mFloatingContentCoordinator, never()).onContentRemoved(any()); + + // Remove all views and verify that we called onContentRemoved only once. + while (mLayout.getChildCount() > 0) { + mLayout.removeView(mLayout.getChildAt(0)); + } + + verify(mFloatingContentCoordinator, times(1)).onContentRemoved(any()); + } + /** * Checks every child view to make sure it's stacked at the given coordinates, off to the left * or right side depending on offset multiplier. @@ -328,6 +351,11 @@ public class StackAnimationControllerTest extends PhysicsAnimationLayoutTestCase * Testable version of the stack controller that dispatches its animations on the main thread. */ private class TestableStackController extends StackAnimationController { + TestableStackController( + FloatingContentCoordinator floatingContentCoordinator) { + super(floatingContentCoordinator); + } + @Override protected void flingThenSpringFirstBubbleWithStackFollowing( DynamicAnimation.ViewProperty property, float vel, float friction, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index 60163f26bb2b..8e87e0a802ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -54,7 +54,6 @@ import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectio import com.android.systemui.statusbar.notification.stack.NotificationListContainer; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; -import com.android.systemui.util.Assert; import com.google.android.collect.Lists; @@ -90,7 +89,7 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); - Assert.sMainLooper = mTestableLooper.getLooper(); + allowTestableLooperAsMainThread(); mHandler = Handler.createAsync(mTestableLooper.getLooper()); mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java index 9d667a9a91c8..0a38f163cfba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/AboveShelfObserverTest.java @@ -21,7 +21,6 @@ import static org.mockito.Mockito.verify; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.widget.FrameLayout; @@ -46,7 +45,7 @@ public class AboveShelfObserverTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mNotificationTestHelper = new NotificationTestHelper(getContext(), mDependency); mHostLayout = new FrameLayout(getContext()); mObserver = new AboveShelfObserver(mHostLayout); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index f384067efec0..6a6e5c897318 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -98,7 +98,6 @@ import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.util.Assert; import com.android.systemui.util.leak.LeakDetector; import com.android.systemui.util.time.FakeSystemClock; @@ -205,7 +204,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { mCountDownLatch = new CountDownLatch(1); - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mDependency.injectTestDependency(Dependency.MAIN_HANDLER, Handler.createAsync(TestableLooper.get(this).getLooper())); when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java index 1116a333125e..97e0a3199e17 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java @@ -32,7 +32,6 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import androidx.test.annotation.UiThreadTest; @@ -79,7 +78,7 @@ public class NotificationFilterTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java index 12e9d31fdd0c..605b59ef3974 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java @@ -77,7 +77,6 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; -import com.android.systemui.util.Assert; import org.junit.Before; import org.junit.Test; @@ -129,7 +128,7 @@ public class NotifCollectionTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(true); when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java index 27ca18cd8033..e570ab8d7f41 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java @@ -51,7 +51,6 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener; -import com.android.systemui.util.Assert; import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; @@ -101,7 +100,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mListBuilder = new ShadeListBuilder(mSystemClock, mLogger, mock(DumpController.class)); mListBuilder.setOnRenderListListener(mOnRenderListListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java index eb1af7c82324..67b1aad94f51 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ForegroundCoordinatorTest.java @@ -44,7 +44,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; -import com.android.systemui.util.Assert; import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; @@ -84,7 +83,7 @@ public class ForegroundCoordinatorTest extends SysuiTestCase { @Before public void setup() { MockitoAnnotations.initMocks(this); - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mForegroundCoordinator = new ForegroundCoordinator( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java index a8918103c4a2..e960185ebe3a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java @@ -39,7 +39,6 @@ import static org.mockito.Mockito.when; import android.app.AppOpsManager; import android.app.NotificationChannel; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.util.ArraySet; import android.view.NotificationHeaderView; @@ -79,7 +78,7 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mNotificationTestHelper = new NotificationTestHelper(mContext, mDependency); mGroupRow = mNotificationTestHelper.createGroup(); mGroupRow.setHeadsUpAnimatingAwayListener( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java index a8c438a390ef..481bac2c19c6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java @@ -49,7 +49,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.util.Assert; import org.junit.Before; import org.junit.Test; @@ -75,7 +74,7 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase { @Before public void setUp() { - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); mDependency.injectMockDependency(BubbleController.class); when(mGutsManager.openGuts( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index bbb6723135a6..54c0bde13408 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -74,7 +74,6 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager.O import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.util.Assert; import org.junit.Before; import org.junit.Ignore; @@ -118,7 +117,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { @Before public void setUp() { mTestableLooper = TestableLooper.get(this); - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mDependency.injectTestDependency(DeviceProvisionedController.class, mDeviceProvisionedController); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java index 0790cb7ca6c4..b661b28c42fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapperTest.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.notification.row.wrapper; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.View; import android.widget.RemoteViews; @@ -43,7 +42,7 @@ public class NotificationCustomViewWrapperTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mRow = new NotificationTestHelper(mContext, mDependency).createRow(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java index 038eff7fa5dc..69e4f2205c35 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapperTest.java @@ -26,7 +26,6 @@ import android.media.MediaMetadata; import android.media.session.MediaSession; import android.media.session.PlaybackState; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.View; import android.widget.RemoteViews; @@ -64,7 +63,7 @@ public class NotificationMediaTemplateViewWrapperTest extends SysuiTestCase { @Before public void setUp() { MockitoAnnotations.initMocks(this); - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java index 9567f3386dda..830e8d93196c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapperTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.mock; import android.content.Context; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.View; import android.widget.LinearLayout; @@ -31,7 +30,6 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.util.Assert; import org.junit.Before; import org.junit.Test; @@ -48,7 +46,7 @@ public class NotificationViewWrapperTest extends SysuiTestCase { @Before public void setup() throws Exception { - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mView = mock(View.class); mRow = new NotificationTestHelper(getContext(), mDependency).createRow(); mNotificationViewWrapper = new TestableNotificationViewWrapper(mContext, mView, mRow); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java index 1773175450ff..a2029c76bb55 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.notification.stack; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.NotificationHeaderView; import android.view.View; @@ -44,7 +43,7 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mNotificationTestHelper = new NotificationTestHelper(mContext, mDependency); mGroup = mNotificationTestHelper.createGroup(); mChildrenContainer = mGroup.getChildrenContainer(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java index 2d1bc7890aed..ba2b94677814 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationRoundnessManagerTest.java @@ -24,7 +24,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import androidx.test.filters.SmallTest; @@ -66,7 +65,7 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase { mRoundnessManager = new NotificationRoundnessManager( mBypassController, new NotificationSectionsFeatureManager(new DeviceConfigProxy(), mContext)); - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); NotificationTestHelper testHelper = new NotificationTestHelper(getContext(), mDependency); mFirst = testHelper.createRow(); mFirst.setHeadsUpAnimatingAwayListener(animatingAway diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index a9e08ba79240..0cb658540f0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -144,7 +144,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { @Before @UiThreadTest public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); mOriginalInterruptionModelSetting = Settings.Secure.getInt(mContext.getContentResolver(), NOTIFICATION_NEW_INTERRUPTION_MODEL, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java index f71d0fc4b43e..a74657e561aa 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java @@ -23,7 +23,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.View; import android.widget.TextView; @@ -69,7 +68,7 @@ public class HeadsUpAppearanceControllerTest extends SysuiTestCase { @Before public void setUp() throws Exception { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); NotificationTestHelper testHelper = new NotificationTestHelper(getContext(), mDependency); mFirst = testHelper.createRow(); mDependency.injectTestDependency(DarkIconDispatcher.class, mDarkIconDispatcher); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 67b8e07f2bec..35971bd4037c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -96,7 +96,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Before public void setup() { - com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); mDependency.injectTestDependency(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor); mDependency.injectTestDependency(KeyguardSecurityModel.class, mKeyguardSecurityModel); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java index df622542e22c..86add98ab929 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java @@ -43,7 +43,6 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.phone.LightBarController; -import com.android.systemui.util.Assert; import org.junit.After; import org.junit.Before; @@ -74,7 +73,7 @@ public class RemoteInputViewTest extends SysuiTestCase { @Before public void setUp() throws Exception { - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); mDependency.injectTestDependency(RemoteInputQuickSettingsDisabler.class, diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java index 20dcbb73c212..1ff9548486ab 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java @@ -21,14 +21,12 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.animation.Animator; -import android.os.Looper; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; -import com.android.systemui.util.Assert; import org.junit.Before; import org.junit.Test; @@ -45,7 +43,7 @@ public class KeepAwakeAnimationListenerTest extends SysuiTestCase { @Before public void setup() { - Assert.sMainLooper = TestableLooper.get(this).getLooper(); + allowTestableLooperAsMainThread(); MockitoAnnotations.initMocks(this); KeepAwakeAnimationListener.sWakeLock = mWakeLock; mKeepAwakeAnimationListener = new KeepAwakeAnimationListener(getContext()); @@ -63,7 +61,10 @@ public class KeepAwakeAnimationListenerTest extends SysuiTestCase { @Test(expected = IllegalStateException.class) public void initThrows_onNonMainThread() { - Assert.sMainLooper = Looper.getMainLooper(); + disallowTestableLooperAsMainThread(); + + // we are creating the KeepAwakeAnimationListener from the TestableLooper, not the main + // looper, so we expect an IllegalStateException: new KeepAwakeAnimationListener(getContext()); } } diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index bfa962a18c9a..fd9f7137c85d 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -212,7 +212,7 @@ public class TetheringManager { new Thread(() -> { while (true) { try { - Thread.sleep(200); + Thread.sleep(CONNECTOR_POLL_INTERVAL_MILLIS); } catch (InterruptedException e) { // Not much to do here, the system needs to wait for the connector } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0f36260d1016..7083281eaa7e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4791,7 +4791,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } - return vpn.startAlwaysOnVpn(); + return vpn.startAlwaysOnVpn(mKeyStore); } } @@ -4806,7 +4806,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.w(TAG, "User " + userId + " has no Vpn configuration"); return false; } - return vpn.isAlwaysOnPackageSupported(packageName); + return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore); } } @@ -4827,11 +4827,11 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.w(TAG, "User " + userId + " has no Vpn configuration"); return false; } - if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist)) { + if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist, mKeyStore)) { return false; } if (!startAlwaysOnVpn(userId)) { - vpn.setAlwaysOnPackage(null, false, null); + vpn.setAlwaysOnPackage(null, false, null, mKeyStore); return false; } } @@ -5017,7 +5017,7 @@ public class ConnectivityService extends IConnectivityManager.Stub loge("Starting user already has a VPN"); return; } - userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId); + userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId, mKeyStore); mVpns.put(userId, userVpn); if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { updateLockdownVpn(); @@ -5088,7 +5088,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) { Slog.d(TAG, "Restarting always-on VPN package " + packageName + " for user " + userId); - vpn.startAlwaysOnVpn(); + vpn.startAlwaysOnVpn(mKeyStore); } } } @@ -5110,7 +5110,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) { Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user " + userId); - vpn.setAlwaysOnPackage(null, false, null); + vpn.setAlwaysOnPackage(null, false, null, mKeyStore); } } } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 7aa466146ddd..207a6aa5b9d0 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -194,6 +194,8 @@ public class LocationManagerService extends ILocationManager.Stub { // time private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100; + private static final String FEATURE_ID = "LocationService"; + private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest(); private final Object mLock = new Object(); @@ -243,7 +245,7 @@ public class LocationManagerService extends ILocationManager.Stub { private int mBatterySaverMode; private LocationManagerService(Context context) { - mContext = context; + mContext = context.createFeatureContext(FEATURE_ID); mHandler = FgThread.getHandler(); mLocalService = new LocalService(); @@ -1452,7 +1454,7 @@ public class LocationManagerService extends ILocationManager.Stub { } throw new SecurityException("uid " + Binder.getCallingUid() + " does not have " - + ACCESS_COARSE_LOCATION + " or " + ACCESS_FINE_LOCATION + "."); + + ACCESS_COARSE_LOCATION + " or " + ACCESS_FINE_LOCATION + "."); } private void enforceCallingOrSelfPackageName(String packageName) { @@ -1830,8 +1832,8 @@ public class LocationManagerService extends ILocationManager.Stub { // Update statistics for historical location requests by package/provider mRequestStatistics.startRequesting( - mReceiver.mCallerIdentity.mPackageName, provider, request.getInterval(), - mIsForegroundUid); + mReceiver.mCallerIdentity.mPackageName, mReceiver.mCallerIdentity.mFeatureId, + provider, request.getInterval(), mIsForegroundUid); } /** @@ -1840,7 +1842,8 @@ public class LocationManagerService extends ILocationManager.Stub { private void updateForeground(boolean isForeground) { mIsForegroundUid = isForeground; mRequestStatistics.updateForeground( - mReceiver.mCallerIdentity.mPackageName, mProvider, isForeground); + mReceiver.mCallerIdentity.mPackageName, mReceiver.mCallerIdentity.mFeatureId, + mProvider, isForeground); } /** @@ -1848,7 +1851,8 @@ public class LocationManagerService extends ILocationManager.Stub { */ private void disposeLocked(boolean removeReceiver) { String packageName = mReceiver.mCallerIdentity.mPackageName; - mRequestStatistics.stopRequesting(packageName, mProvider); + mRequestStatistics.stopRequesting(packageName, mReceiver.mCallerIdentity.mFeatureId, + mProvider); mLocationUsageLogger.logLocationApiUsage( LocationStatsEnums.USAGE_ENDED, @@ -1883,6 +1887,10 @@ public class LocationManagerService extends ILocationManager.Stub { StringBuilder b = new StringBuilder("UpdateRecord["); b.append(mProvider).append(" "); b.append(mReceiver.mCallerIdentity.mPackageName); + String featureId = mReceiver.mCallerIdentity.mFeatureId; + if (featureId != null) { + b.append(" ").append(featureId).append(" "); + } b.append("(").append(mReceiver.mCallerIdentity.mUid); if (mIsForegroundUid) { b.append(" foreground"); @@ -2886,7 +2894,7 @@ public class LocationManagerService extends ILocationManager.Stub { for (Map.Entry<PackageProviderKey, PackageStatistics> entry : sorted.entrySet()) { PackageProviderKey key = entry.getKey(); - ipw.println(key.providerName + ": " + key.packageName + ": " + entry.getValue()); + ipw.println(key.mPackageName + ": " + key.mProviderName + ": " + entry.getValue()); } ipw.decreaseIndent(); diff --git a/services/core/java/com/android/server/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java index 7f5befabc576..9082dca1022c 100644 --- a/services/core/java/com/android/server/SensorNotificationService.java +++ b/services/core/java/com/android/server/SensorNotificationService.java @@ -16,10 +16,8 @@ package com.android.server; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.hardware.GeomagneticField; import android.hardware.Sensor; import android.hardware.SensorAdditionalInfo; @@ -31,9 +29,7 @@ import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.SystemClock; -import android.os.SystemProperties; import android.os.UserHandle; -import android.provider.Settings; import android.util.Slog; public class SensorNotificationService extends SystemService @@ -52,6 +48,8 @@ public class SensorNotificationService extends SystemService private static final long MILLIS_2010_1_1 = 1262358000000l; + private static final String FEATURE_ID = "SensorNotificationService"; + private Context mContext; private SensorManager mSensorManager; private LocationManager mLocationManager; @@ -61,8 +59,8 @@ public class SensorNotificationService extends SystemService private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME; public SensorNotificationService(Context context) { - super(context); - mContext = context; + super(context.createFeatureContext(FEATURE_ID)); + mContext = getContext(); } public void onStart() { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5df3e1f9bfc6..9082807f6bbc 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -468,18 +468,9 @@ public class ActivityManagerService extends IActivityManager.Stub // How long we wait for a launched process to attach to the activity manager // before we decide it's never going to come up for real. static final int PROC_START_TIMEOUT = 10*1000; - // How long we wait for an attached process to publish its content providers - // before we decide it must be hung. - static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000; - // How long we wait to kill an application zygote, after the last process using // it has gone away. static final int KILL_APP_ZYGOTE_DELAY_MS = 5 * 1000; - /** - * How long we wait for an provider to be published. Should be longer than - * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT}. - */ - static final int CONTENT_PROVIDER_WAIT_TIMEOUT = 20 * 1000; // How long we wait for a launched process to attach to the activity manager // before we decide it's never going to come up for real, when the process was @@ -4984,7 +4975,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (providers != null && checkAppInLaunchingProvidersLocked(app)) { Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG); msg.obj = app; - mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT); + mHandler.sendMessageDelayed(msg, + ContentResolver.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS); } checkTime(startTime, "attachApplicationLocked: before bindApplication"); @@ -7273,7 +7265,8 @@ public class ActivityManagerService extends IActivityManager.Stub } // Wait for the provider to be published... - final long timeout = SystemClock.uptimeMillis() + CONTENT_PROVIDER_WAIT_TIMEOUT; + final long timeout = + SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS; boolean timedOut = false; synchronized (cpr) { while (cpr.provider == null) { @@ -7310,12 +7303,14 @@ public class ActivityManagerService extends IActivityManager.Stub } } if (timedOut) { - // Note we do it afer releasing the lock. + // Note we do it after releasing the lock. String callerName = "unknown"; - synchronized (this) { - final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller); - if (record != null) { - callerName = record.processName; + if (caller != null) { + synchronized (this) { + final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller); + if (record != null) { + callerName = record.processName; + } } } @@ -7949,6 +7944,8 @@ public class ActivityManagerService extends IActivityManager.Stub } resultCallback.sendResult(result); })); + } else { + resultCallback.sendResult(Bundle.EMPTY); } } catch (RemoteException e) { Log.w(TAG, "Content provider dead retrieving " + uri, e); diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 5e1582cf4775..a934f22ebf9a 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -2087,7 +2087,7 @@ public class AppOpsService extends IAppOpsService.Stub { } private void setUidMode(int code, int uid, int mode, - @Nullable IAppOpsCallback callbackToIgnore) { + @Nullable IAppOpsCallback permissionPolicyCallback) { if (DEBUG) { Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode) + " by uid " + Binder.getCallingUid()); @@ -2097,7 +2097,9 @@ public class AppOpsService extends IAppOpsService.Stub { verifyIncomingOp(code); code = AppOpsManager.opToSwitch(code); - updatePermissionRevokedCompat(uid, code, mode); + if (permissionPolicyCallback == null) { + updatePermissionRevokedCompat(uid, code, mode); + } synchronized (this) { final int defaultMode = AppOpsManager.opToDefaultMode(code); @@ -2135,7 +2137,7 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.evalForegroundOps(mOpModeWatchers); } - notifyOpChangedForAllPkgsInUid(code, uid, false, callbackToIgnore); + notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback); notifyOpChangedSync(code, uid, null, mode); } @@ -2337,7 +2339,7 @@ public class AppOpsService extends IAppOpsService.Stub { } private void setMode(int code, int uid, @NonNull String packageName, int mode, - @Nullable IAppOpsCallback callbackToIgnore) { + @Nullable IAppOpsCallback permissionPolicyCallback) { enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); verifyIncomingOp(code); ArraySet<ModeCallback> repCbs = null; @@ -2381,8 +2383,8 @@ public class AppOpsService extends IAppOpsService.Stub { } repCbs.addAll(cbs); } - if (repCbs != null && callbackToIgnore != null) { - repCbs.remove(mModeWatchers.get(callbackToIgnore.asBinder())); + if (repCbs != null && permissionPolicyCallback != null) { + repCbs.remove(mModeWatchers.get(permissionPolicyCallback.asBinder())); } if (mode == AppOpsManager.opToDefaultMode(op.op)) { // If going into the default mode, prune this op @@ -6036,15 +6038,15 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public void setUidModeIgnoringCallback(int code, int uid, int mode, - @Nullable IAppOpsCallback callbackToIgnore) { - setUidMode(code, uid, mode, callbackToIgnore); + public void setUidModeFromPermissionPolicy(int code, int uid, int mode, + @Nullable IAppOpsCallback callback) { + setUidMode(code, uid, mode, callback); } @Override - public void setModeIgnoringCallback(int code, int uid, @NonNull String packageName, - int mode, @Nullable IAppOpsCallback callbackToIgnore) { - setMode(code, uid, packageName, mode, callbackToIgnore); + public void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName, + int mode, @Nullable IAppOpsCallback callback) { + setMode(code, uid, packageName, mode, callback); } } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 77f4093f0a18..3138639c4a2b 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -216,14 +216,14 @@ public class Vpn { * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This * only applies to {@link VpnService} connections. */ - private boolean mAlwaysOn = false; + @VisibleForTesting protected boolean mAlwaysOn = false; /** * Whether to disable traffic outside of this VPN even when the VPN is not connected. System * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is - * not set. + * not set. Applies to all types of VPNs. */ - private boolean mLockdown = false; + @VisibleForTesting protected boolean mLockdown = false; /** * Set of packages in addition to the VPN app itself that can access the network directly when @@ -252,14 +252,14 @@ public class Vpn { private final int mUserHandle; public Vpn(Looper looper, Context context, INetworkManagementService netService, - @UserIdInt int userHandle) { - this(looper, context, netService, userHandle, + @UserIdInt int userHandle, @NonNull KeyStore keyStore) { + this(looper, context, netService, userHandle, keyStore, new SystemServices(context), new Ikev2SessionCreator()); } @VisibleForTesting protected Vpn(Looper looper, Context context, INetworkManagementService netService, - int userHandle, SystemServices systemServices, + int userHandle, @NonNull KeyStore keyStore, SystemServices systemServices, Ikev2SessionCreator ikev2SessionCreator) { mContext = context; mNetd = netService; @@ -285,7 +285,7 @@ public class Vpn { mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); updateCapabilities(null /* defaultNetwork */); - loadAlwaysOnPackage(); + loadAlwaysOnPackage(keyStore); } /** @@ -437,23 +437,36 @@ public class Vpn { /** * Checks if a VPN app supports always-on mode. * - * In order to support the always-on feature, an app has to + * <p>In order to support the always-on feature, an app has to either have an installed + * PlatformVpnProfile, or: + * * <ul> - * <li>target {@link VERSION_CODES#N API 24} or above, and - * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON} - * meta-data field. + * <li>target {@link VERSION_CODES#N API 24} or above, and + * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON} + * meta-data field. * </ul> * * @param packageName the canonical package name of the VPN app + * @param keyStore the keystore instance to use for checking if the app has a Platform VPN + * profile installed. * @return {@code true} if and only if the VPN app exists and supports always-on mode */ - public boolean isAlwaysOnPackageSupported(String packageName) { + public boolean isAlwaysOnPackageSupported(String packageName, @NonNull KeyStore keyStore) { enforceSettingsPermission(); if (packageName == null) { return false; } + final long oldId = Binder.clearCallingIdentity(); + try { + if (getVpnProfilePrivileged(packageName, keyStore) != null) { + return true; + } + } finally { + Binder.restoreCallingIdentity(oldId); + } + PackageManager pm = mContext.getPackageManager(); ApplicationInfo appInfo = null; try { @@ -485,27 +498,31 @@ public class Vpn { } /** - * Configures an always-on VPN connection through a specific application. - * This connection is automatically granted and persisted after a reboot. + * Configures an always-on VPN connection through a specific application. This connection is + * automatically granted and persisted after a reboot. * - * <p>The designated package should exist and declare a {@link VpnService} in its - * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, - * otherwise the call will fail. + * <p>The designated package should either have a PlatformVpnProfile installed, or declare a + * {@link VpnService} in its manifest guarded by {@link + * android.Manifest.permission.BIND_VPN_SERVICE}, otherwise the call will fail. * * <p>Note that this method does not check if the VPN app supports always-on mode. The check is - * delayed to {@link #startAlwaysOnVpn()}, which is always called immediately after this - * method in {@link android.net.IConnectivityManager#setAlwaysOnVpnPackage}. + * delayed to {@link #startAlwaysOnVpn()}, which is always called immediately after this method + * in {@link android.net.IConnectivityManager#setAlwaysOnVpnPackage}. * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. * @param lockdownWhitelist packages to be whitelisted from lockdown. + * @param keyStore the Keystore instance to use for checking of PlatformVpnProfile(s) * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ public synchronized boolean setAlwaysOnPackage( - String packageName, boolean lockdown, List<String> lockdownWhitelist) { + @Nullable String packageName, + boolean lockdown, + @Nullable List<String> lockdownWhitelist, + @NonNull KeyStore keyStore) { enforceControlPermissionOrInternalCaller(); - if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist)) { + if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownWhitelist, keyStore)) { saveAlwaysOnPackage(); return true; } @@ -513,20 +530,22 @@ public class Vpn { } /** - * Configures an always-on VPN connection through a specific application, the same as - * {@link #setAlwaysOnPackage}. + * Configures an always-on VPN connection through a specific application, the same as {@link + * #setAlwaysOnPackage}. * - * Does not perform permission checks. Does not persist any of the changes to storage. + * <p>Does not perform permission checks. Does not persist any of the changes to storage. * * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. * @param lockdownWhitelist packages to be whitelisted from lockdown. This is only used if - * {@code lockdown} is {@code true}. Packages must not contain commas. + * {@code lockdown} is {@code true}. Packages must not contain commas. + * @param keyStore the system keystore instance to check for profiles * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ @GuardedBy("this") private boolean setAlwaysOnPackageInternal( - String packageName, boolean lockdown, List<String> lockdownWhitelist) { + @Nullable String packageName, boolean lockdown, + @Nullable List<String> lockdownWhitelist, @NonNull KeyStore keyStore) { if (VpnConfig.LEGACY_VPN.equals(packageName)) { Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); return false; @@ -542,11 +561,18 @@ public class Vpn { } if (packageName != null) { - // TODO: Give the minimum permission possible; if there is a Platform VPN profile, only - // grant ACTIVATE_PLATFORM_VPN. - // Pre-authorize new always-on VPN package. Grant the full ACTIVATE_VPN appop, allowing - // both VpnService and Platform VPNs. - if (!setPackageAuthorization(packageName, VpnManager.TYPE_VPN_SERVICE)) { + final VpnProfile profile; + final long oldId = Binder.clearCallingIdentity(); + try { + profile = getVpnProfilePrivileged(packageName, keyStore); + } finally { + Binder.restoreCallingIdentity(oldId); + } + + // Pre-authorize new always-on VPN package. + final int grantType = + (profile == null) ? VpnManager.TYPE_VPN_SERVICE : VpnManager.TYPE_VPN_PLATFORM; + if (!setPackageAuthorization(packageName, grantType)) { return false; } mAlwaysOn = true; @@ -611,11 +637,9 @@ public class Vpn { } } - /** - * Load the always-on package and lockdown config from Settings.Secure - */ + /** Load the always-on package and lockdown config from Settings. */ @GuardedBy("this") - private void loadAlwaysOnPackage() { + private void loadAlwaysOnPackage(@NonNull KeyStore keyStore) { final long token = Binder.clearCallingIdentity(); try { final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser( @@ -626,17 +650,21 @@ public class Vpn { Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST, mUserHandle); final List<String> whitelistedPackages = TextUtils.isEmpty(whitelistString) ? Collections.emptyList() : Arrays.asList(whitelistString.split(",")); - setAlwaysOnPackageInternal(alwaysOnPackage, alwaysOnLockdown, whitelistedPackages); + setAlwaysOnPackageInternal( + alwaysOnPackage, alwaysOnLockdown, whitelistedPackages, keyStore); } finally { Binder.restoreCallingIdentity(token); } } /** + * Starts the currently selected always-on VPN + * + * @param keyStore the keyStore instance for looking up PlatformVpnProfile(s) * @return {@code true} if the service was started, the service was already connected, or there - * was no always-on VPN to start. {@code false} otherwise. + * was no always-on VPN to start. {@code false} otherwise. */ - public boolean startAlwaysOnVpn() { + public boolean startAlwaysOnVpn(@NonNull KeyStore keyStore) { final String alwaysOnPackage; synchronized (this) { alwaysOnPackage = getAlwaysOnPackage(); @@ -645,8 +673,8 @@ public class Vpn { return true; } // Remove always-on VPN if it's not supported. - if (!isAlwaysOnPackageSupported(alwaysOnPackage)) { - setAlwaysOnPackage(null, false, null); + if (!isAlwaysOnPackageSupported(alwaysOnPackage, keyStore)) { + setAlwaysOnPackage(null, false, null, keyStore); return false; } // Skip if the service is already established. This isn't bulletproof: it's not bound @@ -657,10 +685,24 @@ public class Vpn { } } - // Tell the OS that background services in this app need to be allowed for - // a short time, so we can bootstrap the VPN service. final long oldId = Binder.clearCallingIdentity(); try { + // Prefer VPN profiles, if any exist. + VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage, keyStore); + if (profile != null) { + startVpnProfilePrivileged(profile, alwaysOnPackage); + + // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was + // correctly parsed, and the VPN has started running in a different thread. The only + // other possibility is that the above call threw an exception, which will be + // caught below, and returns false (clearing the always-on VPN). Once started, the + // Platform VPN cannot permanantly fail, and is resiliant to temporary failures. It + // will continue retrying until shut down by the user, or always-on is toggled off. + return true; + } + + // Tell the OS that background services in this app need to be allowed for + // a short time, so we can bootstrap the VPN service. DeviceIdleInternal idleController = LocalServices.getService(DeviceIdleInternal.class); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, @@ -675,6 +717,9 @@ public class Vpn { Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e); return false; } + } catch (Exception e) { + Log.e(TAG, "Error starting always-on VPN", e); + return false; } finally { Binder.restoreCallingIdentity(oldId); } @@ -2820,6 +2865,10 @@ public class Vpn { return isVpnProfilePreConsented(mContext, packageName); } + private boolean isCurrentIkev2VpnLocked(@NonNull String packageName) { + return isCurrentPreparedPackage(packageName) && mVpnRunner instanceof IkeV2VpnRunner; + } + /** * Deletes an app-provisioned VPN profile. * @@ -2836,6 +2885,17 @@ public class Vpn { Binder.withCleanCallingIdentity( () -> { + // If this profile is providing the current VPN, turn it off, disabling + // always-on as well if enabled. + if (isCurrentIkev2VpnLocked(packageName)) { + if (mAlwaysOn) { + // Will transitively call prepareInternal(VpnConfig.LEGACY_VPN). + setAlwaysOnPackage(null, false, null, keyStore); + } else { + prepareInternal(VpnConfig.LEGACY_VPN); + } + } + keyStore.delete(getProfileNameForPackage(packageName), Process.SYSTEM_UID); }); } @@ -2946,11 +3006,9 @@ public class Vpn { // To stop the VPN profile, the caller must be the current prepared package and must be // running an Ikev2VpnProfile. - if (!isCurrentPreparedPackage(packageName) && mVpnRunner instanceof IkeV2VpnRunner) { - return; + if (isCurrentIkev2VpnLocked(packageName)) { + prepareInternal(VpnConfig.LEGACY_VPN); } - - prepareInternal(VpnConfig.LEGACY_VPN); } /** diff --git a/services/core/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java index 8326ef949858..b158388281d8 100644 --- a/services/core/java/com/android/server/location/CountryDetectorBase.java +++ b/services/core/java/com/android/server/location/CountryDetectorBase.java @@ -31,13 +31,15 @@ import android.os.Handler; * @hide */ public abstract class CountryDetectorBase { + private static final String FEATURE_ID = "CountryDetector"; + protected final Handler mHandler; protected final Context mContext; protected CountryListener mListener; protected Country mDetectedCountry; - public CountryDetectorBase(Context ctx) { - mContext = ctx; + public CountryDetectorBase(Context context) { + mContext = context.createFeatureContext(FEATURE_ID); mHandler = new Handler(); } @@ -45,7 +47,7 @@ public abstract class CountryDetectorBase { * Start detecting the country that the user is in. * * @return the country if it is available immediately, otherwise null should - * be returned. + * be returned. */ public abstract Country detectCountry(); diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java index b191338970e9..dcdf48ba08d2 100644 --- a/services/core/java/com/android/server/location/LocationRequestStatistics.java +++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java @@ -16,6 +16,7 @@ package com.android.server.location; +import android.annotation.Nullable; import android.os.SystemClock; import android.util.Log; import android.util.TimeUtils; @@ -25,6 +26,7 @@ import com.android.internal.util.IndentingPrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.Objects; /** * Holds statistics for location requests (active requests by provider). @@ -43,13 +45,14 @@ public class LocationRequestStatistics { /** * Signals that a package has started requesting locations. * - * @param packageName Name of package that has requested locations. + * @param packageName Name of package that has requested locations. + * @param featureId Feature id associated with the request. * @param providerName Name of provider that is requested (e.g. "gps"). - * @param intervalMs The interval that is requested in ms. + * @param intervalMs The interval that is requested in ms. */ - public void startRequesting(String packageName, String providerName, long intervalMs, - boolean isForeground) { - PackageProviderKey key = new PackageProviderKey(packageName, providerName); + public void startRequesting(String packageName, @Nullable String featureId, String providerName, + long intervalMs, boolean isForeground) { + PackageProviderKey key = new PackageProviderKey(packageName, featureId, providerName); PackageStatistics stats = statistics.get(key); if (stats == null) { stats = new PackageStatistics(); @@ -57,32 +60,36 @@ public class LocationRequestStatistics { } stats.startRequesting(intervalMs); stats.updateForeground(isForeground); - history.addRequest(packageName, providerName, intervalMs); + history.addRequest(packageName, featureId, providerName, intervalMs); } /** * Signals that a package has stopped requesting locations. * - * @param packageName Name of package that has stopped requesting locations. + * @param packageName Name of package that has stopped requesting locations. + * @param featureId Feature id associated with the request. * @param providerName Provider that is no longer being requested. */ - public void stopRequesting(String packageName, String providerName) { - PackageProviderKey key = new PackageProviderKey(packageName, providerName); + public void stopRequesting(String packageName, @Nullable String featureId, + String providerName) { + PackageProviderKey key = new PackageProviderKey(packageName, featureId, providerName); PackageStatistics stats = statistics.get(key); if (stats != null) { stats.stopRequesting(); } - history.removeRequest(packageName, providerName); + history.removeRequest(packageName, featureId, providerName); } /** * Signals that a package possibly switched background/foreground. * - * @param packageName Name of package that has stopped requesting locations. + * @param packageName Name of package that has stopped requesting locations. + * @param featureId Feature id associated with the request. * @param providerName Provider that is no longer being requested. */ - public void updateForeground(String packageName, String providerName, boolean isForeground) { - PackageProviderKey key = new PackageProviderKey(packageName, providerName); + public void updateForeground(String packageName, @Nullable String featureId, + String providerName, boolean isForeground) { + PackageProviderKey key = new PackageProviderKey(packageName, featureId, providerName); PackageStatistics stats = statistics.get(key); if (stats != null) { stats.updateForeground(isForeground); @@ -90,30 +97,37 @@ public class LocationRequestStatistics { } /** - * A key that holds both package and provider names. + * A key that holds package, feature id, and provider names. */ public static class PackageProviderKey implements Comparable<PackageProviderKey> { /** * Name of package requesting location. */ - public final String packageName; + public final String mPackageName; + /** + * Feature id associated with the request, which can be used to attribute location access to + * different parts of the application. + */ + @Nullable + public final String mFeatureId; /** * Name of provider being requested (e.g. "gps"). */ - public final String providerName; + public final String mProviderName; - PackageProviderKey(String packageName, String providerName) { - this.packageName = packageName; - this.providerName = providerName; + PackageProviderKey(String packageName, @Nullable String featureId, String providerName) { + this.mPackageName = packageName; + this.mFeatureId = featureId; + this.mProviderName = providerName; } @Override public int compareTo(PackageProviderKey other) { - final int providerCompare = providerName.compareTo(other.providerName); + final int providerCompare = mProviderName.compareTo(other.mProviderName); if (providerCompare != 0) { return providerCompare; } else { - return packageName.compareTo(other.packageName); + return mProviderName.compareTo(other.mProviderName); } } @@ -124,13 +138,18 @@ public class LocationRequestStatistics { } PackageProviderKey otherKey = (PackageProviderKey) other; - return packageName.equals(otherKey.packageName) - && providerName.equals(otherKey.providerName); + return mPackageName.equals(otherKey.mPackageName) + && mProviderName.equals(otherKey.mProviderName) + && Objects.equals(mFeatureId, otherKey.mFeatureId); } @Override public int hashCode() { - return packageName.hashCode() + 31 * providerName.hashCode(); + int hash = mPackageName.hashCode() + 31 * mProviderName.hashCode(); + if (mFeatureId != null) { + hash += mFeatureId.hashCode() + 31 * hash; + } + return hash; } } @@ -147,17 +166,18 @@ public class LocationRequestStatistics { * Append an added location request to the history */ @VisibleForTesting - void addRequest(String packageName, String providerName, long intervalMs) { - addRequestSummary(new RequestSummary(packageName, providerName, intervalMs)); + void addRequest(String packageName, @Nullable String featureId, String providerName, + long intervalMs) { + addRequestSummary(new RequestSummary(packageName, featureId, providerName, intervalMs)); } /** * Append a removed location request to the history */ @VisibleForTesting - void removeRequest(String packageName, String providerName) { + void removeRequest(String packageName, @Nullable String featureId, String providerName) { addRequestSummary(new RequestSummary( - packageName, providerName, RequestSummary.REQUEST_ENDED_INTERVAL)); + packageName, featureId, providerName, RequestSummary.REQUEST_ENDED_INTERVAL)); } private void addRequestSummary(RequestSummary summary) { @@ -193,6 +213,12 @@ public class LocationRequestStatistics { * Name of package requesting location. */ private final String mPackageName; + + /** + * Feature id associated with the request for identifying subsystem of an application. + */ + @Nullable + private final String mFeatureId; /** * Name of provider being requested (e.g. "gps"). */ @@ -211,8 +237,10 @@ public class LocationRequestStatistics { */ static final long REQUEST_ENDED_INTERVAL = -1; - RequestSummary(String packageName, String providerName, long intervalMillis) { + RequestSummary(String packageName, @Nullable String featureId, String providerName, + long intervalMillis) { this.mPackageName = packageName; + this.mFeatureId = featureId; this.mProviderName = providerName; this.mIntervalMillis = intervalMillis; this.mElapsedRealtimeMillis = SystemClock.elapsedRealtime(); @@ -225,6 +253,9 @@ public class LocationRequestStatistics { .append(mIntervalMillis == REQUEST_ENDED_INTERVAL ? "- " : "+ ") .append(String.format("%7s", mProviderName)).append(" request from ") .append(mPackageName); + if (mFeatureId != null) { + s.append(" with feature ").append(mFeatureId); + } if (mIntervalMillis != REQUEST_ENDED_INTERVAL) { s.append(" at interval ").append(mIntervalMillis / 1000).append(" seconds"); } @@ -246,14 +277,15 @@ public class LocationRequestStatistics { private long mFastestIntervalMs; // The slowest interval this package has ever requested. private long mSlowestIntervalMs; - // The total time this app has requested location (not including currently running requests). + // The total time this app has requested location (not including currently running + // requests). private long mTotalDurationMs; // Time when this package most recently went to foreground, requesting location. 0 means // not currently in foreground. private long mLastForegroundElapsedTimeMs; - // The time this app has requested location (not including currently running requests), while - // in foreground. + // The time this app has requested location (not including currently running requests), + // while in foreground. private long mForegroundDurationMs; // Time when package last went dormant (stopped requesting location) @@ -328,7 +360,7 @@ public class LocationRequestStatistics { */ public long getForegroundDurationMs() { long currentDurationMs = mForegroundDurationMs; - if (mLastForegroundElapsedTimeMs != 0 ) { + if (mLastForegroundElapsedTimeMs != 0) { currentDurationMs += SystemClock.elapsedRealtime() - mLastForegroundElapsedTimeMs; } diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java index dc61fb01a246..dbaf8241ddd5 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(rnr); } + public void deleteConversation(String pkg, String conversationId) { + RemoveConversationRunnable rcr = new RemoveConversationRunnable(pkg, conversationId); + mFileWriteHandler.post(rcr); + } + public void addNotification(final HistoricalNotification notification) { synchronized (mLock) { mBuffer.addNewNotificationToWrite(notification); @@ -396,7 +401,7 @@ public class NotificationHistoryDatabase { @Override public void run() { - if (DEBUG) Slog.d(TAG, "RemovePackageRunnable"); + if (DEBUG) Slog.d(TAG, "RemoveNotificationRunnable"); synchronized (mLock) { // Remove from pending history mBuffer.removeNotificationFromWrite(mPkg, mPostedTime); @@ -422,6 +427,49 @@ public class NotificationHistoryDatabase { } } + final class RemoveConversationRunnable implements Runnable { + private String mPkg; + private String mConversationId; + private NotificationHistory mNotificationHistory; + + public RemoveConversationRunnable(String pkg, String conversationId) { + mPkg = pkg; + mConversationId = conversationId; + } + + @VisibleForTesting + void setNotificationHistory(NotificationHistory nh) { + mNotificationHistory = nh; + } + + @Override + public void run() { + if (DEBUG) Slog.d(TAG, "RemoveConversationRunnable"); + synchronized (mLock) { + // Remove from pending history + mBuffer.removeConversationFromWrite(mPkg, mConversationId); + + 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.removeConversationFromWrite(mPkg, mConversationId)) { + writeLocked(af, notificationHistory); + } + } catch (Exception e) { + Slog.e(TAG, "Cannot clean up file on conversation removal " + + af.getBaseFile().getName(), e); + } + } + } + } + } + public static final class NotificationHistoryFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider { final static String TAG = "NotifHistoryFileDate"; diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java index 9aab0fd912e8..88e0dc6e9cc4 100644 --- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java +++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java @@ -166,6 +166,22 @@ public class NotificationHistoryManager { } } + public void deleteConversation(String pkg, int uid, String conversationId) { + 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 conversation for locked/gone/disabled user " + + userId); + return; + } + userHistory.deleteConversation(pkg, conversationId); + } + } + // TODO: wire this up to AMS when power button is long pressed public void triggerWriteToDisk() { synchronized (mLock) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 2e4a977add4e..ad4e81b4840f 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -5655,6 +5655,22 @@ public class NotificationManagerService extends SystemService { mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground)); } + public void onConversationRemoved(String pkg, int uid, String conversationId) { + checkCallerIsSystem(); + Preconditions.checkStringNotEmpty(pkg); + Preconditions.checkStringNotEmpty(conversationId); + + mHistoryManager.deleteConversation(pkg, uid, conversationId); + List<String> deletedChannelIds = + mPreferencesHelper.deleteConversation(pkg, uid, conversationId); + for (String channelId : deletedChannelIds) { + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true, + UserHandle.getUserId(uid), REASON_CHANNEL_BANNED, + null); + } + handleSavePolicyFile(); + } + @VisibleForTesting protected void fixNotification(Notification notification, String pkg, String tag, int id, int userId) throws NameNotFoundException { @@ -8896,7 +8912,9 @@ public class NotificationManagerService extends SystemService { final StatusBarNotification sbn, final boolean isVisible) { final String key = sbn.getKey(); - Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key); + if (DBG) { + Slog.d(TAG, "notifyAssistantVisibilityChangedLocked: " + key); + } notifyAssistantLocked( sbn, false /* sameUserOnly */, diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 9f8362cbc0a4..20c8625d22e4 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -1223,6 +1223,33 @@ public class PreferencesHelper implements RankingConfig { } } + public @NonNull List<String> deleteConversation(String pkg, int uid, String conversationId) { + synchronized (mPackagePreferences) { + List<String> deletedChannelIds = new ArrayList<>(); + PackagePreferences r = getPackagePreferencesLocked(pkg, uid); + if (r == null) { + return deletedChannelIds; + } + int N = r.channels.size(); + for (int i = 0; i < N; i++) { + final NotificationChannel nc = r.channels.valueAt(i); + if (conversationId.equals(nc.getConversationId())) { + nc.setDeleted(true); + LogMaker lm = getChannelLog(nc, pkg); + lm.setType( + com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE); + MetricsLogger.action(lm); + + deletedChannelIds.add(nc.getId()); + } + } + if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) { + updateChannelsBypassingDnd(mContext.getUserId()); + } + return deletedChannelIds; + } + } + @Override public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted) { diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 0fb889c8da22..a1250cb8849f 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -69,7 +69,6 @@ public class AppsFilter { // Logs all filtering instead of enforcing private static final boolean DEBUG_ALLOW_ALL = false; private static final boolean DEBUG_LOGGING = false; - private static final boolean FEATURE_ENABLED_BY_DEFAULT = true; /** * This contains a list of app UIDs that are implicitly queryable because another app explicitly @@ -135,7 +134,8 @@ public class AppsFilter { private static class FeatureConfigImpl implements FeatureConfig { private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled"; private final PackageManagerService.Injector mInjector; - private volatile boolean mFeatureEnabled = FEATURE_ENABLED_BY_DEFAULT; + private volatile boolean mFeatureEnabled = + PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT; private FeatureConfigImpl(PackageManagerService.Injector injector) { mInjector = injector; @@ -145,14 +145,14 @@ public class AppsFilter { public void onSystemReady() { mFeatureEnabled = DeviceConfig.getBoolean( NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, - FEATURE_ENABLED_BY_DEFAULT); + PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT); DeviceConfig.addOnPropertiesChangedListener( NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(), properties -> { if (properties.getKeyset().contains(FILTERING_ENABLED_NAME)) { synchronized (FeatureConfigImpl.this) { mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, - FEATURE_ENABLED_BY_DEFAULT); + PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT); } } }); diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsService.java b/services/core/java/com/android/server/pm/CrossProfileAppsService.java index 027a302a325e..486282aa2c04 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsService.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsService.java @@ -16,6 +16,7 @@ package com.android.server.pm; import android.content.Context; +import android.content.pm.CrossProfileAppsInternal; import com.android.server.SystemService; @@ -30,5 +31,6 @@ public class CrossProfileAppsService extends SystemService { @Override public void onStart() { publishBinderService(Context.CROSS_PROFILE_APPS_SERVICE, mServiceImpl); + publishLocalService(CrossProfileAppsInternal.class, mServiceImpl.getLocalService()); } } diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index 3939f2642bc8..ec9b37db3137 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -45,6 +45,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.os.Binder; +import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -66,6 +67,8 @@ import java.util.Objects; public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { private static final String TAG = "CrossProfileAppsService"; + private final LocalService mLocalService = new LocalService(); + private Context mContext; private Injector mInjector; @@ -77,8 +80,6 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { CrossProfileAppsServiceImpl(Context context, Injector injector) { mContext = context; mInjector = injector; - - LocalServices.addService(CrossProfileAppsInternal.class, new LocalService()); } @Override @@ -167,6 +168,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { launchIntent.setComponent(component); mInjector.getActivityTaskManagerInternal().startActivityAsUser( caller, callingPackage, callingFeatureId, launchIntent, + /* resultTo= */ null, + Intent.FLAG_ACTIVITY_NEW_TASK, launchMainActivity ? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle() : null, @@ -179,7 +182,8 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { String callingPackage, String callingFeatureId, Intent intent, - @UserIdInt int userId) throws RemoteException { + @UserIdInt int userId, + IBinder callingActivity) throws RemoteException { Objects.requireNonNull(callingPackage); Objects.requireNonNull(intent); Objects.requireNonNull(intent.getComponent(), "The intent must have a Component set"); @@ -205,7 +209,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { } if (callerUserId != userId) { - if (!hasInteractAcrossProfilesPermission(callingPackage)) { + if (!hasCallerGotInteractAcrossProfilesPermission(callingPackage)) { throw new SecurityException("Attempt to launch activity without required " + android.Manifest.permission.INTERACT_ACROSS_PROFILES + " permission" + " or target user is not in the same profile group."); @@ -214,8 +218,16 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { verifyActivityCanHandleIntent(launchIntent, callingUid, userId); - mInjector.getActivityTaskManagerInternal().startActivityAsUser(caller, callingPackage, - callingFeatureId, launchIntent, /* options= */ null, userId); + mInjector.getActivityTaskManagerInternal() + .startActivityAsUser( + caller, + callingPackage, + callingFeatureId, + launchIntent, + callingActivity, + /* startFlags= */ 0, + /* options= */ null, + userId); logStartActivityByIntent(callingPackage); } @@ -268,20 +280,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { if (targetUserProfiles.isEmpty()) { return false; } - return hasInteractAcrossProfilesPermission(callingPackage); + return hasCallerGotInteractAcrossProfilesPermission(callingPackage); } - private boolean hasInteractAcrossProfilesPermission(String callingPackage) { - final int callingUid = mInjector.getCallingUid(); - final int callingPid = mInjector.getCallingPid(); - return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingUid) - || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, callingUid) - || PermissionChecker.checkPermissionForPreflight( - mContext, - Manifest.permission.INTERACT_ACROSS_PROFILES, - callingPid, - callingUid, - callingPackage) == PermissionChecker.PERMISSION_GRANTED; + private boolean hasCallerGotInteractAcrossProfilesPermission(String callingPackage) { + return hasInteractAcrossProfilesPermission( + callingPackage, mInjector.getCallingUid(), mInjector.getCallingPid()); } private boolean isCrossProfilePackageWhitelisted(String packageName) { @@ -563,6 +567,10 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op)); } + CrossProfileAppsInternal getLocalService() { + return mLocalService; + } + private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) { return mInjector.withCleanCallingIdentity(() -> mInjector.getUserManager().isSameProfileGroup(callerUserId, userId)); @@ -589,6 +597,20 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { -> mContext.getSystemService(UserManager.class).isManagedProfile(userId)); } + private boolean hasInteractAcrossProfilesPermission(String packageName, int uid, int pid) { + if (isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) + || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, uid)) { + return true; + } + return PermissionChecker.PERMISSION_GRANTED + == PermissionChecker.checkPermissionForPreflight( + mContext, + Manifest.permission.INTERACT_ACROSS_PROFILES, + pid, + uid, + packageName); + } + private static class InjectorImpl implements Injector { private Context mContext; @@ -728,9 +750,11 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { } class LocalService extends CrossProfileAppsInternal { + @Override - public boolean verifyPackageHasInteractAcrossProfilePermission(String packageName, - @UserIdInt int userId) throws PackageManager.NameNotFoundException { + public boolean verifyPackageHasInteractAcrossProfilePermission( + String packageName, @UserIdInt int userId) + throws PackageManager.NameNotFoundException { final int uid = Objects.requireNonNull( mInjector.getPackageManager().getApplicationInfoAsUser( Objects.requireNonNull(packageName), /* flags= */ 0, userId)).uid; @@ -740,16 +764,13 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { @Override public boolean verifyUidHasInteractAcrossProfilePermission(String packageName, int uid) { Objects.requireNonNull(packageName); + return hasInteractAcrossProfilesPermission( + packageName, uid, PermissionChecker.PID_UNKNOWN); + } - return isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) - || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS, uid) - || isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, uid) - || PermissionChecker.checkPermissionForPreflight( - mContext, - Manifest.permission.INTERACT_ACROSS_PROFILES, - PermissionChecker.PID_UNKNOWN, - uid, - packageName) == PermissionChecker.PERMISSION_GRANTED; + @Override + public List<UserHandle> getTargetUserProfiles(String packageName, int userId) { + return getTargetUserProfilesUnchecked(packageName, userId); } } } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index f93c663c551c..3a162173a59f 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -896,7 +896,8 @@ public class LauncherAppsService extends SystemService { i.setSourceBounds(sourceBounds); mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, - callingFeatureId, i, opts, userId); + callingFeatureId, i, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK, opts, + userId); } @Override @@ -955,7 +956,8 @@ public class LauncherAppsService extends SystemService { Binder.restoreCallingIdentity(ident); } mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, - callingFeatureId, launchIntent, opts, user.getIdentifier()); + callingFeatureId, launchIntent, /* resultTo= */ null, + Intent.FLAG_ACTIVITY_NEW_TASK, opts, user.getIdentifier()); } @Override @@ -978,7 +980,8 @@ public class LauncherAppsService extends SystemService { Binder.restoreCallingIdentity(ident); } mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, - callingFeatureId, intent, opts, user.getIdentifier()); + callingFeatureId, intent, /* resultTo= */ null, Intent.FLAG_ACTIVITY_NEW_TASK, + opts, user.getIdentifier()); } /** Checks if user is a profile of or same as listeningUser. diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java index 43d45967f67b..c13cb38544c5 100644 --- a/services/core/java/com/android/server/policy/PermissionPolicyService.java +++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java @@ -683,7 +683,7 @@ public final class PermissionPolicyService extends SystemService { opCode), uid, pkgsOfUid[0]); if (currentMode != MODE_ALLOWED) { if (currentMode != MODE_IGNORED) { - mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, MODE_IGNORED, + mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, MODE_IGNORED, mAppOpsCallback); } return true; @@ -700,7 +700,7 @@ public final class PermissionPolicyService extends SystemService { final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( opCode), uid, pkgsOfUid[0]); if (oldMode != mode) { - mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, mode, + mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, mode, mAppOpsCallback); final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName( opCode), uid, pkgsOfUid[0]); @@ -708,7 +708,7 @@ public final class PermissionPolicyService extends SystemService { // Work around incorrectly-set package mode. It never makes sense for app ops // related to runtime permissions, but can get in the way and we have to reset // it. - mAppOpsManagerInternal.setModeIgnoringCallback(opCode, uid, pkgsOfUid[0], + mAppOpsManagerInternal.setModeFromPermissionPolicy(opCode, uid, pkgsOfUid[0], AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback); } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index a7b0d84ef040..8483c774cb8e 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -242,8 +242,8 @@ public final class PowerManagerService extends SystemService private final ServiceThread mHandlerThread; private final PowerManagerHandler mHandler; private final AmbientDisplayConfiguration mAmbientDisplayConfiguration; - private final BatterySaverPolicy mBatterySaverPolicy; private final BatterySaverController mBatterySaverController; + private final BatterySaverPolicy mBatterySaverPolicy; private final BatterySaverStateMachine mBatterySaverStateMachine; private final BatterySavingStats mBatterySavingStats; private final AttentionDetector mAttentionDetector; @@ -275,7 +275,8 @@ public final class PowerManagerService extends SystemService // Indicates whether the device is awake or asleep or somewhere in between. // This is distinct from the screen power state, which is managed separately. - private int mWakefulness; + // Do not access directly; always use {@link #setWakefulness} and {@link getWakefulness}. + private int mWakefulnessRaw; private boolean mWakefulnessChanging; // True if the sandman has just been summoned for the first time since entering the @@ -764,6 +765,13 @@ public final class PowerManagerService extends SystemService return new BatterySaverPolicy(lock, context, batterySavingStats); } + BatterySaverController createBatterySaverController( + Object lock, Context context, BatterySaverPolicy batterySaverPolicy, + BatterySavingStats batterySavingStats) { + return new BatterySaverController(lock, context, BackgroundThread.get().getLooper(), + batterySaverPolicy, batterySavingStats); + } + NativeWrapper createNativeWrapper() { return new NativeWrapper(); } @@ -794,6 +802,10 @@ public final class PowerManagerService extends SystemService } }; } + + void invalidateIsInteractiveCaches() { + PowerManager.invalidateIsInteractiveCaches(); + } } final Constants mConstants; @@ -833,9 +845,8 @@ public final class PowerManagerService extends SystemService mBatterySavingStats = new BatterySavingStats(mLock); mBatterySaverPolicy = mInjector.createBatterySaverPolicy(mLock, mContext, mBatterySavingStats); - mBatterySaverController = new BatterySaverController(mLock, mContext, - BackgroundThread.get().getLooper(), mBatterySaverPolicy, - mBatterySavingStats); + mBatterySaverController = mInjector.createBatterySaverController(mLock, mContext, + mBatterySaverPolicy, mBatterySavingStats); mBatterySaverStateMachine = new BatterySaverStateMachine( mLock, mContext, mBatterySaverController); @@ -939,13 +950,14 @@ public final class PowerManagerService extends SystemService mHalAutoSuspendModeEnabled = false; mHalInteractiveModeEnabled = true; - mWakefulness = WAKEFULNESS_AWAKE; + mWakefulnessRaw = WAKEFULNESS_AWAKE; sQuiescent = mSystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1"); mNativeWrapper.nativeInit(this); mNativeWrapper.nativeSetAutoSuspend(false); mNativeWrapper.nativeSetInteractive(true); mNativeWrapper.nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0); + mInjector.invalidateIsInteractiveCaches(); } } @@ -1567,8 +1579,8 @@ public final class PowerManagerService extends SystemService mOverriddenTimeout = -1; } - if (mWakefulness == WAKEFULNESS_ASLEEP - || mWakefulness == WAKEFULNESS_DOZING + if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP + || getWakefulnessLocked() == WAKEFULNESS_DOZING || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) { return false; } @@ -1624,7 +1636,7 @@ public final class PowerManagerService extends SystemService Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid); } - if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE + if (eventTime < mLastSleepTime || getWakefulnessLocked() == WAKEFULNESS_AWAKE || mForceSuspendActive || !mSystemReady) { return false; } @@ -1634,7 +1646,7 @@ public final class PowerManagerService extends SystemService Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp"); try { Slog.i(TAG, "Waking up from " - + PowerManagerInternal.wakefulnessToString(mWakefulness) + + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked()) + " (uid=" + reasonUid + ", reason=" + PowerManager.wakeReasonToString(reason) + ", details=" + details @@ -1680,8 +1692,8 @@ public final class PowerManagerService extends SystemService } if (eventTime < mLastWakeTime - || mWakefulness == WAKEFULNESS_ASLEEP - || mWakefulness == WAKEFULNESS_DOZING + || getWakefulnessLocked() == WAKEFULNESS_ASLEEP + || getWakefulnessLocked() == WAKEFULNESS_DOZING || !mSystemReady || !mBootCompleted) { return false; @@ -1738,7 +1750,7 @@ public final class PowerManagerService extends SystemService Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid); } - if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE + if (eventTime < mLastWakeTime || getWakefulnessLocked() != WAKEFULNESS_AWAKE || !mBootCompleted || !mSystemReady) { return false; } @@ -1762,7 +1774,7 @@ public final class PowerManagerService extends SystemService + ", uid=" + uid); } - if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP + if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) { return false; } @@ -1781,13 +1793,15 @@ public final class PowerManagerService extends SystemService @VisibleForTesting void setWakefulnessLocked(int wakefulness, int reason, long eventTime) { - if (mWakefulness != wakefulness) { - mWakefulness = wakefulness; + if (getWakefulnessLocked() != wakefulness) { + // Under lock, invalidate before set ensures caches won't return stale values. + mInjector.invalidateIsInteractiveCaches(); + mWakefulnessRaw = wakefulness; mWakefulnessChanging = true; mDirty |= DIRTY_WAKEFULNESS; // This is only valid while we are in wakefulness dozing. Set to false otherwise. - mDozeStartInProgress &= (mWakefulness == WAKEFULNESS_DOZING); + mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING); if (mNotifier != null) { mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime); @@ -1797,8 +1811,8 @@ public final class PowerManagerService extends SystemService } @VisibleForTesting - int getWakefulness() { - return mWakefulness; + int getWakefulnessLocked() { + return mWakefulnessRaw; } /** @@ -1816,17 +1830,18 @@ public final class PowerManagerService extends SystemService private void finishWakefulnessChangeIfNeededLocked() { if (mWakefulnessChanging && mDisplayReady) { - if (mWakefulness == WAKEFULNESS_DOZING + if (getWakefulnessLocked() == WAKEFULNESS_DOZING && (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) { return; // wait until dream has enabled dozing } else { // Doze wakelock acquired (doze started) or device is no longer dozing. mDozeStartInProgress = false; } - if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) { + if (getWakefulnessLocked() == WAKEFULNESS_DOZING + || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) { logSleepTimeoutRecapturedLocked(); } - if (mWakefulness == WAKEFULNESS_AWAKE) { + if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) { Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0); final int latencyMs = (int) (SystemClock.uptimeMillis() - mLastWakeTime); if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) { @@ -2006,7 +2021,7 @@ public final class PowerManagerService extends SystemService } // If already dreaming and becoming powered, then don't wake. - if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) { + if (mIsPowered && getWakefulnessLocked() == WAKEFULNESS_DREAMING) { return false; } @@ -2016,7 +2031,7 @@ public final class PowerManagerService extends SystemService } // On Always On Display, SystemUI shows the charging indicator - if (mAlwaysOnEnabled && mWakefulness == WAKEFULNESS_DOZING) { + if (mAlwaysOnEnabled && getWakefulnessLocked() == WAKEFULNESS_DOZING) { return false; } @@ -2081,7 +2096,7 @@ public final class PowerManagerService extends SystemService if (DEBUG_SPEW) { Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness=" - + PowerManagerInternal.wakefulnessToString(mWakefulness) + + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked()) + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)); } } @@ -2089,23 +2104,23 @@ public final class PowerManagerService extends SystemService private int adjustWakeLockSummaryLocked(int wakeLockSummary) { // Cancel wake locks that make no sense based on the current state. - if (mWakefulness != WAKEFULNESS_DOZING) { + if (getWakefulnessLocked() != WAKEFULNESS_DOZING) { wakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW); } - if (mWakefulness == WAKEFULNESS_ASLEEP + if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP || (wakeLockSummary & WAKE_LOCK_DOZE) != 0) { wakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM | WAKE_LOCK_BUTTON_BRIGHT); - if (mWakefulness == WAKEFULNESS_ASLEEP) { + if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP) { wakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF; } } // Infer implied wake locks where necessary based on the current state. if ((wakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) { - if (mWakefulness == WAKEFULNESS_AWAKE) { + if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) { wakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE; - } else if (mWakefulness == WAKEFULNESS_DREAMING) { + } else if (getWakefulnessLocked() == WAKEFULNESS_DREAMING) { wakeLockSummary |= WAKE_LOCK_CPU; } } @@ -2213,9 +2228,9 @@ public final class PowerManagerService extends SystemService mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT); long nextTimeout = 0; - if (mWakefulness == WAKEFULNESS_AWAKE - || mWakefulness == WAKEFULNESS_DREAMING - || mWakefulness == WAKEFULNESS_DOZING) { + if (getWakefulnessLocked() == WAKEFULNESS_AWAKE + || getWakefulnessLocked() == WAKEFULNESS_DREAMING + || getWakefulnessLocked() == WAKEFULNESS_DOZING) { final long attentiveTimeout = getAttentiveTimeoutLocked(); final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout); final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout, @@ -2299,7 +2314,7 @@ public final class PowerManagerService extends SystemService if (DEBUG_SPEW) { Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness=" - + PowerManagerInternal.wakefulnessToString(mWakefulness) + + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked()) + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary) + ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout)); } @@ -2368,7 +2383,7 @@ public final class PowerManagerService extends SystemService mInattentiveSleepWarningOverlayController.show(); nextTimeout = goToSleepTime; } else { - if (DEBUG && mWakefulness != WAKEFULNESS_ASLEEP) { + if (DEBUG && getWakefulnessLocked() != WAKEFULNESS_ASLEEP) { Slog.i(TAG, "Going to sleep now due to long user inactivity"); } } @@ -2386,7 +2401,7 @@ public final class PowerManagerService extends SystemService return false; } - if (mWakefulness != WAKEFULNESS_AWAKE) { + if (getWakefulnessLocked() != WAKEFULNESS_AWAKE) { mInattentiveSleepWarningOverlayController.dismiss(false); return true; } else if (attentiveTimeout < 0 || isBeingKeptFromShowingInattentiveSleepWarningLocked() @@ -2490,7 +2505,7 @@ public final class PowerManagerService extends SystemService | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE | DIRTY_DOCK_STATE | DIRTY_ATTENTIVE | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) { - if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) { + if (getWakefulnessLocked() == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) { if (DEBUG_SPEW) { Slog.d(TAG, "updateWakefulnessLocked: Bed time..."); } @@ -2613,7 +2628,7 @@ public final class PowerManagerService extends SystemService final int wakefulness; synchronized (mLock) { mSandmanScheduled = false; - wakefulness = mWakefulness; + wakefulness = getWakefulnessLocked(); if (mSandmanSummoned && mDisplayReady) { startDreaming = canDreamLocked() || canDozeLocked(); mSandmanSummoned = false; @@ -2655,7 +2670,7 @@ public final class PowerManagerService extends SystemService // If preconditions changed, wait for the next iteration to determine // whether the dream should continue (or be restarted). - if (mSandmanSummoned || mWakefulness != wakefulness) { + if (mSandmanSummoned || getWakefulnessLocked() != wakefulness) { return; // wait for next cycle } @@ -2717,7 +2732,7 @@ public final class PowerManagerService extends SystemService * Returns true if the device is allowed to dream in its current state. */ private boolean canDreamLocked() { - if (mWakefulness != WAKEFULNESS_DREAMING + if (getWakefulnessLocked() != WAKEFULNESS_DREAMING || !mDreamsSupportedConfig || !mDreamsEnabledSetting || !mDisplayPowerRequest.isBrightOrDim() @@ -2749,7 +2764,7 @@ public final class PowerManagerService extends SystemService * Returns true if the device is allowed to doze in its current state. */ private boolean canDozeLocked() { - return mWakefulness == WAKEFULNESS_DOZING; + return getWakefulnessLocked() == WAKEFULNESS_DOZING; } /** @@ -2825,7 +2840,7 @@ public final class PowerManagerService extends SystemService if (DEBUG_SPEW) { Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady + ", policy=" + mDisplayPowerRequest.policy - + ", mWakefulness=" + mWakefulness + + ", mWakefulness=" + getWakefulnessLocked() + ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary) + ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary) + ", mBootCompleted=" + mBootCompleted @@ -2871,11 +2886,11 @@ public final class PowerManagerService extends SystemService @VisibleForTesting int getDesiredScreenPolicyLocked() { - if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) { + if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP || sQuiescent) { return DisplayPowerRequest.POLICY_OFF; } - if (mWakefulness == WAKEFULNESS_DOZING) { + if (getWakefulnessLocked() == WAKEFULNESS_DOZING) { if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) { return DisplayPowerRequest.POLICY_DOZE; } @@ -3079,7 +3094,7 @@ public final class PowerManagerService extends SystemService // Here we wait for mWakefulnessChanging to become false since the wakefulness // transition to DOZING isn't considered "changed" until the doze wake lock is // acquired. - if (mWakefulness == WAKEFULNESS_DOZING && mDozeStartInProgress) { + if (getWakefulnessLocked() == WAKEFULNESS_DOZING && mDozeStartInProgress) { return true; } @@ -3119,7 +3134,7 @@ public final class PowerManagerService extends SystemService private boolean isInteractiveInternal() { synchronized (mLock) { - return PowerManagerInternal.isInteractive(mWakefulness); + return PowerManagerInternal.isInteractive(getWakefulnessLocked()); } } @@ -3495,7 +3510,7 @@ public final class PowerManagerService extends SystemService private void boostScreenBrightnessInternal(long eventTime, int uid) { synchronized (mLock) { - if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP + if (!mSystemReady || getWakefulnessLocked() == WAKEFULNESS_ASLEEP || eventTime < mLastScreenBrightnessBoostTime) { return; } @@ -3725,7 +3740,8 @@ public final class PowerManagerService extends SystemService pw.println("Power Manager State:"); mConstants.dump(pw); pw.println(" mDirty=0x" + Integer.toHexString(mDirty)); - pw.println(" mWakefulness=" + PowerManagerInternal.wakefulnessToString(mWakefulness)); + pw.println(" mWakefulness=" + + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())); pw.println(" mWakefulnessChanging=" + mWakefulnessChanging); pw.println(" mIsPowered=" + mIsPowered); pw.println(" mPlugType=" + mPlugType); @@ -3936,7 +3952,7 @@ public final class PowerManagerService extends SystemService synchronized (mLock) { mConstants.dumpProto(proto); proto.write(PowerManagerServiceDumpProto.DIRTY, mDirty); - proto.write(PowerManagerServiceDumpProto.WAKEFULNESS, mWakefulness); + proto.write(PowerManagerServiceDumpProto.WAKEFULNESS, getWakefulnessLocked()); proto.write(PowerManagerServiceDumpProto.IS_WAKEFULNESS_CHANGING, mWakefulnessChanging); proto.write(PowerManagerServiceDumpProto.IS_POWERED, mIsPowered); proto.write(PowerManagerServiceDumpProto.PLUG_TYPE, mPlugType); diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index 4142e6ff4d69..beba106ca0a6 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -38,7 +38,6 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; -import com.android.internal.util.Preconditions; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.power.PowerManagerService; @@ -76,11 +75,19 @@ public class BatterySaverController implements BatterySaverPolicyListener { @GuardedBy("mLock") private final ArrayList<LowPowerModeListener> mListeners = new ArrayList<>(); + /** + * Do not access directly; always use {@link #setFullEnabledLocked} + * and {@link #getFullEnabledLocked} + */ @GuardedBy("mLock") - private boolean mFullEnabled; + private boolean mFullEnabledRaw; + /** + * Do not access directly; always use {@link #setAdaptiveEnabledLocked} and + * {@link #getAdaptiveEnabledLocked}. + */ @GuardedBy("mLock") - private boolean mAdaptiveEnabled; + private boolean mAdaptiveEnabledRaw; @GuardedBy("mLock") private boolean mIsPluggedIn; @@ -208,6 +215,7 @@ public class BatterySaverController implements BatterySaverPolicyListener { mPlugins = new Plugin[] { new BatterySaverLocationPlugin(mContext) }; + PowerManager.invalidatePowerSaveModeCaches(); } /** @@ -294,10 +302,10 @@ public class BatterySaverController implements BatterySaverPolicyListener { @VisibleForTesting public void enableBatterySaver(boolean enable, int reason) { synchronized (mLock) { - if (mFullEnabled == enable) { + if (getFullEnabledLocked() == enable) { return; } - mFullEnabled = enable; + setFullEnabledLocked(enable); if (updatePolicyLevelLocked()) { mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); @@ -306,9 +314,9 @@ public class BatterySaverController implements BatterySaverPolicyListener { } private boolean updatePolicyLevelLocked() { - if (mFullEnabled) { + if (getFullEnabledLocked()) { return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_FULL); - } else if (mAdaptiveEnabled) { + } else if (getAdaptiveEnabledLocked()) { return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_ADAPTIVE); } else { return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_OFF); @@ -321,8 +329,8 @@ public class BatterySaverController implements BatterySaverPolicyListener { */ public boolean isEnabled() { synchronized (mLock) { - return mFullEnabled - || (mAdaptiveEnabled && mBatterySaverPolicy.shouldAdvertiseIsEnabled()); + return getFullEnabledLocked() || (getAdaptiveEnabledLocked() + && mBatterySaverPolicy.shouldAdvertiseIsEnabled()); } } @@ -332,19 +340,19 @@ public class BatterySaverController implements BatterySaverPolicyListener { */ private boolean isPolicyEnabled() { synchronized (mLock) { - return mFullEnabled || mAdaptiveEnabled; + return getFullEnabledLocked() || getAdaptiveEnabledLocked(); } } boolean isFullEnabled() { synchronized (mLock) { - return mFullEnabled; + return getFullEnabledLocked(); } } boolean isAdaptiveEnabled() { synchronized (mLock) { - return mAdaptiveEnabled; + return getAdaptiveEnabledLocked(); } } @@ -375,10 +383,10 @@ public class BatterySaverController implements BatterySaverPolicyListener { } boolean setAdaptivePolicyEnabledLocked(boolean enabled, int reason) { - if (mAdaptiveEnabled == enabled) { + if (getAdaptiveEnabledLocked() == enabled) { return false; } - mAdaptiveEnabled = enabled; + setAdaptiveEnabledLocked(enabled); if (updatePolicyLevelLocked()) { mHandler.postStateChanged(/*sendBroadcast=*/ true, reason); return true; @@ -427,19 +435,19 @@ public class BatterySaverController implements BatterySaverPolicyListener { final ArrayMap<String, String> fileValues; synchronized (mLock) { - enabled = mFullEnabled || mAdaptiveEnabled; + enabled = getFullEnabledLocked() || getAdaptiveEnabledLocked(); EventLogTags.writeBatterySaverMode( mFullPreviouslyEnabled ? 1 : 0, // Previously off or on. mAdaptivePreviouslyEnabled ? 1 : 0, // Previously off or on. - mFullEnabled ? 1 : 0, // Now off or on. - mAdaptiveEnabled ? 1 : 0, // Now off or on. + getFullEnabledLocked() ? 1 : 0, // Now off or on. + getAdaptiveEnabledLocked() ? 1 : 0, // Now off or on. isInteractive ? 1 : 0, // Device interactive state. enabled ? mBatterySaverPolicy.toEventLogString() : "", reason); - mFullPreviouslyEnabled = mFullEnabled; - mAdaptivePreviouslyEnabled = mAdaptiveEnabled; + mFullPreviouslyEnabled = getFullEnabledLocked(); + mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked(); listeners = mListeners.toArray(new LowPowerModeListener[0]); @@ -518,10 +526,40 @@ public class BatterySaverController implements BatterySaverPolicyListener { return; } mBatterySavingStats.transitionState( - mFullEnabled ? BatterySaverState.ON : - (mAdaptiveEnabled ? BatterySaverState.ADAPTIVE : BatterySaverState.OFF), - isInteractive ? InteractiveState.INTERACTIVE : InteractiveState.NON_INTERACTIVE, - dozeMode); + getFullEnabledLocked() ? BatterySaverState.ON : + (getAdaptiveEnabledLocked() ? BatterySaverState.ADAPTIVE : + BatterySaverState.OFF), + isInteractive ? InteractiveState.INTERACTIVE : + InteractiveState.NON_INTERACTIVE, + dozeMode); + } + } + + @GuardedBy("mLock") + private void setFullEnabledLocked(boolean value) { + if (mFullEnabledRaw == value) { + return; } + PowerManager.invalidatePowerSaveModeCaches(); + mFullEnabledRaw = value; + } + + /** Non-blocking getter exists as a reminder not to directly modify the cached field */ + private boolean getFullEnabledLocked() { + return mFullEnabledRaw; + } + + @GuardedBy("mLock") + private void setAdaptiveEnabledLocked(boolean value) { + if (mAdaptiveEnabledRaw == value) { + return; + } + PowerManager.invalidatePowerSaveModeCaches(); + mAdaptiveEnabledRaw = value; + } + + /** Non-blocking getter exists as a reminder not to directly modify the cached field */ + private boolean getAdaptiveEnabledLocked() { + return mAdaptiveEnabledRaw; } } diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java index 38bdc62c5761..233417da3e00 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java @@ -219,8 +219,12 @@ public class BatterySaverPolicy extends ContentObserver { static final int POLICY_LEVEL_ADAPTIVE = 1; static final int POLICY_LEVEL_FULL = 2; + /** + * Do not access directly; always use {@link #setPolicyLevel} + * and {@link #getPolicyLevelLocked} + */ @GuardedBy("mLock") - private int mPolicyLevel = POLICY_LEVEL_OFF; + private int mPolicyLevelRaw = POLICY_LEVEL_OFF; private final Context mContext; private final ContentResolver mContentResolver; @@ -290,6 +294,11 @@ public class BatterySaverPolicy extends ContentObserver { return R.string.config_batterySaverDeviceSpecificConfig; } + @VisibleForTesting + void invalidatePowerSaveModeCaches() { + PowerManager.invalidatePowerSaveModeCaches(); + } + @Override public void onChange(boolean selfChange, Uri uri) { refreshSettings(); @@ -373,14 +382,14 @@ public class BatterySaverPolicy extends ContentObserver { boolean changed = false; Policy newFullPolicy = Policy.fromSettings(setting, deviceSpecificSetting, DEFAULT_FULL_POLICY); - if (mPolicyLevel == POLICY_LEVEL_FULL && !mFullPolicy.equals(newFullPolicy)) { + if (getPolicyLevelLocked() == POLICY_LEVEL_FULL && !mFullPolicy.equals(newFullPolicy)) { changed = true; } mFullPolicy = newFullPolicy; mDefaultAdaptivePolicy = Policy.fromSettings(adaptiveSetting, adaptiveDeviceSpecificSetting, DEFAULT_ADAPTIVE_POLICY); - if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE + if (getPolicyLevelLocked() == POLICY_LEVEL_ADAPTIVE && !mAdaptivePolicy.equals(mDefaultAdaptivePolicy)) { changed = true; } @@ -882,14 +891,14 @@ public class BatterySaverPolicy extends ContentObserver { */ boolean setPolicyLevel(@PolicyLevel int level) { synchronized (mLock) { - if (mPolicyLevel == level) { + if (getPolicyLevelLocked() == level) { return false; } switch (level) { case POLICY_LEVEL_FULL: case POLICY_LEVEL_ADAPTIVE: case POLICY_LEVEL_OFF: - mPolicyLevel = level; + setPolicyLevelLocked(level); break; default: Slog.wtf(TAG, "setPolicyLevel invalid level given: " + level); @@ -911,7 +920,7 @@ public class BatterySaverPolicy extends ContentObserver { } mAdaptivePolicy = p; - if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE) { + if (getPolicyLevelLocked() == POLICY_LEVEL_ADAPTIVE) { updatePolicyDependenciesLocked(); return true; } @@ -924,7 +933,7 @@ public class BatterySaverPolicy extends ContentObserver { } private Policy getCurrentPolicyLocked() { - switch (mPolicyLevel) { + switch (getPolicyLevelLocked()) { case POLICY_LEVEL_FULL: return mFullPolicy; case POLICY_LEVEL_ADAPTIVE: @@ -985,7 +994,7 @@ public class BatterySaverPolicy extends ContentObserver { pw.println(" value: " + mAdaptiveDeviceSpecificSettings); pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled); - pw.println(" mPolicyLevel=" + mPolicyLevel); + pw.println(" mPolicyLevel=" + getPolicyLevelLocked()); dumpPolicyLocked(pw, " ", "full", mFullPolicy); dumpPolicyLocked(pw, " ", "default adaptive", mDefaultAdaptivePolicy); @@ -1067,4 +1076,20 @@ public class BatterySaverPolicy extends ContentObserver { updatePolicyDependenciesLocked(); } } + + /** Non-blocking getter exists as a reminder not to modify cached fields directly */ + @GuardedBy("mLock") + private int getPolicyLevelLocked() { + return mPolicyLevelRaw; + } + + @GuardedBy("mLock") + private void setPolicyLevelLocked(int level) { + if (mPolicyLevelRaw == level) { + return; + } + // Under lock, invalidate before set ensures caches won't return stale values. + invalidatePowerSaveModeCaches(); + mPolicyLevelRaw = level; + } } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 5c79f6e6391d..47a26f576949 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -16,7 +16,8 @@ package com.android.server.stats.pull; -import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED; +import static android.app.AppOpsManager.OP_FLAG_SELF; +import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.os.Debug.getIonHeapsSizeKb; @@ -184,6 +185,7 @@ public class StatsPullAtomService extends SystemService { private static final int MAX_BATTERY_STATS_HELPER_FREQUENCY_MS = 1000; private static final int CPU_TIME_PER_THREAD_FREQ_MAX_NUM_FREQUENCIES = 8; + private static final int OP_FLAGS_PULLED = OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED; private final Object mNetworkStatsLock = new Object(); @GuardedBy("mNetworkStatsLock") @@ -2838,8 +2840,8 @@ public class StatsPullAtomService extends SystemService { AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); CompletableFuture<HistoricalOps> ops = new CompletableFuture<>(); - HistoricalOpsRequest histOpsRequest = - new HistoricalOpsRequest.Builder(0, Long.MAX_VALUE).build(); + HistoricalOpsRequest histOpsRequest = new HistoricalOpsRequest.Builder(0, + Long.MAX_VALUE).setFlags(OP_FLAGS_PULLED).build(); appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete); HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS, @@ -2851,19 +2853,19 @@ public class StatsPullAtomService extends SystemService { for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) { final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx); for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) { - final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx); + final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx); StatsEvent.Builder e = StatsEvent.newBuilder(); e.setAtomId(atomTag); e.writeInt(uid); e.writeString(packageOps.getPackageName()); e.writeInt(op.getOpCode()); - e.writeLong(op.getForegroundAccessCount(OP_FLAGS_ALL_TRUSTED)); - e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_ALL_TRUSTED)); - e.writeLong(op.getForegroundRejectCount(OP_FLAGS_ALL_TRUSTED)); - e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_ALL_TRUSTED)); - e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_ALL_TRUSTED)); - e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_ALL_TRUSTED)); + e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED)); + e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED)); + e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED)); + e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED)); + e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED)); + e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED)); String perm = AppOpsManager.opToPermission(op.getOpCode()); if (perm == null) { diff --git a/services/core/java/com/android/server/tv/tuner/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java index 3845195e6643..bad2b78dab48 100644 --- a/services/core/java/com/android/server/tv/tuner/ClientProfile.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.tv.tuner; +package com.android.server.tv.tunerresourcemanager; /** * A client profile object used by the Tuner Resource Manager to record the registered clients' @@ -122,6 +122,9 @@ public final class ClientProfile { + this.mUseCase + ", " + this.mProcessId; } + /** + * Builder class for {@link ClientProfile}. + */ public static class ClientProfileBuilder { private final int mClientId; private String mTvInputSessionId; diff --git a/services/core/java/com/android/server/tv/tuner/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index e8764214ca21..49a7045bf57a 100644 --- a/services/core/java/com/android/server/tv/tuner/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -14,20 +14,20 @@ * limitations under the License. */ -package com.android.server.tv.tuner; +package com.android.server.tv.tunerresourcemanager; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.media.tv.TvInputManager; -import android.media.tv.tuner.CasSessionRequest; -import android.media.tv.tuner.ITunerResourceManager; -import android.media.tv.tuner.ITunerResourceManagerListener; -import android.media.tv.tuner.ResourceClientProfile; -import android.media.tv.tuner.TunerFrontendInfo; -import android.media.tv.tuner.TunerFrontendRequest; -import android.media.tv.tuner.TunerLnbRequest; -import android.media.tv.tuner.TunerResourceManager; +import android.media.tv.tunerresourcemanager.CasSessionRequest; +import android.media.tv.tunerresourcemanager.IResourcesReclaimListener; +import android.media.tv.tunerresourcemanager.ITunerResourceManager; +import android.media.tv.tunerresourcemanager.ResourceClientProfile; +import android.media.tv.tunerresourcemanager.TunerFrontendInfo; +import android.media.tv.tunerresourcemanager.TunerFrontendRequest; +import android.media.tv.tunerresourcemanager.TunerLnbRequest; +import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.os.RemoteException; import android.util.Log; import android.util.Slog; @@ -48,7 +48,7 @@ public class TunerResourceManagerService extends SystemService { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private SparseArray<ClientProfile> mClientProfiles = new SparseArray<>(); - private SparseArray<ITunerResourceManagerListener> mListeners = new SparseArray<>(); + private SparseArray<IResourcesReclaimListener> mListeners = new SparseArray<>(); private int mNextUnusedFrontendId = 0; private List<Integer> mReleasedClientId = new ArrayList<Integer>(); private List<Integer> mAvailableFrontendIds = new ArrayList<Integer>(); @@ -69,7 +69,7 @@ public class TunerResourceManagerService extends SystemService { private final class BinderService extends ITunerResourceManager.Stub { @Override public void registerClientProfile(@NonNull ResourceClientProfile profile, - @NonNull ITunerResourceManagerListener listener, + @NonNull IResourcesReclaimListener listener, @NonNull int[] clientId) { if (DEBUG) { Slog.d(TAG, "registerClientProfile(clientProfile=" + profile + ")"); diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java index e72ba8d9f01b..761fbf8a0622 100644 --- a/services/core/java/com/android/server/twilight/TwilightService.java +++ b/services/core/java/com/android/server/twilight/TwilightService.java @@ -50,6 +50,7 @@ public final class TwilightService extends SystemService implements AlarmManager.OnAlarmListener, Handler.Callback, LocationListener { private static final String TAG = "TwilightService"; + private static final String FEATURE_ID = "TwilightService"; private static final boolean DEBUG = false; private static final int MSG_START_LISTENING = 1; @@ -73,7 +74,7 @@ public final class TwilightService extends SystemService protected TwilightState mLastTwilightState; public TwilightService(Context context) { - super(context); + super(context.createFeatureContext(FEATURE_ID)); mHandler = new Handler(Looper.getMainLooper(), this); } diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java index 7302e529c1eb..6522294bd083 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java @@ -231,7 +231,8 @@ public abstract class ActivityTaskManagerInternal { * @return error codes used by {@link IActivityManager#startActivity} and its siblings. */ public abstract int startActivityAsUser(IApplicationThread caller, String callingPackage, - @Nullable String callingFeatureId, Intent intent, @Nullable Bundle options, int userId); + @Nullable String callingFeatureId, Intent intent, @Nullable IBinder resultTo, + int startFlags, @Nullable Bundle options, int userId); /** * Called when Keyguard flags might have changed. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index f2917c54c3fa..132e48656df3 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -6270,11 +6270,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public int startActivityAsUser(IApplicationThread caller, String callerPackage, - @Nullable String callerFeatureId, Intent intent, Bundle options, int userId) { + @Nullable String callerFeatureId, Intent intent, @Nullable IBinder resultTo, + int startFlags, Bundle options, int userId) { return ActivityTaskManagerService.this.startActivityAsUser( caller, callerPackage, callerFeatureId, intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), - null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options, userId, + resultTo, null, 0, startFlags, null, options, userId, false /*validateIncomingUser*/); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 1936f13ca6e1..569986c46186 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -162,7 +162,7 @@ import com.android.server.textservices.TextServicesManagerService; import com.android.server.trust.TrustManagerService; import com.android.server.tv.TvInputManagerService; import com.android.server.tv.TvRemoteService; -import com.android.server.tv.tuner.TunerResourceManagerService; +import com.android.server.tv.tunerresourcemanager.TunerResourceManagerService; import com.android.server.twilight.TwilightService; import com.android.server.uri.UriGrantsManagerService; import com.android.server.usage.UsageStatsService; diff --git a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java index 4cbdbd178944..2d0fe5875301 100644 --- a/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java +++ b/services/robotests/src/com/android/server/location/LocationRequestStatisticsTest.java @@ -35,6 +35,7 @@ import java.io.StringWriter; @RunWith(RobolectricTestRunner.class) @Presubmit public class LocationRequestStatisticsTest { + private static final String FEATURE_ID = "featureId"; /** * Check adding and removing requests & strings @@ -43,17 +44,18 @@ public class LocationRequestStatisticsTest { public void testRequestSummary() { LocationRequestStatistics.RequestSummary summary = new LocationRequestStatistics.RequestSummary( - "com.example", "gps", 1000); + "com.example", FEATURE_ID, "gps", 1000); StringWriter stringWriter = new StringWriter(); summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriter), " "), 1234); assertThat(stringWriter.toString()).startsWith("At"); StringWriter stringWriterRemove = new StringWriter(); summary = new LocationRequestStatistics.RequestSummary( - "com.example", "gps", + "com.example", "gps", FEATURE_ID, LocationRequestStatistics.RequestSummary.REQUEST_ENDED_INTERVAL); summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriterRemove), " "), 2345); assertThat(stringWriterRemove.toString()).contains("-"); + assertThat(stringWriterRemove.toString()).contains(FEATURE_ID); } /** @@ -62,11 +64,11 @@ public class LocationRequestStatisticsTest { @Test public void testSummaryList() { LocationRequestStatistics statistics = new LocationRequestStatistics(); - statistics.history.addRequest("com.example", "gps", 1000); + statistics.history.addRequest("com.example", FEATURE_ID, "gps", 1000); assertThat(statistics.history.mList.size()).isEqualTo(1); // Try (not) to overflow for (int i = 0; i < LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE; i++) { - statistics.history.addRequest("com.example", "gps", 1000); + statistics.history.addRequest("com.example", FEATURE_ID, "gps", 1000); } assertThat(statistics.history.mList.size()).isEqualTo( LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE); diff --git a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java index c45820e6ec9d..b6b8b82f191a 100644 --- a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java +++ b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java @@ -1,17 +1,18 @@ package com.android.server.location; -import com.android.server.location.LocationRequestStatistics.PackageProviderKey; -import com.android.server.location.LocationRequestStatistics.PackageStatistics; - import android.os.SystemClock; import android.test.AndroidTestCase; +import com.android.server.location.LocationRequestStatistics.PackageProviderKey; +import com.android.server.location.LocationRequestStatistics.PackageStatistics; + /** * Unit tests for {@link LocationRequestStatistics}. */ public class LocationRequestStatisticsTest extends AndroidTestCase { private static final String PACKAGE1 = "package1"; private static final String PACKAGE2 = "package2"; + private static final String FEATURE_ID = "featureId"; private static final String PROVIDER1 = "provider1"; private static final String PROVIDER2 = "provider2"; private static final long INTERVAL1 = 5000; @@ -30,12 +31,13 @@ public class LocationRequestStatisticsTest extends AndroidTestCase { * Tests that adding a single package works correctly. */ public void testSinglePackage() { - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true); assertEquals(1, mStatistics.statistics.size()); PackageProviderKey key = mStatistics.statistics.keySet().iterator().next(); - assertEquals(PACKAGE1, key.packageName); - assertEquals(PROVIDER1, key.providerName); + assertEquals(PACKAGE1, key.mPackageName); + assertEquals(PROVIDER1, key.mProviderName); + assertEquals(FEATURE_ID, key.mFeatureId); PackageStatistics stats = mStatistics.statistics.values().iterator().next(); verifyStatisticsTimes(stats); assertEquals(INTERVAL1, stats.getFastestIntervalMs()); @@ -47,21 +49,22 @@ public class LocationRequestStatisticsTest extends AndroidTestCase { * Tests that adding a single package works correctly when it is stopped and restarted. */ public void testSinglePackage_stopAndRestart() { - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true); - mStatistics.stopRequesting(PACKAGE1, PROVIDER1); - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true); assertEquals(1, mStatistics.statistics.size()); PackageProviderKey key = mStatistics.statistics.keySet().iterator().next(); - assertEquals(PACKAGE1, key.packageName); - assertEquals(PROVIDER1, key.providerName); + assertEquals(PACKAGE1, key.mPackageName); + assertEquals(FEATURE_ID, key.mFeatureId); + assertEquals(PROVIDER1, key.mProviderName); PackageStatistics stats = mStatistics.statistics.values().iterator().next(); verifyStatisticsTimes(stats); assertEquals(INTERVAL1, stats.getFastestIntervalMs()); assertEquals(INTERVAL1, stats.getSlowestIntervalMs()); assertTrue(stats.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER1); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1); assertFalse(stats.isActive()); } @@ -69,21 +72,22 @@ public class LocationRequestStatisticsTest extends AndroidTestCase { * Tests that adding a single package works correctly when multiple intervals are used. */ public void testSinglePackage_multipleIntervals() { - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true); - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL2, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL2, true); assertEquals(1, mStatistics.statistics.size()); PackageProviderKey key = mStatistics.statistics.keySet().iterator().next(); - assertEquals(PACKAGE1, key.packageName); - assertEquals(PROVIDER1, key.providerName); + assertEquals(PACKAGE1, key.mPackageName); + assertEquals(PROVIDER1, key.mProviderName); + assertEquals(FEATURE_ID, key.mFeatureId); PackageStatistics stats = mStatistics.statistics.values().iterator().next(); verifyStatisticsTimes(stats); assertEquals(INTERVAL1, stats.getFastestIntervalMs()); assertTrue(stats.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER1); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1); assertTrue(stats.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER1); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1); assertFalse(stats.isActive()); } @@ -91,27 +95,27 @@ public class LocationRequestStatisticsTest extends AndroidTestCase { * Tests that adding a single package works correctly when multiple providers are used. */ public void testSinglePackage_multipleProviders() { - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true); - mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL2, true); assertEquals(2, mStatistics.statistics.size()); - PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1); + PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER1); PackageStatistics stats1 = mStatistics.statistics.get(key1); verifyStatisticsTimes(stats1); assertEquals(INTERVAL1, stats1.getSlowestIntervalMs()); assertEquals(INTERVAL1, stats1.getFastestIntervalMs()); assertTrue(stats1.isActive()); - PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, PROVIDER2); + PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER2); PackageStatistics stats2 = mStatistics.statistics.get(key2); verifyStatisticsTimes(stats2); assertEquals(INTERVAL2, stats2.getSlowestIntervalMs()); assertEquals(INTERVAL2, stats2.getFastestIntervalMs()); assertTrue(stats2.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER1); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1); assertFalse(stats1.isActive()); assertTrue(stats2.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER2); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER2); assertFalse(stats1.isActive()); assertFalse(stats2.isActive()); } @@ -120,46 +124,46 @@ public class LocationRequestStatisticsTest extends AndroidTestCase { * Tests that adding multiple packages works correctly. */ public void testMultiplePackages() { - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true); - mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL1, true); - mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2, true); - mStatistics.startRequesting(PACKAGE2, PROVIDER1, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL2, true); + mStatistics.startRequesting(PACKAGE2, FEATURE_ID, PROVIDER1, INTERVAL1, true); assertEquals(3, mStatistics.statistics.size()); - PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1); + PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER1); PackageStatistics stats1 = mStatistics.statistics.get(key1); verifyStatisticsTimes(stats1); assertEquals(INTERVAL1, stats1.getSlowestIntervalMs()); assertEquals(INTERVAL1, stats1.getFastestIntervalMs()); assertTrue(stats1.isActive()); - PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, PROVIDER2); + PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, FEATURE_ID, PROVIDER2); PackageStatistics stats2 = mStatistics.statistics.get(key2); verifyStatisticsTimes(stats2); assertEquals(INTERVAL2, stats2.getSlowestIntervalMs()); assertEquals(INTERVAL1, stats2.getFastestIntervalMs()); assertTrue(stats2.isActive()); - PackageProviderKey key3 = new PackageProviderKey(PACKAGE2, PROVIDER1); + PackageProviderKey key3 = new PackageProviderKey(PACKAGE2, FEATURE_ID, PROVIDER1); PackageStatistics stats3 = mStatistics.statistics.get(key3); verifyStatisticsTimes(stats3); assertEquals(INTERVAL1, stats3.getSlowestIntervalMs()); assertEquals(INTERVAL1, stats3.getFastestIntervalMs()); assertTrue(stats3.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER1); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1); assertFalse(stats1.isActive()); assertTrue(stats2.isActive()); assertTrue(stats3.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER2); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER2); assertFalse(stats1.isActive()); assertTrue(stats2.isActive()); assertTrue(stats3.isActive()); - mStatistics.stopRequesting(PACKAGE1, PROVIDER2); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER2); assertFalse(stats2.isActive()); - mStatistics.stopRequesting(PACKAGE2, PROVIDER1); + mStatistics.stopRequesting(PACKAGE2, FEATURE_ID, PROVIDER1); assertFalse(stats1.isActive()); assertFalse(stats2.isActive()); assertFalse(stats3.isActive()); @@ -169,14 +173,14 @@ public class LocationRequestStatisticsTest extends AndroidTestCase { * Tests that switching foreground & background states accmulates time reasonably. */ public void testForegroundBackground() { - mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1, true); - mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL1, true); - mStatistics.startRequesting(PACKAGE2, PROVIDER1, INTERVAL1, false); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER1, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE1, FEATURE_ID, PROVIDER2, INTERVAL1, true); + mStatistics.startRequesting(PACKAGE2, FEATURE_ID, PROVIDER1, INTERVAL1, false); - mStatistics.updateForeground(PACKAGE1, PROVIDER2, false); - mStatistics.updateForeground(PACKAGE2, PROVIDER1, true); + mStatistics.updateForeground(PACKAGE1, FEATURE_ID, PROVIDER2, false); + mStatistics.updateForeground(PACKAGE2, FEATURE_ID, PROVIDER1, true); - mStatistics.stopRequesting(PACKAGE1, PROVIDER1); + mStatistics.stopRequesting(PACKAGE1, FEATURE_ID, PROVIDER1); for (PackageStatistics stats : mStatistics.statistics.values()) { verifyStatisticsTimes(stats); diff --git a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java index 4d0ad96ac223..19cbb0e6e9b5 100644 --- a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java @@ -16,6 +16,8 @@ package com.android.server.location.gnss; +import static android.location.LocationManager.GPS_PROVIDER; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -293,6 +295,9 @@ public class GnssManagerServiceTest { } return AppOpsManager.MODE_ERRORED; }); + + when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt())) + .thenReturn(true); } private void disableLocationPermissions() { @@ -303,6 +308,9 @@ public class GnssManagerServiceTest { when(mAppOpsManager.checkOp(anyInt(), anyInt(), anyString())).thenReturn(AppOpsManager.MODE_ERRORED); + + when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt())) + .thenReturn(false); } private GnssStatusListenerHelper createGnssStatusListenerHelper(Context context, @@ -527,6 +535,7 @@ public class GnssManagerServiceTest { assertThrows(SecurityException.class, () -> mGnssManagerService.removeGnssBatchingCallback()); + enableLocationPermissions(); mGnssManagerService.onReportLocation(mockLocationList); verify(mockBatchedLocationCallback, times(1)).onLocationBatch(mockLocationList); diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java index 3708571dbdcf..e79b5af32b19 100644 --- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java @@ -31,6 +31,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.PermissionInfo; import android.content.pm.ResolveInfo; import android.os.Bundle; +import android.os.IBinder; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; @@ -237,6 +238,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -260,6 +263,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -285,6 +290,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -310,6 +317,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -333,6 +342,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -356,6 +367,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -381,6 +394,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -411,6 +426,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -434,6 +451,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -457,6 +476,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -480,6 +501,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -503,6 +526,8 @@ public class CrossProfileAppsServiceImplTest { anyString(), nullable(String.class), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), anyInt()); } @@ -525,6 +550,8 @@ public class CrossProfileAppsServiceImplTest { eq(PACKAGE_ONE), eq(FEATURE_ID), any(Intent.class), + nullable(IBinder.class), + anyInt(), nullable(Bundle.class), eq(PRIMARY_USER)); } diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java index 7666ab9ed5ae..1c2d8e80ea99 100644 --- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java +++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java @@ -45,6 +45,7 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.os.BatteryStatsImpl; import com.android.server.LocalServices; import com.android.server.policy.WindowManagerPolicy; +import com.android.server.power.batterysaver.BatterySaverController; import com.android.server.power.batterysaver.BatterySaverPolicy; import com.android.server.power.batterysaver.BatterySavingStats; import com.android.server.statusbar.StatusBarManagerInternal; @@ -61,6 +62,7 @@ public class NotifierTest { private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent"; private static final int USER_ID = 0; + @Mock private BatterySaverController mBatterySaverControllerMock; @Mock private BatterySaverPolicy mBatterySaverPolicyMock; @Mock private PowerManagerService.NativeWrapper mNativeWrapperMock; @Mock private Notifier mNotifierMock; @@ -223,6 +225,13 @@ public class NotifierTest { } @Override + BatterySaverController createBatterySaverController( + Object lock, Context context, BatterySaverPolicy batterySaverPolicy, + BatterySavingStats batterySavingStats) { + return mBatterySaverControllerMock; + } + + @Override PowerManagerService.NativeWrapper createNativeWrapper() { return mNativeWrapperMock; } @@ -247,6 +256,11 @@ public class NotifierTest { public SystemPropertiesWrapper createSystemPropertiesWrapper() { return mSystemPropertiesMock; } + + @Override + void invalidateIsInteractiveCaches() { + // Avoids an SELinux denial. + } }; private void enableChargingFeedback(boolean chargingFeedbackEnabled, boolean dndOn) { diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java index 811089a45758..0ee2f55fbde0 100644 --- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java @@ -81,6 +81,7 @@ import com.android.server.power.PowerManagerService.BatteryReceiver; import com.android.server.power.PowerManagerService.Injector; import com.android.server.power.PowerManagerService.NativeWrapper; import com.android.server.power.PowerManagerService.UserSwitchedReceiver; +import com.android.server.power.batterysaver.BatterySaverController; import com.android.server.power.batterysaver.BatterySaverPolicy; import com.android.server.power.batterysaver.BatterySavingStats; @@ -106,6 +107,7 @@ public class PowerManagerServiceTest { private static final float BRIGHTNESS_FACTOR = 0.7f; private static final boolean BATTERY_SAVER_ENABLED = true; + @Mock private BatterySaverController mBatterySaverControllerMock; @Mock private BatterySaverPolicy mBatterySaverPolicyMock; @Mock private LightsManager mLightsManagerMock; @Mock private DisplayManagerInternal mDisplayManagerInternalMock; @@ -207,6 +209,13 @@ public class PowerManagerServiceTest { } @Override + BatterySaverController createBatterySaverController( + Object lock, Context context, BatterySaverPolicy batterySaverPolicy, + BatterySavingStats batterySavingStats) { + return mBatterySaverControllerMock; + } + + @Override NativeWrapper createNativeWrapper() { return mNativeWrapperMock; } @@ -231,6 +240,11 @@ public class PowerManagerServiceTest { public SystemPropertiesWrapper createSystemPropertiesWrapper() { return mSystemPropertiesMock; } + + @Override + void invalidateIsInteractiveCaches() { + // Avoids an SELinux failure. + } }); return mService; } @@ -369,7 +383,7 @@ public class PowerManagerServiceTest { @Test public void testWakefulnessAwake_InitialValue() throws Exception { createService(); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); } @Test @@ -377,12 +391,12 @@ public class PowerManagerServiceTest { createService(); // Start with AWAKE state startSystem(); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); // Take a nap and verify. mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_APPLICATION, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); } @Test @@ -399,21 +413,21 @@ public class PowerManagerServiceTest { int flags = PowerManager.FULL_WAKE_LOCK; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, null /* workSource */, null /* historyTag */); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */); // Ensure that the flag does *NOT* work with a partial wake lock. flags = PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, null /* workSource */, null /* historyTag */); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */); // Verify that flag forces a wakeup when paired to a FULL_WAKE_LOCK flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP; mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName, null /* workSource */, null /* historyTag */); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */); } @@ -424,7 +438,7 @@ public class PowerManagerServiceTest { forceSleep(); mService.getBinderServiceInstance().wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name"); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); } /** @@ -445,7 +459,7 @@ public class PowerManagerServiceTest { .thenReturn(false); mService.readConfigurationLocked(); setPluggedIn(true); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen)) .thenReturn(true); mService.readConfigurationLocked(); @@ -460,20 +474,20 @@ public class PowerManagerServiceTest { when(mWirelessChargerDetectorMock.update(true /* isPowered */, BatteryManager.BATTERY_PLUGGED_WIRELESS)).thenReturn(false); setPluggedIn(true); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); // Test 3: // Do not wake up if the phone is being REMOVED from a wireless charger when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0); setPluggedIn(false); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); // Test 4: // Do not wake if we are dreaming. forceAwake(); // Needs to be awake first before it can dream. forceDream(); setPluggedIn(true); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DREAMING); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING); forceSleep(); // Test 5: @@ -486,7 +500,7 @@ public class PowerManagerServiceTest { com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug)) .thenReturn(false); setPluggedIn(false); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); Settings.Global.putInt( mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0); mUserSwitchedReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_USER_SWITCHED)); @@ -499,14 +513,14 @@ public class PowerManagerServiceTest { forceAwake(); forceDozing(); setPluggedIn(true); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING); // Test 7: // Finally, take away all the factors above and ensure the device wakes up! forceAwake(); forceSleep(); setPluggedIn(false); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); } @Test @@ -514,12 +528,12 @@ public class PowerManagerServiceTest { createService(); // Start with AWAKE state startSystem(); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); // Take a nap and verify. mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING); } @Test @@ -546,12 +560,12 @@ public class PowerManagerServiceTest { mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); // Verify that we start awake - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); // Grab the wakefulness value when PowerManager finally calls into the // native component to actually perform the suspend. when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> { - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); return true; }); @@ -559,7 +573,7 @@ public class PowerManagerServiceTest { assertThat(retval).isTrue(); // Still asleep when the function returns. - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); } @Test @@ -592,7 +606,7 @@ public class PowerManagerServiceTest { mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); // Verify that we start awake - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); // Create a wakelock mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg, @@ -647,7 +661,7 @@ public class PowerManagerServiceTest { // Start with AWAKE state startSystem(); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); assertTrue(isAcquired[0]); // Take a nap and verify we no longer hold the blocker @@ -657,7 +671,7 @@ public class PowerManagerServiceTest { when(mDreamManagerInternalMock.isDreaming()).thenReturn(true); mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING); assertFalse(isAcquired[0]); // Override the display state by DreamManager and verify is reacquires the blocker. @@ -737,7 +751,7 @@ public class PowerManagerServiceTest { createService(); startSystem(); SystemClock.sleep(20); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); } @FlakyTest @@ -757,7 +771,7 @@ public class PowerManagerServiceTest { null /* workSource */, null /* historyTag */); SystemClock.sleep(11); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); } @Test @@ -765,7 +779,7 @@ public class PowerManagerServiceTest { createService(); startSystem(); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE); verify(mNotifierMock, never()).onWakefulnessChangeStarted(anyInt(), anyInt(), anyLong()); } @@ -784,7 +798,7 @@ public class PowerManagerServiceTest { createService(); startSystem(); - assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP); + assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP); verify(mNotifierMock).onWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP), anyInt(), anyLong()); } diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java index 98cfc41ccfa8..30ab9cd2f875 100644 --- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java +++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java @@ -78,6 +78,11 @@ public class BatterySaverPolicyTest extends AndroidTestCase { return mDeviceSpecificConfigResId; } + @Override + void invalidatePowerSaveModeCaches() { + // Avoids an SELinux denial. + } + @VisibleForTesting void onChange() { onChange(true, null); 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 cbb760a7a871..99b4fd98f9a8 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java @@ -286,6 +286,52 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase { verify(af, never()).startWrite(); } + @Test + public void testRemoveConversationRunnable() throws Exception { + NotificationHistory nh = mock(NotificationHistory.class); + NotificationHistoryDatabase.RemoveConversationRunnable rcr = + mDataBase.new RemoveConversationRunnable("pkg", "convo"); + rcr.setNotificationHistory(nh); + + AtomicFile af = mock(AtomicFile.class); + when(af.getBaseFile()).thenReturn(new File(mRootDir, "af")); + mDataBase.mHistoryFiles.addLast(af); + + when(nh.removeConversationFromWrite("pkg", "convo")).thenReturn(true); + + mDataBase.mBuffer = mock(NotificationHistory.class); + + rcr.run(); + + verify(mDataBase.mBuffer).removeConversationFromWrite("pkg", "convo"); + verify(af).openRead(); + verify(nh).removeConversationFromWrite("pkg", "convo"); + verify(af).startWrite(); + } + + @Test + public void testRemoveConversationRunnable_noChanges() throws Exception { + NotificationHistory nh = mock(NotificationHistory.class); + NotificationHistoryDatabase.RemoveConversationRunnable rcr = + mDataBase.new RemoveConversationRunnable("pkg", "convo"); + rcr.setNotificationHistory(nh); + + AtomicFile af = mock(AtomicFile.class); + when(af.getBaseFile()).thenReturn(new File(mRootDir, "af")); + mDataBase.mHistoryFiles.addLast(af); + + when(nh.removeConversationFromWrite("pkg", "convo")).thenReturn(false); + + mDataBase.mBuffer = mock(NotificationHistory.class); + + rcr.run(); + + verify(mDataBase.mBuffer).removeConversationFromWrite("pkg", "convo"); + verify(af).openRead(); + verify(nh).removeConversationFromWrite("pkg", "convo"); + verify(af, never()).startWrite(); + } + private class TestFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider { public Map<File, Long> creationDates = new HashMap<>(); 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 2c548be185c9..f7c26091a7f4 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java @@ -303,6 +303,20 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase { } @Test + public void testDeleteConversation_userUnlocked() { + String pkg = "pkg"; + String convo = "convo"; + NotificationHistoryDatabase userHistory = mock(NotificationHistoryDatabase.class); + + mHistoryManager.onUserUnlocked(USER_SYSTEM); + mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistory); + + mHistoryManager.deleteConversation(pkg, 1, convo); + + verify(userHistory, times(1)).deleteConversation(pkg, convo); + } + + @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/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 3f690b105d8b..0adf15c8b637 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -3009,7 +3009,7 @@ public class PreferencesHelperTest extends UiServiceTestCase { NotificationChannel channel2 = new NotificationChannel("B person", "B fabulous person", IMPORTANCE_DEFAULT); - channel2.setConversationId(calls.getId(), channel.getName().toString()); + channel2.setConversationId(calls.getId(), channel2.getName().toString()); mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); Map<String, NotificationChannel> expected = new HashMap<>(); @@ -3036,4 +3036,46 @@ public class PreferencesHelperTest extends UiServiceTestCase { .isEqualTo(expectedGroup.get(convo.getNotificationChannel().getId())); } } + + @Test + public void testDeleteConversation() { + String convoId = "convo"; + NotificationChannel messages = + new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false); + NotificationChannel calls = + new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); + mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false); + + NotificationChannel channel = + new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); + channel.setConversationId(messages.getId(), convoId); + mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false); + + NotificationChannel noMatch = + new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); + noMatch.setConversationId(messages.getId(), "different convo"); + mHelper.createNotificationChannel(PKG_O, UID_O, noMatch, true, false); + + NotificationChannel channel2 = + new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); + channel2.setConversationId(calls.getId(), convoId); + mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false); + + assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false)); + assertEquals(channel2, + mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false)); + assertEquals(2, mHelper.deleteConversation(PKG_O, UID_O, convoId).size()); + + assertEquals(messages, + mHelper.getNotificationChannel(PKG_O, UID_O, messages.getId(), false)); + assertEquals(noMatch, + mHelper.getNotificationChannel(PKG_O, UID_O, noMatch.getId(), false)); + + assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false)); + assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false)); + assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), true)); + assertEquals(channel2, + mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), true)); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 70e5ee71b448..683fca46923f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -209,6 +209,7 @@ public class AppWindowTokenTests extends WindowTestsBase { } @Test + @FlakyTest(bugId = 149760957) public void testSizeCompatBounds() { // Disable the real configuration resolving because we only simulate partial flow. // TODO: Have test use full flow. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java index 8ac1d24333be..cc9173ad12ad 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java @@ -40,6 +40,8 @@ import static java.util.stream.Collectors.toList; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; +import androidx.test.filters.FlakyTest; + import org.hamcrest.CustomTypeSafeMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; @@ -65,6 +67,7 @@ public class DisplayAreaPolicyBuilderTest { private TestWindowManagerPolicy mPolicy = new TestWindowManagerPolicy(null, null); @Test + @FlakyTest(bugId = 149760939) public void testBuilder() { WindowManagerService wms = mSystemServices.getWindowManagerService(); DisplayArea.Root root = new SurfacelessDisplayAreaRoot(wms); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index c19312debce3..ba577454f9d5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -599,6 +599,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { } @Test + @FlakyTest(bugId = 149760800) public void layoutWindowLw_withLongEdgeDisplayCutout() { addLongEdgeDisplayCutout(); @@ -618,6 +619,7 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { } @Test + @FlakyTest(bugId = 149760800) public void layoutWindowLw_withLongEdgeDisplayCutout_never() { addLongEdgeDisplayCutout(); diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java index eda1fb8839a5..b5663bd7e26b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java +++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java @@ -255,4 +255,9 @@ public class StubTransaction extends SurfaceControl.Transaction { int priority) { return this; } + + @Override + public SurfaceControl.Transaction unsetColor(SurfaceControl sc) { + return this; + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 8ad75053060f..55d12dbd0abb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -137,6 +137,7 @@ public class SystemServicesTestRule implements TestRule { } throw t; } + if (throwable != null) throw throwable; } } }; diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java new file mode 100644 index 000000000000..4056c7195c9b --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRuleTest.java @@ -0,0 +1,74 @@ +/* + * 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.wm; + +import static junit.framework.Assert.assertTrue; + +import android.platform.test.annotations.Presubmit; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runners.model.Statement; + +import java.io.IOException; + +@Presubmit +public class SystemServicesTestRuleTest { + @Rule + public ExpectedException mExpectedException = ExpectedException.none(); + + @Test + public void testRule_rethrows_unchecked_exceptions() throws Throwable { + final SystemServicesTestRule mWmsRule = new SystemServicesTestRule(); + Statement statement = new Statement() { + @Override + public void evaluate() throws Throwable { + throw new RuntimeException("A failing test!"); + } + }; + mExpectedException.expect(RuntimeException.class); + mWmsRule.apply(statement, null /* Description*/).evaluate(); + } + + @Test + public void testRule_rethrows_checked_exceptions() throws Throwable { + final SystemServicesTestRule mWmsRule = new SystemServicesTestRule(); + Statement statement = new Statement() { + @Override + public void evaluate() throws Throwable { + throw new IOException("A failing test!"); + } + }; + mExpectedException.expect(IOException.class); + mWmsRule.apply(statement, null /* Description*/).evaluate(); + } + + @Test + public void testRule_ranSuccessfully() throws Throwable { + final boolean[] testRan = {false}; + final SystemServicesTestRule mWmsRule = new SystemServicesTestRule(); + Statement statement = new Statement() { + @Override + public void evaluate() throws Throwable { + testRan[0] = true; + } + }; + mWmsRule.apply(statement, null /* Description*/).evaluate(); + assertTrue(testRan[0]); + } +} diff --git a/telephony/java/android/service/carrier/CarrierService.java b/telephony/java/android/service/carrier/CarrierService.java index eefc1b70bac9..d06ec11f3e61 100644 --- a/telephony/java/android/service/carrier/CarrierService.java +++ b/telephony/java/android/service/carrier/CarrierService.java @@ -25,6 +25,9 @@ import android.os.ResultReceiver; import android.telephony.TelephonyRegistryManager; import android.util.Log; +import java.io.FileDescriptor; +import java.io.PrintWriter; + /** * A service that exposes carrier-specific functionality to the system. * <p> @@ -156,5 +159,10 @@ public abstract class CarrierService extends Service { result.send(RESULT_ERROR, null); } } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + CarrierService.this.dump(fd, pw, args); + } } } diff --git a/tests/WindowInsetsTests/Android.bp b/tests/WindowInsetsTests/Android.bp index 12395e70468d..7272152dc257 100644 --- a/tests/WindowInsetsTests/Android.bp +++ b/tests/WindowInsetsTests/Android.bp @@ -18,5 +18,10 @@ android_test { resource_dirs: ["res"], certificate: "platform", platform_apis: true, + static_libs: [ + "androidx.core_core", + "androidx.appcompat_appcompat", + "com.google.android.material_material", + ], } diff --git a/tests/WindowInsetsTests/AndroidManifest.xml b/tests/WindowInsetsTests/AndroidManifest.xml index 8d33f70c33a2..0f6282e20b41 100644 --- a/tests/WindowInsetsTests/AndroidManifest.xml +++ b/tests/WindowInsetsTests/AndroidManifest.xml @@ -20,7 +20,7 @@ <application android:label="@string/activity_title"> <activity android:name=".WindowInsetsActivity" - android:theme="@android:style/Theme.Material" + android:theme="@style/appTheme" android:windowSoftInputMode="adjustResize"> <intent-filter> diff --git a/tests/WindowInsetsTests/res/drawable/bubble.xml b/tests/WindowInsetsTests/res/drawable/bubble.xml new file mode 100644 index 000000000000..26deb1e59e41 --- /dev/null +++ b/tests/WindowInsetsTests/res/drawable/bubble.xml @@ -0,0 +1,23 @@ +<?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. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/bubble" /> + <corners android:radius="@dimen/bubble_corner" /> + <padding android:left="@dimen/bubble_padding_side" android:top="@dimen/bubble_padding" + android:right="@dimen/bubble_padding_side" android:bottom="@dimen/bubble_padding" /> +</shape>
\ No newline at end of file diff --git a/tests/WindowInsetsTests/res/drawable/bubble_self.xml b/tests/WindowInsetsTests/res/drawable/bubble_self.xml new file mode 100644 index 000000000000..5f098a2fea60 --- /dev/null +++ b/tests/WindowInsetsTests/res/drawable/bubble_self.xml @@ -0,0 +1,23 @@ +<?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. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@color/bubble_self" /> + <corners android:radius="@dimen/bubble_corner" /> + <padding android:left="@dimen/bubble_padding_side" android:top="@dimen/bubble_padding" + android:right="@dimen/bubble_padding_side" android:bottom="@dimen/bubble_padding" /> +</shape>
\ No newline at end of file diff --git a/tests/WindowInsetsTests/res/drawable/ic_send.xml b/tests/WindowInsetsTests/res/drawable/ic_send.xml new file mode 100644 index 000000000000..15bc411e85fb --- /dev/null +++ b/tests/WindowInsetsTests/res/drawable/ic_send.xml @@ -0,0 +1,27 @@ +<?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. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:autoMirrored="true" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + <path + android:fillColor="#FF000000" + android:pathData="M4.02,42.0L46.0,24.0 4.02,6.0 4.0,20.0l30.0,4.0 -30.0,4.0z"/> +</vector> diff --git a/tests/WindowInsetsTests/res/layout/message.xml b/tests/WindowInsetsTests/res/layout/message.xml new file mode 100644 index 000000000000..d6b29c33f662 --- /dev/null +++ b/tests/WindowInsetsTests/res/layout/message.xml @@ -0,0 +1,26 @@ +<?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. + --> + +<TextView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/bubble" + android:textSize="32sp" + android:text="Hello World"> + +</TextView>
\ No newline at end of file diff --git a/tests/WindowInsetsTests/res/layout/message_self.xml b/tests/WindowInsetsTests/res/layout/message_self.xml new file mode 100644 index 000000000000..de34e4896331 --- /dev/null +++ b/tests/WindowInsetsTests/res/layout/message_self.xml @@ -0,0 +1,30 @@ +<?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. + --> + +<merge> + <include + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + layout="@layout/message"> + <aapt:attr name="android:theme"> + <style> + <item name="android:layout_gravity">end</item> + <item name="bubbleBackground">@color/bubble_self</item> + </style> + </aapt:attr> + </include> +</merge> diff --git a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml b/tests/WindowInsetsTests/res/layout/window_inset_activity.xml index 38e00298f49f..1b51c4f83fe0 100644 --- a/tests/WindowInsetsTests/res/layout/window_inset_activity.xml +++ b/tests/WindowInsetsTests/res/layout/window_inset_activity.xml @@ -17,17 +17,82 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center" + android:clipToPadding="false" android:id="@+id/root"> - <Button - android:id="@+id/button" - android:layout_width="wrap_content" - android:layout_height="48dp" - android:text="Hello insets" /> + <androidx.appcompat.widget.Toolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + /> + <FrameLayout + android:id="@+id/scrollView" + android:layout_height="0dp" + android:layout_width="match_parent" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:layout_weight="1"> + + <LinearLayout + android:orientation="vertical" + android:layout_gravity="bottom" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/bubble" + android:text="Hey, look at this buttery smooth animation!" /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/bubble_self" + android:text="Wow, that's pretty neat, how does this work?" /> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + style="@style/bubble" + android:text="Using the new WindowInsets animation system of course!" /> + + </LinearLayout> + + </FrameLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="8dp" + android:paddingEnd="8dp" + android:id="@+id/editText"> + + <com.google.android.material.textfield.TextInputLayout + style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1"> + + <com.google.android.material.textfield.TextInputEditText + android:hint="Text message" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> + + </com.google.android.material.textfield.TextInputLayout> + + <com.google.android.material.floatingactionbutton.FloatingActionButton + android:id="@+id/floating_action_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + app:elevation="0dp" + app:fabSize="mini" + app:srcCompat="@drawable/ic_send"/> + + </LinearLayout> </LinearLayout> diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml index 242823d06fc8..2b8e5f3da362 100644 --- a/tests/WindowInsetsTests/res/values/strings.xml +++ b/tests/WindowInsetsTests/res/values/strings.xml @@ -16,5 +16,5 @@ --> <resources> - <string name="activity_title">Window Insets Tests</string> + <string name="activity_title">New Insets Chat</string> </resources> diff --git a/tests/WindowInsetsTests/res/values/styles.xml b/tests/WindowInsetsTests/res/values/styles.xml new file mode 100644 index 000000000000..220671fb8e71 --- /dev/null +++ b/tests/WindowInsetsTests/res/values/styles.xml @@ -0,0 +1,67 @@ +<?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. + --> + +<resources> + + <style name="appTheme" parent="@style/Theme.MaterialComponents.Light"> + <item name="windowActionBar">false</item> + <item name="windowNoTitle">true</item> + + <item name="colorPrimary">@color/primaryColor</item> + <item name="colorPrimaryDark">@color/primaryDarkColor</item> + <item name="colorSecondary">?attr/colorPrimary</item> + <item name="colorOnSecondary">@color/primaryTextColor</item> + + <!-- Window decor --> + <item name="android:statusBarColor">#ffffff</item> + <item name="android:windowLightStatusBar">true</item> + <item name="android:windowLightNavigationBar">true</item> + <item name="android:navigationBarColor">#ffffff</item> + + </style> + + <style name="bubble_base" parent=""> + <item name="android:textSize">20sp</item> + <item name="android:layout_marginBottom">16dp</item> + </style> + + <style name="bubble" parent="@style/bubble_base"> + <item name="android:layout_marginEnd">56dp</item> + <item name="android:background">@drawable/bubble</item> + <item name="android:layout_gravity">start</item> + </style> + + <style name="bubble_self" parent="@style/bubble_base"> + <item name="android:layout_marginStart">56dp</item> + <item name="android:background">@drawable/bubble_self</item> + <item name="android:layout_gravity">end</item> + </style> + + <color name="primaryColor">#1c3fef</color> + <color name="primaryLightColor">#6f6bff</color> + <color name="primaryDarkColor">#0016bb</color> + <color name="primaryTextColor">#ffffff</color> + + <color name="bubble">#eeeeee</color> + <color name="bubble_self">#D8DCF0</color> + + <dimen name="bubble_corner">16dp</dimen> + <dimen name="bubble_padding">8dp</dimen> + <dimen name="bubble_padding_side">16dp</dimen> + + +</resources>
\ No newline at end of file diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java index b9f5ac0270b2..8e6f1985a7d9 100644 --- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java @@ -18,134 +18,216 @@ package com.google.android.test.windowinsetstests; import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP; -import android.animation.ObjectAnimator; -import android.animation.TypeEvaluator; -import android.animation.ValueAnimator; -import android.app.Activity; +import static java.lang.Math.max; +import static java.lang.Math.min; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; import android.graphics.Insets; import android.os.Bundle; -import android.util.Property; +import android.util.AttributeSet; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewConfiguration; +import android.view.Window; import android.view.WindowInsets; import android.view.WindowInsets.Type; import android.view.WindowInsetsAnimation; +import android.view.WindowInsetsAnimation.Callback; import android.view.WindowInsetsAnimationControlListener; import android.view.WindowInsetsAnimationController; +import android.view.animation.LinearInterpolator; +import android.widget.LinearLayout; -import com.google.android.test.windowinsetstests.R; +import androidx.appcompat.app.AppCompatActivity; +import java.util.ArrayList; import java.util.List; -public class WindowInsetsActivity extends Activity { +public class WindowInsetsActivity extends AppCompatActivity { private View mRoot; - private View mButton; - private static class InsetsProperty extends Property<WindowInsetsAnimationController, Insets> { + final ArrayList<Transition> mTransitions = new ArrayList<>(); - private final View mViewToAnimate; - private final Insets mShowingInsets; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.window_inset_activity); - public InsetsProperty(View viewToAnimate, Insets showingInsets) { - super(Insets.class, "Insets"); - mViewToAnimate = viewToAnimate; - mShowingInsets = showingInsets; - } + setSupportActionBar(findViewById(R.id.toolbar)); - @Override - public Insets get(WindowInsetsAnimationController object) { - return object.getCurrentInsets(); - } + mRoot = findViewById(R.id.root); + mRoot.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); + + mTransitions.add(new Transition(findViewById(R.id.scrollView))); + mTransitions.add(new Transition(findViewById(R.id.editText))); + + mRoot.setOnTouchListener(new View.OnTouchListener() { + private final ViewConfiguration mViewConfiguration = + ViewConfiguration.get(WindowInsetsActivity.this); + WindowInsetsAnimationController mAnimationController; + WindowInsetsAnimationControlListener mCurrentRequest; + boolean mRequestedController = false; + float mDown = 0; + float mCurrent = 0; + Insets mDownInsets = Insets.NONE; + boolean mShownAtDown; - @Override - public void set(WindowInsetsAnimationController object, Insets value) { - object.setInsetsAndAlpha(value, 1.0f, 0.5f); - if (mShowingInsets.bottom != 0) { - mViewToAnimate.setTranslationY(mShowingInsets.bottom - value.bottom); - } else if (mShowingInsets.right != 0) { - mViewToAnimate.setTranslationX(mShowingInsets.right - value.right); - } else if (mShowingInsets.left != 0) { - mViewToAnimate.setTranslationX(value.left - mShowingInsets.left); + @Override + public boolean onTouch(View v, MotionEvent event) { + mCurrent = event.getY(); + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mDown = event.getY(); + mDownInsets = v.getRootWindowInsets().getInsets(Type.ime()); + mShownAtDown = v.getRootWindowInsets().isVisible(Type.ime()); + mRequestedController = false; + mCurrentRequest = null; + break; + case MotionEvent.ACTION_MOVE: + if (mAnimationController != null) { + updateInset(); + } else if (Math.abs(mDown - event.getY()) + > mViewConfiguration.getScaledTouchSlop() + && !mRequestedController) { + mRequestedController = true; + v.getWindowInsetsController().controlWindowInsetsAnimation(Type.ime(), + 1000, new LinearInterpolator(), + mCurrentRequest = new WindowInsetsAnimationControlListener() { + @Override + public void onReady( + @NonNull WindowInsetsAnimationController controller, + int types) { + if (mCurrentRequest == this) { + mAnimationController = controller; + updateInset(); + } else { + controller.finish(mShownAtDown); + } + } + + @Override + public void onCancelled() { + mAnimationController = null; + } + }); + } + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + if (mAnimationController != null) { + boolean isCancel = event.getAction() == MotionEvent.ACTION_CANCEL; + mAnimationController.finish(isCancel ? mShownAtDown : !mShownAtDown); + mAnimationController = null; + } + mRequestedController = false; + mCurrentRequest = null; + break; + } + return true; } - } - }; - float startY; - float endY; - WindowInsetsAnimation imeAnim; + private void updateInset() { + int inset = (int) (mDownInsets.bottom + (mDown - mCurrent)); + final int hidden = mAnimationController.getHiddenStateInsets().bottom; + final int shown = mAnimationController.getShownStateInsets().bottom; + final int start = mShownAtDown ? shown : hidden; + final int end = mShownAtDown ? hidden : shown; + inset = max(inset, hidden); + inset = min(inset, shown); + mAnimationController.setInsetsAndAlpha( + Insets.of(0, 0, 0, inset), + 1f, (inset - start) / (float)(end - start)); + } + }); - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.window_inset_activity); - mRoot = findViewById(R.id.root); - mButton = findViewById(R.id.button); - mButton.setOnClickListener(v -> { - if (!v.getRootWindowInsets().isVisible(Type.ime())) { - v.getWindowInsetsController().show(Type.ime()); - } else { - v.getWindowInsetsController().hide(Type.ime()); + mRoot.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + @Override + public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + mRoot.setPadding(insets.getSystemWindowInsetLeft(), + insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), + insets.getSystemWindowInsetBottom()); + return WindowInsets.CONSUMED; } }); - mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimation.Callback( - DISPATCH_MODE_STOP) { + + mRoot.setWindowInsetsAnimationCallback(new Callback(DISPATCH_MODE_STOP) { @Override public void onPrepare(WindowInsetsAnimation animation) { - if ((animation.getTypeMask() & Type.ime()) != 0) { - imeAnim = animation; - } - startY = mButton.getTop(); + mTransitions.forEach(it -> it.onPrepare(animation)); } @Override public WindowInsets onProgress(WindowInsets insets, - List<WindowInsetsAnimation> runningAnimations) { - mButton.setY(startY + (endY - startY) * imeAnim.getInterpolatedFraction()); + @NonNull List<WindowInsetsAnimation> runningAnimations) { + mTransitions.forEach(it -> it.onProgress(insets)); return insets; } @Override public WindowInsetsAnimation.Bounds onStart(WindowInsetsAnimation animation, WindowInsetsAnimation.Bounds bounds) { - endY = mButton.getTop(); + mTransitions.forEach(Transition::onStart); return bounds; } @Override public void onEnd(WindowInsetsAnimation animation) { - imeAnim = null; + mTransitions.forEach(it -> it.onFinish(animation)); } }); } @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); + public void onResume() { + super.onResume(); + // TODO: move this to onCreate once setDecorFitsSystemWindows can be safely called there. + getWindow().getDecorView().post(() -> getWindow().setDecorFitsSystemWindows(false)); + } - TypeEvaluator<Insets> evaluator = (fraction, startValue, endValue) -> Insets.of( - (int)(startValue.left + fraction * (endValue.left - startValue.left)), - (int)(startValue.top + fraction * (endValue.top - startValue.top)), - (int)(startValue.right + fraction * (endValue.right - startValue.right)), - (int)(startValue.bottom + fraction * (endValue.bottom - startValue.bottom))); + static class Transition { + private int mEndBottom; + private int mStartBottom; + private final View mView; + private WindowInsetsAnimation mInsetsAnimation; - WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() { - @Override - public void onReady(WindowInsetsAnimationController controller, int types) { - ObjectAnimator animator = ObjectAnimator.ofObject(controller, - new InsetsProperty(findViewById(R.id.button), - controller.getShownStateInsets()), - evaluator, controller.getShownStateInsets(), - controller.getHiddenStateInsets()); - animator.setRepeatCount(ValueAnimator.INFINITE); - animator.setRepeatMode(ValueAnimator.REVERSE); - animator.start(); + Transition(View root) { + mView = root; + } + + void onPrepare(WindowInsetsAnimation animation) { + if ((animation.getTypeMask() & Type.ime()) != 0) { + mInsetsAnimation = animation; } + mStartBottom = mView.getBottom(); + } - @Override - public void onCancelled() { + void onProgress(WindowInsets insets) { + mView.setY(mStartBottom + (mEndBottom - mStartBottom) + * mInsetsAnimation.getInterpolatedFraction() + - mView.getHeight()); + } + + void onStart() { + mEndBottom = mView.getBottom(); + } + void onFinish(WindowInsetsAnimation animation) { + if (mInsetsAnimation == animation) { + mInsetsAnimation = null; } - }; + } + } + + static class ImeLinearLayout extends LinearLayout { + + public ImeLinearLayout(Context context, + @Nullable AttributeSet attrs) { + super(context, attrs); + } } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 957683e05de7..08869751b93e 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -204,6 +204,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.KeyStore; import android.system.Os; import android.test.mock.MockContentResolver; import android.text.TextUtils; @@ -1019,7 +1020,7 @@ public class ConnectivityServiceTest { public MockVpn(int userId) { super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService, - userId); + userId, mock(KeyStore.class)); } public void setNetworkAgent(TestNetworkAgentWrapper agent) { diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index ac1c51837e93..0e3b79761319 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -72,6 +72,7 @@ import android.os.Looper; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; +import android.provider.Settings; import android.security.Credentials; import android.security.KeyStore; import android.util.ArrayMap; @@ -260,17 +261,17 @@ public class VpnTest { assertFalse(vpn.getLockdown()); // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList())); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList(), mKeyStore)); assertTrue(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList())); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList(), mKeyStore)); assertTrue(vpn.getAlwaysOn()); assertTrue(vpn.getLockdown()); // Remove always-on configuration. - assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList())); + assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList(), mKeyStore)); assertFalse(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); } @@ -284,11 +285,11 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore)); assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) @@ -297,7 +298,7 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[1]); // Switch to another app. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) @@ -316,7 +317,8 @@ public class VpnTest { final UidRange user = UidRange.createForUser(primaryUser.id); // Set always-on with lockdown and whitelist app PKGS[2] from lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[2]))); + assertTrue(vpn.setAlwaysOnPackage( + PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) @@ -325,7 +327,8 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]); // Change whitelisted app to PKGS[3]. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.singletonList(PKGS[3]))); + assertTrue(vpn.setAlwaysOnPackage( + PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) })); @@ -337,7 +340,8 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]); // Change the VPN app. - assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[3]))); + assertTrue(vpn.setAlwaysOnPackage( + PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1) @@ -350,7 +354,7 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]); // Remove the whitelist. - assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) @@ -363,7 +367,8 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[0]); // Add the whitelist. - assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList(PKGS[1]))); + assertTrue(vpn.setAlwaysOnPackage( + PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] { new UidRange(user.start + PKG_UIDS[0] + 1, user.stop) })); @@ -375,12 +380,13 @@ public class VpnTest { assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]); // Try whitelisting a package with a comma, should be rejected. - assertFalse(vpn.setAlwaysOnPackage(PKGS[0], true, Collections.singletonList("a.b,c.d"))); + assertFalse(vpn.setAlwaysOnPackage( + PKGS[0], true, Collections.singletonList("a.b,c.d"), mKeyStore)); // Pass a non-existent packages in the whitelist, they (and only they) should be ignored. // Whitelisted package should change from PGKS[1] to PKGS[2]. - assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, - Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"))); + assertTrue(vpn.setAlwaysOnPackage( + PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{ new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), new UidRange(user.start + PKG_UIDS[1] + 1, user.stop) @@ -405,7 +411,7 @@ public class VpnTest { final UidRange profile = UidRange.createForUser(tempProfile.id); // Set lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore)); verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] { new UidRange(user.start, user.start + PKG_UIDS[3] - 1), new UidRange(user.start + PKG_UIDS[3] + 1, user.stop) @@ -499,22 +505,22 @@ public class VpnTest { .thenReturn(Collections.singletonList(resInfo)); // null package name should return false - assertFalse(vpn.isAlwaysOnPackageSupported(null)); + assertFalse(vpn.isAlwaysOnPackageSupported(null, mKeyStore)); // Pre-N apps are not supported appInfo.targetSdkVersion = VERSION_CODES.M; - assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0])); + assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore)); // N+ apps are supported by default appInfo.targetSdkVersion = VERSION_CODES.N; - assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0])); + assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore)); // Apps that opt out explicitly are not supported appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT; Bundle metaData = new Bundle(); metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false); svcInfo.metaData = metaData; - assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0])); + assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore)); } @Test @@ -531,7 +537,7 @@ public class VpnTest { .cancelAsUser(anyString(), anyInt(), eq(userHandle)); // Start showing a notification for disconnected once always-on. - vpn.setAlwaysOnPackage(PKGS[0], false, null); + vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore); order.verify(mNotificationManager) .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); @@ -545,7 +551,7 @@ public class VpnTest { .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle)); // Notification should be cleared after unsetting always-on package. - vpn.setAlwaysOnPackage(null, false, null); + vpn.setAlwaysOnPackage(null, false, null, mKeyStore); order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle)); } @@ -920,12 +926,48 @@ public class VpnTest { eq(AppOpsManager.MODE_IGNORED)); } + private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) { + assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null, mKeyStore)); + + verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); + verify(mAppOps).setMode( + eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG), + eq(AppOpsManager.MODE_ALLOWED)); + + verify(mSystemServices).settingsSecurePutStringForUser( + eq(Settings.Secure.ALWAYS_ON_VPN_APP), eq(TEST_VPN_PKG), eq(primaryUser.id)); + verify(mSystemServices).settingsSecurePutIntForUser( + eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN), eq(lockdownEnabled ? 1 : 0), + eq(primaryUser.id)); + verify(mSystemServices).settingsSecurePutStringForUser( + eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST), eq(""), eq(primaryUser.id)); + } + + @Test + public void testSetAndStartAlwaysOnVpn() throws Exception { + final Vpn vpn = createVpn(primaryUser.id); + setMockedUsers(primaryUser); + + // UID checks must return a different UID; otherwise it'll be treated as already prepared. + final int uid = Process.myUid() + 1; + when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt())) + .thenReturn(uid); + when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + .thenReturn(mVpnProfile.encode()); + + setAndVerifyAlwaysOnPackage(vpn, uid, false); + assertTrue(vpn.startAlwaysOnVpn(mKeyStore)); + + // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in + // a subsequent CL. + } + /** * Mock some methods of vpn object. */ private Vpn createVpn(@UserIdInt int userId) { return new Vpn(Looper.myLooper(), mContext, mNetService, - userId, mSystemServices, mIkev2SessionCreator); + userId, mKeyStore, mSystemServices, mIkev2SessionCreator); } private static void assertBlocked(Vpn vpn, int... uids) { diff --git a/wifi/Android.bp b/wifi/Android.bp index 7669983f20aa..9f26203a3842 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -48,7 +48,7 @@ filegroup { // to a separate package. "java/android/net/wifi/WifiNetworkScoreCache.java", "java/android/net/wifi/WifiOemMigrationHook.java", - "java/android/net/wifi/wificond/*.java", + "java/android/net/wifi/nl80211/*.java", ":libwificond_ipc_aidl", ], } diff --git a/wifi/java/android/net/wifi/wificond/ChannelSettings.java b/wifi/java/android/net/wifi/nl80211/ChannelSettings.java index c2d65b581491..4c14fd499c28 100644 --- a/wifi/java/android/net/wifi/wificond/ChannelSettings.java +++ b/wifi/java/android/net/wifi/nl80211/ChannelSettings.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.os.Parcel; import android.os.Parcelable; diff --git a/wifi/java/android/net/wifi/wificond/DeviceWiphyCapabilities.java b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java index 13ae3b322841..a045aad9f64c 100644 --- a/wifi/java/android/net/wifi/wificond/DeviceWiphyCapabilities.java +++ b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.annotation.NonNull; import android.annotation.SystemApi; diff --git a/wifi/java/android/net/wifi/wificond/HiddenNetwork.java b/wifi/java/android/net/wifi/nl80211/HiddenNetwork.java index 38dacea77488..b1475b2c7b43 100644 --- a/wifi/java/android/net/wifi/wificond/HiddenNetwork.java +++ b/wifi/java/android/net/wifi/nl80211/HiddenNetwork.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.os.Parcel; import android.os.Parcelable; diff --git a/wifi/java/android/net/wifi/wificond/NativeScanResult.java b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java index bd99476afe43..a8e999973fe8 100644 --- a/wifi/java/android/net/wifi/wificond/NativeScanResult.java +++ b/wifi/java/android/net/wifi/nl80211/NativeScanResult.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.annotation.IntDef; import android.annotation.NonNull; diff --git a/wifi/java/android/net/wifi/wificond/NativeWifiClient.java b/wifi/java/android/net/wifi/nl80211/NativeWifiClient.java index 9ad2a2769add..984d7d034302 100644 --- a/wifi/java/android/net/wifi/wificond/NativeWifiClient.java +++ b/wifi/java/android/net/wifi/nl80211/NativeWifiClient.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.annotation.NonNull; import android.annotation.Nullable; diff --git a/wifi/java/android/net/wifi/wificond/PnoNetwork.java b/wifi/java/android/net/wifi/nl80211/PnoNetwork.java index ca0b1cfb6223..e8eff09583b9 100644 --- a/wifi/java/android/net/wifi/wificond/PnoNetwork.java +++ b/wifi/java/android/net/wifi/nl80211/PnoNetwork.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.annotation.NonNull; import android.annotation.SystemApi; diff --git a/wifi/java/android/net/wifi/wificond/PnoSettings.java b/wifi/java/android/net/wifi/nl80211/PnoSettings.java index 533d37d3a23a..00ebe624ba0d 100644 --- a/wifi/java/android/net/wifi/wificond/PnoSettings.java +++ b/wifi/java/android/net/wifi/nl80211/PnoSettings.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.annotation.DurationMillisLong; import android.annotation.NonNull; diff --git a/wifi/java/android/net/wifi/wificond/RadioChainInfo.java b/wifi/java/android/net/wifi/nl80211/RadioChainInfo.java index 97c0ee9d1c2c..2c12163dc9a1 100644 --- a/wifi/java/android/net/wifi/wificond/RadioChainInfo.java +++ b/wifi/java/android/net/wifi/nl80211/RadioChainInfo.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.annotation.NonNull; import android.annotation.SystemApi; diff --git a/wifi/java/android/net/wifi/wificond/SingleScanSettings.java b/wifi/java/android/net/wifi/nl80211/SingleScanSettings.java index 8c341b8bd916..24b1854fbf6c 100644 --- a/wifi/java/android/net/wifi/wificond/SingleScanSettings.java +++ b/wifi/java/android/net/wifi/nl80211/SingleScanSettings.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.os.Parcel; import android.os.Parcelable; diff --git a/wifi/java/android/net/wifi/wificond/WifiNl80211Manager.java b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java index 89f642fdbb66..3215246a9c1f 100644 --- a/wifi/java/android/net/wifi/wificond/WifiNl80211Manager.java +++ b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import android.annotation.CallbackExecutor; import android.annotation.IntDef; diff --git a/wifi/tests/src/android/net/wifi/wificond/DeviceWiphyCapabilitiesTest.java b/wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java index 8e3627acd4ed..7b900fec70a8 100644 --- a/wifi/tests/src/android/net/wifi/wificond/DeviceWiphyCapabilitiesTest.java +++ b/wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import static org.junit.Assert.assertEquals; @@ -27,7 +27,7 @@ import org.junit.Before; import org.junit.Test; /** - * Unit tests for {@link android.net.wifi.wificond.DeviceWiphyCapabilities}. + * Unit tests for {@link android.net.wifi.nl80211.DeviceWiphyCapabilities}. */ @SmallTest public class DeviceWiphyCapabilitiesTest { diff --git a/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java b/wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java index 0df170f8786c..8ddd1899179a 100644 --- a/wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java +++ b/wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -30,7 +30,7 @@ import java.util.ArrayList; import java.util.Arrays; /** - * Unit tests for {@link android.net.wifi.wificond.NativeScanResult}. + * Unit tests for {@link android.net.wifi.nl80211.NativeScanResult}. */ @SmallTest public class NativeScanResultTest { diff --git a/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java b/wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java index 9439c796e1a5..dec1db8d274e 100644 --- a/wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java +++ b/wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import static org.junit.Assert.assertEquals; @@ -30,7 +30,7 @@ import java.util.Arrays; import java.util.HashMap; /** - * Unit tests for {@link android.net.wifi.wificond.PnoSettings}. + * Unit tests for {@link android.net.wifi.nl80211.PnoSettings}. */ @SmallTest public class PnoSettingsTest { diff --git a/wifi/tests/src/android/net/wifi/wificond/SingleScanSettingsTest.java b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java index f20ec4788655..905920888012 100644 --- a/wifi/tests/src/android/net/wifi/wificond/SingleScanSettingsTest.java +++ b/wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import static org.junit.Assert.assertEquals; @@ -30,7 +30,7 @@ import java.util.Arrays; import java.util.HashMap; /** - * Unit tests for {@link android.net.wifi.wificond.SingleScanSettingsResult}. + * Unit tests for {@link android.net.wifi.nl80211.SingleScanSettingsResult}. */ @SmallTest public class SingleScanSettingsTest { diff --git a/wifi/tests/src/android/net/wifi/wificond/WifiNl80211ManagerTest.java b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java index a8184068ff5a..9ee0acbfbaa2 100644 --- a/wifi/tests/src/android/net/wifi/wificond/WifiNl80211ManagerTest.java +++ b/wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package android.net.wifi.wificond; +package android.net.wifi.nl80211; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -71,7 +71,7 @@ import java.util.List; import java.util.Set; /** - * Unit tests for {@link android.net.wifi.wificond.WifiNl80211Manager}. + * Unit tests for {@link android.net.wifi.nl80211.WifiNl80211Manager}. */ @SmallTest public class WifiNl80211ManagerTest { |