Merge changes Id701f7c7,I660bbcd1
* changes:
Add Bitmap#getHardwareBuffer
[HWUI] Remove private references to AHardwareBuffer
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 f6af09c..02df5e2 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 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 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 @@
runShellCommand("cmd jobscheduler run -f android 191934935");
}
- @Ignore
@Test
public void testComputeDigest() throws Exception {
mAtraceUtils.startTrace(ATRACE_CATEGORY_SYSTEM_SERVER);
@@ -104,7 +104,8 @@
durations.clear();
collectDigestDurationsFromTrace(parser, durations);
- // TODO: get and delete blobId before next iteration.
+
+ deleteBlob(blobData.getBlobHandle());
}
} finally {
mAtraceUtils.stopTrace();
@@ -137,6 +138,16 @@
}
}
+ 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 9c3bd81..bcef8ce 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 @@
*/
// 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 1efdbda..d4ceabd 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 @@
}
}
+ 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 3ac30f8..d58294b 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 @@
return runClearAllSessions(pw);
case "clear-all-blobs":
return runClearAllBlobs(pw);
+ case "delete-blob":
+ return runDeleteBlob(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -68,6 +73,17 @@
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 @@
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 @@
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 c8aa526..0e93110 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -27,6 +27,7 @@
"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 @@
"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 23637eb..140b6ae 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4351,7 +4351,7 @@
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 @@
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 @@
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 @@
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 @@
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 {
@@ -43545,7 +43541,6 @@
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
@@ -43556,30 +43551,6 @@
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();
@@ -72122,6 +72093,7 @@
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 2a8f04f..569e838 100644
--- a/api/lint-baseline.txt
+++ b/api/lint-baseline.txt
@@ -561,6 +561,9 @@
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 5b6bd21..79a9b21 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -371,8 +371,8 @@
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,6 +8163,174 @@
}
+package android.net.wifi.nl80211 {
+
+ public final class DeviceWiphyCapabilities implements android.os.Parcelable {
+ ctor public DeviceWiphyCapabilities();
+ method public int describeContents();
+ method public int getMaxNumberRxSpatialStreams();
+ method public int getMaxNumberTxSpatialStreams();
+ method public boolean isChannelWidthSupported(int);
+ method public boolean isWifiStandardSupported(int);
+ method public void setChannelWidthSupported(int, boolean);
+ method public void setMaxNumberRxSpatialStreams(int);
+ 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.nl80211.DeviceWiphyCapabilities> CREATOR;
+ }
+
+ public final class NativeScanResult implements android.os.Parcelable {
+ ctor public NativeScanResult();
+ method public int describeContents();
+ method @Nullable public android.net.MacAddress getBssid();
+ method public int getCapabilities();
+ method public int getFrequencyMhz();
+ method @NonNull public byte[] getInformationElements();
+ 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();
+ method public boolean isAssociated();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int BSS_CAPABILITY_APSD = 2048; // 0x800
+ field public static final int BSS_CAPABILITY_CF_POLLABLE = 4; // 0x4
+ field public static final int BSS_CAPABILITY_CF_POLL_REQUEST = 8; // 0x8
+ field public static final int BSS_CAPABILITY_CHANNEL_AGILITY = 128; // 0x80
+ field public static final int BSS_CAPABILITY_DELAYED_BLOCK_ACK = 16384; // 0x4000
+ field public static final int BSS_CAPABILITY_DSSS_OFDM = 8192; // 0x2000
+ field public static final int BSS_CAPABILITY_ESS = 1; // 0x1
+ field public static final int BSS_CAPABILITY_IBSS = 2; // 0x2
+ field public static final int BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK = 32768; // 0x8000
+ field public static final int BSS_CAPABILITY_PBCC = 64; // 0x40
+ field public static final int BSS_CAPABILITY_PRIVACY = 16; // 0x10
+ field public static final int BSS_CAPABILITY_QOS = 512; // 0x200
+ field public static final int BSS_CAPABILITY_RADIO_MANAGEMENT = 4096; // 0x1000
+ 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.nl80211.NativeScanResult> CREATOR;
+ }
+
+ public final class NativeWifiClient implements android.os.Parcelable {
+ ctor public NativeWifiClient(@Nullable android.net.MacAddress);
+ 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.nl80211.NativeWifiClient> CREATOR;
+ }
+
+ public final class PnoNetwork implements android.os.Parcelable {
+ ctor public PnoNetwork();
+ method public int describeContents();
+ method @NonNull public int[] getFrequenciesMhz();
+ method @NonNull public byte[] getSsid();
+ method public boolean isHidden();
+ method public void setFrequenciesMhz(@NonNull int[]);
+ 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.nl80211.PnoNetwork> CREATOR;
+ }
+
+ public final class PnoSettings implements android.os.Parcelable {
+ ctor public PnoSettings();
+ method public int describeContents();
+ method public long getIntervalMillis();
+ method public int getMin2gRssiDbm();
+ method public int getMin5gRssiDbm();
+ method public int getMin6gRssiDbm();
+ 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.nl80211.PnoNetwork>);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.PnoSettings> CREATOR;
+ }
+
+ public final class RadioChainInfo implements android.os.Parcelable {
+ ctor public RadioChainInfo(int, int);
+ method public int describeContents();
+ 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.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.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.nl80211.WifiNl80211Manager.ScanEventCallback, @NonNull android.net.wifi.nl80211.WifiNl80211Manager.ScanEventCallback);
+ method public boolean setupInterfaceForSoftApMode(@NonNull String);
+ 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);
+ method public boolean tearDownInterfaces();
+ method public boolean tearDownSoftApInterface(@NonNull String);
+ field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
+ field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
+ field public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5; // 0x5
+ field public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2; // 0x2
+ field public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3; // 0x3
+ field public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4; // 0x4
+ field public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; // 0x1
+ }
+
+ public static class WifiNl80211Manager.OemSecurityType {
+ ctor public WifiNl80211Manager.OemSecurityType(int, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, int);
+ field public final int groupCipher;
+ field @NonNull public final java.util.List<java.lang.Integer> keyManagement;
+ field @NonNull public final java.util.List<java.lang.Integer> pairwiseCipher;
+ field public final int protocol;
+ }
+
+ public static interface WifiNl80211Manager.PnoScanRequestCallback {
+ method public void onPnoRequestFailed();
+ method public void onPnoRequestSucceeded();
+ }
+
+ public static interface WifiNl80211Manager.ScanEventCallback {
+ method public void onScanFailed();
+ method public void onScanResultReady();
+ }
+
+ public static interface WifiNl80211Manager.SendMgmtFrameCallback {
+ method public void onAck(int);
+ method public void onFailure(int);
+ }
+
+ public static class WifiNl80211Manager.SignalPollResult {
+ field public final int associationFrequencyMHz;
+ field public final int currentRssiDbm;
+ field public final int rxBitrateMbps;
+ field public final int txBitrateMbps;
+ }
+
+ public static interface WifiNl80211Manager.SoftApCallback {
+ method public void onConnectedClientsChanged(@NonNull android.net.wifi.nl80211.NativeWifiClient, boolean);
+ method public void onFailure();
+ method public void onSoftApChannelSwitched(int, int);
+ }
+
+ public static class WifiNl80211Manager.TxPacketCounters {
+ field public final int txPacketFailed;
+ field public final int txPacketSucceeded;
+ }
+
+}
+
package android.net.wifi.p2p {
public final class WifiP2pGroupList implements android.os.Parcelable {
@@ -8250,174 +8418,6 @@
}
-package android.net.wifi.wificond {
-
- public final class DeviceWiphyCapabilities implements android.os.Parcelable {
- ctor public DeviceWiphyCapabilities();
- method public int describeContents();
- method public int getMaxNumberRxSpatialStreams();
- method public int getMaxNumberTxSpatialStreams();
- method public boolean isChannelWidthSupported(int);
- method public boolean isWifiStandardSupported(int);
- method public void setChannelWidthSupported(int, boolean);
- method public void setMaxNumberRxSpatialStreams(int);
- 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;
- }
-
- public final class NativeScanResult implements android.os.Parcelable {
- ctor public NativeScanResult();
- method public int describeContents();
- method @Nullable public android.net.MacAddress getBssid();
- 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 public int getSignalMbm();
- method @NonNull public byte[] getSsid();
- method public long getTsf();
- method public boolean isAssociated();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int BSS_CAPABILITY_APSD = 2048; // 0x800
- field public static final int BSS_CAPABILITY_CF_POLLABLE = 4; // 0x4
- field public static final int BSS_CAPABILITY_CF_POLL_REQUEST = 8; // 0x8
- field public static final int BSS_CAPABILITY_CHANNEL_AGILITY = 128; // 0x80
- field public static final int BSS_CAPABILITY_DELAYED_BLOCK_ACK = 16384; // 0x4000
- field public static final int BSS_CAPABILITY_DSSS_OFDM = 8192; // 0x2000
- field public static final int BSS_CAPABILITY_ESS = 1; // 0x1
- field public static final int BSS_CAPABILITY_IBSS = 2; // 0x2
- field public static final int BSS_CAPABILITY_IMMEDIATE_BLOCK_ACK = 32768; // 0x8000
- field public static final int BSS_CAPABILITY_PBCC = 64; // 0x40
- field public static final int BSS_CAPABILITY_PRIVACY = 16; // 0x10
- field public static final int BSS_CAPABILITY_QOS = 512; // 0x200
- field public static final int BSS_CAPABILITY_RADIO_MANAGEMENT = 4096; // 0x1000
- 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;
- }
-
- public final class NativeWifiClient implements android.os.Parcelable {
- ctor public NativeWifiClient(@Nullable android.net.MacAddress);
- 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;
- }
-
- public final class PnoNetwork implements android.os.Parcelable {
- ctor public PnoNetwork();
- method public int describeContents();
- method @NonNull public int[] getFrequenciesMhz();
- method @NonNull public byte[] getSsid();
- method public boolean isHidden();
- method public void setFrequenciesMhz(@NonNull int[]);
- 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;
- }
-
- public final class PnoSettings implements android.os.Parcelable {
- ctor public PnoSettings();
- method public int describeContents();
- method public long getIntervalMillis();
- 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 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 writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.wificond.PnoSettings> CREATOR;
- }
-
- public final class RadioChainInfo implements android.os.Parcelable {
- ctor public RadioChainInfo(int, int);
- method public int describeContents();
- 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;
- }
-
- 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 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 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 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);
- method public boolean tearDownInterfaces();
- method public boolean tearDownSoftApInterface(@NonNull String);
- field public static final int SCAN_TYPE_PNO_SCAN = 1; // 0x1
- field public static final int SCAN_TYPE_SINGLE_SCAN = 0; // 0x0
- field public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5; // 0x5
- field public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2; // 0x2
- field public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3; // 0x3
- field public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4; // 0x4
- field public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1; // 0x1
- }
-
- public static class WifiNl80211Manager.OemSecurityType {
- ctor public WifiNl80211Manager.OemSecurityType(int, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>, int);
- field public final int groupCipher;
- field @NonNull public final java.util.List<java.lang.Integer> keyManagement;
- field @NonNull public final java.util.List<java.lang.Integer> pairwiseCipher;
- field public final int protocol;
- }
-
- public static interface WifiNl80211Manager.PnoScanRequestCallback {
- method public void onPnoRequestFailed();
- method public void onPnoRequestSucceeded();
- }
-
- public static interface WifiNl80211Manager.ScanEventCallback {
- method public void onScanFailed();
- method public void onScanResultReady();
- }
-
- public static interface WifiNl80211Manager.SendMgmtFrameCallback {
- method public void onAck(int);
- method public void onFailure(int);
- }
-
- public static class WifiNl80211Manager.SignalPollResult {
- field public final int associationFrequencyMHz;
- field public final int currentRssiDbm;
- field public final int rxBitrateMbps;
- field public final int txBitrateMbps;
- }
-
- public static interface WifiNl80211Manager.SoftApCallback {
- method public void onConnectedClientsChanged(@NonNull android.net.wifi.wificond.NativeWifiClient, boolean);
- method public void onFailure();
- method public void onSoftApChannelSwitched(int, int);
- }
-
- public static class WifiNl80211Manager.TxPacketCounters {
- field public final int txPacketFailed;
- field public final int txPacketSucceeded;
- }
-
-}
-
package android.nfc {
public final class NfcAdapter {
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index f440381..55333cf 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -234,7 +234,7 @@
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 79d29f6..957794c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -180,8 +180,8 @@
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 27c4f4e..bf6afe7 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -678,17 +678,32 @@
* 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/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2838ad8..0293346 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -694,7 +694,7 @@
/** @hide Should this process state be considered a background state? */
public static final boolean isProcStateBackground(int procState) {
- return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
+ return procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
}
/** @hide Is this a foreground service type? */
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index f6bbc68..9ed4798 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -97,15 +97,77 @@
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 @@
@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 @@
/** 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 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 @@
@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 @@
@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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
* @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 @@
* @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 @@
* 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 @@
}
/**
- * 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 @@
* @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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 c13c5a5..309e91f 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -94,14 +94,16 @@
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 d16120d..8c2cc94 100644
--- a/core/java/android/app/NotificationHistory.java
+++ b/core/java/android/app/NotificationHistory.java
@@ -384,6 +384,26 @@
}
/**
+ * 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 9b73060..655dd9b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -109,8 +109,8 @@
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.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 d9b9c56..d08dbc6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4741,7 +4741,8 @@
* @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 @@
* <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 4e9fa19..405277b 100644
--- a/core/java/android/companion/IFindDeviceCallback.aidl
+++ b/core/java/android/companion/IFindDeviceCallback.aidl
@@ -21,6 +21,6 @@
/** @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 f32a4ab..0e0161f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -700,6 +700,27 @@
/** @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 @@
}
}
- 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 eb1da67..3261cb1 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -19,6 +19,7 @@
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 @@
* @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 9ff4417..16a749f 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 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 98bf2dd..5a6e008 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -31,7 +31,7 @@
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 03ed373..5a56b0e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3023,6 +3023,18 @@
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 f19ba0f..2041cfb 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -126,7 +126,11 @@
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 267613f..a8fa6db 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -26,6 +26,7 @@
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 @@
}
}
+ 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 @@
* @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 @@
* @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 @@
};
}
}
+
+ /**
+ * @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 d2c0f76..a5156e3 100644
--- a/core/java/android/service/controls/templates/ControlTemplate.java
+++ b/core/java/android/service/controls/templates/ControlTemplate.java
@@ -74,8 +74,6 @@
TYPE_TOGGLE,
TYPE_RANGE,
TYPE_THUMBNAIL,
- TYPE_DISCRETE_TOGGLE,
- TYPE_COORD_RANGE,
TYPE_TOGGLE_RANGE,
TYPE_TEMPERATURE,
TYPE_STATELESS
@@ -104,16 +102,6 @@
*/
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 @@
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 6aa5480..0000000
--- 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 7a1331a..0000000
--- 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 44ab596..043e5be 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -666,7 +666,22 @@
int localChanges;
}
+ // If set, ViewRootImpl will call BLASTBufferQueue::setNextTransaction with
+ // mRtBLASTSyncTransaction, prior to invoking draw. This provides a way
+ // to redirect the buffers in to transactions.
private boolean mNextDrawUseBLASTSyncTransaction;
+ // Set when calling setNextTransaction, we can't just reuse mNextDrawUseBLASTSyncTransaction
+ // because, imagine this scenario:
+ // 1. First draw is using BLAST, mNextDrawUseBLAST = true
+ // 2. We call perform draw and are waiting on the callback
+ // 3. After the first perform draw but before the first callback and the
+ // second perform draw, a second draw sets mNextDrawUseBLAST = true (it already was)
+ // 4. At this point the callback fires and we set mNextDrawUseBLAST = false;
+ // 5. We get to performDraw and fail to sync as we intended because mNextDrawUseBLAST
+ // is now false.
+ // This is why we use a two-step latch with the two booleans, one consumed from
+ // performDraw and one consumed from finishBLASTSync()
+ private boolean mNextReportConsumeBLAST;
// Be very careful with the threading here. This is used from the render thread while
// the UI thread is paused and then applied and cleared from the UI thread right after
// draw returns.
@@ -2206,8 +2221,9 @@
return insets;
}
- void dispatchApplyInsets(View host) {
+ public void dispatchApplyInsets(View host) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "dispatchApplyInsets");
+ mApplyInsetsRequested = false;
WindowInsets insets = getWindowInsets(true /* forceConstruct */);
final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
== LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
@@ -2444,7 +2460,6 @@
}
if (mApplyInsetsRequested) {
- mApplyInsetsRequested = false;
updateVisibleInsets();
dispatchApplyInsets(host);
if (mLayoutRequested) {
@@ -2621,7 +2636,6 @@
if (contentInsetsChanged || mLastSystemUiVisibility !=
mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
- mApplyInsetsRequested = false;
dispatchApplyInsets(host);
// We applied insets so force contentInsetsChanged to ensure the
// hierarchy is measured below.
@@ -3719,9 +3733,9 @@
usingAsyncReport = mReportNextDraw;
if (needFrameCompleteCallback) {
final Handler handler = mAttachInfo.mHandler;
- mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) ->
+ mAttachInfo.mThreadedRenderer.setFrameCompleteCallback((long frameNr) -> {
+ finishBLASTSync();
handler.postAtFrontOfQueue(() -> {
- finishBLASTSync();
if (reportNextDraw) {
// TODO: Use the frame number
pendingDrawFinished();
@@ -3731,12 +3745,23 @@
commitCallbacks.get(i).run();
}
}
- }));
+ });});
}
}
try {
if (mNextDrawUseBLASTSyncTransaction) {
+ // TODO(b/149747443)
+ // We aren't prepared to handle overlapping use of mRtBLASTSyncTransaction
+ // so if we are BLAST syncing we make sure the previous draw has
+ // totally finished.
+ if (mAttachInfo.mThreadedRenderer != null) {
+ mAttachInfo.mThreadedRenderer.fence();
+ }
+
+ mNextReportConsumeBLAST = true;
+ mNextDrawUseBLASTSyncTransaction = false;
+
mBlastBufferQueue.setNextTransaction(mRtBLASTSyncTransaction);
}
boolean canUseAsync = draw(fullRedrawNeeded);
@@ -9556,8 +9581,8 @@
}
private void finishBLASTSync() {
- if (mNextDrawUseBLASTSyncTransaction) {
- mNextDrawUseBLASTSyncTransaction = false;
+ if (mNextReportConsumeBLAST) {
+ mNextReportConsumeBLAST = false;
mRtBLASTSyncTransaction.apply();
}
}
@@ -9566,7 +9591,10 @@
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 a6a5ec5..47ea1cb 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -1257,7 +1257,8 @@
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/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 5dc8b0b..8f0ffd9 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -1304,8 +1304,11 @@
+ "cannot be null.");
}
// We partially rebuild the inactive adapter to determine if we should auto launch
- boolean rebuildActiveCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true);
- boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false);
+ boolean rebuildCompleted = mMultiProfilePagerAdapter.rebuildActiveTab(true);
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
+ boolean rebuildInactiveCompleted = mMultiProfilePagerAdapter.rebuildInactiveTab(false);
+ rebuildCompleted = rebuildCompleted && rebuildInactiveCompleted;
+ }
if (useLayoutWithDefault()) {
mLayoutId = R.layout.resolver_list_with_default;
@@ -1314,7 +1317,7 @@
}
setContentView(mLayoutId);
mMultiProfilePagerAdapter.setupViewPager(findViewById(R.id.profile_pager));
- return postRebuildList(rebuildActiveCompleted && rebuildInactiveCompleted);
+ return postRebuildList(rebuildCompleted);
}
/**
@@ -1378,6 +1381,10 @@
return false;
}
+ if (mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() != null) {
+ return false;
+ }
+
// Only one target, so we're a candidate to auto-launch!
final TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter()
.targetInfoForPosition(0, false);
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 578c0cc..3378c07 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -1160,6 +1160,10 @@
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 ce9a048..3f81b11 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -236,7 +236,6 @@
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/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index c039570..6850d01 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -366,6 +366,15 @@
// Whether battery level is low or not.
optional bool is_battery_level_low = 8;
+ // Denotes which threshold should be used for automatic Battery Saver triggering.
+ enum AutomaticTriggerEnum {
+ TRIGGER_PERCENTAGE = 0;
+ TRIGGER_DYNAMIC = 1;
+ }
+ // The value of Global.AUTOMATIC_POWER_SAVE_MODE. This is a cached value, so it could
+ // be slightly different from what's in GlobalSettingsProto.DynamicPowerSavings.
+ optional AutomaticTriggerEnum setting_automatic_trigger = 19;
+
// The value of Global.LOW_POWER_MODE. This is a cached value, so it could
// be slightly different from what's in GlobalSettingsProto.LowPowerMode.
optional bool setting_battery_saver_enabled = 9;
@@ -390,5 +399,18 @@
// using elapsed realtime as the timebase.
optional int64 last_adaptive_battery_saver_changed_externally_elapsed = 17;
- // Next tag: 19
+ // The default disable threshold for Dynamic Power Savings enabled battery saver.
+ optional int32 default_dynamic_disable_threshold = 20;
+
+ // When to disable battery saver again if it was enabled due to an external suggestion.
+ // Corresponds to Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD. This is a cached value,
+ // so it could be slightly different from what's in GlobalSettingsProto.DynamicPowerSavings.
+ optional int32 dynamic_disable_threshold = 21;
+
+ // Whether we've received a suggestion that battery saver should be on from an external app.
+ // Corresponds to Global.DYNAMIC_POWER_SAVINGS_ENABLED. This is a cached value, so it could
+ // be slightly different from what's in GlobalSettingsProto.DynamicPowerSavings.
+ optional bool dynamic_battery_saver_enabled = 22;
+
+ // Next tag: 23
}
diff --git a/core/proto/android/stats/devicepolicy/device_policy_enums.proto b/core/proto/android/stats/devicepolicy/device_policy_enums.proto
index a4e2193..782b269 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 @@
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 6530036..488698a 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 e91806f..f62eb27 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/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index 7098c95..9aecfd9 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -30,8 +30,8 @@
android:background="?attr/selectableItemBackgroundBorderless">
<ImageView android:id="@+id/icon"
- android:layout_width="@dimen/resolver_icon_size"
- android:layout_height="@dimen/resolver_icon_size"
+ android:layout_width="@dimen/chooser_icon_size"
+ android:layout_height="@dimen/chooser_icon_size"
android:scaleType="fitCenter" />
<!-- Size manually tuned to match specs -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c44a0be..48049b4 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -768,6 +768,7 @@
<dimen name="chooser_header_scroll_elevation">4dp</dimen>
<dimen name="chooser_max_collapsed_height">288dp</dimen>
<dimen name="chooser_direct_share_label_placeholder_max_width">72dp</dimen>
+ <dimen name="chooser_icon_size">42dp</dimen>
<dimen name="resolver_icon_size">32dp</dimen>
<dimen name="resolver_button_bar_spacing">8dp</dimen>
<dimen name="resolver_badge_size">18dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e6a93e5..e7ad8eb 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/symbols.xml b/core/res/res/values/symbols.xml
index 02d90a7..89cc770 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3765,6 +3765,7 @@
<java-symbol type="dimen" name="resolver_small_margin"/>
<java-symbol type="dimen" name="resolver_edge_margin"/>
<java-symbol type="dimen" name="resolver_elevation"/>
+ <java-symbol type="dimen" name="chooser_icon_size"/>
<!-- For DropBox -->
<java-symbol type="integer" name="config_dropboxLowPriorityBroadcastRateLimitPeriod" />
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 0000000..0435c30
--- /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 59335a5..718ca46 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 8d8acb7..0443d3a 100644
--- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java
+++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
@@ -289,6 +289,44 @@
}
@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 9dcce1e..78c4420 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.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 @@
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 0000000..aba32e8
--- /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 c9b5eec..292ac09 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 @@
}
@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 65f2f17..453704e 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -102,12 +102,6 @@
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 @@
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 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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/MediaFormat.java b/media/java/android/media/MediaFormat.java
index b57182e..5832fc1 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -656,16 +656,20 @@
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 @@
* <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 @@
* 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 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 32a4a4f..d3e9c7e 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -21,6 +21,7 @@
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 @@
* @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 @@
* 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 0000000..c65d25a
--- /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
similarity index 93%
rename from media/java/android/media/tv/tuner/CasSessionRequest.aidl
rename to media/java/android/media/tv/tunerresourcemanager/CasSessionRequest.aidl
index 3dbf3d8..c918d88 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
similarity index 98%
rename from media/java/android/media/tv/tuner/CasSessionRequest.java
rename to media/java/android/media/tv/tunerresourcemanager/CasSessionRequest.java
index 0f6a885..59802ff 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
similarity index 82%
rename from media/java/android/media/tv/tuner/ITunerResourceManagerListener.aidl
rename to media/java/android/media/tv/tunerresourcemanager/IResourcesReclaimListener.aidl
index 557032c..1a4eb29 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
similarity index 90%
rename from media/java/android/media/tv/tuner/ITunerResourceManager.aidl
rename to media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index 758c689..20efaa1 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 @@
* <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 @@
* <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 @@
*
* <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 @@
*
* <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 @@
* <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 0000000..76b84d9
--- /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
similarity index 94%
rename from media/java/android/media/tv/tuner/ResourceClientProfile.aidl
rename to media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.aidl
index da3c5c4..ed90c1d 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
similarity index 98%
rename from media/java/android/media/tv/tuner/ResourceClientProfile.java
rename to media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java
index e203135..6837244 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
similarity index 93%
rename from media/java/android/media/tv/tuner/TunerFrontendInfo.aidl
rename to media/java/android/media/tv/tunerresourcemanager/TunerFrontendInfo.aidl
index 012e051..e649c2a 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
similarity index 98%
rename from media/java/android/media/tv/tuner/TunerFrontendInfo.java
rename to media/java/android/media/tv/tunerresourcemanager/TunerFrontendInfo.java
index a62ecb3..8957c37 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
similarity index 93%
rename from media/java/android/media/tv/tuner/TunerFrontendRequest.aidl
rename to media/java/android/media/tv/tunerresourcemanager/TunerFrontendRequest.aidl
index 25c298f..5e48adc 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
similarity index 98%
rename from media/java/android/media/tv/tuner/TunerFrontendRequest.java
rename to media/java/android/media/tv/tunerresourcemanager/TunerFrontendRequest.java
index 01a0a09..12f8032 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
similarity index 93%
rename from media/java/android/media/tv/tuner/TunerLnbRequest.aidl
rename to media/java/android/media/tv/tunerresourcemanager/TunerLnbRequest.aidl
index b811e39..0e6fcde 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
similarity index 97%
rename from media/java/android/media/tv/tuner/TunerLnbRequest.java
rename to media/java/android/media/tv/tunerresourcemanager/TunerLnbRequest.java
index 60cd790..5ed7f3f 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
similarity index 93%
rename from media/java/android/media/tv/tuner/TunerResourceManager.java
rename to media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index 68ca572..7c11ed4 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 @@
* <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 @@
* @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 @@
*
* <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 @@
*
* <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 @@
* <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 @@
/**
* 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/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 585acfe..a0d5a1b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -43,9 +43,11 @@
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.volume.CarVolumeDialogComponent;
@@ -74,10 +76,14 @@
@Singleton
@Provides
- static HeadsUpManagerPhone provideHeadsUpManagerPhone(Context context,
+ static HeadsUpManagerPhone provideHeadsUpManagerPhone(
+ Context context,
StatusBarStateController statusBarStateController,
- KeyguardBypassController bypassController) {
- return new HeadsUpManagerPhone(context, statusBarStateController, bypassController);
+ KeyguardBypassController bypassController,
+ NotificationGroupManager groupManager,
+ ConfigurationController configurationController) {
+ return new HeadsUpManagerPhone(context, statusBarStateController, bypassController,
+ groupManager, configurationController);
}
@Binds
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
index 51b263e..7d544c9 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.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 @@
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 210dd32..a4eada4 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -128,6 +128,7 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -324,6 +325,7 @@
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
DismissCallbackRegistry dismissCallbackRegistry,
+ StatusBarTouchableRegionManager statusBarTouchableRegionManager,
/* Car Settings injected components. */
CarServiceProvider carServiceProvider,
Lazy<PowerManagerHelper> powerManagerHelperLazy,
@@ -405,7 +407,8 @@
keyguardDismissUtil,
extensionController,
userInfoControllerImpl,
- dismissCallbackRegistry);
+ dismissCallbackRegistry,
+ statusBarTouchableRegionManager);
mUserSwitcherController = userSwitcherController;
mScrimController = scrimController;
mLockscreenLockIconController = lockscreenLockIconController;
@@ -916,7 +919,6 @@
Dependency.get(KeyguardUpdateMonitor.class).dump(fd, pw, args);
}
- Dependency.get(FalsingManager.class).dump(pw);
FalsingLog.dump(pw);
pw.println("SharedPreferences:");
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 7f64990..7294965 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -87,6 +87,7 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneDependenciesModule;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -197,6 +198,7 @@
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
DismissCallbackRegistry dismissCallbackRegistry,
+ StatusBarTouchableRegionManager statusBarTouchableRegionManager,
CarServiceProvider carServiceProvider,
Lazy<PowerManagerHelper> powerManagerHelperLazy,
FullscreenUserSwitcher fullscreenUserSwitcher,
@@ -277,6 +279,7 @@
extensionController,
userInfoControllerImpl,
dismissCallbackRegistry,
+ statusBarTouchableRegionManager,
carServiceProvider,
powerManagerHelperLazy,
fullscreenUserSwitcher,
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index bb49994..90ea5e2 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/strings.xml b/packages/SystemUI/res/values/strings.xml
index ef9e705..5e9feff 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/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index e80b437..7dcf4b0 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.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 @@
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 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 @@
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 @@
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 073688b..8f4926f 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.Rect;
import android.view.Surface;
import android.view.SurfaceControl.Transaction;
+import android.view.SurfaceControl;
public class TransactionCompat {
@@ -87,8 +88,8 @@
}
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 @@
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 e5f6d3c..9ba3860 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.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 @@
@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 @@
}
private void handleSimSubscriptionInfoChanged() {
- checkIsHandlerThread();
+ Assert.isMainThread();
if (DEBUG_SIM_STATES) {
Log.v(TAG, "onSubscriptionInfoChanged()");
List<SubscriptionInfo> sil = mSubscriptionManager
@@ -403,7 +404,7 @@
}
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 @@
@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 @@
@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 @@
}
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 @@
}
private void handleFingerprintAcquired(int acquireInfo) {
- checkIsHandlerThread();
+ Assert.isMainThread();
if (acquireInfo != FingerprintManager.FINGERPRINT_ACQUIRED_GOOD) {
return;
}
@@ -599,7 +600,7 @@
}
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 @@
};
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 @@
}
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 @@
@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 @@
}
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 @@
}
private void handleFaceAcquired(int acquireInfo) {
- checkIsHandlerThread();
+ Assert.isMainThread();
if (acquireInfo != FaceManager.FACE_ACQUIRED_GOOD) {
return;
}
@@ -767,7 +768,7 @@
}
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 @@
};
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 @@
}
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 @@
}
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 @@
* Cached version of {@link TrustManager#isTrustUsuallyManaged(int)}.
*/
public boolean isTrustUsuallyManaged(int userId) {
- checkIsHandlerThread();
+ Assert.isMainThread();
return mUserTrustIsUsuallyManaged.get(userId);
}
@@ -996,7 +997,7 @@
}
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 @@
}
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 @@
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 @@
}
protected void handleStartedGoingToSleep(int arg1) {
- checkIsHandlerThread();
+ Assert.isMainThread();
mLockIconPressed = false;
clearBiometricRecognized();
for (int i = 0; i < mCallbacks.size(); i++) {
@@ -1349,7 +1350,7 @@
}
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 @@
}
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 @@
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 @@
}
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 @@
}
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 @@
}
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 @@
}
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 @@
* @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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
*/
@VisibleForTesting
void updateTelephonyCapable(boolean capable) {
- checkIsHandlerThread();
+ Assert.isMainThread();
if (capable == mTelephonyCapable) {
return;
}
@@ -2152,7 +2155,7 @@
*/
@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 @@
* <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 @@
* @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 @@
* 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 @@
* @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 @@
* @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 @@
if (!bypassHandler) {
mHandler.obtainMessage(MSG_REPORT_EMERGENCY_CALL_ACTION).sendToTarget();
} else {
- checkIsHandlerThread();
+ Assert.isMainThread();
handleReportEmergencyCallAction();
}
}
@@ -2466,7 +2469,7 @@
}
public void clearBiometricRecognized() {
- checkIsHandlerThread();
+ Assert.isMainThread();
mUserFingerprintAuthenticated.clear();
mUserFaceAuthenticated.clear();
mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT);
@@ -2653,7 +2656,7 @@
}
private void updateLogoutEnabled() {
- checkIsHandlerThread();
+ Assert.isMainThread();
boolean logoutEnabled = mDevicePolicyManager.isLogoutEnabled();
if (mLogoutEnabled != logoutEnabled) {
mLogoutEnabled = logoutEnabled;
@@ -2667,13 +2670,6 @@
}
}
- 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 27fe37e..d317b7e 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.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 @@
@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 @@
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 03bc738..4473b01 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -168,12 +168,13 @@
@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 @@
@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 @@
@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 @@
@Override
public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
+ if (mWorker == null) return;
if (DEBUG) {
Log.d(TAG, "onSurfaceRedrawNeeded: mNeedRedraw=" + mNeedRedraw);
}
@@ -267,7 +271,7 @@
@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 @@
}
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 1f94dbd..de707b9 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.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 @@
@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 @@
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 @@
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 @@
*/
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 9a6295a..3d9865c 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.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 @@
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 @@
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 @@
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 793f8b9..60c8c4e 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.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 @@
*/
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 @@
/** 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 @@
* 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 @@
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 @@
.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 @@
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 @@
// 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 0337ee3..f057d0b 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.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 @@
NotificationEntryManager entryManager,
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
- DumpController dumpController) {
+ DumpController dumpController,
+ FloatingContentCoordinator floatingContentCoordinator) {
return new BubbleController(
context,
notificationShadeWindowController,
@@ -76,6 +78,7 @@
entryManager,
notifPipeline,
featureFlags,
- dumpController);
+ dumpController,
+ floatingContentCoordinator);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index a57ec5b..3e257b6 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -38,8 +38,10 @@
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -92,10 +94,14 @@
@Singleton
@Provides
- static HeadsUpManagerPhone provideHeadsUpManagerPhone(Context context,
+ static HeadsUpManagerPhone provideHeadsUpManagerPhone(
+ Context context,
StatusBarStateController statusBarStateController,
- KeyguardBypassController bypassController) {
- return new HeadsUpManagerPhone(context, statusBarStateController, bypassController);
+ KeyguardBypassController bypassController,
+ NotificationGroupManager groupManager,
+ ConfigurationController configurationController) {
+ return new HeadsUpManagerPhone(context, statusBarStateController, bypassController,
+ groupManager, configurationController);
}
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index 3bf5ad7..12b9be1 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.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 @@
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 92aa020..adee7f2 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 cecdc9c..599c845 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.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 @@
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 @@
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 239ef36..cb94e28 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.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 @@
}
}
- 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 @@
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 @@
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 3ae627d..c6e2852 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 @@
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.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 @@
/**
* 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 @@
/** 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 @@
*/
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 @@
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 @@
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 @@
}
/**
- * 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 @@
});
}
+ /** 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 @@
/**
* @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 @@
/**
* Animates the PiP to the minimized state, slightly offscreen.
*/
- void animateToClosestMinimizedState(Rect movementBounds, @Nullable Runnable updateAction) {
- final Rect toBounds = getClosestMinimizedBounds(mBounds, movementBounds);
+ void animateToClosestMinimizedState(@Nullable Runnable updateAction) {
+ final Rect toBounds = getClosestMinimizedBounds(mBounds);
- prepareForBoundsAnimation(movementBounds);
-
+ mAnimatedBounds.set(mBounds);
mAnimatedBoundsPhysicsAnimator
.spring(FloatProperties.RECT_X, toBounds.left, mSpringConfig)
.spring(FloatProperties.RECT_Y, toBounds.top, mSpringConfig);
@@ -285,10 +350,8 @@
* 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 @@
.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 @@
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 @@
currentMovementBounds);
}
mSnapAlgorithm.applySnapFraction(normalBounds, normalMovementBounds, savedSnapFraction);
+
if (minimized) {
- normalBounds = getClosestMinimizedBounds(normalBounds, normalMovementBounds);
+ normalBounds = getClosestMinimizedBounds(normalBounds);
}
+
if (immediate) {
movePip(normalBounds);
} else {
@@ -400,19 +480,15 @@
*/
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 @@
}
/**
+ * 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 @@
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 924edb6..8e588e6 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.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 @@
// 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 @@
@Override
public void onPipMinimize() {
setMinimizedStateInternal(true);
- mMotionHelper.animateToClosestMinimizedState(mMovementBounds, null /* updateAction */);
+ mMotionHelper.animateToClosestMinimizedState(null /* updateAction */);
}
@Override
@@ -172,7 +174,8 @@
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 @@
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 @@
inputConsumerController.setRegistrationListener(this::onRegistrationChanged);
mPipBoundsHandler = pipBoundsHandler;
+ mFloatingContentCoordinator = floatingContentCoordinator;
mConnection = new PipAccessibilityInteractionConnection(mMotionHelper,
this::onAccessibilityShowMenu, mHandler);
}
@@ -228,15 +232,18 @@
}
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 @@
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 @@
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 @@
mMenuController.hideMenu();
} else {
mMotionHelper.animateToClosestMinimizedState(
- mMovementBounds,
PipTouchHandler.this::updateDismissFraction /* updateAction */);
}
return true;
@@ -748,16 +753,15 @@
}
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 @@
: mNormalMovementBounds;
mPipBoundsHandler.setMinEdgeSize(
isMenuExpanded ? mExpandedShortestEdgeSize : 0);
+ mMotionHelper.setCurrentMovementBounds(mMovementBounds);
}
/**
@@ -800,16 +805,6 @@
}
/**
- * 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 0000000..c8b6982
--- /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 a40b72b..9c175bc 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}
- }
- });
+ PipControlButtonView getFullButtonView() {
+ return findViewById(R.id.full_button);
}
- @Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- updateMediaController();
- mPipManager.addMediaListener(mPipMediaListener);
+ PipControlButtonView getCloseButtonView() {
+ return findViewById(R.id.close_button);
}
- @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;
- }
-
- /**
- * Updates the set of activity-defined actions.
- */
- public void setActions(List<RemoteAction> actions) {
- mCustomActions.clear();
- mCustomActions.addAll(actions);
- updateUserActions();
- }
-
- /**
- * 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 0000000..1fe531b
--- /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 7532f9f..487c253 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.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 @@
}
}
- 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 @@
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 @@
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 3a5fa22..f43f8e7 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.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 @@
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 @@
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 @@
@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 ca15131..b01c2f4 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 @@
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 PipNotification(Context context, BroadcastDispatcher broadcastDispatcher) {
+ public PipNotification(Context context, BroadcastDispatcher broadcastDispatcher,
+ PipManager pipManager) {
mNotificationManager = (NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
@@ -156,6 +157,7 @@
.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 0000000..52b38a9
--- /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 0000000..8e8b7f3
--- /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/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 0c86157..1ab77f3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -17,9 +17,9 @@
package com.android.systemui.qs.tiles;
import android.annotation.Nullable;
-import android.content.ComponentName;
import android.content.Intent;
import android.os.UserManager;
+import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.util.Log;
import android.widget.Switch;
@@ -36,9 +36,6 @@
/** Quick settings tile: Hotspot **/
public class HotspotTile extends QSTileImpl<BooleanState> {
- private static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
- "com.android.settings", "com.android.settings.TetherSettings"));
-
private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot);
private final HotspotController mHotspotController;
@@ -79,7 +76,7 @@
@Override
public Intent getLongClickIntent() {
- return new Intent(TETHER_SETTINGS);
+ return new Intent(Settings.ACTION_TETHER_SETTINGS);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 72a7e11..07cf9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -53,12 +53,14 @@
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
- NotificationListener notificationListener) {
+ NotificationListener notificationListener,
+ HeadsUpManager headsUpManager) {
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
mStatusBarStateController = statusBarStateController;
mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mNotificationListener = notificationListener;
+ mHeadsUpManager = headsUpManager;
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
@@ -81,10 +83,6 @@
});
}
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
/**
* Adds the entry to the respective alerting manager if the content view was inflated and
* the entry should still alert.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 4f55e02..5ebd368 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -49,9 +49,7 @@
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.leak.LeakDetector;
@@ -230,9 +228,7 @@
mRemoveInterceptors.remove(interceptor);
}
- public void setUpWithPresenter(NotificationPresenter presenter,
- NotificationListContainer listContainer,
- HeadsUpManager headsUpManager) {
+ public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 616c110..fabe3a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -61,7 +61,8 @@
* Injected constructor. See {@link NotificationsModule}.
*/
public VisualStabilityManager(
- NotificationEntryManager notificationEntryManager, @Main Handler handler) {
+ NotificationEntryManager notificationEntryManager,
+ @Main Handler handler) {
mHandler = handler;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 8f8f742..d0b553d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -47,6 +47,7 @@
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.leak.LeakDetector;
import java.util.concurrent.Executor;
@@ -123,14 +124,16 @@
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
- NotificationListener notificationListener) {
+ NotificationListener notificationListener,
+ HeadsUpManager headsUpManager) {
return new NotificationAlertingManager(
notificationEntryManager,
remoteInputManager,
visualStabilityManager,
statusBarStateController,
notificationInterruptionStateProvider,
- notificationListener);
+ notificationListener,
+ headsUpManager);
}
/** Provides an instance of {@link NotificationLogger} */
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 3eac229..b03ba3c 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 @@
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 8465658..2643ec9 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 @@
} 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 923c348..248e5fe 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 @@
@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/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index c6e3fde..63fe700 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -19,24 +19,15 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Rect;
import android.graphics.Region;
-import android.util.Log;
import android.util.Pools;
-import android.view.DisplayCutout;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.WindowInsets;
import androidx.collection.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
-import com.android.systemui.ScreenDecorations;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.StatusBarState;
@@ -49,31 +40,27 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Stack;
/**
* A implementation of HeadsUpManager for phone and car.
*/
public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
- VisualStabilityManager.Callback, OnHeadsUpChangedListener,
- ConfigurationController.ConfigurationListener, StateListener {
+ VisualStabilityManager.Callback, OnHeadsUpChangedListener {
private static final String TAG = "HeadsUpManagerPhone";
@VisibleForTesting
final int mExtensionTime;
- private final StatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mBypassController;
+ private final NotificationGroupManager mGroupManager;
+ private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
private final int mAutoHeadsUpNotificationDecay;
- private View mNotificationShadeWindowView;
- private NotificationGroupManager mGroupManager;
private VisualStabilityManager mVisualStabilityManager;
- private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
private boolean mReleaseOnExpandFinish;
- private int mStatusBarHeight;
- private int mHeadsUpInset;
- private int mDisplayCutoutTouchableRegionSize;
private boolean mTrackingHeadsUp;
private HashSet<String> mSwipedOutKeys = new HashSet<>();
private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
@@ -81,12 +68,13 @@
private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
= new ArraySet<>();
private boolean mIsExpanded;
- private int[] mTmpTwoArray = new int[2];
private boolean mHeadsUpGoingAway;
private int mStatusBarState;
- private Region mTouchableRegion = new Region();
-
private AnimationStateHandler mAnimationStateHandler;
+ private int mHeadsUpInset;
+
+ // Used for determining the region for touch interaction
+ private final Region mTouchableRegion = new Region();
private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();
@@ -111,76 +99,96 @@
public HeadsUpManagerPhone(@NonNull final Context context,
StatusBarStateController statusBarStateController,
- KeyguardBypassController bypassController) {
+ KeyguardBypassController bypassController,
+ NotificationGroupManager groupManager,
+ ConfigurationController configurationController) {
super(context);
Resources resources = mContext.getResources();
mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
mAutoHeadsUpNotificationDecay = resources.getInteger(
R.integer.auto_heads_up_notification_decay);
- mStatusBarStateController = statusBarStateController;
- mStatusBarStateController.addCallback(this);
+ statusBarStateController.addCallback(mStatusBarStateListener);
mBypassController = bypassController;
-
- initResources();
- }
-
- public void setUp(@NonNull View notificationShadeWindowView,
- @NonNull NotificationGroupManager groupManager,
- @NonNull StatusBar bar,
- @NonNull VisualStabilityManager visualStabilityManager) {
- mNotificationShadeWindowView = notificationShadeWindowView;
- mStatusBarTouchableRegionManager = new StatusBarTouchableRegionManager(this, bar,
- notificationShadeWindowView);
mGroupManager = groupManager;
- mVisualStabilityManager = visualStabilityManager;
- addListener(new OnHeadsUpChangedListener() {
+ updateResources();
+ configurationController.addCallback(new ConfigurationController.ConfigurationListener() {
@Override
- public void onHeadsUpPinnedModeChanged(boolean hasPinnedNotification) {
- if (Log.isLoggable(TAG, Log.WARN)) {
- Log.w(TAG, "onHeadsUpPinnedModeChanged");
- }
- mStatusBarTouchableRegionManager.updateTouchableRegion();
+ public void onDensityOrFontScaleChanged() {
+ updateResources();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ updateResources();
}
});
}
+ void setup(VisualStabilityManager visualStabilityManager) {
+ mVisualStabilityManager = visualStabilityManager;
+ }
+
public void setAnimationStateHandler(AnimationStateHandler handler) {
mAnimationStateHandler = handler;
}
- private void initResources() {
+ private void updateResources() {
Resources resources = mContext.getResources();
- mStatusBarHeight = resources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
- mHeadsUpInset = mStatusBarHeight + resources.getDimensionPixelSize(
- R.dimen.heads_up_status_bar_padding);
- mDisplayCutoutTouchableRegionSize = resources.getDimensionPixelSize(
- com.android.internal.R.dimen.display_cutout_touchable_region_size);
- }
-
- @Override
- public void onDensityOrFontScaleChanged() {
- super.onDensityOrFontScaleChanged();
- initResources();
- }
-
- @Override
- public void onOverlayChanged() {
- initResources();
+ mHeadsUpInset =
+ resources.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height)
+ + resources.getDimensionPixelSize(R.dimen.heads_up_status_bar_padding);
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Public methods:
/**
+ * Add a listener to receive callbacks onHeadsUpGoingAway
+ */
+ void addHeadsUpPhoneListener(OnHeadsUpPhoneListenerChange listener) {
+ mHeadsUpPhoneListeners.add(listener);
+ }
+
+ /**
+ * Gets the touchable region needed for heads up notifications. Returns null if no touchable
+ * region is required (ie: no heads up notification currently exists).
+ */
+ @Nullable Region getTouchableRegion() {
+ NotificationEntry topEntry = getTopEntry();
+
+ // This call could be made in an inconsistent state while the pinnedMode hasn't been
+ // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's
+ // therefore also check if the topEntry is null.
+ if (!hasPinnedHeadsUp() || topEntry == null) {
+ return null;
+ } else {
+ if (topEntry.isChildInGroup()) {
+ final NotificationEntry groupSummary =
+ mGroupManager.getGroupSummary(topEntry.getSbn());
+ if (groupSummary != null) {
+ topEntry = groupSummary;
+ }
+ }
+ ExpandableNotificationRow topRow = topEntry.getRow();
+ int[] tmpArray = new int[2];
+ topRow.getLocationOnScreen(tmpArray);
+ int minX = tmpArray[0];
+ int maxX = tmpArray[0] + topRow.getWidth();
+ int height = topRow.getIntrinsicHeight();
+ mTouchableRegion.set(minX, 0, maxX, mHeadsUpInset + height);
+ return mTouchableRegion;
+ }
+ }
+
+ /**
* Decides whether a click is invalid for a notification, i.e it has not been shown long enough
* that a user might have consciously clicked on it.
*
* @param key the key of the touched notification
* @return whether the touch is invalid and should be discarded
*/
- public boolean shouldSwallowClick(@NonNull String key) {
+ boolean shouldSwallowClick(@NonNull String key) {
HeadsUpManager.HeadsUpEntry entry = getHeadsUpEntry(key);
return entry != null && mClock.currentTimeMillis() < entry.mPostTime;
}
@@ -213,39 +221,12 @@
*
* @param isExpanded True to notify expanded, false to notify collapsed.
*/
- public void setIsPanelExpanded(boolean isExpanded) {
+ void setIsPanelExpanded(boolean isExpanded) {
if (isExpanded != mIsExpanded) {
mIsExpanded = isExpanded;
if (isExpanded) {
mHeadsUpGoingAway = false;
}
- mStatusBarTouchableRegionManager.setIsStatusBarExpanded(isExpanded);
- mStatusBarTouchableRegionManager.updateTouchableRegion();
- }
- }
-
- @Override
- public void onStateChanged(int newState) {
- boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
- boolean isKeyguard = newState == StatusBarState.KEYGUARD;
- mStatusBarState = newState;
- if (wasKeyguard && !isKeyguard && mKeysToRemoveWhenLeavingKeyguard.size() != 0) {
- String[] keys = mKeysToRemoveWhenLeavingKeyguard.toArray(new String[0]);
- for (String key : keys) {
- removeAlertEntry(key);
- }
- mKeysToRemoveWhenLeavingKeyguard.clear();
- }
- }
-
- @Override
- public void onDozingChanged(boolean isDozing) {
- if (!isDozing) {
- // Let's make sure all huns we got while dozing time out within the normal timeout
- // duration. Otherwise they could get stuck for a very long time
- for (AlertEntry entry : mAlertEntries.values()) {
- entry.updateEntry(true /* updatePostTime */);
- }
}
}
@@ -262,18 +243,16 @@
* Set that we are exiting the headsUp pinned mode, but some notifications might still be
* animating out. This is used to keep the touchable regions in a sane state.
*/
- public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+ void setHeadsUpGoingAway(boolean headsUpGoingAway) {
if (headsUpGoingAway != mHeadsUpGoingAway) {
mHeadsUpGoingAway = headsUpGoingAway;
- if (!headsUpGoingAway) {
- mStatusBarTouchableRegionManager.updateTouchableRegionAfterLayout();
- } else {
- mStatusBarTouchableRegionManager.updateTouchableRegion();
+ for (OnHeadsUpPhoneListenerChange listener : mHeadsUpPhoneListeners) {
+ listener.onHeadsUpGoingAwayStateChanged(headsUpGoingAway);
}
}
}
- public boolean isHeadsUpGoingAway() {
+ boolean isHeadsUpGoingAway() {
return mHeadsUpGoingAway;
}
@@ -346,63 +325,6 @@
dumpInternal(fd, pw, args);
}
- /**
- * Update touch insets to include any area needed for touching a heads up notification.
- *
- * @param info Insets that will include heads up notification touch area after execution.
- */
- @Nullable
- public void updateTouchableRegion(ViewTreeObserver.InternalInsetsInfo info) {
- info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- info.touchableRegion.set(calculateTouchableRegion());
- }
-
- public Region calculateTouchableRegion() {
- NotificationEntry topEntry = getTopEntry();
- // This call could be made in an inconsistent state while the pinnedMode hasn't been
- // updated yet, but callbacks leading out of the headsUp manager, querying it. Let's
- // therefore also check if the topEntry is null.
- if (!hasPinnedHeadsUp() || topEntry == null) {
- mTouchableRegion.set(0, 0, mNotificationShadeWindowView.getWidth(), mStatusBarHeight);
- updateRegionForNotch(mTouchableRegion);
-
- } else {
- if (topEntry.isChildInGroup()) {
- final NotificationEntry groupSummary =
- mGroupManager.getGroupSummary(topEntry.getSbn());
- if (groupSummary != null) {
- topEntry = groupSummary;
- }
- }
- ExpandableNotificationRow topRow = topEntry.getRow();
- topRow.getLocationOnScreen(mTmpTwoArray);
- int minX = mTmpTwoArray[0];
- int maxX = mTmpTwoArray[0] + topRow.getWidth();
- int height = topRow.getIntrinsicHeight();
- mTouchableRegion.set(minX, 0, maxX, mHeadsUpInset + height);
- }
- return mTouchableRegion;
- }
-
- private void updateRegionForNotch(Region region) {
- WindowInsets windowInsets = mNotificationShadeWindowView.getRootWindowInsets();
- if (windowInsets == null) {
- Log.w(TAG, "StatusBarWindowView is not attached.");
- return;
- }
- DisplayCutout cutout = windowInsets.getDisplayCutout();
- if (cutout == null) {
- return;
- }
-
- // Expand touchable region such that we also catch touches that just start below the notch
- // area.
- Rect bounds = new Rect();
- ScreenDecorations.DisplayCutoutView.boundsFromDirection(cutout, Gravity.TOP, bounds);
- bounds.offset(0, mDisplayCutoutTouchableRegionSize);
- region.union(bounds);
- }
-
@Override
public boolean shouldExtendLifetime(NotificationEntry entry) {
// We should not defer the removal if reordering isn't allowed since otherwise
@@ -411,11 +333,6 @@
return mVisualStabilityManager.isReorderingAllowed() && super.shouldExtendLifetime(entry);
}
- @Override
- public void onConfigChanged(Configuration newConfig) {
- initResources();
- }
-
///////////////////////////////////////////////////////////////////////////////////////////////
// VisualStabilityManager.Callback overrides:
@@ -522,8 +439,7 @@
// time out anyway
&& !entry.showingPulsing()) {
mEntriesToRemoveWhenReorderingAllowed.add(entry);
- mVisualStabilityManager.addReorderingAllowedCallback(
- HeadsUpManagerPhone.this);
+ mVisualStabilityManager.addReorderingAllowedCallback(HeadsUpManagerPhone.this);
} else if (mTrackingHeadsUp) {
mEntriesToRemoveAfterExpand.add(entry);
} else if (mIsAutoHeadsUp && mStatusBarState == StatusBarState.KEYGUARD) {
@@ -626,4 +542,42 @@
public interface AnimationStateHandler {
void setHeadsUpGoingAwayAnimationsAllowed(boolean allowed);
}
+
+ /**
+ * Listener to register for HeadsUpNotification Phone changes.
+ */
+ public interface OnHeadsUpPhoneListenerChange {
+ /**
+ * Called when a heads up notification is 'going away' or no longer 'going away'.
+ * See {@link HeadsUpManagerPhone#setHeadsUpGoingAway}.
+ */
+ void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway);
+ }
+
+ private final StateListener mStatusBarStateListener = new StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
+ boolean isKeyguard = newState == StatusBarState.KEYGUARD;
+ mStatusBarState = newState;
+ if (wasKeyguard && !isKeyguard && mKeysToRemoveWhenLeavingKeyguard.size() != 0) {
+ String[] keys = mKeysToRemoveWhenLeavingKeyguard.toArray(new String[0]);
+ for (String key : keys) {
+ removeAlertEntry(key);
+ }
+ mKeysToRemoveWhenLeavingKeyguard.clear();
+ }
+ }
+
+ @Override
+ public void onDozingChanged(boolean isDozing) {
+ if (!isDozing) {
+ // Let's make sure all huns we got while dozing time out within the normal timeout
+ // duration. Otherwise they could get stuck for a very long time
+ for (AlertEntry entry : mAlertEntries.values()) {
+ entry.updateEntry(true /* updatePostTime */);
+ }
+ }
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index d2186f9..fb7976f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -453,10 +453,11 @@
KeyguardUpdateMonitor keyguardUpdateMonitor, MetricsLogger metricsLogger,
ActivityManager activityManager, ZenModeController zenModeController,
ConfigurationController configurationController,
- FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
+ FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
+ StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
- latencyTracker, flingAnimationUtilsBuilder);
+ latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
mView = view;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
@@ -704,9 +705,9 @@
private Rect calculateGestureExclusionRect() {
Rect exclusionRect = null;
- Region touchableRegion = mHeadsUpManager.calculateTouchableRegion();
+ Region touchableRegion = mStatusBarTouchableRegionManager.calculateTouchableRegion();
if (isFullyCollapsed() && touchableRegion != null) {
- // Note: The heads up manager also calculates the non-pinned touchable region
+ // Note: The manager also calculates the non-pinned touchable region
exclusionRect = touchableRegion.getBounds();
}
return exclusionRect != null ? exclusionRect : EMPTY_RECT;
@@ -1914,6 +1915,7 @@
boolean isExpanded = !isFullyCollapsed() || mExpectingSynthesizedDown;
if (mPanelExpanded != isExpanded) {
mHeadsUpManager.setIsPanelExpanded(isExpanded);
+ mStatusBarTouchableRegionManager.setPanelExpanded(isExpanded);
mStatusBar.setPanelExpanded(isExpanded);
mPanelExpanded = isExpanded;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index af46f7b..30367ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -73,6 +73,7 @@
protected StatusBar mStatusBar;
protected HeadsUpManagerPhone mHeadsUpManager;
+ protected final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
private float mPeekHeight;
private float mHintDistance;
@@ -206,7 +207,9 @@
FalsingManager falsingManager, DozeLog dozeLog,
KeyguardStateController keyguardStateController,
SysuiStatusBarStateController statusBarStateController, VibratorHelper vibratorHelper,
- LatencyTracker latencyTracker, FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
+ LatencyTracker latencyTracker,
+ FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
+ StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
mView = view;
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
@@ -251,6 +254,7 @@
R.bool.config_enableNotificationShadeDrag);
mVibratorHelper = vibratorHelper;
mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation);
+ mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
}
protected void loadDimens() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 301eac2..d8d96c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -356,6 +356,7 @@
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardStateController mKeyguardStateController;
private final HeadsUpManagerPhone mHeadsUpManager;
+ private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
private final DynamicPrivacyController mDynamicPrivacyController;
private final BypassHeadsUpNotifier mBypassHeadsUpNotifier;
private final FalsingManager mFalsingManager;
@@ -676,7 +677,8 @@
KeyguardDismissUtil keyguardDismissUtil,
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
- DismissCallbackRegistry dismissCallbackRegistry) {
+ DismissCallbackRegistry dismissCallbackRegistry,
+ StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
super(context);
mNotificationsController = notificationsController;
mLightBarController = lightBarController;
@@ -688,6 +690,7 @@
mKeyguardBypassController = keyguardBypassController;
mKeyguardStateController = keyguardStateController;
mHeadsUpManager = headsUpManagerPhone;
+ mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
mDynamicPrivacyController = dynamicPrivacyController;
mBypassHeadsUpNotifier = bypassHeadsUpNotifier;
mFalsingManager = falsingManager;
@@ -1031,9 +1034,8 @@
CollapsedStatusBarFragment.TAG)
.commit();
- mHeadsUpManager.setUp(mNotificationShadeWindowView, mGroupManager, this,
- mVisualStabilityManager);
- mConfigurationController.addCallback(mHeadsUpManager);
+ mHeadsUpManager.setup(mVisualStabilityManager);
+ mStatusBarTouchableRegionManager.setup(this, mNotificationShadeWindowView);
mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener());
mHeadsUpManager.addListener(mVisualStabilityManager);
@@ -2468,6 +2470,12 @@
pw.println(" mHeadsUpManager: null");
}
+ if (mStatusBarTouchableRegionManager != null) {
+ mStatusBarTouchableRegionManager.dump(fd, pw, args);
+ } else {
+ pw.println(" mStatusBarTouchableRegionManager: null");
+ }
+
if (mLightBarController != null) {
mLightBarController.dump(fd, pw, args);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 2485513..693cdd2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -209,7 +209,7 @@
};
mViewHierarchyManager.setUpWithPresenter(this, notifListContainer);
- mEntryManager.setUpWithPresenter(this, notifListContainer, mHeadsUpManager);
+ mEntryManager.setUpWithPresenter(this);
mEntryManager.addNotificationEntryListener(notificationEntryListener);
mEntryManager.addNotificationLifetimeExtender(mHeadsUpManager);
mEntryManager.addNotificationLifetimeExtender(mGutsManager);
@@ -230,8 +230,6 @@
onUserSwitched(mLockscreenUserManager.getCurrentUserId());
});
Dependency.get(ConfigurationController.class).addCallback(this);
-
- notificationAlertingManager.setHeadsUpManager(mHeadsUpManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index b8fb6d3..5bab867 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -17,66 +17,187 @@
package com.android.systemui.statusbar.phone;
import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.Log;
+import android.view.DisplayCutout;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.WindowInsets;
-import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.ScreenDecorations;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
/**
- * Manages what parts of the status bar are touchable. Clients are primarily UI that displays in the
- * status bar even though the UI doesn't look like part of the status bar.
+ * Manages what parts of the status bar are touchable. Clients are primarily UI that display in the
+ * status bar even though the UI doesn't look like part of the status bar. Currently this
+ * includes HeadsUpNotifications and Bubbles.
*/
-public final class StatusBarTouchableRegionManager implements
- OnComputeInternalInsetsListener, ConfigurationListener {
+@Singleton
+public final class StatusBarTouchableRegionManager implements Dumpable {
+ private static final String TAG = "TouchableRegionManager";
- private final BubbleController mBubbleController = Dependency.get(BubbleController.class);
+ private final Context mContext;
private final HeadsUpManagerPhone mHeadsUpManager;
+ private final NotificationShadeWindowController mNotificationShadeWindowController;
+ private final BubbleController mBubbleController;
+
private boolean mIsStatusBarExpanded = false;
private boolean mShouldAdjustInsets = false;
- private final StatusBar mStatusBar;
- private final View mNotificationShadeWindowView;
+ private StatusBar mStatusBar;
+ private View mNotificationShadeWindowView;
private View mNotificationPanelView;
private boolean mForceCollapsedUntilLayout = false;
- private final NotificationShadeWindowController mNotificationShadeWindowController;
- public StatusBarTouchableRegionManager(HeadsUpManagerPhone headsUpManager,
- @NonNull StatusBar statusBar,
- @NonNull View notificationShadeWindowView) {
- mHeadsUpManager = headsUpManager;
- mStatusBar = statusBar;
- mNotificationShadeWindowView = notificationShadeWindowView;
- mNotificationShadeWindowController =
- Dependency.get(NotificationShadeWindowController.class);
+ private Region mTouchableRegion = new Region();
+ private int mDisplayCutoutTouchableRegionSize;
+ private int mStatusBarHeight;
- mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
- updateTouchableRegion();
+ @Inject
+ public StatusBarTouchableRegionManager(
+ Context context,
+ NotificationShadeWindowController notificationShadeWindowController,
+ ConfigurationController configurationController,
+ HeadsUpManagerPhone headsUpManager,
+ BubbleController bubbleController
+ ) {
+ mContext = context;
+ initResources();
+ configurationController.addCallback(new ConfigurationListener() {
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ initResources();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ initResources();
+ }
});
+ mHeadsUpManager = headsUpManager;
+ mHeadsUpManager.addListener(
+ new OnHeadsUpChangedListener() {
+ @Override
+ public void onHeadsUpPinnedModeChanged(boolean hasPinnedNotification) {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "onHeadsUpPinnedModeChanged");
+ }
+ updateTouchableRegion();
+ }
+ });
+ mHeadsUpManager.addHeadsUpPhoneListener(
+ new HeadsUpManagerPhone.OnHeadsUpPhoneListenerChange() {
+ @Override
+ public void onHeadsUpGoingAwayStateChanged(boolean headsUpGoingAway) {
+ if (!headsUpGoingAway) {
+ updateTouchableRegionAfterLayout();
+ } else {
+ updateTouchableRegion();
+ }
+ }
+ });
+
+ mNotificationShadeWindowController = notificationShadeWindowController;
mNotificationShadeWindowController.setForcePluginOpenListener((forceOpen) -> {
updateTouchableRegion();
});
- Dependency.get(ConfigurationController.class).addCallback(this);
- if (mNotificationShadeWindowView != null) {
- mNotificationPanelView = mNotificationShadeWindowView.findViewById(
- R.id.notification_panel);
+
+ mBubbleController = bubbleController;
+ mBubbleController.setBubbleStateChangeListener((hasBubbles) -> {
+ updateTouchableRegion();
+ });
+ }
+
+ protected void setup(
+ @NonNull StatusBar statusBar,
+ @NonNull View notificationShadeWindowView) {
+ mStatusBar = statusBar;
+ mNotificationShadeWindowView = notificationShadeWindowView;
+ mNotificationPanelView = mNotificationShadeWindowView.findViewById(R.id.notification_panel);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("StatusBarTouchableRegionManager state:");
+ pw.print(" mTouchableRegion=");
+ pw.println(mTouchableRegion);
+ }
+
+ /**
+ * Notify that the status bar panel gets expanded or collapsed.
+ *
+ * @param isExpanded True to notify expanded, false to notify collapsed.
+ */
+ void setPanelExpanded(boolean isExpanded) {
+ if (isExpanded != mIsStatusBarExpanded) {
+ mIsStatusBarExpanded = isExpanded;
+ if (isExpanded) {
+ // make sure our state is sane
+ mForceCollapsedUntilLayout = false;
+ }
+ updateTouchableRegion();
}
}
/**
+ * Calculates the touch region needed for heads up notifications, taking into consideration
+ * any existing display cutouts (notch)
+ * @return the heads up notification touch area
+ */
+ Region calculateTouchableRegion() {
+ // Update touchable region for HeadsUp notifications
+ final Region headsUpTouchableRegion = mHeadsUpManager.getTouchableRegion();
+ if (headsUpTouchableRegion != null) {
+ mTouchableRegion.set(headsUpTouchableRegion);
+ } else {
+ // If there aren't any HUNs, update the touch region to the status bar
+ // width/height, potentially adjusting for a display cutout (notch)
+ mTouchableRegion.set(0, 0, mNotificationShadeWindowView.getWidth(),
+ mStatusBarHeight);
+ updateRegionForNotch(mTouchableRegion);
+ }
+
+ // Update touchable region for bubbles
+ Rect bubbleRect = mBubbleController.getTouchableRegion();
+ if (bubbleRect != null) {
+ mTouchableRegion.union(bubbleRect);
+ }
+ return mTouchableRegion;
+ }
+
+ private void initResources() {
+ Resources resources = mContext.getResources();
+ mDisplayCutoutTouchableRegionSize = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.display_cutout_touchable_region_size);
+ mStatusBarHeight =
+ resources.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ }
+
+ /**
* Set the touchable portion of the status bar based on what elements are visible.
*/
- public void updateTouchableRegion() {
+ private void updateTouchableRegion() {
boolean hasCutoutInset = (mNotificationShadeWindowView != null)
&& (mNotificationShadeWindowView.getRootWindowInsets() != null)
&& (mNotificationShadeWindowView.getRootWindowInsets().getDisplayCutout() != null);
- boolean shouldObserve =
- mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpManager.isHeadsUpGoingAway()
+ boolean shouldObserve = mHeadsUpManager.hasPinnedHeadsUp()
+ || mHeadsUpManager.isHeadsUpGoingAway()
|| mBubbleController.hasBubbles()
|| mForceCollapsedUntilLayout
|| hasCutoutInset
@@ -87,11 +208,11 @@
if (shouldObserve) {
mNotificationShadeWindowView.getViewTreeObserver()
- .addOnComputeInternalInsetsListener(this);
+ .addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
mNotificationShadeWindowView.requestLayout();
} else {
mNotificationShadeWindowView.getViewTreeObserver()
- .removeOnComputeInternalInsetsListener(this);
+ .removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
mShouldAdjustInsets = shouldObserve;
}
@@ -99,7 +220,7 @@
/**
* Calls {@code updateTouchableRegion()} after a layout pass completes.
*/
- public void updateTouchableRegionAfterLayout() {
+ private void updateTouchableRegionAfterLayout() {
if (mNotificationPanelView != null) {
mForceCollapsedUntilLayout = true;
mNotificationPanelView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@@ -116,34 +237,38 @@
}
}
- /**
- * Notify that the status bar panel gets expanded or collapsed.
- *
- * @param isExpanded True to notify expanded, false to notify collapsed.
- */
- public void setIsStatusBarExpanded(boolean isExpanded) {
- if (isExpanded != mIsStatusBarExpanded) {
- mIsStatusBarExpanded = isExpanded;
- if (isExpanded) {
- // make sure our state is sane
- mForceCollapsedUntilLayout = false;
- }
- updateTouchableRegion();
+ private void updateRegionForNotch(Region touchableRegion) {
+ WindowInsets windowInsets = mNotificationShadeWindowView.getRootWindowInsets();
+ if (windowInsets == null) {
+ Log.w(TAG, "StatusBarWindowView is not attached.");
+ return;
}
- }
-
- @Override
- public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
- if (mIsStatusBarExpanded || mStatusBar.isBouncerShowing()) {
- // The touchable region is always the full area when expanded
+ DisplayCutout cutout = windowInsets.getDisplayCutout();
+ if (cutout == null) {
return;
}
- mHeadsUpManager.updateTouchableRegion(info);
-
- Rect bubbleRect = mBubbleController.getTouchableRegion();
- if (bubbleRect != null) {
- info.touchableRegion.union(bubbleRect);
- }
+ // Expand touchable region such that we also catch touches that just start below the notch
+ // area.
+ Rect bounds = new Rect();
+ ScreenDecorations.DisplayCutoutView.boundsFromDirection(cutout, Gravity.TOP, bounds);
+ bounds.offset(0, mDisplayCutoutTouchableRegionSize);
+ touchableRegion.union(bounds);
}
+
+ private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener =
+ new OnComputeInternalInsetsListener() {
+ @Override
+ public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
+ if (mIsStatusBarExpanded || mStatusBar.isBouncerShowing()) {
+ // The touchable region is always the full area when expanded
+ return;
+ }
+
+ // Update touch insets to include any area needed for touching features that live in
+ // the status bar (ie: heads up notifications or bubbles)
+ info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ info.touchableRegion.set(calculateTouchableRegion());
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 26459a9..e64f821 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -85,6 +85,7 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarNotificationActivityStarter;
+import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -192,7 +193,8 @@
KeyguardDismissUtil keyguardDismissUtil,
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
- DismissCallbackRegistry dismissCallbackRegistry) {
+ DismissCallbackRegistry dismissCallbackRegistry,
+ StatusBarTouchableRegionManager statusBarTouchableRegionManager) {
return new StatusBar(
context,
notificationsController,
@@ -267,6 +269,7 @@
keyguardDismissUtil,
extensionController,
userInfoControllerImpl,
- dismissCallbackRegistry);
+ dismissCallbackRegistry,
+ statusBarTouchableRegionManager);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
index 264ddc0..be30a4a 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 f6e921e..3f05657 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 @@
* 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 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 082782d..b6ca8d8e 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 @@
@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 116f8fc..462b042 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.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 @@
@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 e4b83cc..bc3c3d9 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 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 @@
@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 7e4ba92..befe3e1 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 @@
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 ffe8c28..471149c 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 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.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 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 8d11b54..c912b67 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.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 @@
@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 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 fc331d6..689eed9 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 @@
@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 c85d600..7ac5443 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.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 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 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 fc79fcb..daea7a7 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.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 @@
private SysuiStatusBarStateController mStatusBarStateController;
@Mock
private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private FloatingContentCoordinator mFloatingContentCoordinator;
@Captor
private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
@@ -243,7 +246,8 @@
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 24f8a7b..b412ca5 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.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 @@
private SysuiStatusBarStateController mStatusBarStateController;
@Mock
private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private FloatingContentCoordinator mFloatingContentCoordinator;
@Captor
private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
@@ -232,7 +235,8 @@
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 338abf5..f9849f4 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.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 @@
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 d79128c..9cc0349 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 @@
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.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 @@
@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 @@
@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 @@
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 @@
* 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/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 6d83ac3..644ed3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -85,7 +85,7 @@
Dependency.get(NotificationLockscreenUserManager.class);
NotificationViewHierarchyManager viewHierarchyManager =
Dependency.get(NotificationViewHierarchyManager.class);
- entryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
+ entryManager.setUpWithPresenter(mPresenter);
entryManager.addNotificationEntryListener(mEntryListener);
gutsManager.setUpWithPresenter(mPresenter, mListContainer,
mCheckSaveListener, mOnSettingsClickListener);
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 60163f2..8e87e0a 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.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 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 9d667a9..0a38f16 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 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 @@
@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 f1fba79..6a6e5c8 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.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 @@
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);
@@ -256,7 +255,7 @@
mLeakDetector,
mock(ForegroundServiceDismissalFeatureController.class)
);
- mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
+ mEntryManager.setUpWithPresenter(mPresenter);
mEntryManager.addNotificationEntryListener(mEntryListener);
mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor);
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 1116a33..97e0a31 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.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 @@
@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/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
index 0e730e5..d522f90 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -22,11 +22,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.NotificationGroupManager
import com.android.systemui.util.leak.LeakDetector
-
import java.util.concurrent.CountDownLatch
/**
@@ -53,11 +50,9 @@
}
fun setUpForTest(
- presenter: NotificationPresenter?,
- listContainer: NotificationListContainer?,
- headsUpManager: HeadsUpManagerPhone?
+ presenter: NotificationPresenter?
) {
- super.setUpWithPresenter(presenter, listContainer, headsUpManager)
+ super.setUpWithPresenter(presenter)
}
fun setActiveNotificationList(activeList: List<NotificationEntry>) {
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 12e9d31..605b59e 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.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 @@
@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 27ca18c..e570ab8 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.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 @@
@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 eb1af7c..67b1aad 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.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 @@
@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 a891810..e960185 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 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 @@
@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 a8c438a..481bac2 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.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 @@
@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 bbb6723..54c0bde 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.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 @@
@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/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 9a52ee8..5a89fc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -56,6 +56,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpansionLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -102,8 +103,8 @@
mStatusBarStateController = mock(StatusBarStateController.class);
mGroupManager = new NotificationGroupManager(mStatusBarStateController);
mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController,
- mock(KeyguardBypassController.class));
- mHeadsUpManager.setUp(null, mGroupManager, null, null);
+ mock(KeyguardBypassController.class), mock(NotificationGroupManager.class),
+ mock(ConfigurationControllerImpl.class));
mGroupManager.setHeadsUpManager(mHeadsUpManager);
NotificationContentInflater contentBinder = new NotificationContentInflater(
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 0790cb7..b661b28 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 @@
@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 038eff7..69e4f22 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.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 @@
@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 9567f33..830e8d9 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 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 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 @@
@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 1773175..a2029c7 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 @@
@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 2d1bc78..ba2b946 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.when;
import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
@@ -66,7 +65,7 @@
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 9ccee75..0cb6585 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 @@
@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);
@@ -185,7 +185,7 @@
mock(LeakDetector.class),
mock(ForegroundServiceDismissalFeatureController.class)
);
- mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
+ mEntryManager.setUpForTest(mock(NotificationPresenter.class));
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
NotificationShelf notificationShelf = mock(NotificationShelf.class);
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 f71d0fc..a74657e 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.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 @@
@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/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 50d8bf0b0..6d642ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -62,16 +62,21 @@
@Mock private StatusBar mBar;
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private KeyguardBypassController mBypassController;
+ @Mock private ConfigurationControllerImpl mConfigurationController;
private boolean mLivesPastNormalTime;
private final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
- TestableHeadsUpManagerPhone(Context context, View notificationShadeWindowView,
- NotificationGroupManager groupManager, StatusBar bar,
+ TestableHeadsUpManagerPhone(
+ Context context,
+ NotificationGroupManager groupManager,
VisualStabilityManager vsManager,
StatusBarStateController statusBarStateController,
- KeyguardBypassController keyguardBypassController) {
- super(context, statusBarStateController, keyguardBypassController);
- setUp(notificationShadeWindowView, groupManager, bar, vsManager);
+ KeyguardBypassController keyguardBypassController,
+ ConfigurationController configurationController
+ ) {
+ super(context, statusBarStateController, keyguardBypassController,
+ groupManager, configurationController);
+ setup(vsManager);
mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
}
@@ -91,8 +96,8 @@
mDependency.injectMockDependency(BubbleController.class);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
mDependency.injectMockDependency(ConfigurationController.class);
- mHeadsUpManager = new TestableHeadsUpManagerPhone(mContext, mNotificationShadeWindowView,
- mGroupManager, mBar, mVSManager, mStatusBarStateController, mBypassController);
+ mHeadsUpManager = new TestableHeadsUpManagerPhone(mContext, mGroupManager, mVSManager,
+ mStatusBarStateController, mBypassController, mConfigurationController);
super.setUp();
mHeadsUpManager.mHandler = mTestHandler;
}
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 67b8e07..35971bd 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 @@
@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/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 5fb7159..13bf38c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -138,6 +138,8 @@
@Mock
private NotificationEntryManager mNotificationEntryManager;
@Mock
+ private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+ @Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private DozeLog mDozeLog;
@@ -221,7 +223,7 @@
mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
- mFlingAnimationUtilsBuilder);
+ mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager);
mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager,
mNotificationShelf, mNotificationAreaController, mScrimController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index db17a6e..e5ee439 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -236,6 +236,7 @@
@Mock private LightsOutNotifController mLightsOutNotifController;
@Mock private ViewMediatorCallback mViewMediatorCallback;
@Mock private DismissCallbackRegistry mDismissCallbackRegistry;
+ @Mock private StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
@Mock private ScreenPinningRequest mScreenPinningRequest;
@Mock private LockscreenLockIconController mLockscreenLockIconController;
@Mock private StatusBarNotificationActivityStarter.Builder
@@ -397,7 +398,8 @@
mKeyguardDismissUtil,
mExtensionController,
mUserInfoControllerImpl,
- mDismissCallbackRegistry);
+ mDismissCallbackRegistry,
+ mStatusBarTouchableRegionManager);
when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
mLockIconContainer);
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 df62254..86add98 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.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 @@
@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 20dcbb7..1ff9548 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.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 @@
@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 @@
@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 bfa962a..fd9f713 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 @@
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 0f36260..7083281 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4791,7 +4791,7 @@
return false;
}
- return vpn.startAlwaysOnVpn();
+ return vpn.startAlwaysOnVpn(mKeyStore);
}
}
@@ -4806,7 +4806,7 @@
Slog.w(TAG, "User " + userId + " has no Vpn configuration");
return false;
}
- return vpn.isAlwaysOnPackageSupported(packageName);
+ return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
}
}
@@ -4827,11 +4827,11 @@
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 @@
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 @@
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 @@
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 7aa4661..207a6aa 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -194,6 +194,8 @@
// 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 @@
private int mBatterySaverMode;
private LocationManagerService(Context context) {
- mContext = context;
+ mContext = context.createFeatureContext(FEATURE_ID);
mHandler = FgThread.getHandler();
mLocalService = new LocalService();
@@ -1452,7 +1454,7 @@
}
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 @@
// 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 @@
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 @@
*/
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 @@
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 @@
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 7f5befa..9082dca 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.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 @@
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 @@
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 5df3e1f..9082807 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 @@
// 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 @@
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 @@
}
// 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 @@
}
}
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 @@
}
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 5e1582c..a934f22 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 @@
}
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 @@
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 @@
uidState.evalForegroundOps(mOpModeWatchers);
}
- notifyOpChangedForAllPkgsInUid(code, uid, false, callbackToIgnore);
+ notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
notifyOpChangedSync(code, uid, null, mode);
}
@@ -2337,7 +2339,7 @@
}
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 @@
}
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 @@
}
@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 77f4093..3138639 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 @@
* 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 @@
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 @@
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
updateCapabilities(null /* defaultNetwork */);
- loadAlwaysOnPackage();
+ loadAlwaysOnPackage(keyStore);
}
/**
@@ -437,23 +437,36 @@
/**
* 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
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 @@
}
}
- /**
- * 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 @@
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 @@
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 @@
}
}
- // 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 @@
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 @@
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 @@
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 @@
// 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/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 6d130d9..4a1afb2 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1216,7 +1216,7 @@
for (SyncOperation op: ops) {
if (op.isPeriodic && op.target.matchesSpec(target)) {
periodicSyncs.add(new PeriodicSync(op.target.account, op.target.provider,
- op.extras, op.periodMillis / 1000, op.flexMillis / 1000));
+ op.getClonedExtras(), op.periodMillis / 1000, op.flexMillis / 1000));
}
}
@@ -1478,7 +1478,7 @@
Slog.e(TAG, "Can't schedule null sync operation.");
return;
}
- if (!syncOperation.ignoreBackoff()) {
+ if (!syncOperation.hasIgnoreBackoff()) {
Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(syncOperation.target);
if (backoff == null) {
Slog.e(TAG, "Couldn't find backoff values for "
@@ -1631,7 +1631,7 @@
getSyncStorageEngine().markPending(syncOperation.target, true);
}
- if (syncOperation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING)) {
+ if (syncOperation.hasRequireCharging()) {
b.setRequiresCharging(true);
}
@@ -1686,7 +1686,7 @@
List<SyncOperation> ops = getAllPendingSyncs();
for (SyncOperation op: ops) {
if (!op.isPeriodic && op.target.matchesSpec(info)
- && syncExtrasEquals(extras, op.extras, false)) {
+ && op.areExtrasEqual(extras, /*includeSyncSettings=*/ false)) {
cancelJob(op, "cancelScheduledSyncOperation");
}
}
@@ -1704,15 +1704,9 @@
Log.d(TAG, "encountered error(s) during the sync: " + syncResult + ", " + operation);
}
- // The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
- // request. Retries of the request will always honor the backoff, so clear the
- // flag in case we retry this request.
- if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)) {
- operation.extras.remove(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
- }
+ operation.enableBackoff();
- if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
- && !syncResult.syncAlreadyInProgress) {
+ if (operation.hasDoNotRetry() && !syncResult.syncAlreadyInProgress) {
// syncAlreadyInProgress flag is set by AbstractThreadedSyncAdapter. The sync adapter
// has no way of knowing that a sync error occured. So we DO retry if the error is
// syncAlreadyInProgress.
@@ -1720,10 +1714,9 @@
Log.d(TAG, "not retrying sync operation because SYNC_EXTRAS_DO_NOT_RETRY was specified "
+ operation);
}
- } else if (operation.extras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false)
- && !syncResult.syncAlreadyInProgress) {
+ } else if (operation.isUpload() && !syncResult.syncAlreadyInProgress) {
// If this was an upward sync then schedule a two-way sync immediately.
- operation.extras.remove(ContentResolver.SYNC_EXTRAS_UPLOAD);
+ operation.enableTwoWaySync();
if (isLoggable) {
Log.d(TAG, "retrying sync operation as a two-way sync because an upload-only sync "
+ "encountered an error: " + operation);
@@ -3326,7 +3319,7 @@
List<SyncOperation> ops = getAllPendingSyncs();
for (SyncOperation op: ops) {
if (op.isPeriodic && op.target.matchesSpec(target)
- && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
+ && op.areExtrasEqual(extras, /*includeSyncSettings=*/ true)) {
maybeUpdateSyncPeriodH(op, pollFrequencyMillis, flexMillis);
return;
}
@@ -3408,7 +3401,7 @@
List<SyncOperation> ops = getAllPendingSyncs();
for (SyncOperation op: ops) {
if (op.isPeriodic && op.target.matchesSpec(target)
- && syncExtrasEquals(op.extras, extras, true /* includeSyncSettings */)) {
+ && op.areExtrasEqual(extras, /*includeSyncSettings=*/ true)) {
removePeriodicSyncInternalH(op, why);
}
}
@@ -3559,16 +3552,18 @@
activeSyncContext.mIsLinkedToDeath = true;
syncAdapter.linkToDeath(activeSyncContext, 0);
- mLogger.log("Sync start: account=" + syncOperation.target.account,
- " authority=", syncOperation.target.provider,
- " reason=", SyncOperation.reasonToString(null, syncOperation.reason),
- " extras=", SyncOperation.extrasToString(syncOperation.extras),
- " adapter=", activeSyncContext.mSyncAdapter);
+ if (mLogger.enabled()) {
+ mLogger.log("Sync start: account=" + syncOperation.target.account,
+ " authority=", syncOperation.target.provider,
+ " reason=", SyncOperation.reasonToString(null, syncOperation.reason),
+ " extras=", syncOperation.getExtrasAsString(),
+ " adapter=", activeSyncContext.mSyncAdapter);
+ }
activeSyncContext.mSyncAdapter = ISyncAdapter.Stub.asInterface(syncAdapter);
activeSyncContext.mSyncAdapter
.startSync(activeSyncContext, syncOperation.target.provider,
- syncOperation.target.account, syncOperation.extras);
+ syncOperation.target.account, syncOperation.getClonedExtras());
mLogger.log("Sync is running now...");
} catch (RemoteException remoteExc) {
@@ -3602,9 +3597,8 @@
continue;
}
if (extras != null &&
- !syncExtrasEquals(activeSyncContext.mSyncOperation.extras,
- extras,
- false /* no config settings */)) {
+ !activeSyncContext.mSyncOperation.areExtrasEqual(extras,
+ /*includeSyncSettings=*/ false)) {
continue;
}
SyncJobService.callJobFinished(activeSyncContext.mSyncOperation.jobId, false,
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 2abc2e6..09b7828 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -74,7 +74,14 @@
/** Where this sync was initiated. */
public final int syncSource;
public final boolean allowParallelSyncs;
- public final Bundle extras;
+
+ /**
+ * Sync extras. Note, DO NOT modify this bundle directly. When changing the content, always
+ * create a copy, update it, set it in this field. This is to avoid concurrent modifications
+ * when other threads are reading it.
+ */
+ private volatile Bundle mImmutableExtras;
+
public final boolean isPeriodic;
/** jobId of the periodic SyncOperation that initiated this one */
public final int sourcePeriodicId;
@@ -118,20 +125,21 @@
public SyncOperation(SyncOperation op, long periodMillis, long flexMillis) {
this(op.target, op.owningUid, op.owningPackage, op.reason, op.syncSource,
- new Bundle(op.extras), op.allowParallelSyncs, op.isPeriodic, op.sourcePeriodicId,
+ op.mImmutableExtras, op.allowParallelSyncs, op.isPeriodic, op.sourcePeriodicId,
periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
}
public SyncOperation(SyncStorageEngine.EndPoint info, int owningUid, String owningPackage,
- int reason, int source, Bundle extras, boolean allowParallelSyncs,
- boolean isPeriodic, int sourcePeriodicId, long periodMillis,
- long flexMillis, @SyncExemption int syncExemptionFlag) {
+ int reason, int source, Bundle extras,
+ boolean allowParallelSyncs,
+ boolean isPeriodic, int sourcePeriodicId, long periodMillis,
+ long flexMillis, @SyncExemption int syncExemptionFlag) {
this.target = info;
this.owningUid = owningUid;
this.owningPackage = owningPackage;
this.reason = reason;
this.syncSource = source;
- this.extras = new Bundle(extras);
+ this.mImmutableExtras = new Bundle(extras);
this.allowParallelSyncs = allowParallelSyncs;
this.isPeriodic = isPeriodic;
this.sourcePeriodicId = sourcePeriodicId;
@@ -148,7 +156,7 @@
return null;
}
SyncOperation op = new SyncOperation(target, owningUid, owningPackage, reason, syncSource,
- new Bundle(extras), allowParallelSyncs, false, jobId /* sourcePeriodicId */,
+ mImmutableExtras, allowParallelSyncs, false, jobId /* sourcePeriodicId */,
periodMillis, flexMillis, ContentResolver.SYNC_EXEMPTION_NONE);
return op;
}
@@ -160,7 +168,10 @@
reason = other.reason;
syncSource = other.syncSource;
allowParallelSyncs = other.allowParallelSyncs;
- extras = new Bundle(other.extras);
+
+ // Since we treat this field as immutable, it's okay to use a shallow copy here.
+ // No need to create a copy.
+ mImmutableExtras = other.mImmutableExtras;
wakeLockName = other.wakeLockName();
isPeriodic = other.isPeriodic;
sourcePeriodicId = other.sourcePeriodicId;
@@ -173,7 +184,8 @@
/**
* All fields are stored in a corresponding key in the persistable bundle.
*
- * {@link #extras} is a Bundle and can contain parcelable objects. But only the type Account
+ * {@link #mImmutableExtras} is a Bundle and can contain parcelable objects.
+ * But only the type Account
* is allowed {@link ContentResolver#validateSyncExtrasBundle(Bundle)} that can't be stored in
* a PersistableBundle. For every value of type Account with key 'key', we store a
* PersistableBundle containing account information at key 'ACCOUNT:key'. The Account object
@@ -188,7 +200,9 @@
PersistableBundle jobInfoExtras = new PersistableBundle();
PersistableBundle syncExtrasBundle = new PersistableBundle();
- for (String key: extras.keySet()) {
+
+ final Bundle extras = mImmutableExtras;
+ for (String key : extras.keySet()) {
Object value = extras.get(key);
if (value instanceof Account) {
Account account = (Account) value;
@@ -327,7 +341,7 @@
boolean matchesPeriodicOperation(SyncOperation other) {
return target.matchesSpec(other.target)
- && SyncManager.syncExtrasEquals(extras, other.extras, true)
+ && SyncManager.syncExtrasEquals(mImmutableExtras, other.mImmutableExtras, true)
&& periodMillis == other.periodMillis && flexMillis == other.flexMillis;
}
@@ -345,6 +359,7 @@
}
private String toKey() {
+ final Bundle extras = mImmutableExtras;
StringBuilder sb = new StringBuilder();
sb.append("provider: ").append(target.provider);
sb.append(" account {name=" + target.account.name
@@ -372,6 +387,7 @@
String dump(PackageManager pm, boolean shorter, SyncAdapterStateFetcher appStates,
boolean logSafe) {
+ final Bundle extras = mImmutableExtras;
StringBuilder sb = new StringBuilder();
sb.append("JobId=").append(jobId)
.append(" ")
@@ -468,33 +484,67 @@
}
boolean isInitialization() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
}
boolean isExpedited() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false);
}
- boolean ignoreBackoff() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
+ boolean isUpload() {
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, false);
+ }
+
+ /**
+ * Disable SYNC_EXTRAS_UPLOAD, so it will be a two-way (normal) sync.
+ */
+ void enableTwoWaySync() {
+ removeExtra(ContentResolver.SYNC_EXTRAS_UPLOAD);
+ }
+
+ boolean hasIgnoreBackoff() {
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false);
+ }
+
+ /**
+ * Disable SYNC_EXTRAS_IGNORE_BACKOFF.
+ *
+ * The SYNC_EXTRAS_IGNORE_BACKOFF only applies to the first attempt to sync a given
+ * request. Retries of the request will always honor the backoff, so clear the
+ * flag in case we retry this request.
+ */
+ void enableBackoff() {
+ removeExtra(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF);
+ }
+
+ boolean hasDoNotRetry() {
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false);
}
boolean isNotAllowedOnMetered() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, false);
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_DISALLOW_METERED, false);
}
boolean isManual() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false);
}
boolean isIgnoreSettings() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false);
+ }
+
+ boolean hasRequireCharging() {
+ return mImmutableExtras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING, false);
}
boolean isAppStandbyExempted() {
return syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE;
}
+ boolean areExtrasEqual(Bundle other, boolean includeSyncSettings) {
+ return SyncManager.syncExtrasEquals(mImmutableExtras, other, includeSyncSettings);
+ }
+
static void extrasToStringBuilder(Bundle bundle, StringBuilder sb) {
if (bundle == null) {
sb.append("null");
@@ -507,7 +557,7 @@
sb.append("]");
}
- static String extrasToString(Bundle bundle) {
+ private static String extrasToString(Bundle bundle) {
final StringBuilder sb = new StringBuilder();
extrasToStringBuilder(bundle, sb);
return sb.toString();
@@ -531,4 +581,25 @@
logArray[3] = target.account.name.hashCode();
return logArray;
}
+
+ /**
+ * Removes a sync extra. Note do not call it from multiple threads simultaneously.
+ */
+ private void removeExtra(String key) {
+ final Bundle b = mImmutableExtras;
+ if (!b.containsKey(key)) {
+ return;
+ }
+ final Bundle clone = new Bundle(b);
+ clone.remove(key);
+ mImmutableExtras = clone;
+ }
+
+ public Bundle getClonedExtras() {
+ return new Bundle(mImmutableExtras);
+ }
+
+ public String getExtrasAsString() {
+ return extrasToString(mImmutableExtras);
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index afdcda9..8c510b7 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -137,7 +137,7 @@
/**
* String names for the sync source types.
*
- * KEEP THIS AND {@link SyncStatusInfo#SOURCE_COUNT} IN SYNC.
+ * KEEP THIS AND {@link SyncStatusInfo}.SOURCE_COUNT IN SYNC.
*/
public static final String[] SOURCES = {
"OTHER",
@@ -1117,7 +1117,7 @@
Slog.v(TAG, "setActiveSync: account="
+ " auth=" + activeSyncContext.mSyncOperation.target
+ " src=" + activeSyncContext.mSyncOperation.syncSource
- + " extras=" + activeSyncContext.mSyncOperation.extras);
+ + " extras=" + activeSyncContext.mSyncOperation.getExtrasAsString());
}
final EndPoint info = activeSyncContext.mSyncOperation.target;
AuthorityInfo authorityInfo = getOrCreateAuthorityLocked(
@@ -1179,7 +1179,7 @@
item.eventTime = now;
item.source = op.syncSource;
item.reason = op.reason;
- item.extras = op.extras;
+ item.extras = op.getClonedExtras();
item.event = EVENT_START;
item.syncExemptionFlag = op.syncExemptionFlag;
mSyncHistory.add(0, item);
diff --git a/services/core/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java
index 8326ef9..b158388 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 @@
* @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 @@
* 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 b1913389..dcdf48b 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 java.util.ArrayList;
import java.util.HashMap;
+import java.util.Objects;
/**
* Holds statistics for location requests (active requests by provider).
@@ -43,13 +45,14 @@
/**
* 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 @@
}
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 @@
}
/**
- * 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 @@
}
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 @@
* 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 @@
* 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 @@
*/
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 @@
.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 @@
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 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 dc61fb0..dbaf824 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 @@
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 @@
@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 @@
}
}
+ 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 9aab0fd..88e0dc6 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 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 90dd3c6..ad4e81b 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 @@
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 {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 9f8362c..20c8625 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 @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 0fb889c..a1250cb 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 @@
// 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 @@
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 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 027a302..486282a 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 @@
@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 3939f26..ec9b37d 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.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 @@
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 @@
CrossProfileAppsServiceImpl(Context context, Injector injector) {
mContext = context;
mInjector = injector;
-
- LocalServices.addService(CrossProfileAppsInternal.class, new LocalService());
}
@Override
@@ -167,6 +168,8 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
-> 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 @@
}
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 @@
@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 f93c663..3a16217 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 @@
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 @@
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 @@
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 43d4596..c13cb38 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 @@
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 @@
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 @@
// 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 a7b0d84..8483c77 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 @@
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 @@
// 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 @@
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 @@
}
};
}
+
+ void invalidateIsInteractiveCaches() {
+ PowerManager.invalidateIsInteractiveCaches();
+ }
}
final Constants mConstants;
@@ -833,9 +845,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
if (eventTime < mLastWakeTime
- || mWakefulness == WAKEFULNESS_ASLEEP
- || mWakefulness == WAKEFULNESS_DOZING
+ || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
+ || getWakefulnessLocked() == WAKEFULNESS_DOZING
|| !mSystemReady
|| !mBootCompleted) {
return false;
@@ -1738,7 +1750,7 @@
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 @@
+ ", uid=" + uid);
}
- if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
|| !mBootCompleted || !mSystemReady) {
return false;
}
@@ -1781,13 +1793,15 @@
@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 @@
}
@VisibleForTesting
- int getWakefulness() {
- return mWakefulness;
+ int getWakefulnessLocked() {
+ return mWakefulnessRaw;
}
/**
@@ -1816,17 +1830,18 @@
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 @@
}
// 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 @@
}
// 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 @@
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
- + PowerManagerInternal.wakefulnessToString(mWakefulness)
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
}
}
@@ -2089,23 +2104,23 @@
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 @@
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 @@
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 @@
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 @@
return false;
}
- if (mWakefulness != WAKEFULNESS_AWAKE) {
+ if (getWakefulnessLocked() != WAKEFULNESS_AWAKE) {
mInattentiveSleepWarningOverlayController.dismiss(false);
return true;
} else if (attentiveTimeout < 0 || isBeingKeptFromShowingInattentiveSleepWarningLocked()
@@ -2490,7 +2505,7 @@
| 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 @@
final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
- wakefulness = mWakefulness;
+ wakefulness = getWakefulnessLocked();
if (mSandmanSummoned && mDisplayReady) {
startDreaming = canDreamLocked() || canDozeLocked();
mSandmanSummoned = false;
@@ -2655,7 +2670,7 @@
// 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 @@
* 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 @@
* 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 @@
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 @@
@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 @@
// 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 @@
private boolean isInteractiveInternal() {
synchronized (mLock) {
- return PowerManagerInternal.isInteractive(mWakefulness);
+ return PowerManagerInternal.isInteractive(getWakefulnessLocked());
}
}
@@ -3495,7 +3510,7 @@
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 @@
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 @@
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 4142e6f..beba106 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 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 @@
@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 @@
mPlugins = new Plugin[] {
new BatterySaverLocationPlugin(mContext)
};
+ PowerManager.invalidatePowerSaveModeCaches();
}
/**
@@ -294,10 +302,10 @@
@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 @@
}
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 boolean isEnabled() {
synchronized (mLock) {
- return mFullEnabled
- || (mAdaptiveEnabled && mBatterySaverPolicy.shouldAdvertiseIsEnabled());
+ return getFullEnabledLocked() || (getAdaptiveEnabledLocked()
+ && mBatterySaverPolicy.shouldAdvertiseIsEnabled());
}
}
@@ -332,19 +340,19 @@
*/
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 @@
}
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 @@
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 @@
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 38bdc62..233417d 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 @@
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 @@
return R.string.config_batterySaverDeviceSpecificConfig;
}
+ @VisibleForTesting
+ void invalidatePowerSaveModeCaches() {
+ PowerManager.invalidatePowerSaveModeCaches();
+ }
+
@Override
public void onChange(boolean selfChange, Uri uri) {
refreshSettings();
@@ -373,14 +382,14 @@
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 @@
*/
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 @@
}
mAdaptivePolicy = p;
- if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE) {
+ if (getPolicyLevelLocked() == POLICY_LEVEL_ADAPTIVE) {
updatePolicyDependenciesLocked();
return true;
}
@@ -924,7 +933,7 @@
}
private Policy getCurrentPolicyLocked() {
- switch (mPolicyLevel) {
+ switch (getPolicyLevelLocked()) {
case POLICY_LEVEL_FULL:
return mFullPolicy;
case POLICY_LEVEL_ADAPTIVE:
@@ -985,7 +994,7 @@
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 @@
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/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index 4b3746b..42aaec9 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -176,8 +176,10 @@
@GuardedBy("mLock")
private int mSettingBatterySaverStickyAutoDisableThreshold;
- /** Config flag to track default disable threshold for Dynamic Power Savings enabled battery
- * saver. */
+ /**
+ * Config flag to track default disable threshold for Dynamic Power Savings enabled battery
+ * saver.
+ */
@GuardedBy("mLock")
private final int mDynamicPowerSavingsDefaultDisableThreshold;
@@ -192,8 +194,9 @@
@GuardedBy("mLock")
private int mSettingAutomaticBatterySaver;
- /** When to disable battery saver again if it was enabled due to an external suggestion.
- * Corresponds to Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD.
+ /**
+ * When to disable battery saver again if it was enabled due to an external suggestion.
+ * Corresponds to Settings.Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD.
*/
@GuardedBy("mLock")
private int mDynamicPowerSavingsDisableThreshold;
@@ -203,7 +206,7 @@
* Updates when Settings.Global.DYNAMIC_POWER_SAVINGS_ENABLED changes.
*/
@GuardedBy("mLock")
- private boolean mDynamicPowerSavingsBatterySaver;
+ private boolean mDynamicPowerSavingsEnableBatterySaver;
/**
* Last reason passed to {@link #enableBatterySaverLocked}.
@@ -265,7 +268,7 @@
/** @return true if the dynamic mode should be used */
private boolean isDynamicModeActiveLocked() {
return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVE_MODE_TRIGGER_DYNAMIC
- && mDynamicPowerSavingsBatterySaver;
+ && mDynamicPowerSavingsEnableBatterySaver;
}
/**
@@ -428,7 +431,7 @@
final boolean dynamicPowerSavingsThresholdChanged =
mDynamicPowerSavingsDisableThreshold != dynamicPowerSavingsDisableThreshold;
final boolean dynamicPowerSavingsBatterySaverChanged =
- mDynamicPowerSavingsBatterySaver != dynamicPowerSavingsBatterySaver;
+ mDynamicPowerSavingsEnableBatterySaver != dynamicPowerSavingsBatterySaver;
if (!(enabledChanged || stickyChanged || thresholdChanged || automaticModeChanged
|| stickyAutoDisableEnabledChanged || stickyAutoDisableThresholdChanged
@@ -443,7 +446,7 @@
mSettingBatterySaverStickyAutoDisableThreshold = stickyAutoDisableThreshold;
mSettingAutomaticBatterySaver = automaticBatterySaver;
mDynamicPowerSavingsDisableThreshold = dynamicPowerSavingsDisableThreshold;
- mDynamicPowerSavingsBatterySaver = dynamicPowerSavingsBatterySaver;
+ mDynamicPowerSavingsEnableBatterySaver = dynamicPowerSavingsBatterySaver;
if (thresholdChanged) {
// To avoid spamming the event log, we throttle logging here.
@@ -923,6 +926,8 @@
pw.print(" mIsBatteryLevelLow=");
pw.println(mIsBatteryLevelLow);
+ pw.print(" mSettingAutomaticBatterySaver=");
+ pw.println(mSettingAutomaticBatterySaver);
pw.print(" mSettingBatterySaverEnabled=");
pw.println(mSettingBatterySaverEnabled);
pw.print(" mSettingBatterySaverEnabledSticky=");
@@ -936,6 +941,13 @@
pw.print(" mBatterySaverStickyBehaviourDisabled=");
pw.println(mBatterySaverStickyBehaviourDisabled);
+ pw.print(" mDynamicPowerSavingsDefaultDisableThreshold=");
+ pw.println(mDynamicPowerSavingsDefaultDisableThreshold);
+ pw.print(" mDynamicPowerSavingsDisableThreshold=");
+ pw.println(mDynamicPowerSavingsDisableThreshold);
+ pw.print(" mDynamicPowerSavingsEnableBatterySaver=");
+ pw.println(mDynamicPowerSavingsEnableBatterySaver);
+
pw.print(" mLastAdaptiveBatterySaverChangedExternallyElapsed=");
pw.println(mLastAdaptiveBatterySaverChangedExternallyElapsed);
}
@@ -964,6 +976,8 @@
proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
proto.write(BatterySaverStateMachineProto.IS_BATTERY_LEVEL_LOW, mIsBatteryLevelLow);
+ proto.write(BatterySaverStateMachineProto.SETTING_AUTOMATIC_TRIGGER,
+ mSettingAutomaticBatterySaver);
proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED,
mSettingBatterySaverEnabled);
proto.write(BatterySaverStateMachineProto.SETTING_BATTERY_SAVER_ENABLED_STICKY,
@@ -979,6 +993,16 @@
mSettingBatterySaverStickyAutoDisableThreshold);
proto.write(
+ BatterySaverStateMachineProto.DEFAULT_DYNAMIC_DISABLE_THRESHOLD,
+ mDynamicPowerSavingsDefaultDisableThreshold);
+ proto.write(
+ BatterySaverStateMachineProto.DYNAMIC_DISABLE_THRESHOLD,
+ mDynamicPowerSavingsDisableThreshold);
+ proto.write(
+ BatterySaverStateMachineProto.DYNAMIC_BATTERY_SAVER_ENABLED,
+ mDynamicPowerSavingsEnableBatterySaver);
+
+ proto.write(
BatterySaverStateMachineProto
.LAST_ADAPTIVE_BATTERY_SAVER_CHANGED_EXTERNALLY_ELAPSED,
mLastAdaptiveBatterySaverChangedExternallyElapsed);
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 5c79f6e..47a26f5 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 @@
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 @@
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 @@
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
similarity index 97%
rename from services/core/java/com/android/server/tv/tuner/ClientProfile.java
rename to services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index 3845195..bad2b78 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 @@
+ 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
similarity index 91%
rename from services/core/java/com/android/server/tv/tuner/TunerResourceManagerService.java
rename to services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index e876421..49a7045 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 @@
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 @@
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 e72ba8d..761fbf8 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 @@
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 @@
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 7302e52..6522294 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 @@
* @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 f2917c5..132e486 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 @@
@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 1936f13..569986c 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.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 4cbdbd17..2d0fe58 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 @@
@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 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 @@
@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/content/SyncOperationTest.java b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
index e37ed79..2cbc3f3 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncOperationTest.java
@@ -124,8 +124,9 @@
SyncOperation op2 = SyncOperation.maybeCreateFromJobExtras(pb);
assertTrue("Account fields in extras not persisted.",
- account1.equals(op2.extras.get("acc")));
- assertTrue("Fields in extras not persisted", "String".equals(op2.extras.getString("str")));
+ account1.equals(op2.getClonedExtras().get("acc")));
+ assertTrue("Fields in extras not persisted", "String".equals(
+ op2.getClonedExtras().getString("str")));
}
@SmallTest
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 c45820e6..b6b8b82 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 4d0ad96..19cbb0e 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 @@
}
return AppOpsManager.MODE_ERRORED;
});
+
+ when(mLocationManagerInternal.isProviderEnabledForUser(eq(GPS_PROVIDER), anyInt()))
+ .thenReturn(true);
}
private void disableLocationPermissions() {
@@ -303,6 +308,9 @@
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 @@
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 3708571..e79b5af 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.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 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -260,6 +263,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -285,6 +290,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -310,6 +317,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -333,6 +342,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -356,6 +367,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -381,6 +394,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -411,6 +426,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -434,6 +451,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -457,6 +476,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -480,6 +501,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -503,6 +526,8 @@
anyString(),
nullable(String.class),
any(Intent.class),
+ nullable(IBinder.class),
+ anyInt(),
nullable(Bundle.class),
anyInt());
}
@@ -525,6 +550,8 @@
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 7666ab9..1c2d8e8 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.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 @@
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 @@
}
@Override
+ BatterySaverController createBatterySaverController(
+ Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
+ BatterySavingStats batterySavingStats) {
+ return mBatterySaverControllerMock;
+ }
+
+ @Override
PowerManagerService.NativeWrapper createNativeWrapper() {
return mNativeWrapperMock;
}
@@ -247,6 +256,11 @@
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 811089a..0ee2f55 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.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 @@
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 @@
}
@Override
+ BatterySaverController createBatterySaverController(
+ Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
+ BatterySavingStats batterySavingStats) {
+ return mBatterySaverControllerMock;
+ }
+
+ @Override
NativeWrapper createNativeWrapper() {
return mNativeWrapperMock;
}
@@ -231,6 +240,11 @@
public SystemPropertiesWrapper createSystemPropertiesWrapper() {
return mSystemPropertiesMock;
}
+
+ @Override
+ void invalidateIsInteractiveCaches() {
+ // Avoids an SELinux failure.
+ }
});
return mService;
}
@@ -369,7 +383,7 @@
@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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
createService();
startSystem();
SystemClock.sleep(20);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
}
@FlakyTest
@@ -757,7 +771,7 @@
null /* workSource */, null /* historyTag */);
SystemClock.sleep(11);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
}
@Test
@@ -765,7 +779,7 @@
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 @@
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 98cfc41..30ab9cd 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 @@
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 cbb760a..99b4fd9 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 @@
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 2c548be..f7c2609 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 @@
}
@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 3f690b1..0adf15c 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 @@
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 @@
.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 70e5ee7..683fca4 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 @@
}
@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 8ac1d24..cc9173a 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 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 @@
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 c19312d..ba57745 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 @@
}
@Test
+ @FlakyTest(bugId = 149760800)
public void layoutWindowLw_withLongEdgeDisplayCutout() {
addLongEdgeDisplayCutout();
@@ -618,6 +619,7 @@
}
@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 eda1fb8..b5663bd 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 @@
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 8ad7505..55d12db 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 @@
}
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 0000000..4056c71
--- /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 eefc1b7..d06ec11 100644
--- a/telephony/java/android/service/carrier/CarrierService.java
+++ b/telephony/java/android/service/carrier/CarrierService.java
@@ -25,6 +25,9 @@
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 @@
result.send(RESULT_ERROR, null);
}
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ CarrierService.this.dump(fd, pw, args);
+ }
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c51a852..795de57 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3391,6 +3391,25 @@
"subscription_group_uuid_string";
/**
+ * Data switch validation minimal gap time, in milliseconds.
+ *
+ * Which means, if the same subscription on the same network (based on MCC+MNC+TAC+subId)
+ * was recently validated (within this time gap), and Telephony receives a request to switch to
+ * it again, Telephony will skip the validation part and switch to it as soon as connection
+ * is setup, as if it's already validated.
+ *
+ * If the network was validated within the gap but the latest validation result is false, the
+ * validation will not be skipped.
+ *
+ * If not set or set to 0, validation will never be skipped.
+ * The max acceptable value of this config is 24 hours.
+ *
+ * @hide
+ */
+ public static final String KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG =
+ "data_switch_validation_min_gap_LONG";
+
+ /**
* A boolean property indicating whether this subscription should be managed as an opportunistic
* subscription.
*
@@ -4339,6 +4358,7 @@
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
+ sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, 0);
sDefaults.putAll(Iwlan.getDefaults());
}
diff --git a/tests/WindowInsetsTests/Android.bp b/tests/WindowInsetsTests/Android.bp
index 12395e7..7272152 100644
--- a/tests/WindowInsetsTests/Android.bp
+++ b/tests/WindowInsetsTests/Android.bp
@@ -18,5 +18,10 @@
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 8d33f70..0f6282e 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 0000000..26deb1e
--- /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 0000000..5f098a2
--- /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 0000000..15bc411
--- /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 0000000..d6b29c3
--- /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 0000000..de34e48
--- /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 38e0029..1b51c4f 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 242823d..2b8e5f3d 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 0000000..220671f
--- /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 b9f5ac0..8e6f198 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 @@
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> {
-
- private final View mViewToAnimate;
- private final Insets mShowingInsets;
-
- public InsetsProperty(View viewToAnimate, Insets showingInsets) {
- super(Insets.class, "Insets");
- mViewToAnimate = viewToAnimate;
- mShowingInsets = showingInsets;
- }
-
- @Override
- public Insets get(WindowInsetsAnimationController object) {
- return object.getCurrentInsets();
- }
-
- @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);
- }
- }
- };
-
- float startY;
- float endY;
- WindowInsetsAnimation imeAnim;
+ final ArrayList<Transition> mTransitions = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.window_inset_activity);
+
+ setSupportActionBar(findViewById(R.id.toolbar));
+
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.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 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;
+ }
+
+ 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));
}
});
- mRoot.setWindowInsetsAnimationCallback(new WindowInsetsAnimation.Callback(
- DISPATCH_MODE_STOP) {
+
+ 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 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 957683e..0886975 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.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 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 ac1c518..0e3b797 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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
.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 @@
.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 @@
.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 @@
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 7669983..9f26203 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -48,7 +48,7 @@
// 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
similarity index 98%
rename from wifi/java/android/net/wifi/wificond/ChannelSettings.java
rename to wifi/java/android/net/wifi/nl80211/ChannelSettings.java
index c2d65b5..4c14fd4 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
similarity index 99%
rename from wifi/java/android/net/wifi/wificond/DeviceWiphyCapabilities.java
rename to wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
index 13ae3b3..a045aad 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
similarity index 98%
rename from wifi/java/android/net/wifi/wificond/HiddenNetwork.java
rename to wifi/java/android/net/wifi/nl80211/HiddenNetwork.java
index 38dacea..b1475b2 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
similarity index 99%
rename from wifi/java/android/net/wifi/wificond/NativeScanResult.java
rename to wifi/java/android/net/wifi/nl80211/NativeScanResult.java
index bd99476..a8e9999 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
similarity index 98%
rename from wifi/java/android/net/wifi/wificond/NativeWifiClient.java
rename to wifi/java/android/net/wifi/nl80211/NativeWifiClient.java
index 9ad2a27..984d7d0 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
similarity index 99%
rename from wifi/java/android/net/wifi/wificond/PnoNetwork.java
rename to wifi/java/android/net/wifi/nl80211/PnoNetwork.java
index ca0b1cf..e8eff09 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
similarity index 99%
rename from wifi/java/android/net/wifi/wificond/PnoSettings.java
rename to wifi/java/android/net/wifi/nl80211/PnoSettings.java
index 533d37d..00ebe62 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
similarity index 98%
rename from wifi/java/android/net/wifi/wificond/RadioChainInfo.java
rename to wifi/java/android/net/wifi/nl80211/RadioChainInfo.java
index 97c0ee9..2c12163 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
similarity index 98%
rename from wifi/java/android/net/wifi/wificond/SingleScanSettings.java
rename to wifi/java/android/net/wifi/nl80211/SingleScanSettings.java
index 8c341b8..24b1854 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
similarity index 99%
rename from wifi/java/android/net/wifi/wificond/WifiNl80211Manager.java
rename to wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
index 89f642f..3215246 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
similarity index 96%
rename from wifi/tests/src/android/net/wifi/wificond/DeviceWiphyCapabilitiesTest.java
rename to wifi/tests/src/android/net/wifi/nl80211/DeviceWiphyCapabilitiesTest.java
index 8e3627a..7b900fe 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.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
similarity index 96%
rename from wifi/tests/src/android/net/wifi/wificond/NativeScanResultTest.java
rename to wifi/tests/src/android/net/wifi/nl80211/NativeScanResultTest.java
index 0df170f..8ddd189 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.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
similarity index 97%
rename from wifi/tests/src/android/net/wifi/wificond/PnoSettingsTest.java
rename to wifi/tests/src/android/net/wifi/nl80211/PnoSettingsTest.java
index 9439c79..dec1db8 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.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
similarity index 97%
rename from wifi/tests/src/android/net/wifi/wificond/SingleScanSettingsTest.java
rename to wifi/tests/src/android/net/wifi/nl80211/SingleScanSettingsTest.java
index f20ec47..9059208 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.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
similarity index 99%
rename from wifi/tests/src/android/net/wifi/wificond/WifiNl80211ManagerTest.java
rename to wifi/tests/src/android/net/wifi/nl80211/WifiNl80211ManagerTest.java
index a818406..9ee0acb 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.Set;
/**
- * Unit tests for {@link android.net.wifi.wificond.WifiNl80211Manager}.
+ * Unit tests for {@link android.net.wifi.nl80211.WifiNl80211Manager}.
*/
@SmallTest
public class WifiNl80211ManagerTest {