Merge "Read the sessionId value as long."
diff --git a/apex/blobstore/TEST_MAPPING b/apex/blobstore/TEST_MAPPING
index 25a1537..6d3c0d7 100644
--- a/apex/blobstore/TEST_MAPPING
+++ b/apex/blobstore/TEST_MAPPING
@@ -4,6 +4,9 @@
"name": "CtsBlobStoreTestCases"
},
{
+ "name": "CtsBlobStoreHostTestCases"
+ },
+ {
"name": "FrameworksMockingServicesTests",
"options": [
{
@@ -12,4 +15,4 @@
]
}
]
-}
\ No newline at end of file
+}
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 a8c2453..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";
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/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index c0390d2..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;
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/internal/os/KernelCpuUidBpfMapReader.java b/core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java
new file mode 100644
index 0000000..26f81d9
--- /dev/null
+++ b/core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java
@@ -0,0 +1,202 @@
+/*
+ * 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.internal.os;
+
+import android.os.StrictMode;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Reads cpu time bpf maps.
+ *
+ * It is implemented as singletons for each separate set of per-UID times. Get___Instance() method
+ * returns the corresponding reader instance. In order to prevent frequent GC, it reuses the same
+ * SparseArray to store data read from BPF maps.
+ *
+ * A KernelCpuUidBpfMapReader instance keeps an error counter. When the number of read errors within
+ * that instance accumulates to 5, this instance will reject all further read requests.
+ *
+ * Data fetched within last 500ms is considered fresh, since the reading lifecycle can take up to
+ * 25ms. KernelCpuUidBpfMapReader always tries to use cache if it is fresh and valid, but it can
+ * be disabled through a parameter.
+ *
+ * A KernelCpuUidBpfMapReader instance is thread-safe. It acquires a write lock when reading the bpf
+ * map, releases it right after, then acquires a read lock before returning a BpfMapIterator. Caller
+ * is responsible for closing BpfMapIterator (also auto-closable) after reading, otherwise deadlock
+ * will occur.
+ */
+public abstract class KernelCpuUidBpfMapReader {
+ private static final int ERROR_THRESHOLD = 5;
+ private static final long FRESHNESS_MS = 500L;
+
+ private static final KernelCpuUidBpfMapReader FREQ_TIME_READER =
+ new KernelCpuUidFreqTimeBpfMapReader();
+
+ private static final KernelCpuUidBpfMapReader ACTIVE_TIME_READER =
+ new KernelCpuUidActiveTimeBpfMapReader();
+
+ private static final KernelCpuUidBpfMapReader CLUSTER_TIME_READER =
+ new KernelCpuUidClusterTimeBpfMapReader();
+
+ static KernelCpuUidBpfMapReader getFreqTimeReaderInstance() {
+ return FREQ_TIME_READER;
+ }
+
+ static KernelCpuUidBpfMapReader getActiveTimeReaderInstance() {
+ return ACTIVE_TIME_READER;
+ }
+
+ static KernelCpuUidBpfMapReader getClusterTimeReaderInstance() {
+ return CLUSTER_TIME_READER;
+ }
+
+ final String mTag = this.getClass().getSimpleName();
+ private int mErrors = 0;
+ private boolean mTracking = false;
+ protected SparseArray<long[]> mData = new SparseArray<>();
+ private long mLastReadTime = 0;
+ protected final ReentrantReadWriteLock mLock = new ReentrantReadWriteLock();
+ protected final ReentrantReadWriteLock.ReadLock mReadLock = mLock.readLock();
+ protected final ReentrantReadWriteLock.WriteLock mWriteLock = mLock.writeLock();
+
+ public native boolean startTrackingBpfTimes();
+
+ protected abstract boolean readBpfData();
+
+ /**
+ * Returns an array of metadata used to inform the caller of 1) the size of array required by
+ * getNextUid and 2) how to interpret the raw data copied to that array.
+ */
+ public abstract long[] getDataDimensions();
+
+ public void removeUidsInRange(int startUid, int endUid) {
+ if (mErrors > ERROR_THRESHOLD) {
+ return;
+ }
+ mWriteLock.lock();
+ int firstIndex = mData.indexOfKey(startUid);
+ int lastIndex = mData.indexOfKey(endUid);
+ mData.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
+ mWriteLock.unlock();
+ }
+
+ public BpfMapIterator open() {
+ return open(false);
+ }
+
+ public BpfMapIterator open(boolean ignoreCache) {
+ if (mErrors > ERROR_THRESHOLD) {
+ return null;
+ }
+ if (!mTracking && !startTrackingBpfTimes()) {
+ Slog.w(mTag, "Failed to start tracking");
+ mErrors++;
+ return null;
+ }
+ if (ignoreCache) {
+ mWriteLock.lock();
+ } else {
+ mReadLock.lock();
+ if (dataValid()) {
+ return new BpfMapIterator();
+ }
+ mReadLock.unlock();
+ mWriteLock.lock();
+ if (dataValid()) {
+ mReadLock.lock();
+ mWriteLock.unlock();
+ return new BpfMapIterator();
+ }
+ }
+ if (readBpfData()) {
+ mLastReadTime = SystemClock.elapsedRealtime();
+ mReadLock.lock();
+ mWriteLock.unlock();
+ return new BpfMapIterator();
+ }
+
+ mWriteLock.unlock();
+ mErrors++;
+ Slog.w(mTag, "Failed to read bpf times");
+ return null;
+ }
+
+ private boolean dataValid() {
+ return mData.size() > 0 && (SystemClock.elapsedRealtime() - mLastReadTime < FRESHNESS_MS);
+ }
+
+ public class BpfMapIterator implements AutoCloseable {
+ private int mPos;
+
+ public BpfMapIterator() {
+ };
+
+ public boolean getNextUid(long[] buf) {
+ if (mPos >= mData.size()) {
+ return false;
+ }
+ buf[0] = mData.keyAt(mPos);
+ System.arraycopy(mData.valueAt(mPos), 0, buf, 1, mData.valueAt(mPos).length);
+ mPos++;
+ return true;
+ }
+
+ public void close() {
+ mReadLock.unlock();
+ }
+ }
+
+ public static class KernelCpuUidFreqTimeBpfMapReader extends KernelCpuUidBpfMapReader {
+
+ private final native boolean removeUidRange(int startUid, int endUid);
+
+ @Override
+ protected final native boolean readBpfData();
+
+ @Override
+ public final native long[] getDataDimensions();
+
+ @Override
+ public void removeUidsInRange(int startUid, int endUid) {
+ mWriteLock.lock();
+ super.removeUidsInRange(startUid, endUid);
+ removeUidRange(startUid, endUid);
+ mWriteLock.unlock();
+ }
+ }
+
+ public static class KernelCpuUidActiveTimeBpfMapReader extends KernelCpuUidBpfMapReader {
+
+ @Override
+ protected final native boolean readBpfData();
+
+ @Override
+ public final native long[] getDataDimensions();
+ }
+
+ public static class KernelCpuUidClusterTimeBpfMapReader extends KernelCpuUidBpfMapReader {
+
+ @Override
+ protected final native boolean readBpfData();
+
+ @Override
+ public final native long[] getDataDimensions();
+ }
+}
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index f1eb2fb..f7fad2c 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -28,6 +28,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.KernelCpuProcStringReader.ProcFileIterator;
+import com.android.internal.os.KernelCpuUidBpfMapReader.BpfMapIterator;
import java.io.BufferedReader;
import java.io.FileWriter;
@@ -57,6 +58,8 @@
final SparseArray<T> mLastTimes = new SparseArray<>();
final KernelCpuProcStringReader mReader;
final boolean mThrottle;
+ protected boolean mBpfTimesAvailable;
+ final KernelCpuUidBpfMapReader mBpfReader;
private long mMinTimeBetweenRead = DEFAULT_MIN_TIME_BETWEEN_READ;
private long mLastReadTimeMs = 0;
@@ -73,9 +76,15 @@
void onUidCpuTime(int uid, T time);
}
- KernelCpuUidTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
+ KernelCpuUidTimeReader(KernelCpuProcStringReader reader, @Nullable KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
mReader = reader;
mThrottle = throttle;
+ mBpfReader = bpfReader;
+ mBpfTimesAvailable = (mBpfReader != null);
+ }
+
+ KernelCpuUidTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
+ this(reader, null, throttle);
}
/**
@@ -151,9 +160,13 @@
}
mLastTimes.put(startUid, null);
mLastTimes.put(endUid, null);
- final int firstIndex = mLastTimes.indexOfKey(startUid);
- final int lastIndex = mLastTimes.indexOfKey(endUid);
+ int firstIndex = mLastTimes.indexOfKey(startUid);
+ int lastIndex = mLastTimes.indexOfKey(endUid);
mLastTimes.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
+
+ if (mBpfTimesAvailable) {
+ mBpfReader.removeUidsInRange(startUid, endUid);
+ }
}
/**
@@ -323,13 +336,13 @@
public KernelCpuUidFreqTimeReader(boolean throttle) {
this(UID_TIMES_PROC_FILE, KernelCpuProcStringReader.getFreqTimeReaderInstance(),
- throttle);
+ KernelCpuUidBpfMapReader.getFreqTimeReaderInstance(), throttle);
}
@VisibleForTesting
public KernelCpuUidFreqTimeReader(String procFile, KernelCpuProcStringReader reader,
- boolean throttle) {
- super(reader, throttle);
+ KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
+ super(reader, bpfReader, throttle);
mProcFilePath = Paths.get(procFile);
}
@@ -370,19 +383,24 @@
if (!mAllUidTimesAvailable) {
return null;
}
- final int oldMask = StrictMode.allowThreadDiskReadsMask();
- try (BufferedReader reader = Files.newBufferedReader(mProcFilePath)) {
- if (readFreqs(reader.readLine()) == null) {
+ if (mBpfTimesAvailable) {
+ readFreqsThroughBpf();
+ }
+ if (mCpuFreqs == null) {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try (BufferedReader reader = Files.newBufferedReader(mProcFilePath)) {
+ if (readFreqs(reader.readLine()) == null) {
+ return null;
+ }
+ } catch (IOException e) {
+ if (++mErrors >= MAX_ERROR_COUNT) {
+ mAllUidTimesAvailable = false;
+ }
+ Slog.e(mTag, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
return null;
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
- } catch (IOException e) {
- if (++mErrors >= MAX_ERROR_COUNT) {
- mAllUidTimesAvailable = false;
- }
- Slog.e(mTag, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
- return null;
- } finally {
- StrictMode.setThreadPolicyMask(oldMask);
}
// Check if the freqs in the proc file correspond to per-cluster freqs.
final IntArray numClusterFreqs = extractClusterInfoFromProcFileFreqs();
@@ -402,6 +420,21 @@
return mCpuFreqs;
}
+ private long[] readFreqsThroughBpf() {
+ if (!mBpfTimesAvailable || mBpfReader == null) {
+ return null;
+ }
+ mCpuFreqs = mBpfReader.getDataDimensions();
+ if (mCpuFreqs == null) {
+ return null;
+ }
+ mFreqCount = mCpuFreqs.length;
+ mCurTimes = new long[mFreqCount];
+ mDeltaTimes = new long[mFreqCount];
+ mBuffer = new long[mFreqCount + 1];
+ return mCpuFreqs;
+ }
+
private long[] readFreqs(String line) {
if (line == null || line.trim().isEmpty()) {
return null;
@@ -422,8 +455,45 @@
return mCpuFreqs;
}
+ private void processUidDelta(@Nullable Callback<long[]> cb) {
+ final int uid = (int) mBuffer[0];
+ long[] lastTimes = mLastTimes.get(uid);
+ if (lastTimes == null) {
+ lastTimes = new long[mFreqCount];
+ mLastTimes.put(uid, lastTimes);
+ }
+ copyToCurTimes();
+ boolean notify = false;
+ boolean valid = true;
+ for (int i = 0; i < mFreqCount; i++) {
+ // Unit is 10ms.
+ mDeltaTimes[i] = mCurTimes[i] - lastTimes[i];
+ if (mDeltaTimes[i] < 0) {
+ Slog.e(mTag, "Negative delta from freq time proc: " + mDeltaTimes[i]);
+ valid = false;
+ }
+ notify |= mDeltaTimes[i] > 0;
+ }
+ if (notify && valid) {
+ System.arraycopy(mCurTimes, 0, lastTimes, 0, mFreqCount);
+ if (cb != null) {
+ cb.onUidCpuTime(uid, mDeltaTimes);
+ }
+ }
+ }
+
@Override
void readDeltaImpl(@Nullable Callback<long[]> cb) {
+ if (mBpfTimesAvailable) {
+ try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
+ if (checkPrecondition(iter)) {
+ while (iter.getNextUid(mBuffer)) {
+ processUidDelta(cb);
+ }
+ return;
+ }
+ }
+ }
try (ProcFileIterator iter = mReader.open(!mThrottle)) {
if (!checkPrecondition(iter)) {
return;
@@ -434,36 +504,24 @@
Slog.wtf(mTag, "Invalid line: " + buf.toString());
continue;
}
- final int uid = (int) mBuffer[0];
- long[] lastTimes = mLastTimes.get(uid);
- if (lastTimes == null) {
- lastTimes = new long[mFreqCount];
- mLastTimes.put(uid, lastTimes);
- }
- copyToCurTimes();
- boolean notify = false;
- boolean valid = true;
- for (int i = 0; i < mFreqCount; i++) {
- // Unit is 10ms.
- mDeltaTimes[i] = mCurTimes[i] - lastTimes[i];
- if (mDeltaTimes[i] < 0) {
- Slog.e(mTag, "Negative delta from freq time proc: " + mDeltaTimes[i]);
- valid = false;
- }
- notify |= mDeltaTimes[i] > 0;
- }
- if (notify && valid) {
- System.arraycopy(mCurTimes, 0, lastTimes, 0, mFreqCount);
- if (cb != null) {
- cb.onUidCpuTime(uid, mDeltaTimes);
- }
- }
+ processUidDelta(cb);
}
}
}
@Override
void readAbsoluteImpl(Callback<long[]> cb) {
+ if (mBpfTimesAvailable) {
+ try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
+ if (checkPrecondition(iter)) {
+ while (iter.getNextUid(mBuffer)) {
+ copyToCurTimes();
+ cb.onUidCpuTime((int) mBuffer[0], mCurTimes);
+ }
+ return;
+ }
+ }
+ }
try (ProcFileIterator iter = mReader.open(!mThrottle)) {
if (!checkPrecondition(iter)) {
return;
@@ -481,11 +539,24 @@
}
private void copyToCurTimes() {
+ long factor = mBpfTimesAvailable ? 1 : 10;
for (int i = 0; i < mFreqCount; i++) {
- mCurTimes[i] = mBuffer[i + 1] * 10;
+ mCurTimes[i] = mBuffer[i + 1] * factor;
}
}
+ private boolean checkPrecondition(BpfMapIterator iter) {
+ if (iter == null) {
+ mBpfTimesAvailable = false;
+ return false;
+ }
+ if (mCpuFreqs != null) {
+ return true;
+ }
+ mBpfTimesAvailable = (readFreqsThroughBpf() != null);
+ return mBpfTimesAvailable;
+ }
+
private boolean checkPrecondition(ProcFileIterator iter) {
if (iter == null || !iter.hasNextLine()) {
// Error logged in KernelCpuProcStringReader.
@@ -544,16 +615,43 @@
private long[] mBuffer;
public KernelCpuUidActiveTimeReader(boolean throttle) {
- super(KernelCpuProcStringReader.getActiveTimeReaderInstance(), throttle);
+ super(KernelCpuProcStringReader.getActiveTimeReaderInstance(),
+ KernelCpuUidBpfMapReader.getActiveTimeReaderInstance(), throttle);
}
@VisibleForTesting
- public KernelCpuUidActiveTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
- super(reader, throttle);
+ public KernelCpuUidActiveTimeReader(KernelCpuProcStringReader reader, KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
+ super(reader, bpfReader, throttle);
+ }
+
+ private void processUidDelta(@Nullable Callback<Long> cb) {
+ int uid = (int) mBuffer[0];
+ long cpuActiveTime = sumActiveTime(mBuffer, mBpfTimesAvailable ? 1 : 10);
+ if (cpuActiveTime > 0) {
+ long delta = cpuActiveTime - mLastTimes.get(uid, 0L);
+ if (delta > 0) {
+ mLastTimes.put(uid, cpuActiveTime);
+ if (cb != null) {
+ cb.onUidCpuTime(uid, delta);
+ }
+ } else if (delta < 0) {
+ Slog.e(mTag, "Negative delta from active time proc: " + delta);
+ }
+ }
}
@Override
void readDeltaImpl(@Nullable Callback<Long> cb) {
+ if (mBpfTimesAvailable) {
+ try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
+ if (checkPrecondition(iter)) {
+ while (iter.getNextUid(mBuffer)) {
+ processUidDelta(cb);
+ }
+ return;
+ }
+ }
+ }
try (ProcFileIterator iter = mReader.open(!mThrottle)) {
if (!checkPrecondition(iter)) {
return;
@@ -564,25 +662,30 @@
Slog.wtf(mTag, "Invalid line: " + buf.toString());
continue;
}
- int uid = (int) mBuffer[0];
- long cpuActiveTime = sumActiveTime(mBuffer);
- if (cpuActiveTime > 0) {
- long delta = cpuActiveTime - mLastTimes.get(uid, 0L);
- if (delta > 0) {
- mLastTimes.put(uid, cpuActiveTime);
- if (cb != null) {
- cb.onUidCpuTime(uid, delta);
- }
- } else if (delta < 0) {
- Slog.e(mTag, "Negative delta from active time proc: " + delta);
- }
- }
+ processUidDelta(cb);
}
}
}
+ private void processUidAbsolute(@Nullable Callback<Long> cb) {
+ long cpuActiveTime = sumActiveTime(mBuffer, mBpfTimesAvailable ? 1 : 10);
+ if (cpuActiveTime > 0) {
+ cb.onUidCpuTime((int) mBuffer[0], cpuActiveTime);
+ }
+ }
+
@Override
void readAbsoluteImpl(Callback<Long> cb) {
+ if (mBpfTimesAvailable) {
+ try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
+ if (checkPrecondition(iter)) {
+ while (iter.getNextUid(mBuffer)) {
+ processUidAbsolute(cb);
+ }
+ return;
+ }
+ }
+ }
try (ProcFileIterator iter = mReader.open(!mThrottle)) {
if (!checkPrecondition(iter)) {
return;
@@ -593,23 +696,38 @@
Slog.wtf(mTag, "Invalid line: " + buf.toString());
continue;
}
- long cpuActiveTime = sumActiveTime(mBuffer);
- if (cpuActiveTime > 0) {
- cb.onUidCpuTime((int) mBuffer[0], cpuActiveTime);
- }
+ processUidAbsolute(cb);
}
}
}
- private static long sumActiveTime(long[] times) {
+ private static long sumActiveTime(long[] times, double factor) {
// UID is stored at times[0].
double sum = 0;
for (int i = 1; i < times.length; i++) {
- sum += (double) times[i] * 10 / i; // Unit is 10ms.
+ sum += (double) times[i] * factor / i; // Unit is 10ms.
}
return (long) sum;
}
+ private boolean checkPrecondition(BpfMapIterator iter) {
+ if (iter == null) {
+ mBpfTimesAvailable = false;
+ return false;
+ }
+ if (mCores > 0) {
+ return true;
+ }
+ long[] cores = mBpfReader.getDataDimensions();
+ if (cores == null || cores.length < 1) {
+ mBpfTimesAvailable = false;
+ return false;
+ }
+ mCores = (int) cores[0];
+ mBuffer = new long[mCores + 1];
+ return true;
+ }
+
private boolean checkPrecondition(ProcFileIterator iter) {
if (iter == null || !iter.hasNextLine()) {
// Error logged in KernelCpuProcStringReader.
@@ -668,16 +786,54 @@
private long[] mDeltaTime;
public KernelCpuUidClusterTimeReader(boolean throttle) {
- super(KernelCpuProcStringReader.getClusterTimeReaderInstance(), throttle);
+ super(KernelCpuProcStringReader.getClusterTimeReaderInstance(),
+ KernelCpuUidBpfMapReader.getClusterTimeReaderInstance(), throttle);
}
@VisibleForTesting
- public KernelCpuUidClusterTimeReader(KernelCpuProcStringReader reader, boolean throttle) {
- super(reader, throttle);
+ public KernelCpuUidClusterTimeReader(KernelCpuProcStringReader reader,
+ KernelCpuUidBpfMapReader bpfReader, boolean throttle) {
+ super(reader, bpfReader, throttle);
+ }
+
+ void processUidDelta(@Nullable Callback<long[]> cb) {
+ int uid = (int) mBuffer[0];
+ long[] lastTimes = mLastTimes.get(uid);
+ if (lastTimes == null) {
+ lastTimes = new long[mNumClusters];
+ mLastTimes.put(uid, lastTimes);
+ }
+ sumClusterTime();
+ boolean valid = true;
+ boolean notify = false;
+ for (int i = 0; i < mNumClusters; i++) {
+ mDeltaTime[i] = mCurTime[i] - lastTimes[i];
+ if (mDeltaTime[i] < 0) {
+ Slog.e(mTag, "Negative delta from cluster time proc: " + mDeltaTime[i]);
+ valid = false;
+ }
+ notify |= mDeltaTime[i] > 0;
+ }
+ if (notify && valid) {
+ System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters);
+ if (cb != null) {
+ cb.onUidCpuTime(uid, mDeltaTime);
+ }
+ }
}
@Override
void readDeltaImpl(@Nullable Callback<long[]> cb) {
+ if (mBpfTimesAvailable) {
+ try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
+ if (checkPrecondition(iter)) {
+ while (iter.getNextUid(mBuffer)) {
+ processUidDelta(cb);
+ }
+ return;
+ }
+ }
+ }
try (ProcFileIterator iter = mReader.open(!mThrottle)) {
if (!checkPrecondition(iter)) {
return;
@@ -688,35 +844,24 @@
Slog.wtf(mTag, "Invalid line: " + buf.toString());
continue;
}
- int uid = (int) mBuffer[0];
- long[] lastTimes = mLastTimes.get(uid);
- if (lastTimes == null) {
- lastTimes = new long[mNumClusters];
- mLastTimes.put(uid, lastTimes);
- }
- sumClusterTime();
- boolean valid = true;
- boolean notify = false;
- for (int i = 0; i < mNumClusters; i++) {
- mDeltaTime[i] = mCurTime[i] - lastTimes[i];
- if (mDeltaTime[i] < 0) {
- Slog.e(mTag, "Negative delta from cluster time proc: " + mDeltaTime[i]);
- valid = false;
- }
- notify |= mDeltaTime[i] > 0;
- }
- if (notify && valid) {
- System.arraycopy(mCurTime, 0, lastTimes, 0, mNumClusters);
- if (cb != null) {
- cb.onUidCpuTime(uid, mDeltaTime);
- }
- }
+ processUidDelta(cb);
}
}
}
@Override
void readAbsoluteImpl(Callback<long[]> cb) {
+ if (mBpfTimesAvailable) {
+ try (BpfMapIterator iter = mBpfReader.open(!mThrottle)) {
+ if (checkPrecondition(iter)) {
+ while (iter.getNextUid(mBuffer)) {
+ sumClusterTime();
+ cb.onUidCpuTime((int) mBuffer[0], mCurTime);
+ }
+ return;
+ }
+ }
+ }
try (ProcFileIterator iter = mReader.open(!mThrottle)) {
if (!checkPrecondition(iter)) {
return;
@@ -734,17 +879,45 @@
}
private void sumClusterTime() {
+ double factor = mBpfTimesAvailable ? 1 : 10;
// UID is stored at mBuffer[0].
int core = 1;
for (int i = 0; i < mNumClusters; i++) {
double sum = 0;
for (int j = 1; j <= mCoresOnClusters[i]; j++) {
- sum += (double) mBuffer[core++] * 10 / j; // Unit is 10ms.
+ sum += (double) mBuffer[core++] * factor / j; // Unit is 10ms.
}
mCurTime[i] = (long) sum;
}
}
+ private boolean checkPrecondition(BpfMapIterator iter) {
+ if (iter == null) {
+ mBpfTimesAvailable = false;
+ return false;
+ }
+ if (mNumClusters > 0) {
+ return true;
+ }
+ long[] coresOnClusters = mBpfReader.getDataDimensions();
+ if (coresOnClusters == null || coresOnClusters.length < 1) {
+ mBpfTimesAvailable = false;
+ return false;
+ }
+ mNumClusters = coresOnClusters.length;
+ mCoresOnClusters = new int[mNumClusters];
+ int cores = 0;
+ for (int i = 0; i < mNumClusters; i++) {
+ mCoresOnClusters[i] = (int) coresOnClusters[i];
+ cores += mCoresOnClusters[i];
+ }
+ mNumCores = cores;
+ mBuffer = new long[cores + 1];
+ mCurTime = new long[mNumClusters];
+ mDeltaTime = new long[mNumClusters];
+ return true;
+ }
+
private boolean checkPrecondition(ProcFileIterator iter) {
if (iter == null || !iter.hasNextLine()) {
// Error logged in KernelCpuProcStringReader.
diff --git a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
index 3c43a11..fc0ce6f 100644
--- a/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelSingleUidTimeReader.java
@@ -53,6 +53,8 @@
private int mReadErrorCounter;
@GuardedBy("this")
private boolean mSingleUidCpuTimesAvailable = true;
+ @GuardedBy("this")
+ private boolean mBpfTimesAvailable = true;
// We use the freq count obtained from /proc/uid_time_in_state to decide how many longs
// to read from each /proc/uid/<uid>/time_in_state. On the first read, verify if this is
// correct and if not, set {@link #mSingleUidCpuTimesAvailable} to false. This flag will
@@ -62,6 +64,8 @@
private final Injector mInjector;
+ private static final native boolean canReadBpfTimes();
+
KernelSingleUidTimeReader(int cpuFreqsCount) {
this(cpuFreqsCount, new Injector());
}
@@ -83,6 +87,18 @@
if (!mSingleUidCpuTimesAvailable) {
return null;
}
+ if (mBpfTimesAvailable) {
+ final long[] cpuTimesMs = mInjector.readBpfData(uid);
+ if (cpuTimesMs.length == 0) {
+ mBpfTimesAvailable = false;
+ } else if (!mCpuFreqsCountVerified && cpuTimesMs.length != mCpuFreqsCount) {
+ mSingleUidCpuTimesAvailable = false;
+ return null;
+ } else {
+ mCpuFreqsCountVerified = true;
+ return computeDelta(uid, cpuTimesMs);
+ }
+ }
// Read total cpu times from the proc file.
final String procFile = new StringBuilder(PROC_FILE_DIR)
.append(uid)
@@ -230,6 +246,8 @@
public byte[] readData(String procFile) throws IOException {
return Files.readAllBytes(Paths.get(procFile));
}
+
+ public native long[] readBpfData(int uid);
}
@VisibleForTesting
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 775368b..24222d3 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -335,7 +335,7 @@
super(context);
mLayoutInflater = LayoutInflater.from(context);
mRenderShadowsInCompositor = Settings.Global.getInt(context.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
/**
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.bp b/core/jni/Android.bp
index 900445c..07ea876 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -199,6 +199,8 @@
"android_security_Scrypt.cpp",
"com_android_internal_os_ClassLoaderFactory.cpp",
"com_android_internal_os_FuseAppLoop.cpp",
+ "com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
+ "com_android_internal_os_KernelSingleUidTimeReader.cpp",
"com_android_internal_os_Zygote.cpp",
"com_android_internal_os_ZygoteInit.cpp",
"hwbinder/EphemeralStorage.cpp",
@@ -273,6 +275,7 @@
"libdl",
"libdl_android",
"libstatslog",
+ "libtimeinstate",
"server_configurable_flags",
"libstatspull",
],
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d790ada..c6eb8f2 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -188,6 +188,8 @@
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
+extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
+extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env);
@@ -1558,6 +1560,8 @@
REG_JNI(register_android_security_Scrypt),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_os_FuseAppLoop),
+ REG_JNI(register_com_android_internal_os_KernelCpuUidBpfMapReader),
+ REG_JNI(register_com_android_internal_os_KernelSingleUidTimeReader),
};
/*
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 30e914d..130322a 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -19,11 +19,10 @@
#include <utils/Color.h>
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
-#include <binder/Parcel.h>
-#include <renderthread/RenderProxy.h>
#include <android_runtime/android_graphics_GraphicBuffer.h>
-#include <android_runtime/android_hardware_HardwareBuffer.h>
-#include <private/android/AHardwareBufferHelpers.h>
+#include <binder/Parcel.h>
+#include <dlfcn.h>
+#include <renderthread/RenderProxy.h>
#endif
#include "core_jni_helpers.h"
@@ -1027,11 +1026,18 @@
return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
}
+#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
+typedef AHardwareBuffer* (*AHB_from_HB)(JNIEnv*, jobject);
+AHB_from_HB AHardwareBuffer_fromHardwareBuffer;
+
+typedef jobject (*AHB_to_HB)(JNIEnv*, AHardwareBuffer*);
+AHB_to_HB AHardwareBuffer_toHardwareBuffer;
+#endif
+
static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
jlong colorSpacePtr) {
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
- AHardwareBuffer* buffer = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
- hardwareBuffer);
+ AHardwareBuffer* buffer = AHardwareBuffer_fromHardwareBuffer(env, hardwareBuffer);
sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer,
GraphicsJNI::getNativeColorSpace(colorSpacePtr));
if (!bitmap.get()) {
@@ -1057,6 +1063,19 @@
#endif
}
+static jobject Bitmap_getHardwareBuffer(JNIEnv* env, jobject, jlong bitmapPtr) {
+#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
+ LocalScopedBitmap bitmapHandle(bitmapPtr);
+ LOG_ALWAYS_FATAL_IF(!bitmapHandle->isHardware(),
+ "Hardware config is only supported config in Bitmap_getHardwareBuffer");
+
+ Bitmap& bitmap = bitmapHandle->bitmap();
+ return AHardwareBuffer_toHardwareBuffer(env, bitmap.hardwareBuffer());
+#else
+ return NULL;
+#endif
+}
+
static jboolean Bitmap_isImmutable(CRITICAL_JNI_PARAMS_COMMA jlong bitmapHandle) {
LocalScopedBitmap bitmapHolder(bitmapHandle);
if (!bitmapHolder.valid()) return JNI_FALSE;
@@ -1123,6 +1142,8 @@
(void*) Bitmap_wrapHardwareBufferBitmap },
{ "nativeCreateGraphicBufferHandle", "(J)Landroid/graphics/GraphicBuffer;",
(void*) Bitmap_createGraphicBufferHandle },
+ { "nativeGetHardwareBuffer", "(J)Landroid/hardware/HardwareBuffer;",
+ (void*) Bitmap_getHardwareBuffer },
{ "nativeComputeColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*)Bitmap_computeColorSpace },
{ "nativeSetColorSpace", "(JJ)V", (void*)Bitmap_setColorSpace },
{ "nativeIsSRGB", "(J)Z", (void*)Bitmap_isSRGB },
@@ -1140,6 +1161,18 @@
gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
+
+#ifdef __ANDROID__ // Layoutlib does not support graphic buffer
+ void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
+ AHardwareBuffer_fromHardwareBuffer =
+ (AHB_from_HB)dlsym(handle_, "AHardwareBuffer_fromHardwareBuffer");
+ LOG_ALWAYS_FATAL_IF(AHardwareBuffer_fromHardwareBuffer == nullptr,
+ "Failed to find required symbol AHardwareBuffer_fromHardwareBuffer!");
+
+ AHardwareBuffer_toHardwareBuffer = (AHB_to_HB)dlsym(handle_, "AHardwareBuffer_toHardwareBuffer");
+ LOG_ALWAYS_FATAL_IF(AHardwareBuffer_toHardwareBuffer == nullptr,
+ " Failed to find required symbol AHardwareBuffer_toHardwareBuffer!");
+#endif
return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
NELEM(gBitmapMethods));
}
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/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp b/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp
new file mode 100644
index 0000000..7c68de5
--- /dev/null
+++ b/core/jni/com_android_internal_os_KernelCpuUidBpfMapReader.cpp
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+#include "core_jni_helpers.h"
+
+#include <sys/sysinfo.h>
+
+#include <android-base/stringprintf.h>
+#include <cputimeinstate.h>
+
+namespace android {
+
+static constexpr uint64_t NSEC_PER_MSEC = 1000000;
+
+static struct {
+ jclass clazz;
+ jmethodID put;
+ jmethodID get;
+} gSparseArrayClassInfo;
+
+static jfieldID gmData;
+
+static jlongArray getUidArray(JNIEnv *env, jobject sparseAr, uint32_t uid, jsize sz) {
+ jlongArray ar = (jlongArray)env->CallObjectMethod(sparseAr, gSparseArrayClassInfo.get, uid);
+ if (!ar) {
+ ar = env->NewLongArray(sz);
+ if (ar == NULL) return ar;
+ env->CallVoidMethod(sparseAr, gSparseArrayClassInfo.put, uid, ar);
+ }
+ return ar;
+}
+
+static void copy2DVecToArray(JNIEnv *env, jlongArray ar, std::vector<std::vector<uint64_t>> &vec) {
+ jsize start = 0;
+ for (auto &subVec : vec) {
+ for (uint32_t i = 0; i < subVec.size(); ++i) subVec[i] /= NSEC_PER_MSEC;
+ env->SetLongArrayRegion(ar, start, subVec.size(),
+ reinterpret_cast<const jlong *>(subVec.data()));
+ start += subVec.size();
+ }
+}
+
+static jboolean KernelCpuUidFreqTimeBpfMapReader_removeUidRange(JNIEnv *env, jclass, jint startUid,
+ jint endUid) {
+ for (uint32_t uid = startUid; uid <= endUid; ++uid) {
+ if (!android::bpf::clearUidTimes(uid)) return false;
+ }
+ return true;
+}
+
+static jboolean KernelCpuUidFreqTimeBpfMapReader_readBpfData(JNIEnv *env, jobject thiz) {
+ static uint64_t lastUpdate = 0;
+ uint64_t newLastUpdate = lastUpdate;
+ auto sparseAr = env->GetObjectField(thiz, gmData);
+ if (sparseAr == NULL) return false;
+ auto data = android::bpf::getUidsUpdatedCpuFreqTimes(&newLastUpdate);
+ if (!data.has_value()) return false;
+
+ jsize s = 0;
+ for (auto &[uid, times] : *data) {
+ if (s == 0) {
+ for (const auto &subVec : times) s += subVec.size();
+ }
+ jlongArray ar = getUidArray(env, sparseAr, uid, s);
+ if (ar == NULL) return false;
+ copy2DVecToArray(env, ar, times);
+ }
+ lastUpdate = newLastUpdate;
+ return true;
+}
+
+static jlongArray KernelCpuUidFreqTimeBpfMapReader_getDataDimensions(JNIEnv *env, jobject) {
+ auto freqs = android::bpf::getCpuFreqs();
+ if (!freqs) return NULL;
+
+ std::vector<uint64_t> allFreqs;
+ for (const auto &vec : *freqs) std::copy(vec.begin(), vec.end(), std::back_inserter(allFreqs));
+
+ auto ar = env->NewLongArray(allFreqs.size());
+ if (ar != NULL) {
+ env->SetLongArrayRegion(ar, 0, allFreqs.size(),
+ reinterpret_cast<const jlong *>(allFreqs.data()));
+ }
+ return ar;
+}
+
+static const JNINativeMethod gFreqTimeMethods[] = {
+ {"removeUidRange", "(II)Z", (void *)KernelCpuUidFreqTimeBpfMapReader_removeUidRange},
+ {"readBpfData", "()Z", (void *)KernelCpuUidFreqTimeBpfMapReader_readBpfData},
+ {"getDataDimensions", "()[J", (void *)KernelCpuUidFreqTimeBpfMapReader_getDataDimensions},
+};
+
+static jboolean KernelCpuUidActiveTimeBpfMapReader_readBpfData(JNIEnv *env, jobject thiz) {
+ static uint64_t lastUpdate = 0;
+ uint64_t newLastUpdate = lastUpdate;
+ auto sparseAr = env->GetObjectField(thiz, gmData);
+ if (sparseAr == NULL) return false;
+ auto data = android::bpf::getUidsUpdatedConcurrentTimes(&newLastUpdate);
+ if (!data.has_value()) return false;
+
+ for (auto &[uid, times] : *data) {
+ // TODO: revise calling code so we can divide by NSEC_PER_MSEC here instead
+ for (auto &time : times.active) time /= NSEC_PER_MSEC;
+ jlongArray ar = getUidArray(env, sparseAr, uid, times.active.size());
+ if (ar == NULL) return false;
+ env->SetLongArrayRegion(ar, 0, times.active.size(),
+ reinterpret_cast<const jlong *>(times.active.data()));
+ }
+ lastUpdate = newLastUpdate;
+ return true;
+}
+
+static jlongArray KernelCpuUidActiveTimeBpfMapReader_getDataDimensions(JNIEnv *env, jobject) {
+ jlong nCpus = get_nprocs_conf();
+
+ auto ar = env->NewLongArray(1);
+ if (ar != NULL) env->SetLongArrayRegion(ar, 0, 1, &nCpus);
+ return ar;
+}
+
+static const JNINativeMethod gActiveTimeMethods[] = {
+ {"readBpfData", "()Z", (void *)KernelCpuUidActiveTimeBpfMapReader_readBpfData},
+ {"getDataDimensions", "()[J", (void *)KernelCpuUidActiveTimeBpfMapReader_getDataDimensions},
+};
+
+static jboolean KernelCpuUidClusterTimeBpfMapReader_readBpfData(JNIEnv *env, jobject thiz) {
+ static uint64_t lastUpdate = 0;
+ uint64_t newLastUpdate = lastUpdate;
+ auto sparseAr = env->GetObjectField(thiz, gmData);
+ if (sparseAr == NULL) return false;
+ auto data = android::bpf::getUidsUpdatedConcurrentTimes(&newLastUpdate);
+ if (!data.has_value()) return false;
+
+ jsize s = 0;
+ for (auto &[uid, times] : *data) {
+ if (s == 0) {
+ for (const auto &subVec : times.policy) s += subVec.size();
+ }
+ jlongArray ar = getUidArray(env, sparseAr, uid, s);
+ if (ar == NULL) return false;
+ copy2DVecToArray(env, ar, times.policy);
+ }
+ lastUpdate = newLastUpdate;
+ return true;
+}
+
+static jlongArray KernelCpuUidClusterTimeBpfMapReader_getDataDimensions(JNIEnv *env, jobject) {
+ auto times = android::bpf::getUidConcurrentTimes(0);
+ if (!times.has_value()) return NULL;
+
+ std::vector<jlong> clusterCores;
+ for (const auto &vec : times->policy) clusterCores.push_back(vec.size());
+ auto ar = env->NewLongArray(clusterCores.size());
+ if (ar != NULL) env->SetLongArrayRegion(ar, 0, clusterCores.size(), clusterCores.data());
+ return ar;
+}
+
+static const JNINativeMethod gClusterTimeMethods[] = {
+ {"readBpfData", "()Z", (void *)KernelCpuUidClusterTimeBpfMapReader_readBpfData},
+ {"getDataDimensions", "()[J",
+ (void *)KernelCpuUidClusterTimeBpfMapReader_getDataDimensions},
+};
+
+struct readerMethods {
+ const char *name;
+ const JNINativeMethod *methods;
+ int numMethods;
+};
+
+static const readerMethods gAllMethods[] = {
+ {"KernelCpuUidFreqTimeBpfMapReader", gFreqTimeMethods, NELEM(gFreqTimeMethods)},
+ {"KernelCpuUidActiveTimeBpfMapReader", gActiveTimeMethods, NELEM(gActiveTimeMethods)},
+ {"KernelCpuUidClusterTimeBpfMapReader", gClusterTimeMethods, NELEM(gClusterTimeMethods)},
+};
+
+static jboolean KernelCpuUidBpfMapReader_startTrackingBpfTimes(JNIEnv *, jobject) {
+ return android::bpf::startTrackingUidTimes();
+}
+
+int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env) {
+ gSparseArrayClassInfo.clazz = FindClassOrDie(env, "android/util/SparseArray");
+ gSparseArrayClassInfo.clazz = MakeGlobalRefOrDie(env, gSparseArrayClassInfo.clazz);
+ gSparseArrayClassInfo.put =
+ GetMethodIDOrDie(env, gSparseArrayClassInfo.clazz, "put", "(ILjava/lang/Object;)V");
+ gSparseArrayClassInfo.get =
+ GetMethodIDOrDie(env, gSparseArrayClassInfo.clazz, "get", "(I)Ljava/lang/Object;");
+ constexpr auto readerName = "com/android/internal/os/KernelCpuUidBpfMapReader";
+ constexpr JNINativeMethod method = {"startTrackingBpfTimes", "()Z",
+ (void *)KernelCpuUidBpfMapReader_startTrackingBpfTimes};
+
+ int ret = RegisterMethodsOrDie(env, readerName, &method, 1);
+ if (ret < 0) return ret;
+ auto c = FindClassOrDie(env, readerName);
+ gmData = GetFieldIDOrDie(env, c, "mData", "Landroid/util/SparseArray;");
+
+ for (const auto &m : gAllMethods) {
+ auto fullName = android::base::StringPrintf("%s$%s", readerName, m.name);
+ ret = RegisterMethodsOrDie(env, fullName.c_str(), m.methods, m.numMethods);
+ if (ret < 0) break;
+ }
+ return ret;
+}
+
+} // namespace android
diff --git a/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp
new file mode 100644
index 0000000..c0ecf33
--- /dev/null
+++ b/core/jni/com_android_internal_os_KernelSingleUidTimeReader.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include "core_jni_helpers.h"
+
+#include <cputimeinstate.h>
+
+namespace android {
+
+static constexpr uint64_t NSEC_PER_MSEC = 1000000;
+
+static jlongArray copyVecsToArray(JNIEnv *env, std::vector<std::vector<uint64_t>> &vec) {
+ jsize s = 0;
+ for (const auto &subVec : vec) s += subVec.size();
+ jlongArray ar = env->NewLongArray(s);
+ jsize start = 0;
+ for (auto &subVec : vec) {
+ for (uint32_t i = 0; i < subVec.size(); ++i) subVec[i] /= NSEC_PER_MSEC;
+ env->SetLongArrayRegion(ar, start, subVec.size(),
+ reinterpret_cast<const jlong*>(subVec.data()));
+ start += subVec.size();
+ }
+ return ar;
+}
+
+static jlongArray getUidCpuFreqTimeMs(JNIEnv *env, jclass, jint uid) {
+ auto out = android::bpf::getUidCpuFreqTimes(uid);
+ if (!out) return env->NewLongArray(0);
+ return copyVecsToArray(env, out.value());
+}
+
+static const JNINativeMethod g_single_methods[] = {
+ {"readBpfData", "(I)[J", (void *)getUidCpuFreqTimeMs},
+};
+
+int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env) {
+ return RegisterMethodsOrDie(env, "com/android/internal/os/KernelSingleUidTimeReader$Injector",
+ g_single_methods, NELEM(g_single_methods));
+}
+
+}
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/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/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
index a6329298..2ad8e18 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTests.java
@@ -40,6 +40,7 @@
BatteryStatsUserLifecycleTests.class,
KernelCpuProcStringReaderTest.class,
KernelCpuUidActiveTimeReaderTest.class,
+ KernelCpuUidBpfMapReaderTest.class,
KernelCpuUidClusterTimeReaderTest.class,
KernelCpuUidFreqTimeReaderTest.class,
KernelCpuUidUserSysTimeReaderTest.class,
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
index 1b13a99..2ccd74e 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidActiveTimeReaderTest.java
@@ -21,11 +21,11 @@
import android.content.Context;
import android.os.FileUtils;
+import android.util.SparseArray;
import android.util.SparseLongArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidActiveTimeReader;
@@ -33,11 +33,15 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Random;
/**
@@ -46,14 +50,16 @@
* $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidActiveTimeReaderTest
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class KernelCpuUidActiveTimeReaderTest {
private File mTestDir;
private File mTestFile;
private KernelCpuUidActiveTimeReader mReader;
+ private KernelCpuUidTestBpfMapReader mBpfMapReader;
private VerifiableCallback mCallback;
private Random mRand = new Random(12345);
+ protected boolean mUseBpf;
private final int mCpus = 4;
private final String mHeadline = "cpus: 4\n";
private final int[] mUids = {0, 1, 22, 333, 4444, 55555};
@@ -62,12 +68,22 @@
return InstrumentationRegistry.getContext();
}
+ @Parameters(name="useBpf={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { {true}, {false} });
+ }
+
+ public KernelCpuUidActiveTimeReaderTest(boolean useBpf) {
+ mUseBpf = useBpf;
+ }
+
@Before
public void setUp() {
mTestDir = getContext().getDir("test", Context.MODE_PRIVATE);
mTestFile = new File(mTestDir, "test.file");
+ mBpfMapReader = new KernelCpuUidTestBpfMapReader();
mReader = new KernelCpuUidActiveTimeReader(
- new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false);
+ new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), mBpfMapReader, false);
mCallback = new VerifiableCallback();
}
@@ -80,7 +96,7 @@
@Test
public void testReadDelta() throws Exception {
final long[][] times = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times));
+ setCpusAndData(times);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], getActiveTime(times[i]));
@@ -90,7 +106,7 @@
// Verify that a second call will only return deltas.
mCallback.clear();
final long[][] newTimes1 = increaseTime(times);
- writeToFile(mHeadline + uidLines(mUids, newTimes1));
+ setCpusAndData(newTimes1);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], getActiveTime(newTimes1[i]) - getActiveTime(times[i]));
@@ -105,7 +121,7 @@
// Verify that calling with a null callback doesn't result in any crashes
mCallback.clear();
final long[][] newTimes2 = increaseTime(newTimes1);
- writeToFile(mHeadline + uidLines(mUids, newTimes2));
+ setCpusAndData(newTimes2);
mReader.readDelta(null);
mCallback.verifyNoMoreInteractions();
@@ -113,19 +129,20 @@
// the previous call had null callback.
mCallback.clear();
final long[][] newTimes3 = increaseTime(newTimes2);
+ setCpusAndData(newTimes3);
writeToFile(mHeadline + uidLines(mUids, newTimes3));
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], getActiveTime(newTimes3[i]) - getActiveTime(newTimes2[i]));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCpusAndData();
}
@Test
public void testReadAbsolute() throws Exception {
final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times1));
+ setCpusAndData(times1);
mReader.readAbsolute(mCallback);
for (int i = 0; i < mUids.length; i++) {
mCallback.verify(mUids[i], getActiveTime(times1[i]));
@@ -135,19 +152,19 @@
// Verify that a second call should still return absolute values
mCallback.clear();
final long[][] times2 = increaseTime(times1);
- writeToFile(mHeadline + uidLines(mUids, times2));
+ setCpusAndData(times2);
mReader.readAbsolute(mCallback);
for (int i = 0; i < mUids.length; i++) {
mCallback.verify(mUids[i], getActiveTime(times2[i]));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCpusAndData();
}
@Test
public void testReadDeltaDecreasedTime() throws Exception {
final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times1));
+ setCpusAndData(times1);
mReader.readDelta(mCallback);
// Verify that there should not be a callback for a particular UID if its time decreases.
@@ -155,19 +172,19 @@
final long[][] times2 = increaseTime(times1);
System.arraycopy(times1[0], 0, times2[0], 0, mCpus);
times2[0][0] = 100;
- writeToFile(mHeadline + uidLines(mUids, times2));
+ setCpusAndData(times2);
mReader.readDelta(mCallback);
for (int i = 1; i < mUids.length; i++) {
mCallback.verify(mUids[i], getActiveTime(times2[i]) - getActiveTime(times1[i]));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCpusAndData();
// Verify that the internal state was not modified.
mCallback.clear();
final long[][] times3 = increaseTime(times2);
times3[0] = increaseTime(times1)[0];
- writeToFile(mHeadline + uidLines(mUids, times3));
+ setCpusAndData(times3);
mReader.readDelta(mCallback);
mCallback.verify(mUids[0], getActiveTime(times3[0]) - getActiveTime(times1[0]));
for (int i = 1; i < mUids.length; i++) {
@@ -179,26 +196,26 @@
@Test
public void testReadDeltaNegativeTime() throws Exception {
final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times1));
+ setCpusAndData(times1);
mReader.readDelta(mCallback);
// Verify that there should not be a callback for a particular UID if its time is -ve.
mCallback.clear();
final long[][] times2 = increaseTime(times1);
times2[0][0] *= -1;
- writeToFile(mHeadline + uidLines(mUids, times2));
+ setCpusAndData(times2);
mReader.readDelta(mCallback);
for (int i = 1; i < mUids.length; i++) {
mCallback.verify(mUids[i], getActiveTime(times2[i]) - getActiveTime(times1[i]));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCpusAndData();
// Verify that the internal state was not modified.
mCallback.clear();
final long[][] times3 = increaseTime(times2);
times3[0] = increaseTime(times1)[0];
- writeToFile(mHeadline + uidLines(mUids, times3));
+ setCpusAndData(times3);
mReader.readDelta(mCallback);
mCallback.verify(mUids[0], getActiveTime(times3[0]) - getActiveTime(times1[0]));
for (int i = 1; i < mUids.length; i++) {
@@ -207,6 +224,28 @@
mCallback.verifyNoMoreInteractions();
}
+ private void setCpusAndData(long[][] times) throws IOException {
+ if (mUseBpf) {
+ mBpfMapReader.setCpus(new long[]{ mCpus });
+ SparseArray<long[]> data = new SparseArray<>();
+ for (int i = 0; i < mUids.length; i++) {
+ data.put(mUids[i], times[i]);
+ }
+ mBpfMapReader.setData(data);
+ } else {
+ writeToFile(mHeadline + uidLines(mUids, times));
+ }
+ }
+
+ private void clearCpusAndData() {
+ if (mUseBpf) {
+ mBpfMapReader.setCpus(null);
+ mBpfMapReader.setData(new SparseArray<>());
+ } else {
+ assertTrue(mTestFile.delete());
+ }
+ }
+
private String uidLines(int[] uids, long[][] times) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < uids.length; i++) {
@@ -261,4 +300,36 @@
assertEquals(0, mData.size());
}
}
+
+ private class KernelCpuUidTestBpfMapReader extends KernelCpuUidBpfMapReader {
+ private long[] mCpus;
+ private SparseArray<long[]> mNewData = new SparseArray<>();
+
+ public void setData(SparseArray<long[]> data) {
+ mNewData = data;
+ }
+
+ public void setCpus(long[] cpus) {
+ mCpus = cpus;
+ }
+
+ @Override
+ public final boolean startTrackingBpfTimes() {
+ return true;
+ }
+
+ @Override
+ protected final boolean readBpfData() {
+ if (!mUseBpf) {
+ return false;
+ }
+ mData = mNewData;
+ return true;
+ }
+
+ @Override
+ public final long[] getDataDimensions() {
+ return mCpus;
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java
new file mode 100644
index 0000000..257b388
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidBpfMapReaderTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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.internal.os;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.util.SparseArray;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.runner.RunWith;
+
+import com.android.internal.os.KernelCpuUidBpfMapReader.BpfMapIterator;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.IntStream;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KernelCpuUidBpfMapReaderTest {
+ private Random mRand = new Random(12345);
+ private KernelCpuUidTestBpfMapReader mReader;
+
+ private Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
+ @Before
+ public void setUp() {
+ mReader = new KernelCpuUidTestBpfMapReader();
+ }
+
+ /**
+ * Tests that reading returns null if readBpfData() fails.
+ */
+ @Test
+ public void testUnsuccessfulRead() {
+ assertEquals(null, mReader.open());
+ }
+
+ /**
+ * Tests that reading will always return null after 5 failures.
+ */
+ @Test
+ public void testReadErrorsLimit() {
+ for (int i = 0; i < 3; i++) {
+ try (BpfMapIterator iter = mReader.open()) {
+ assertNull(iter);
+ }
+ }
+
+ SparseArray<long[]> data = new SparseArray<>();
+ long[] times = {2};
+ data.put(1, new long[]{2});
+ mReader.setData(data);
+ testOpenAndReadData(data);
+
+ mReader.setData(null);
+ for (int i = 0; i < 3; i++) {
+ try (BpfMapIterator iter = mReader.open(true)) {
+ assertNull(iter);
+ }
+ }
+ mReader.setData(data);
+ try (BpfMapIterator iter = mReader.open(true)) {
+ assertNull(iter);
+ }
+ }
+
+ /** Tests getNextUid functionality. */
+ @Test
+ public void testGetNextUid() {
+ final SparseArray<long[]> data = getTestSparseArray(800, 50);
+ mReader.setData(data);
+ testOpenAndReadData(data);
+ }
+
+ @Test
+ public void testConcurrent() throws Exception {
+ final SparseArray<long[]> data = getTestSparseArray(200, 50);
+ final SparseArray<long[]> data1 = getTestSparseArray(180, 70);
+ final List<Throwable> errs = Collections.synchronizedList(new ArrayList<>());
+ mReader.setData(data);
+ // An additional thread for modifying the data.
+ ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(11);
+ final CountDownLatch ready = new CountDownLatch(10);
+ final CountDownLatch start = new CountDownLatch(1);
+ final CountDownLatch modify = new CountDownLatch(1);
+ final CountDownLatch done = new CountDownLatch(10);
+
+ for (int i = 0; i < 5; i++) {
+ threadPool.submit(() -> {
+ ready.countDown();
+ try {
+ start.await();
+ testOpenAndReadData(data);
+ } catch (Throwable e) {
+ errs.add(e);
+ } finally {
+ done.countDown();
+ }
+ });
+ threadPool.submit(() -> {
+ ready.countDown();
+ try {
+ start.await();
+ // Wait for data modification.
+ modify.await();
+ testOpenAndReadData(data1);
+ } catch (Throwable e) {
+ errs.add(e);
+ } finally {
+ done.countDown();
+ }
+ });
+ }
+
+ assertTrue("Prep timed out", ready.await(100, TimeUnit.MILLISECONDS));
+ start.countDown();
+
+ threadPool.schedule(() -> {
+ mReader.setData(data1);
+ modify.countDown();
+ }, 600, TimeUnit.MILLISECONDS);
+
+ assertTrue("Execution timed out", done.await(3, TimeUnit.SECONDS));
+ threadPool.shutdownNow();
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ errs.forEach(e -> e.printStackTrace(pw));
+
+ assertTrue("All Exceptions:\n" + sw.toString(), errs.isEmpty());
+ }
+
+ @Test
+ public void testRemoveUidsInRange() {
+ final SparseArray<long[]> data = getTestSparseArray(200, 50);
+ mReader.setData(data);
+ testOpenAndReadData(data);
+ SparseArray<long[]> changedData = new SparseArray<>();
+ for (int i = 6; i < 200; i++) {
+ changedData.put(i, data.get(i));
+ }
+ mReader.removeUidsInRange(0, 5);
+ testOpenAndReadData(changedData);
+ }
+
+ private void testOpenAndReadData(SparseArray<long[]> expectedData) {
+ try (BpfMapIterator iter = mReader.open()) {
+ long[] actual;
+ if (expectedData.size() > 0) {
+ actual = new long[expectedData.valueAt(0).length + 1];
+ } else {
+ actual = new long[0];
+ }
+ for (int i = 0; i < expectedData.size(); i++) {
+ assertTrue(iter.getNextUid(actual));
+ assertEquals(expectedData.keyAt(i), actual[0]);
+ assertArrayEquals(expectedData.valueAt(i), Arrays.copyOfRange(actual, 1, actual.length));
+ }
+ assertFalse(iter.getNextUid(actual));
+ assertFalse(iter.getNextUid(actual));
+ }
+ }
+
+
+ private SparseArray<long[]> getTestSparseArray(int uids, int numPerUid) {
+ SparseArray<long[]> data = new SparseArray<>();
+ for (int i = 0; i < uids; i++) {
+ data.put(i, mRand.longs(numPerUid, 0, Long.MAX_VALUE).toArray());
+ }
+ return data;
+ }
+
+
+ private class KernelCpuUidTestBpfMapReader extends KernelCpuUidBpfMapReader {
+ private SparseArray<long[]> mNewData;
+
+ public final void setData(SparseArray<long[]> newData) {
+ mNewData = newData;
+ }
+
+ @Override
+ public final boolean startTrackingBpfTimes() {
+ return true;
+ }
+
+ @Override
+ public final boolean readBpfData() {
+ if (mNewData == null) {
+ return false;
+ }
+ mData = mNewData;
+ return true;
+ }
+
+ @Override
+ public final long[] getDataDimensions() {
+ return null;
+ }
+
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
index 2ea80da..a0dab28 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidClusterTimeReaderTest.java
@@ -27,7 +27,6 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidClusterTimeReader;
@@ -35,11 +34,15 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Random;
/**
@@ -48,28 +51,42 @@
* $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidClusterTimeReaderTest
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class KernelCpuUidClusterTimeReaderTest {
private File mTestDir;
private File mTestFile;
private KernelCpuUidClusterTimeReader mReader;
+ private KernelCpuUidTestBpfMapReader mBpfMapReader;
private VerifiableCallback mCallback;
private Random mRand = new Random(12345);
+ protected boolean mUseBpf;
private final int mCpus = 6;
private final String mHeadline = "policy0: 4 policy4: 2\n";
+ private final long[] mCores = {4, 2};
private final int[] mUids = {0, 1, 22, 333, 4444, 55555};
private Context getContext() {
return InstrumentationRegistry.getContext();
}
+ @Parameters(name="useBpf={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { {true}, {false} });
+ }
+
+ public KernelCpuUidClusterTimeReaderTest(boolean useBpf) {
+ mUseBpf = useBpf;
+ }
+
@Before
public void setUp() {
mTestDir = getContext().getDir("test", Context.MODE_PRIVATE);
mTestFile = new File(mTestDir, "test.file");
+ mBpfMapReader = new KernelCpuUidTestBpfMapReader();
mReader = new KernelCpuUidClusterTimeReader(
- new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false);
+ new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), mBpfMapReader,
+ false);
mCallback = new VerifiableCallback();
}
@@ -82,7 +99,7 @@
@Test
public void testReadDelta() throws Exception {
final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times1));
+ setCoresAndData(times1);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], clusterTime(times1[i]));
@@ -92,7 +109,7 @@
// Verify that a second call will only return deltas.
mCallback.clear();
final long[][] times2 = increaseTime(times1);
- writeToFile(mHeadline + uidLines(mUids, times2));
+ setCoresAndData(times2);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], subtract(clusterTime(times2[i]), clusterTime(times1[i])));
@@ -107,7 +124,7 @@
// Verify that calling with a null callback doesn't result in any crashes
mCallback.clear();
final long[][] times3 = increaseTime(times2);
- writeToFile(mHeadline + uidLines(mUids, times3));
+ setCoresAndData(times3);
mReader.readDelta(null);
mCallback.verifyNoMoreInteractions();
@@ -115,19 +132,19 @@
// the previous call had null callback.
mCallback.clear();
final long[][] times4 = increaseTime(times3);
- writeToFile(mHeadline + uidLines(mUids, times4));
+ setCoresAndData(times4);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], subtract(clusterTime(times4[i]), clusterTime(times3[i])));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCoresAndData();
}
@Test
public void testReadAbsolute() throws Exception {
final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times1));
+ setCoresAndData(times1);
mReader.readAbsolute(mCallback);
for (int i = 0; i < mUids.length; i++) {
mCallback.verify(mUids[i], clusterTime(times1[i]));
@@ -137,19 +154,19 @@
// Verify that a second call should still return absolute values
mCallback.clear();
final long[][] times2 = increaseTime(times1);
- writeToFile(mHeadline + uidLines(mUids, times2));
+ setCoresAndData(times2);
mReader.readAbsolute(mCallback);
for (int i = 0; i < mUids.length; i++) {
mCallback.verify(mUids[i], clusterTime(times2[i]));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCoresAndData();
}
@Test
public void testReadDeltaDecreasedTime() throws Exception {
final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times1));
+ setCoresAndData(times1);
mReader.readDelta(mCallback);
// Verify that there should not be a callback for a particular UID if its time decreases.
@@ -157,19 +174,19 @@
final long[][] times2 = increaseTime(times1);
System.arraycopy(times1[0], 0, times2[0], 0, mCpus);
times2[0][0] = 100;
- writeToFile(mHeadline + uidLines(mUids, times2));
+ setCoresAndData(times2);
mReader.readDelta(mCallback);
for (int i = 1; i < mUids.length; i++) {
mCallback.verify(mUids[i], subtract(clusterTime(times2[i]), clusterTime(times1[i])));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCoresAndData();
// Verify that the internal state was not modified.
mCallback.clear();
final long[][] times3 = increaseTime(times2);
times3[0] = increaseTime(times1)[0];
- writeToFile(mHeadline + uidLines(mUids, times3));
+ setCoresAndData(times3);
mReader.readDelta(mCallback);
mCallback.verify(mUids[0], subtract(clusterTime(times3[0]), clusterTime(times1[0])));
for (int i = 1; i < mUids.length; i++) {
@@ -181,26 +198,26 @@
@Test
public void testReadDeltaNegativeTime() throws Exception {
final long[][] times1 = increaseTime(new long[mUids.length][mCpus]);
- writeToFile(mHeadline + uidLines(mUids, times1));
+ setCoresAndData(times1);
mReader.readDelta(mCallback);
// Verify that there should not be a callback for a particular UID if its time decreases.
mCallback.clear();
final long[][] times2 = increaseTime(times1);
times2[0][0] *= -1;
- writeToFile(mHeadline + uidLines(mUids, times2));
+ setCoresAndData(times2);
mReader.readDelta(mCallback);
for (int i = 1; i < mUids.length; i++) {
mCallback.verify(mUids[i], subtract(clusterTime(times2[i]), clusterTime(times1[i])));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearCoresAndData();
// Verify that the internal state was not modified.
mCallback.clear();
final long[][] times3 = increaseTime(times2);
times3[0] = increaseTime(times1)[0];
- writeToFile(mHeadline + uidLines(mUids, times3));
+ setCoresAndData(times3);
mReader.readDelta(mCallback);
mCallback.verify(mUids[0], subtract(clusterTime(times3[0]), clusterTime(times1[0])));
for (int i = 1; i < mUids.length; i++) {
@@ -209,6 +226,28 @@
mCallback.verifyNoMoreInteractions();
}
+ private void setCoresAndData(long[][] times) throws IOException {
+ if (mUseBpf) {
+ mBpfMapReader.setClusterCores(mCores);
+ SparseArray<long[]> data = new SparseArray<>();
+ for (int i = 0; i < mUids.length; i++) {
+ data.put(mUids[i], times[i]);
+ }
+ mBpfMapReader.setData(data);
+ } else {
+ writeToFile(mHeadline + uidLines(mUids, times));
+ }
+ }
+
+ private void clearCoresAndData() {
+ if (mUseBpf) {
+ mBpfMapReader.setClusterCores(null);
+ mBpfMapReader.setData(new SparseArray<>());
+ } else {
+ assertTrue(mTestFile.delete());
+ }
+ }
+
private long[] clusterTime(long[] times) {
// Assumes 4 + 2 cores
return new long[]{times[0] + times[1] / 2 + times[2] / 3 + times[3] / 4,
@@ -277,4 +316,36 @@
assertEquals(0, mData.size());
}
}
+
+ private class KernelCpuUidTestBpfMapReader extends KernelCpuUidBpfMapReader {
+ private long[] mClusterCores;
+ private SparseArray<long[]> mNewData = new SparseArray<>();
+
+ public void setData(SparseArray<long[]> data) {
+ mNewData = data;
+ }
+
+ public void setClusterCores(long[] cores) {
+ mClusterCores = cores;
+ }
+
+ @Override
+ public final boolean startTrackingBpfTimes() {
+ return true;
+ }
+
+ @Override
+ protected final boolean readBpfData() {
+ if (!mUseBpf) {
+ return false;
+ }
+ mData = mNewData;
+ return true;
+ }
+
+ @Override
+ public final long[] getDataDimensions() {
+ return mClusterCores;
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
index 0b6fed3..c60a6d6 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuUidFreqTimeReaderTest.java
@@ -29,7 +29,6 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.internal.os.KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader;
@@ -37,6 +36,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -45,6 +46,7 @@
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Random;
/**
@@ -53,14 +55,16 @@
* $ atest FrameworksCoreTests:com.android.internal.os.KernelCpuUidFreqTimeReaderTest
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class KernelCpuUidFreqTimeReaderTest {
private File mTestDir;
private File mTestFile;
private KernelCpuUidFreqTimeReader mReader;
+ private KernelCpuUidTestBpfMapReader mBpfMapReader;
private VerifiableCallback mCallback;
@Mock
private PowerProfile mPowerProfile;
+ private boolean mUseBpf;
private Random mRand = new Random(12345);
private final int[] mUids = {0, 1, 22, 333, 4444, 55555};
@@ -69,13 +73,23 @@
return InstrumentationRegistry.getContext();
}
+ @Parameters(name="useBpf={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { {true}, {false} });
+ }
+
+ public KernelCpuUidFreqTimeReaderTest(boolean useBpf) {
+ mUseBpf = useBpf;
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestDir = getContext().getDir("test", Context.MODE_PRIVATE);
mTestFile = new File(mTestDir, "test.file");
+ mBpfMapReader = new KernelCpuUidTestBpfMapReader();
mReader = new KernelCpuUidFreqTimeReader(mTestFile.getAbsolutePath(),
- new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false);
+ new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), mBpfMapReader, false);
mCallback = new VerifiableCallback();
}
@@ -97,17 +111,17 @@
final int[][] numFreqs = {{3, 6}, {4, 5}, {3, 5, 4}, {3}};
for (int i = 0; i < freqs.length; ++i) {
mReader = new KernelCpuUidFreqTimeReader(mTestFile.getAbsolutePath(),
- new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false);
+ new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), mBpfMapReader, false);
setCpuClusterFreqs(numClusters[i], numFreqs[i]);
- writeToFile(freqsLine(freqs[i]));
+ setFreqs(freqs[i]);
long[] actualFreqs = mReader.readFreqs(mPowerProfile);
assertArrayEquals(freqs[i], actualFreqs);
final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s",
Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i]));
assertFalse(errMsg, mReader.perClusterTimesAvailable());
- // Verify that a second call won't read the proc file again
- assertTrue(mTestFile.delete());
+ // Verify that a second call won't re-read the freqs
+ clearFreqsAndData();
actualFreqs = mReader.readFreqs(mPowerProfile);
assertArrayEquals(freqs[i], actualFreqs);
assertFalse(errMsg, mReader.perClusterTimesAvailable());
@@ -125,17 +139,17 @@
final int[][] numFreqs = {{4}, {3, 5}, {3, 5, 4}};
for (int i = 0; i < freqs.length; ++i) {
mReader = new KernelCpuUidFreqTimeReader(mTestFile.getAbsolutePath(),
- new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), false);
+ new KernelCpuProcStringReader(mTestFile.getAbsolutePath()), mBpfMapReader, false);
setCpuClusterFreqs(numClusters[i], numFreqs[i]);
- writeToFile(freqsLine(freqs[i]));
+ setFreqs(freqs[i]);
long[] actualFreqs = mReader.readFreqs(mPowerProfile);
assertArrayEquals(freqs[i], actualFreqs);
final String errMsg = String.format("Freqs=%s, nClusters=%d, nFreqs=%s",
Arrays.toString(freqs[i]), numClusters[i], Arrays.toString(numFreqs[i]));
assertTrue(errMsg, mReader.perClusterTimesAvailable());
- // Verify that a second call won't read the proc file again
- assertTrue(mTestFile.delete());
+ // Verify that a second call won't re-read the freqs
+ clearFreqsAndData();
actualFreqs = mReader.readFreqs(mPowerProfile);
assertArrayEquals(freqs[i], actualFreqs);
assertTrue(errMsg, mReader.perClusterTimesAvailable());
@@ -147,7 +161,7 @@
final long[] freqs = {110, 123, 145, 167, 289, 997};
final long[][] times = increaseTime(new long[mUids.length][freqs.length]);
- writeToFile(freqsLine(freqs) + uidLines(mUids, times));
+ setFreqsAndData(freqs, times);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], times[i]);
@@ -155,14 +169,14 @@
mCallback.verifyNoMoreInteractions();
// Verify that readDelta also reads the frequencies if not already available.
- assertTrue(mTestFile.delete());
+ clearFreqsAndData();
long[] actualFreqs = mReader.readFreqs(mPowerProfile);
assertArrayEquals(freqs, actualFreqs);
// Verify that a second call will only return deltas.
mCallback.clear();
final long[][] newTimes1 = increaseTime(times);
- writeToFile(freqsLine(freqs) + uidLines(mUids, newTimes1));
+ setFreqsAndData(freqs, newTimes1);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], subtract(newTimes1[i], times[i]));
@@ -177,7 +191,7 @@
// Verify that calling with a null callback doesn't result in any crashes
mCallback.clear();
final long[][] newTimes2 = increaseTime(newTimes1);
- writeToFile(freqsLine(freqs) + uidLines(mUids, newTimes2));
+ setFreqsAndData(freqs, newTimes2);
mReader.readDelta(null);
mCallback.verifyNoMoreInteractions();
@@ -185,13 +199,13 @@
// the previous call had null callback.
mCallback.clear();
final long[][] newTimes3 = increaseTime(newTimes2);
- writeToFile(freqsLine(freqs) + uidLines(mUids, newTimes3));
+ setFreqsAndData(freqs, newTimes3);
mReader.readDelta(mCallback);
for (int i = 0; i < mUids.length; ++i) {
mCallback.verify(mUids[i], subtract(newTimes3[i], newTimes2[i]));
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearFreqsAndData();
}
@Test
@@ -199,7 +213,7 @@
final long[] freqs = {110, 123, 145, 167, 289, 997};
final long[][] times1 = increaseTime(new long[mUids.length][freqs.length]);
- writeToFile(freqsLine(freqs) + uidLines(mUids, times1));
+ setFreqsAndData(freqs, times1);
mReader.readAbsolute(mCallback);
for (int i = 0; i < mUids.length; i++) {
mCallback.verify(mUids[i], times1[i]);
@@ -207,20 +221,20 @@
mCallback.verifyNoMoreInteractions();
// Verify that readDelta also reads the frequencies if not already available.
- assertTrue(mTestFile.delete());
+ clearFreqsAndData();
long[] actualFreqs = mReader.readFreqs(mPowerProfile);
assertArrayEquals(freqs, actualFreqs);
// Verify that a second call should still return absolute values
mCallback.clear();
final long[][] times2 = increaseTime(times1);
- writeToFile(freqsLine(freqs) + uidLines(mUids, times2));
+ setFreqsAndData(freqs, times2);
mReader.readAbsolute(mCallback);
for (int i = 0; i < mUids.length; i++) {
mCallback.verify(mUids[i], times2[i]);
}
mCallback.verifyNoMoreInteractions();
- assertTrue(mTestFile.delete());
+ clearFreqsAndData();
}
@Test
@@ -228,14 +242,14 @@
final long[] freqs = {110, 123, 145, 167, 289, 997};
final long[][] times1 = increaseTime(new long[mUids.length][freqs.length]);
- writeToFile(freqsLine(freqs) + uidLines(mUids, times1));
+ setFreqsAndData(freqs, times1);
mReader.readDelta(mCallback);
// Verify that there should not be a callback for a particular UID if its time decreases.
mCallback.clear();
final long[][] times2 = increaseTime(times1);
times2[0][0] = 1000;
- writeToFile(freqsLine(freqs) + uidLines(mUids, times2));
+ setFreqsAndData(freqs, times2);
mReader.readDelta(mCallback);
for (int i = 1; i < mUids.length; i++) {
mCallback.verify(mUids[i], subtract(times2[i], times1[i]));
@@ -246,7 +260,7 @@
mCallback.clear();
final long[][] times3 = increaseTime(times2);
times3[0] = increaseTime(times1)[0];
- writeToFile(freqsLine(freqs) + uidLines(mUids, times3));
+ setFreqsAndData(freqs, times3);
mReader.readDelta(mCallback);
mCallback.verify(mUids[0], subtract(times3[0], times1[0]));
for (int i = 1; i < mUids.length; i++) {
@@ -258,7 +272,7 @@
mCallback.clear();
final long[][] times4 = increaseTime(times3);
times4[0][0] *= -1;
- writeToFile(freqsLine(freqs) + uidLines(mUids, times4));
+ setFreqsAndData(freqs, times4);
mReader.readDelta(mCallback);
for (int i = 1; i < mUids.length; ++i) {
mCallback.verify(mUids[i], subtract(times4[i], times3[i]));
@@ -269,14 +283,44 @@
mCallback.clear();
final long[][] times5 = increaseTime(times4);
times5[0] = increaseTime(times3)[0];
- writeToFile(freqsLine(freqs) + uidLines(mUids, times5));
+ setFreqsAndData(freqs, times5);
mReader.readDelta(mCallback);
mCallback.verify(mUids[0], subtract(times5[0], times3[0]));
for (int i = 1; i < mUids.length; i++) {
mCallback.verify(mUids[i], subtract(times5[i], times4[i]));
}
- assertTrue(mTestFile.delete());
+ clearFreqsAndData();
+ }
+
+ private void setFreqs(long[] freqs) throws IOException {
+ if (mUseBpf) {
+ mBpfMapReader.setFreqs(freqs);
+ } else {
+ writeToFile(freqsLine(freqs));
+ }
+ }
+
+ private void setFreqsAndData(long[] freqs, long[][] times) throws IOException {
+ if (mUseBpf) {
+ mBpfMapReader.setFreqs(freqs);
+ SparseArray<long[]> data = new SparseArray<>();
+ for (int i = 0; i < mUids.length; i++) {
+ data.put(mUids[i], times[i]);
+ }
+ mBpfMapReader.setData(data);
+ } else {
+ writeToFile(freqsLine(freqs) + uidLines(mUids, times));
+ }
+ }
+
+ private void clearFreqsAndData() {
+ if (mUseBpf) {
+ mBpfMapReader.setFreqs(null);
+ mBpfMapReader.setData(new SparseArray<>());
+ } else {
+ assertTrue(mTestFile.delete());
+ }
}
private String freqsLine(long[] freqs) {
@@ -358,4 +402,36 @@
assertEquals(0, mData.size());
}
}
+
+ private class KernelCpuUidTestBpfMapReader extends KernelCpuUidBpfMapReader {
+ private long[] mCpuFreqs;
+ private SparseArray<long[]> mNewData = new SparseArray<>();
+
+ public void setData(SparseArray<long[]> data) {
+ mNewData = data;
+ }
+
+ public void setFreqs(long[] freqs) {
+ mCpuFreqs = freqs;
+ }
+
+ @Override
+ public final boolean startTrackingBpfTimes() {
+ return true;
+ }
+
+ @Override
+ protected final boolean readBpfData() {
+ if (!mUseBpf) {
+ return false;
+ }
+ mData = mNewData;
+ return true;
+ }
+
+ @Override
+ public final long[] getDataDimensions() {
+ return mCpuFreqs;
+ }
+ }
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
index 479e19e..dac35e5 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleUidTimeReaderTest.java
@@ -31,20 +31,33 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
+import java.util.Collection;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
public class KernelSingleUidTimeReaderTest {
private final static int TEST_UID = 2222;
private final static int TEST_FREQ_COUNT = 5;
private KernelSingleUidTimeReader mReader;
private TestInjector mInjector;
+ protected boolean mUseBpf;
+
+ @Parameters(name="useBpf={0}")
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] { {true}, {false} });
+ }
+
+ public KernelSingleUidTimeReaderTest(boolean useBpf) {
+ mUseBpf = useBpf;
+ }
@Before
public void setUp() {
@@ -273,6 +286,7 @@
class TestInjector extends Injector {
private byte[] mData;
+ private long[] mBpfData;
private boolean mThrowExcpetion;
@Override
@@ -284,6 +298,14 @@
}
}
+ @Override
+ public long[] readBpfData(int uid) {
+ if (!mUseBpf || mBpfData == null) {
+ return new long[0];
+ }
+ return mBpfData;
+ }
+
public void setData(long[] cpuTimes) {
final ByteBuffer buffer = ByteBuffer.allocate(cpuTimes.length * Long.BYTES);
buffer.order(ByteOrder.nativeOrder());
@@ -291,6 +313,7 @@
buffer.putLong(time / 10);
}
mData = buffer.array();
+ mBpfData = cpuTimes.clone();
}
public void letReadDataThrowException(boolean throwException) {
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 9c2e95f..c1e7a36 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -2243,6 +2243,19 @@
return nativeCreateGraphicBufferHandle(mNativePtr);
}
+ /**
+ * @return {@link HardwareBuffer} which is internally used by hardware bitmap
+ *
+ * Note: the HardwareBuffer does *not* have an associated {@link ColorSpace}.
+ * To render this object the same as its rendered with this Bitmap, you
+ * should also call {@link getColorSpace}.
+ *
+ * @hide
+ */
+ public HardwareBuffer getHardwareBuffer() {
+ return nativeGetHardwareBuffer(mNativePtr);
+ }
+
//////////// native methods
private static native Bitmap nativeCreate(int[] colors, int offset,
@@ -2308,6 +2321,7 @@
private static native Bitmap nativeWrapHardwareBufferBitmap(HardwareBuffer buffer,
long nativeColorSpace);
private static native GraphicBuffer nativeCreateGraphicBufferHandle(long nativeBitmap);
+ private static native HardwareBuffer nativeGetHardwareBuffer(long nativeBitmap);
private static native ColorSpace nativeComputeColorSpace(long nativePtr);
private static native void nativeSetColorSpace(long nativePtr, long nativeColorSpace);
private static native boolean nativeIsSRGB(long nativePtr);
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/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 5af3ad5..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;
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/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/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/pip/BasePipManager.java b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
index 383d459..adee7f2 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/BasePipManager.java
@@ -20,6 +20,7 @@
import java.io.PrintWriter;
+
public interface BasePipManager {
void showPictureInPictureMenu();
default void expandPip() {}
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 b5c8d66..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,6 +46,7 @@
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;
@@ -229,7 +230,8 @@
@Inject
public PipManager(Context context, BroadcastDispatcher broadcastDispatcher,
- DisplayController displayController) {
+ DisplayController displayController,
+ FloatingContentCoordinator floatingContentCoordinator) {
mContext = context;
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
@@ -247,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);
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/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/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/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 97b5eaa..430a5b9 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -79,6 +79,7 @@
import android.os.TransactionTooLargeException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
@@ -187,6 +188,9 @@
AppWidgetManagerInternal mAppWidgetManagerInternal;
+ // white listed packageName.
+ ArraySet<String> mWhiteListAllowWhileInUsePermissionInFgs = new ArraySet<>();
+
final Runnable mLastAnrDumpClearer = new Runnable() {
@Override public void run() {
synchronized (mAm) {
@@ -389,6 +393,20 @@
AppStateTracker ast = LocalServices.getService(AppStateTracker.class);
ast.addListener(new ForcedStandbyListener());
mAppWidgetManagerInternal = LocalServices.getService(AppWidgetManagerInternal.class);
+ setWhiteListAllowWhileInUsePermissionInFgs();
+ }
+
+ private void setWhiteListAllowWhileInUsePermissionInFgs() {
+ final String attentionServicePackageName =
+ mAm.mContext.getPackageManager().getAttentionServicePackageName();
+ if (!TextUtils.isEmpty(attentionServicePackageName)) {
+ mWhiteListAllowWhileInUsePermissionInFgs.add(attentionServicePackageName);
+ }
+ final String systemCaptionsServicePackageName =
+ mAm.mContext.getPackageManager().getSystemCaptionsServicePackageName();
+ if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
+ mWhiteListAllowWhileInUsePermissionInFgs.add(systemCaptionsServicePackageName);
+ }
}
ServiceRecord getServiceByNameLocked(ComponentName name, int callingUser) {
@@ -4634,6 +4652,12 @@
return true;
}
+ final boolean isWhiteListedPackage =
+ mWhiteListAllowWhileInUsePermissionInFgs.contains(callingPackage);
+ if (isWhiteListedPackage) {
+ return true;
+ }
+
r.mInfoDenyWhileInUsePermissionInFgs =
"Background FGS start while-in-use permission restriction [callingPackage: "
+ callingPackage
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index fabe92db..8fbe923 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -19,12 +19,16 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
import android.app.ActivityThread;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertiesChangedListener;
import android.provider.DeviceConfig.Properties;
@@ -33,6 +37,7 @@
import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Slog;
+import android.util.SparseArray;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -289,6 +294,12 @@
// started, the restriction is on while-in-use permissions.)
volatile boolean mFlagBackgroundFgsStartRestrictionEnabled = true;
+ /**
+ * UserId to Assistant ComponentName mapping.
+ * Per user Assistant ComponentName is from {@link android.provider.Settings.Secure#ASSISTANT}
+ */
+ SparseArray<ComponentName> mAssistants = new SparseArray<>();
+
private final ActivityManagerService mService;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -364,6 +375,8 @@
Settings.Global.getUriFor(
Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED);
+ private static final Uri ASSISTANT_URI = Settings.Secure.getUriFor(Settings.Secure.ASSISTANT);
+
private static final Uri ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI =
Settings.Global.getUriFor(Settings.Global.ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS);
@@ -430,6 +443,8 @@
mResolver.registerContentObserver(ACTIVITY_STARTS_LOGGING_ENABLED_URI, false, this);
mResolver.registerContentObserver(FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED_URI,
false, this);
+ mResolver.registerContentObserver(ASSISTANT_URI, false, this,
+ UserHandle.USER_ALL);
if (mSystemServerAutomaticHeapDumpEnabled) {
mResolver.registerContentObserver(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI,
false, this);
@@ -445,6 +460,7 @@
// The following read from Settings.
updateActivityStartsLoggingEnabled();
updateForegroundServiceStartsLoggingEnabled();
+ updateAssistant();
}
private void loadDeviceConfigConstants() {
@@ -476,6 +492,8 @@
updateForegroundServiceStartsLoggingEnabled();
} else if (ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_URI.equals(uri)) {
updateEnableAutomaticSystemServerHeapDumps();
+ } else if (ASSISTANT_URI.equals(uri)) {
+ updateAssistant();
}
}
@@ -573,6 +591,31 @@
Settings.Global.FOREGROUND_SERVICE_STARTS_LOGGING_ENABLED, 1) == 1;
}
+ private void updateAssistant() {
+ final List<UserInfo> users =
+ mService.mContext.getSystemService(UserManager.class).getUsers();
+ SparseArray<ComponentName> componentNames = new SparseArray<>();
+ for (int i = 0; i < users.size(); i++) {
+ final int userId = users.get(i).id;
+ final String str = Settings.Secure.getStringForUser(mResolver,
+ Settings.Secure.ASSISTANT, userId);
+ if (!TextUtils.isEmpty(str)) {
+ componentNames.put(userId, ComponentName.unflattenFromString(str));
+ }
+ }
+ synchronized (mService) {
+ for (int i = 0; i < mAssistants.size(); i++) {
+ mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.remove(
+ mAssistants.valueAt(i).getPackageName());
+ }
+ mAssistants = componentNames;
+ for (int i = 0; i < mAssistants.size(); i++) {
+ mService.mServices.mWhiteListAllowWhileInUsePermissionInFgs.add(
+ mAssistants.valueAt(i).getPackageName());
+ }
+ }
+ }
+
private void updateBackgroundFgsStartsRestriction() {
mFlagBackgroundFgsStartRestrictionEnabled = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -581,9 +624,6 @@
}
private void updateOomAdjUpdatePolicy() {
-
-
-
OOMADJ_UPDATE_QUICK = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_OOMADJ_UPDATE_POLICY,
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/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..ec8e1a0 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -39,7 +39,9 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.PackageListObserver;
import android.content.pm.PermissionInfo;
+import android.content.pm.parsing.AndroidPackage;
import android.os.Build;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -50,15 +52,14 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongSparseLongArray;
+import android.util.Pair;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.internal.infra.AndroidFuture;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IntPair;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
@@ -69,7 +70,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
import java.util.concurrent.ExecutionException;
/**
@@ -100,7 +100,7 @@
* scheduled for a package/user.
*/
@GuardedBy("mLock")
- private final ArraySet<Integer> mIsPackageSyncsScheduled = new ArraySet<>();
+ private final ArraySet<Pair<String, Integer>> mIsPackageSyncsScheduled = new ArraySet<>();
public PermissionPolicyService(@NonNull Context context) {
super(context);
@@ -125,8 +125,10 @@
@Override
public void onPackageChanged(String packageName, int uid) {
- if (isStarted(UserHandle.getUserId(uid))) {
- synchronizePackagePermissionsAndAppOpsForUser(uid);
+ final int userId = UserHandle.getUserId(uid);
+
+ if (isStarted(userId)) {
+ synchronizePackagePermissionsAndAppOpsForUser(packageName, userId);
}
}
@@ -137,21 +139,12 @@
});
permManagerInternal.addOnRuntimePermissionStateChangedListener(
- (packageName, userId) -> {
- int uid;
- try {
- uid = getContext().getPackageManager().getPackageUidAsUser(packageName, 0,
- userId);
- } catch (NameNotFoundException e) {
- Slog.e(LOG_TAG, "Cannot synchronize changed package " + packageName, e);
- return;
- }
- synchronizeUidPermissionsAndAppOpsAsync(uid);
- });
+ this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
mAppOpsCallback = new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName) {
- synchronizeUidPermissionsAndAppOpsAsync(uid);
+ synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
+ UserHandle.getUserId(uid));
}
};
@@ -201,17 +194,19 @@
return AppOpsManager.opToSwitch(op);
}
- private void synchronizeUidPermissionsAndAppOpsAsync(int uid) {
- if (isStarted(UserHandle.getUserId(uid))) {
+ private void synchronizePackagePermissionsAndAppOpsAsyncForUser(@NonNull String packageName,
+ @UserIdInt int changedUserId) {
+ if (isStarted(changedUserId)) {
synchronized (mLock) {
- if (mIsPackageSyncsScheduled.add(uid)) {
+ if (mIsPackageSyncsScheduled.add(new Pair<>(packageName, changedUserId))) {
FgThread.getHandler().sendMessage(PooledLambda.obtainMessage(
PermissionPolicyService
::synchronizePackagePermissionsAndAppOpsForUser,
- this, uid));
+ this, packageName, changedUserId));
} else {
if (DEBUG) {
- Slog.v(LOG_TAG, "sync for " + uid + " already scheduled");
+ Slog.v(LOG_TAG, "sync for " + packageName + "/" + changedUserId
+ + " already scheduled");
}
}
}
@@ -340,20 +335,39 @@
/**
* Synchronize a single package.
*/
- private void synchronizePackagePermissionsAndAppOpsForUser(int uid) {
+ private void synchronizePackagePermissionsAndAppOpsForUser(@NonNull String packageName,
+ @UserIdInt int userId) {
synchronized (mLock) {
- mIsPackageSyncsScheduled.remove(uid);
+ mIsPackageSyncsScheduled.remove(new Pair<>(packageName, userId));
}
if (DEBUG) {
Slog.v(LOG_TAG,
- "synchronizePackagePermissionsAndAppOpsForUser(" + uid + ")");
+ "synchronizePackagePermissionsAndAppOpsForUser(" + packageName + ", "
+ + userId + ")");
}
+ final PackageManagerInternal packageManagerInternal = LocalServices.getService(
+ PackageManagerInternal.class);
+ final PackageInfo pkg = packageManagerInternal.getPackageInfo(packageName, 0,
+ Process.SYSTEM_UID, userId);
+ if (pkg == null) {
+ return;
+ }
final PermissionToOpSynchroniser synchroniser = new PermissionToOpSynchroniser(
- getUserContext(getContext(), UserHandle.getUserHandleForUid(uid)));
- synchroniser.addUid(uid);
- synchroniser.syncUids();
+ getUserContext(getContext(), UserHandle.of(userId)));
+ synchroniser.addPackage(pkg.packageName);
+ final String[] sharedPkgNames = packageManagerInternal.getSharedUserPackagesForPackage(
+ pkg.packageName, userId);
+
+ for (String sharedPkgName : sharedPkgNames) {
+ final AndroidPackage sharedPkg = packageManagerInternal
+ .getPackage(sharedPkgName);
+ if (sharedPkg != null) {
+ synchroniser.addPackage(sharedPkg.getPackageName());
+ }
+ }
+ synchroniser.syncPackages();
}
/**
@@ -367,8 +381,8 @@
final PermissionToOpSynchroniser synchronizer = new PermissionToOpSynchroniser(
getUserContext(getContext(), UserHandle.of(userId)));
packageManagerInternal.forEachPackage(
- (pkg) -> synchronizer.addUid(pkg.getUid()));
- synchronizer.syncUids();
+ (pkg) -> synchronizer.addPackage(pkg.getPackageName()));
+ synchronizer.syncPackages();
}
/**
@@ -383,51 +397,37 @@
private final @NonNull ArrayMap<String, PermissionInfo> mRuntimePermissionInfos;
- // Cache uid -> packageNames
- private SparseArray<String[]> mUidToPkg = new SparseArray<>();
-
/**
* All ops that need to be flipped to allow.
*
- * @see #syncUids
+ * @see #syncPackages
*/
- private final @NonNull ArraySet<OpToChange> mOpsToAllow = new ArraySet<>();
+ private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>();
/**
* All ops that need to be flipped to ignore.
*
- * @see #syncUids
+ * @see #syncPackages
*/
- private final @NonNull ArraySet<OpToChange> mOpsToIgnore = new ArraySet<>();
+ private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>();
/**
* All ops that need to be flipped to ignore if not allowed.
*
* Currently, only used by soft restricted permissions logic.
*
- * @see #syncUids
+ * @see #syncPackages
*/
- private final @NonNull ArraySet<OpToChange> mOpsToIgnoreIfNotAllowed = new ArraySet<>();
+ private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>();
/**
* All ops that need to be flipped to foreground.
*
* Currently, only used by the foreground/background permissions logic.
*
- * @see #syncUids
+ * @see #syncPackages
*/
- private final @NonNull ArraySet<OpToChange> mOpsToForeground = new ArraySet<>();
-
- private @Nullable String[] getPackageNamesForUid(int uid) {
- String[] pkgs = mUidToPkg.get(uid);
- if (pkgs != null) {
- return pkgs;
- }
-
- pkgs = mPackageManager.getPackagesForUid(uid);
- mUidToPkg.put(uid, pkgs);
- return pkgs;
- }
+ private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>();
PermissionToOpSynchroniser(@NonNull Context context) {
mContext = context;
@@ -449,11 +449,11 @@
}
/**
- * Set app ops that were added in {@link #addUid}.
+ * Set app ops that were added in {@link #addPackage}.
*
* <p>This processes ops previously added by {@link #addAppOps(PackageInfo, String)}
*/
- private void syncUids() {
+ private void syncPackages() {
// Remember which ops were already set. This makes sure that we always set the most
// permissive mode if two OpChanges are scheduled. This can e.g. happen if two
// permissions change the same op. See {@link #getSwitchOp}.
@@ -461,42 +461,42 @@
final int allowCount = mOpsToAllow.size();
for (int i = 0; i < allowCount; i++) {
- final OpToChange op = mOpsToAllow.valueAt(i);
+ final OpToChange op = mOpsToAllow.get(i);
- setUidModeAllowed(op.code, op.uid);
+ setUidModeAllowed(op.code, op.uid, op.packageName);
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
final int foregroundCount = mOpsToForeground.size();
for (int i = 0; i < foregroundCount; i++) {
- final OpToChange op = mOpsToForeground.valueAt(i);
+ final OpToChange op = mOpsToForeground.get(i);
if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
continue;
}
- setUidModeForeground(op.code, op.uid);
+ setUidModeForeground(op.code, op.uid, op.packageName);
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
final int ignoreCount = mOpsToIgnore.size();
for (int i = 0; i < ignoreCount; i++) {
- final OpToChange op = mOpsToIgnore.valueAt(i);
+ final OpToChange op = mOpsToIgnore.get(i);
if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
continue;
}
- setUidModeIgnored(op.code, op.uid);
+ setUidModeIgnored(op.code, op.uid, op.packageName);
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size();
for (int i = 0; i < ignoreIfNotAllowedCount; i++) {
- final OpToChange op = mOpsToIgnoreIfNotAllowed.valueAt(i);
+ final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i);
if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
continue;
}
- boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid);
+ boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName);
if (wasSet) {
alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
}
@@ -555,7 +555,7 @@
}
int uid = packageInfo.applicationInfo.uid;
- OpToChange opToChange = new OpToChange(uid, appOpCode);
+ OpToChange opToChange = new OpToChange(uid, packageName, appOpCode);
switch (appOpMode) {
case MODE_ALLOWED:
mOpsToAllow.add(opToChange);
@@ -618,7 +618,8 @@
}
int uid = packageInfo.applicationInfo.uid;
- OpToChange extraOpToChange = new OpToChange(uid, extraOpCode);
+ String packageName = packageInfo.packageName;
+ OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode);
if (policy.mayAllowExtraAppOp()) {
mOpsToAllow.add(extraOpToChange);
} else {
@@ -631,59 +632,48 @@
}
/**
- * Add a Uid for {@link #syncUids() processing} later.
+ * Add a package for {@link #syncPackages() processing} later.
*
* <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
*
- * @param uid The uid to add for later processing.
+ * @param pkgName The package to add for later processing.
*/
- void addUid(int uid) {
- String[] pkgNames = getPackageNamesForUid(uid);
- if (pkgNames == null) {
+ void addPackage(@NonNull String pkgName) {
+ final PackageInfo pkg;
+ try {
+ pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
+ } catch (NameNotFoundException e) {
return;
}
- for (String pkgName : pkgNames) {
- final PackageInfo pkg;
- try {
- pkg = mPackageManager.getPackageInfo(pkgName, GET_PERMISSIONS);
- } catch (NameNotFoundException e) {
- continue;
- }
+ if (pkg.requestedPermissions == null) {
+ return;
+ }
- if (pkg.requestedPermissions == null) {
- continue;
- }
-
- for (String permission : pkg.requestedPermissions) {
- addAppOps(pkg, permission);
- }
+ for (String permission : pkg.requestedPermissions) {
+ addAppOps(pkg, permission);
}
}
- private void setUidModeAllowed(int opCode, int uid) {
- setUidMode(opCode, uid, MODE_ALLOWED);
+ private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
+ setUidMode(opCode, uid, MODE_ALLOWED, packageName);
}
- private void setUidModeForeground(int opCode, int uid) {
- setUidMode(opCode, uid, MODE_FOREGROUND);
+ private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
+ setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
}
- private void setUidModeIgnored(int opCode, int uid) {
- setUidMode(opCode, uid, MODE_IGNORED);
+ private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
+ setUidMode(opCode, uid, MODE_IGNORED, packageName);
}
- private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid) {
- String[] pkgsOfUid = getPackageNamesForUid(uid);
- if (ArrayUtils.isEmpty(pkgsOfUid)) {
- return false;
- }
-
+ private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid,
+ @NonNull String packageName) {
final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
- opCode), uid, pkgsOfUid[0]);
+ opCode), uid, packageName);
if (currentMode != MODE_ALLOWED) {
if (currentMode != MODE_IGNORED) {
- mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, MODE_IGNORED,
+ mAppOpsManagerInternal.setUidModeFromPermissionPolicy(opCode, uid, MODE_IGNORED,
mAppOpsCallback);
}
return true;
@@ -691,24 +681,20 @@
return false;
}
- private void setUidMode(int opCode, int uid, int mode) {
- String[] pkgsOfUid = getPackageNamesForUid(uid);
- if (ArrayUtils.isEmpty(pkgsOfUid)) {
- return;
- }
-
+ private void setUidMode(int opCode, int uid, int mode,
+ @NonNull String packageName) {
final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
- opCode), uid, pkgsOfUid[0]);
+ opCode), uid, packageName);
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]);
+ opCode), uid, packageName);
if (newMode != mode) {
// 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, packageName,
AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback);
}
}
@@ -716,30 +702,14 @@
private class OpToChange {
final int uid;
+ final @NonNull String packageName;
final int code;
- OpToChange(int uid, int code) {
+ OpToChange(int uid, @NonNull String packageName, int code) {
this.uid = uid;
+ this.packageName = packageName;
this.code = code;
}
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- OpToChange other = (OpToChange) o;
- return uid == other.uid && code == other.code;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(uid, code);
- }
}
}
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/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e1f713e..68504bd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -912,7 +912,7 @@
private void setShadowRenderer() {
mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 0) != 0;
+ DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
}
PowerManager mPowerManager;
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/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/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/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index a251c05..e566d27 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -123,5 +123,12 @@
"libcutils",
],
static_libs: ["libstatssocket"],
+
+ apex_available: [
+ "//apex_available:platform",
+ //TODO(b/149781190): Remove this once statsd no longer depends on libstatslog
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
}