Merge "Import translations. DO NOT MERGE" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index 398fc3f..9c0e630 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -42821,17 +42821,17 @@
ctor public ServiceState(android.os.Parcel);
method protected void copyFrom(android.telephony.ServiceState);
method public int describeContents();
+ method public int getCdmaNetworkId();
+ method public int getCdmaSystemId();
method public int[] getCellBandwidths();
method public int getChannelNumber();
method public int getDuplexMode();
method public boolean getIsManualSelection();
- method public int getNetworkId();
method public java.lang.String getOperatorAlphaLong();
method public java.lang.String getOperatorAlphaShort();
method public java.lang.String getOperatorNumeric();
method public boolean getRoaming();
method public int getState();
- method public int getSystemId();
method public void setIsManualSelection(boolean);
method public void setOperatorName(java.lang.String, java.lang.String, java.lang.String);
method public void setRoaming(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index af783ca..1080669 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -729,9 +729,14 @@
public final class UsageStatsManager {
method public int getAppStandbyBucket(java.lang.String);
method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
+ method public void registerAppUsageObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent);
method public void setAppStandbyBucket(java.lang.String, int);
method public void setAppStandbyBuckets(java.util.Map<java.lang.String, java.lang.Integer>);
+ method public void unregisterAppUsageObserver(int);
method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
+ field public static final java.lang.String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
+ field public static final java.lang.String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
+ field public static final java.lang.String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
field public static final int STANDBY_BUCKET_EXEMPTED = 5; // 0x5
field public static final int STANDBY_BUCKET_NEVER = 50; // 0x32
}
@@ -4327,11 +4332,14 @@
method public deprecated java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context);
+ method public java.security.Key getKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
+ method public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public int[] getPendingRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+ method public java.security.Key importKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException;
diff --git a/api/test-current.txt b/api/test-current.txt
index 54ddd5d..3ddbdba 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -759,7 +759,7 @@
}
public class ServiceState implements android.os.Parcelable {
- method public void setSystemAndNetworkId(int, int);
+ method public void setCdmaSystemAndNetworkId(int, int);
}
}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index fff1a00..d52bd37 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -16,6 +16,7 @@
package android.app.usage;
+import android.app.PendingIntent;
import android.app.usage.UsageEvents;
import android.content.pm.ParceledListSlice;
@@ -43,4 +44,7 @@
void setAppStandbyBucket(String packageName, int bucket, int userId);
ParceledListSlice getAppStandbyBuckets(String callingPackage, int userId);
void setAppStandbyBuckets(in ParceledListSlice appBuckets, int userId);
+ void registerAppUsageObserver(int observerId, in String[] packages, long timeLimitMs,
+ in PendingIntent callback, String callingPackage);
+ void unregisterAppUsageObserver(int observerId, String callingPackage);
}
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 5f9fa43..59f001c 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -20,6 +20,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
@@ -32,6 +33,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
/**
* Provides access to device usage history and statistics. Usage data is aggregated into
@@ -179,6 +181,31 @@
@Retention(RetentionPolicy.SOURCE)
public @interface StandbyBuckets {}
+ /**
+ * Observer id of the registered observer for the group of packages that reached the usage
+ * time limit. Included as an extra in the PendingIntent that was registered.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
+
+ /**
+ * Original time limit in milliseconds specified by the registered observer for the group of
+ * packages that reached the usage time limit. Included as an extra in the PendingIntent that
+ * was registered.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
+
+ /**
+ * Actual usage time in milliseconds for the group of packages that reached the specified time
+ * limit. Included as an extra in the PendingIntent that was registered.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
+
private static final UsageEvents sEmptyResults = new UsageEvents();
private final Context mContext;
@@ -470,6 +497,53 @@
}
}
+ /**
+ * @hide
+ * Register an app usage limit observer that receives a callback on the provided intent when
+ * the sum of usages of apps in the packages array exceeds the timeLimit specified. The
+ * observer will automatically be unregistered when the time limit is reached and the intent
+ * is delivered.
+ * @param observerId A unique id associated with the group of apps to be monitored. There can
+ * be multiple groups with common packages and different time limits.
+ * @param packages The list of packages to observe for foreground activity time. Must include
+ * at least one package.
+ * @param timeLimit The total time the set of apps can be in the foreground before the
+ * callbackIntent is delivered. Must be greater than 0.
+ * @param timeUnit The unit for time specified in timeLimit.
+ * @param callbackIntent The PendingIntent that will be dispatched when the time limit is
+ * exceeded by the group of apps. The delivered Intent will also contain
+ * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
+ * {@link #EXTRA_TIME_USED}.
+ * @throws SecurityException if the caller doesn't have the PACKAGE_USAGE_STATS permission.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+ public void registerAppUsageObserver(int observerId, String[] packages, long timeLimit,
+ TimeUnit timeUnit, PendingIntent callbackIntent) {
+ try {
+ mService.registerAppUsageObserver(observerId, packages, timeUnit.toMillis(timeLimit),
+ callbackIntent, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ * Unregister the app usage observer specified by the observerId. This will only apply to any
+ * observer registered by this application. Unregistering an observer that was already
+ * unregistered or never registered will have no effect.
+ * @param observerId The id of the observer that was previously registered.
+ * @throws SecurityException if the caller doesn't have the PACKAGE_USAGE_STATS permission.
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
+ public void unregisterAppUsageObserver(int observerId) {
+ try {
+ mService.unregisterAppUsageObserver(observerId, mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ }
+ }
+
/** @hide */
public static String reasonToString(int standbyReason) {
StringBuilder sb = new StringBuilder();
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 04cceb8..848c596 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -331,7 +331,6 @@
final long looperToken = proto.start(fieldId);
proto.write(LooperProto.THREAD_NAME, mThread.getName());
proto.write(LooperProto.THREAD_ID, mThread.getId());
- proto.write(LooperProto.IDENTITY_HASH_CODE, System.identityHashCode(this));
mQueue.writeToProto(proto, LooperProto.QUEUE);
proto.end(looperToken);
}
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 97d415e..66fa629 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -1643,12 +1643,12 @@
public void writeToProto(ProtoOutputStream proto, long fieldId) {
synchronized (mToken) {
final long token = proto.start(fieldId);
- proto.write(PowerManagerProto.WakeLockProto.HEX_STRING,
- Integer.toHexString(System.identityHashCode(this)));
- proto.write(PowerManagerProto.WakeLockProto.HELD, mHeld);
- proto.write(PowerManagerProto.WakeLockProto.INTERNAL_COUNT, mInternalCount);
+ proto.write(PowerManagerProto.WakeLock.TAG, mTag);
+ proto.write(PowerManagerProto.WakeLock.PACKAGE_NAME, mPackageName);
+ proto.write(PowerManagerProto.WakeLock.HELD, mHeld);
+ proto.write(PowerManagerProto.WakeLock.INTERNAL_COUNT, mInternalCount);
if (mWorkSource != null) {
- mWorkSource.writeToProto(proto, PowerManagerProto.WakeLockProto.WORK_SOURCE);
+ mWorkSource.writeToProto(proto, PowerManagerProto.WakeLock.WORK_SOURCE);
}
proto.end(token);
}
diff --git a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
index aa09f10..3d3b6d5 100644
--- a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
+++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
@@ -215,8 +215,8 @@
/**
* Creates a new {@link KeyChainProtectionParams} instance.
- * The instance will include default values, if {@link setSecret}
- * or {@link setUserSecretType} were not called.
+ * The instance will include default values, if {@link #setSecret}
+ * or {@link #setUserSecretType} were not called.
*
* @return new instance
* @throws NullPointerException if some required fields were not set.
diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
index fc909a0..ef5e90c 100644
--- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
@@ -30,7 +30,7 @@
/**
* Collection of parameters which define a key derivation function.
- * Currently only supports salted SHA-256
+ * Currently only supports salted SHA-256.
*
* @hide
*/
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 4881375..7523afd 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -33,6 +33,7 @@
import java.security.Key;
import java.security.UnrecoverableKeyException;
+import java.security.cert.CertPath;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
@@ -156,6 +157,7 @@
/**
* Gets a new instance of the class.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public static RecoveryController getInstance(Context context) {
ILockSettings lockSettings =
ILockSettings.Stub.asInterface(ServiceManager.getService("lock_settings"));
@@ -245,8 +247,6 @@
* @return Data necessary to recover keystore or {@code null} if snapshot is not available.
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
- *
- * @hide
*/
@RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public @Nullable KeyChainSnapshot getKeyChainSnapshot()
@@ -288,7 +288,7 @@
/**
* Server parameters used to generate new recovery key blobs. This value will be included in
* {@code KeyChainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included
- * in vaultParams {@link #startRecoverySession}
+ * in vaultParams {@link RecoverySession#start(CertPath, byte[], byte[], List)}.
*
* @param serverParams included in recovery key blob.
* @see #getRecoveryData
@@ -310,6 +310,7 @@
* @deprecated Use {@link #getAliases()}.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public List<String> getAliases(@Nullable String packageName)
throws InternalRecoveryServiceException {
return getAliases();
@@ -318,6 +319,7 @@
/**
* Returns a list of aliases of keys belonging to the application.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public List<String> getAliases() throws InternalRecoveryServiceException {
try {
Map<String, Integer> allStatuses = mBinder.getRecoveryStatus();
@@ -367,6 +369,7 @@
* @deprecated Use {@link #getRecoveryStatus(String)}.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public int getRecoveryStatus(String packageName, String alias)
throws InternalRecoveryServiceException {
return getRecoveryStatus(alias);
@@ -385,6 +388,7 @@
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public int getRecoveryStatus(String alias) throws InternalRecoveryServiceException {
try {
Map<String, Integer> allStatuses = mBinder.getRecoveryStatus();
@@ -410,6 +414,7 @@
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public void setRecoverySecretTypes(
@NonNull @KeyChainProtectionParams.UserSecretType int[] secretTypes)
throws InternalRecoveryServiceException {
@@ -431,6 +436,7 @@
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public @NonNull @KeyChainProtectionParams.UserSecretType int[] getRecoverySecretTypes()
throws InternalRecoveryServiceException {
try {
@@ -452,6 +458,7 @@
* service.
*/
@NonNull
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public @KeyChainProtectionParams.UserSecretType int[] getPendingRecoverySecretTypes()
throws InternalRecoveryServiceException {
try {
@@ -474,6 +481,7 @@
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public void recoverySecretAvailable(@NonNull KeyChainProtectionParams recoverySecret)
throws InternalRecoveryServiceException {
try {
@@ -498,6 +506,7 @@
* to generate recoverable keys, as the snapshots are encrypted using a key derived from the
* lock screen.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
throws InternalRecoveryServiceException, LockScreenRequiredException {
try {
@@ -512,11 +521,11 @@
}
}
- // TODO: Unhide the following APIs, generateKey(), importKey(), and getKey()
/**
* @deprecated Use {@link #generateKey(String)}.
*/
@Deprecated
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public Key generateKey(@NonNull String alias, byte[] account)
throws InternalRecoveryServiceException, LockScreenRequiredException {
return generateKey(alias);
@@ -530,6 +539,7 @@
* @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
* screen is required to generate recoverable keys.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public Key generateKey(@NonNull String alias) throws InternalRecoveryServiceException,
LockScreenRequiredException {
try {
@@ -562,8 +572,8 @@
* @throws LockScreenRequiredException if the user does not have a lock screen set. A lock
* screen is required to generate recoverable keys.
*
- * @hide
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public Key importKey(@NonNull String alias, byte[] keyBytes)
throws InternalRecoveryServiceException, LockScreenRequiredException {
try {
@@ -595,8 +605,8 @@
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
* @throws UnrecoverableKeyException if key is permanently invalidated or not found.
- * @hide
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public @Nullable Key getKey(@NonNull String alias)
throws InternalRecoveryServiceException, UnrecoverableKeyException {
try {
@@ -622,6 +632,7 @@
* @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
* service.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public void removeKey(@NonNull String alias) throws InternalRecoveryServiceException {
try {
mBinder.removeKey(alias);
@@ -637,6 +648,7 @@
*
* <p>A recovery session is required to restore keys from a remote store.
*/
+ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
public RecoverySession createRecoverySession() {
return RecoverySession.newInstance(this);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index d908e79..d521684 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -29,6 +29,7 @@
import android.Manifest;
import android.animation.LayoutTransition;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ResourcesManager;
@@ -4152,9 +4153,7 @@
Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
}
KeyEvent event = (KeyEvent) msg.obj;
- // send InputEvent to pre IME, set FLAG_FROM_AUTOFILL so the InputEvent
- // wont be dropped as app window is not focus.
- enqueueInputEvent(event, null, QueuedInputEvent.FLAG_FROM_AUTOFILL, true);
+ enqueueInputEvent(event, null, 0, true);
} break;
case MSG_CHECK_FOCUS: {
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -4447,7 +4446,7 @@
return true;
} else if ((!mAttachInfo.mHasWindowFocus
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
- && (q.mFlags & QueuedInputEvent.FLAG_FROM_AUTOFILL) == 0) || mStopped
+ && !isAutofillUiShowing()) || mStopped
|| (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
|| (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
@@ -4782,18 +4781,11 @@
ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
}
- if (action == MotionEvent.ACTION_DOWN && mView instanceof ViewGroup) {
+ if (action == MotionEvent.ACTION_DOWN) {
// Upon motion event within app window, close autofill ui.
- ViewGroup decorView = (ViewGroup) mView;
- if (decorView.getChildCount() > 0) {
- // We cannot use decorView's Context for querying AutofillManager: DecorView's
- // context is based on Application Context, it would allocate a different
- // AutofillManager instance.
- AutofillManager afm = (AutofillManager) decorView.getChildAt(0).getContext()
- .getSystemService(Context.AUTOFILL_MANAGER_SERVICE);
- if (afm != null) {
- afm.requestHideFillUi();
- }
+ AutofillManager afm = getAutofillManager();
+ if (afm != null) {
+ afm.requestHideFillUi();
}
}
@@ -6435,6 +6427,28 @@
return mAudioManager;
}
+ private @Nullable AutofillManager getAutofillManager() {
+ if (mView instanceof ViewGroup) {
+ ViewGroup decorView = (ViewGroup) mView;
+ if (decorView.getChildCount() > 0) {
+ // We cannot use decorView's Context for querying AutofillManager: DecorView's
+ // context is based on Application Context, it would allocate a different
+ // AutofillManager instance.
+ return decorView.getChildAt(0).getContext()
+ .getSystemService(AutofillManager.class);
+ }
+ }
+ return null;
+ }
+
+ private boolean isAutofillUiShowing() {
+ AutofillManager afm = getAutofillManager();
+ if (afm == null) {
+ return false;
+ }
+ return afm.isAutofillUiShowing();
+ }
+
public AccessibilityInteractionController getAccessibilityInteractionController() {
if (mView == null) {
throw new IllegalStateException("getAccessibilityInteractionController"
@@ -6840,7 +6854,6 @@
public static final int FLAG_FINISHED_HANDLED = 1 << 3;
public static final int FLAG_RESYNTHESIZED = 1 << 4;
public static final int FLAG_UNHANDLED = 1 << 5;
- public static final int FLAG_FROM_AUTOFILL = 1 << 6;
public QueuedInputEvent mNext;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 158c2ee0b..c109297 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1407,6 +1407,15 @@
return client;
}
+ /**
+ * Check if autofill ui is showing, must be called on UI thread.
+ * @hide
+ */
+ public boolean isAutofillUiShowing() {
+ final AutofillClient client = mContext.getAutofillClient();
+ return client != null & client.autofillClientIsFillUiShowing();
+ }
+
/** @hide */
public void onAuthenticationResult(int authenticationId, Intent data, View focusView) {
if (!hasAutofillFeature()) {
diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto
index 74b47d2..6a174e8 100644
--- a/core/proto/android/content/configuration.proto
+++ b/core/proto/android/content/configuration.proto
@@ -32,7 +32,7 @@
optional float font_scale = 1;
optional uint32 mcc = 2;
- optional uint32 mnc = 3;
+ optional uint32 mnc = 3 [ (.android.privacy).dest = DEST_EXPLICIT ];
repeated LocaleProto locales = 4;
optional uint32 screen_layout = 5;
optional uint32 color_mode = 6;
diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto
index 5e0ed11..3b2c4fc 100644
--- a/core/proto/android/content/intent.proto
+++ b/core/proto/android/content/intent.proto
@@ -59,7 +59,7 @@
optional ComponentNameProto component = 7;
optional string source_bounds = 8;
optional string clip_data = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
- optional string extras = 10 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ optional string extras = 10 [ (.android.privacy).dest = DEST_LOCAL ];
optional int32 content_user_hint = 11;
optional string selector = 12;
}
diff --git a/core/proto/android/os/looper.proto b/core/proto/android/os/looper.proto
index 435c648..dce65d3 100644
--- a/core/proto/android/os/looper.proto
+++ b/core/proto/android/os/looper.proto
@@ -25,8 +25,8 @@
message LooperProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string thread_name = 1 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ // the thread name, usually set by developers.
+ optional string thread_name = 1;
optional int64 thread_id = 2;
- optional int32 identity_hash_code = 3;
- optional android.os.MessageQueueProto queue = 4;
+ optional android.os.MessageQueueProto queue = 3;
}
diff --git a/core/proto/android/os/powermanager.proto b/core/proto/android/os/powermanager.proto
index 78a28ed..20b0a74 100644
--- a/core/proto/android/os/powermanager.proto
+++ b/core/proto/android/os/powermanager.proto
@@ -36,13 +36,14 @@
}
// WakeLock class in android.os.PowerManager, it is the one used by sdk
- message WakeLockProto {
+ message WakeLock {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string hex_string = 1;
- optional bool held = 2;
- optional int32 internal_count = 3;
- optional WorkSourceProto work_source = 4;
+ optional string tag = 1;
+ optional string package_name = 2;
+ optional bool held = 3;
+ optional int32 internal_count = 4;
+ optional WorkSourceProto work_source = 5;
}
}
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 3b9150f..5491ca5 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -157,7 +157,7 @@
optional BroadcastRecordProto current = 5;
optional bool linked_to_death = 6;
repeated BroadcastFilterProto filters = 7;
- optional string hex_hash = 8; // this hash is used to find the object in IntentResolver
+ optional string hex_hash = 8; // used to find this ReceiverList object in IntentResolver
}
message ProcessRecordProto {
@@ -184,7 +184,7 @@
optional .android.content.IntentFilterProto intent_filter = 1;
optional string required_permission = 2;
- optional string hex_hash = 3; // used to find the object in IntentResolver
+ optional string hex_hash = 3; // used to find the BroadcastFilter object in IntentResolver
optional int32 owning_user_id = 4;
}
@@ -458,13 +458,12 @@
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional string short_name = 1;
- optional string hex_hash = 2;
- optional bool is_running = 3; // false if the application service is null
- optional int32 pid = 4;
- optional .android.content.IntentProto intent = 5;
- optional string package_name = 6;
- optional string process_name = 7;
- optional string permission = 8;
+ optional bool is_running = 2; // false if the application service is null
+ optional int32 pid = 3;
+ optional .android.content.IntentProto intent = 4;
+ optional string package_name = 5;
+ optional string process_name = 6;
+ optional string permission = 7;
message AppInfo {
option (.android.msg_privacy).dest = DEST_EXPLICIT;
@@ -473,11 +472,11 @@
optional string res_dir = 2;
optional string data_dir = 3;
}
- optional AppInfo appinfo = 9;
- optional ProcessRecordProto app = 10;
- optional ProcessRecordProto isolated_proc = 11;
- optional bool whitelist_manager = 12;
- optional bool delayed = 13;
+ optional AppInfo appinfo = 8;
+ optional ProcessRecordProto app = 9;
+ optional ProcessRecordProto isolated_proc = 10;
+ optional bool whitelist_manager = 11;
+ optional bool delayed = 12;
message Foreground {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -485,13 +484,13 @@
optional int32 id = 1;
optional .android.app.NotificationProto notification = 2;
}
- optional Foreground foreground = 14;
+ optional Foreground foreground = 13;
- optional .android.util.Duration create_real_time = 15;
- optional .android.util.Duration starting_bg_timeout = 16;
- optional .android.util.Duration last_activity_time = 17;
- optional .android.util.Duration restart_time = 18;
- optional bool created_from_fg = 19;
+ optional .android.util.Duration create_real_time = 14;
+ optional .android.util.Duration starting_bg_timeout = 15;
+ optional .android.util.Duration last_activity_time = 16;
+ optional .android.util.Duration restart_time = 17;
+ optional bool created_from_fg = 18;
// variables used to track states related to service start
message Start {
@@ -503,7 +502,7 @@
optional bool call_start = 4;
optional int32 last_start_id = 5;
}
- optional Start start = 20;
+ optional Start start = 19;
message ExecuteNesting {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -512,9 +511,9 @@
optional bool execute_fg = 2;
optional .android.util.Duration executing_start = 3;
}
- optional ExecuteNesting execute = 21;
+ optional ExecuteNesting execute = 20;
- optional .android.util.Duration destory_time = 22;
+ optional .android.util.Duration destory_time = 21;
message Crash {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -524,9 +523,9 @@
optional .android.util.Duration next_restart_time = 3;
optional int32 crash_count = 4;
}
- optional Crash crash = 23;
+ optional Crash crash = 22;
- message StartItemProto {
+ message StartItem {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional int32 id = 1;
@@ -537,17 +536,20 @@
optional NeededUriGrantsProto needed_grants = 6;
optional UriPermissionOwnerProto uri_permissions = 7;
}
- repeated StartItemProto delivered_starts = 24;
- repeated StartItemProto pending_starts = 25;
+ repeated StartItem delivered_starts = 23;
+ repeated StartItem pending_starts = 24;
- repeated IntentBindRecordProto bindings = 26;
- repeated ConnectionRecordProto connections = 27;
+ repeated IntentBindRecordProto bindings = 25;
+ repeated ConnectionRecordProto connections = 26;
+
+ // Next Tag: 27
}
message ConnectionRecordProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string hex_hash = 1;
+ // used to find same record, e.g. AppBindRecord has the hex_hash
+ optional string hex_hash = 1; // cross reference the object and avoid double logging.
optional int32 user_id = 2;
enum Flag {
@@ -570,30 +572,28 @@
}
repeated Flag flags = 3;
optional string service_name = 4;
- optional string conn_hex_hash = 5;
}
message AppBindRecordProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string hex_hash = 1;
- optional ProcessRecordProto client = 2;
- repeated ConnectionRecordProto connections = 3;
+ optional string service_name = 1;
+ optional string client_proc_name = 2;
+ repeated string connections = 3; // hex_hash of ConnectionRecordProto
}
message IntentBindRecordProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string hex_hash = 1;
- optional bool is_create = 2;
- optional .android.content.IntentProto intent = 3;
- optional string binder = 4;
- optional bool requested = 5;
- optional bool received = 6;
- optional bool has_bound = 7;
- optional bool do_rebind = 8;
+ optional .android.content.IntentProto intent = 1;
+ optional string binder = 2;
+ optional bool auto_create = 3; // value of BIND_AUTO_CREATE flag.
+ optional bool requested = 4;
+ optional bool received = 5;
+ optional bool has_bound = 6;
+ optional bool do_rebind = 7;
- repeated AppBindRecordProto apps = 9;
+ repeated AppBindRecordProto apps = 8;
}
// TODO: "dumpsys activity --proto processes"
@@ -688,10 +688,10 @@
optional SleepStatus sleep_status = 27;
message VoiceProto {
- option (.android.msg_privacy).dest = DEST_EXPLICIT;
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional string session = 1;
- optional .android.os.PowerManagerProto.WakeLockProto wakelock = 2;
+ optional .android.os.PowerManagerProto.WakeLock wakelock = 2;
}
optional VoiceProto running_voice = 28;
@@ -780,8 +780,8 @@
optional bool call_finish_booting = 44;
optional bool boot_animation_complete = 45;
optional int64 last_power_check_uptime_ms = 46;
- optional .android.os.PowerManagerProto.WakeLockProto going_to_sleep = 47;
- optional .android.os.PowerManagerProto.WakeLockProto launching_activity = 48;
+ optional .android.os.PowerManagerProto.WakeLock going_to_sleep = 47;
+ optional .android.os.PowerManagerProto.WakeLock launching_activity = 48;
optional int32 adj_seq = 49;
optional int32 lru_seq = 50;
optional int32 num_non_cached_procs = 51;
@@ -813,14 +813,13 @@
message UidRecordProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional string hex_hash = 1;
- optional int32 uid = 2;
- optional .android.app.ProcessStateEnum current = 3;
- optional bool ephemeral = 4;
- optional bool fg_services = 5;
- optional bool whilelist = 6;
- optional .android.util.Duration last_background_time = 7;
- optional bool idle = 8;
+ optional int32 uid = 1;
+ optional .android.app.ProcessStateEnum current = 2;
+ optional bool ephemeral = 3;
+ optional bool fg_services = 4;
+ optional bool whilelist = 5;
+ optional .android.util.Duration last_background_time = 6;
+ optional bool idle = 7;
enum Change {
CHANGE_GONE = 0;
@@ -829,8 +828,8 @@
CHANGE_CACHED = 3;
CHANGE_UNCACHED = 4;
}
- repeated Change last_reported_changes = 9;
- optional int32 num_procs = 10;
+ repeated Change last_reported_changes = 8;
+ optional int32 num_procs = 9;
message ProcStateSequence {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -839,7 +838,9 @@
optional int64 last_network_updated = 2;
optional int64 last_dispatched = 3;
}
- optional ProcStateSequence network_state_update = 11;
+ optional ProcStateSequence network_state_update = 10;
+
+ // Next Tag: 11
}
// proto of class ImportanceToken in ActivityManagerService
diff --git a/core/proto/android/server/intentresolver.proto b/core/proto/android/server/intentresolver.proto
index 0ada895..e67723e 100644
--- a/core/proto/android/server/intentresolver.proto
+++ b/core/proto/android/server/intentresolver.proto
@@ -24,9 +24,9 @@
message IntentResolverProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
+ // A mapping bewteen some key string to IntentFilter's toString().
message ArrayMapEntry {
- option (.android.msg_privacy).dest = DEST_EXPLICIT;
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional string key = 1;
repeated string values = 2;
diff --git a/core/proto/android/service/diskstats.proto b/core/proto/android/service/diskstats.proto
index e5bdc8b..f55f0e7 100644
--- a/core/proto/android/service/diskstats.proto
+++ b/core/proto/android/service/diskstats.proto
@@ -37,8 +37,8 @@
}
// Whether the latency test resulted in an error
optional bool has_test_error = 1;
- // If the test errored, error message is contained here
- optional string error_message = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
+ // If the test errored, error message is contained here, it is just IOException.
+ optional string error_message = 2;
// 512B write latency in milliseconds, if the test was successful
optional int32 write_512b_latency_millis = 3;
// Free Space in the major partitions
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index e3be5d4..62d941a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5507,6 +5507,10 @@
// internal platform metrics use.
RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS = 1359;
+ // OPEN: Settings > Gestures > Prevent Ringing
+ // OS: P
+ SETTINGS_PREVENT_RINGING = 1360;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dd31a84..04d46aa 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -25932,16 +25932,19 @@
Bundle bOptions) {
Preconditions.checkNotNull(intents, "intents");
final String[] resolvedTypes = new String[intents.length];
- for (int i = 0; i < intents.length; i++) {
- resolvedTypes[i] = intents[i].resolveTypeIfNeeded(mContext.getContentResolver());
- }
// UID of the package on user userId.
// "= 0" is needed because otherwise catch(RemoteException) would make it look like
// packageUid may not be initialized.
int packageUid = 0;
final long ident = Binder.clearCallingIdentity();
+
try {
+ for (int i = 0; i < intents.length; i++) {
+ resolvedTypes[i] =
+ intents[i].resolveTypeIfNeeded(mContext.getContentResolver());
+ }
+
packageUid = AppGlobals.getPackageManager().getPackageUid(
packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a24f84a..8f987be 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -5287,6 +5287,14 @@
boolean shouldSleepActivities() {
final ActivityDisplay display = getDisplay();
+
+ // Do not sleep activities in this stack if we're marked as focused and the keyguard
+ // is in the process of going away.
+ if (mStackSupervisor.getFocusedStack() == this
+ && mStackSupervisor.getKeyguardController().isKeyguardGoingAway()) {
+ return false;
+ }
+
return display != null ? display.isSleeping() : mService.isSleepingLocked();
}
diff --git a/services/core/java/com/android/server/am/AppBindRecord.java b/services/core/java/com/android/server/am/AppBindRecord.java
index 7b38597..972a692 100644
--- a/services/core/java/com/android/server/am/AppBindRecord.java
+++ b/services/core/java/com/android/server/am/AppBindRecord.java
@@ -66,14 +66,13 @@
void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
- proto.write(AppBindRecordProto.HEX_HASH,
- Integer.toHexString(System.identityHashCode(this)));
- if (client != null) {
- client.writeToProto(proto, AppBindRecordProto.CLIENT);
- }
+ proto.write(AppBindRecordProto.SERVICE_NAME, service.shortName);
+ proto.write(AppBindRecordProto.CLIENT_PROC_NAME, client.processName);
final int N = connections.size();
for (int i=0; i<N; i++) {
- connections.valueAt(i).writeToProto(proto, AppBindRecordProto.CONNECTIONS);
+ ConnectionRecord conn = connections.valueAt(i);
+ proto.write(AppBindRecordProto.CONNECTIONS,
+ Integer.toHexString(System.identityHashCode(conn)));
}
proto.end(token);
}
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index d320fb1..a8e9ad9 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -176,10 +176,6 @@
if (binding.service != null) {
proto.write(ConnectionRecordProto.SERVICE_NAME, binding.service.shortName);
}
- if (conn != null) {
- proto.write(ConnectionRecordProto.CONN_HEX_HASH,
- Integer.toHexString(System.identityHashCode(conn.asBinder())));
- }
proto.end(token);
}
}
diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
index 01ce64c..3457a80 100644
--- a/services/core/java/com/android/server/am/IntentBindRecord.java
+++ b/services/core/java/com/android/server/am/IntentBindRecord.java
@@ -113,10 +113,6 @@
public void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
- proto.write(IntentBindRecordProto.HEX_HASH,
- Integer.toHexString(System.identityHashCode(this)));
- proto.write(IntentBindRecordProto.IS_CREATE,
- (collectFlags()&Context.BIND_AUTO_CREATE) != 0);
if (intent != null) {
intent.getIntent().writeToProto(proto,
IntentBindRecordProto.INTENT, false, true, false, false);
@@ -124,6 +120,8 @@
if (binder != null) {
proto.write(IntentBindRecordProto.BINDER, binder.toString());
}
+ proto.write(IntentBindRecordProto.AUTO_CREATE,
+ (collectFlags()&Context.BIND_AUTO_CREATE) != 0);
proto.write(IntentBindRecordProto.REQUESTED, requested);
proto.write(IntentBindRecordProto.RECEIVED, received);
proto.write(IntentBindRecordProto.HAS_BOUND, hasBound);
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 72882de..0d7eab6 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -98,6 +98,14 @@
}
/**
+ * @return {@code true} if the keyguard is going away, {@code false} otherwise.
+ */
+ boolean isKeyguardGoingAway() {
+ // Also check keyguard showing in case value is stale.
+ return mKeyguardGoingAway && mKeyguardShowing;
+ }
+
+ /**
* Update the Keyguard showing state.
*/
void setKeyguardShown(boolean showing, int secondaryDisplayShowing) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index b6eff00..49a55cb 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -164,21 +164,20 @@
public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
long token = proto.start(fieldId);
- proto.write(ServiceRecordProto.StartItemProto.ID, id);
+ proto.write(ServiceRecordProto.StartItem.ID, id);
ProtoUtils.toDuration(proto,
- ServiceRecordProto.StartItemProto.DURATION, deliveredTime, now);
- proto.write(ServiceRecordProto.StartItemProto.DELIVERY_COUNT, deliveryCount);
- proto.write(ServiceRecordProto.StartItemProto.DONE_EXECUTING_COUNT, doneExecutingCount);
+ ServiceRecordProto.StartItem.DURATION, deliveredTime, now);
+ proto.write(ServiceRecordProto.StartItem.DELIVERY_COUNT, deliveryCount);
+ proto.write(ServiceRecordProto.StartItem.DONE_EXECUTING_COUNT, doneExecutingCount);
if (intent != null) {
- intent.writeToProto(proto, ServiceRecordProto.StartItemProto.INTENT, true, true,
+ intent.writeToProto(proto, ServiceRecordProto.StartItem.INTENT, true, true,
true, false);
}
if (neededGrants != null) {
- neededGrants.writeToProto(proto, ServiceRecordProto.StartItemProto.NEEDED_GRANTS);
+ neededGrants.writeToProto(proto, ServiceRecordProto.StartItem.NEEDED_GRANTS);
}
if (uriPermissions != null) {
- uriPermissions.writeToProto(proto,
- ServiceRecordProto.StartItemProto.URI_PERMISSIONS);
+ uriPermissions.writeToProto(proto, ServiceRecordProto.StartItem.URI_PERMISSIONS);
}
proto.end(token);
}
@@ -236,8 +235,6 @@
void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(ServiceRecordProto.SHORT_NAME, this.shortName);
- proto.write(ServiceRecordProto.HEX_HASH,
- Integer.toHexString(System.identityHashCode(this)));
proto.write(ServiceRecordProto.IS_RUNNING, app != null);
if (app != null) {
proto.write(ServiceRecordProto.PID, app.pid);
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 3886e5a..d49f3ba 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -148,7 +148,6 @@
void writeToProto(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
- proto.write(UidRecordProto.HEX_HASH, Integer.toHexString(System.identityHashCode(this)));
proto.write(UidRecordProto.UID, uid);
proto.write(UidRecordProto.CURRENT, ProcessList.makeProcStateProtoEnum(curProcState));
proto.write(UidRecordProto.EPHEMERAL, ephemeral);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 4fd8686..05549e7 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -163,8 +163,14 @@
private int mBatterySaverEnabledCount = 0;
@GuardedBy("mLock")
+ private boolean mIsBatterySaverEnabled;
+
+ @GuardedBy("mLock")
private long mLastBatterySaverEnabledTime = 0;
+ @GuardedBy("mLock")
+ private long mLastBatterySaverDisabledTime = 0;
+
private final MetricsLoggerHelper mMetricsLoggerHelper = new MetricsLoggerHelper();
@VisibleForTesting
@@ -312,11 +318,12 @@
final boolean newBatterySaverEnabled =
BatterySaverState.fromIndex(newState) != BatterySaverState.OFF;
if (oldBatterySaverEnabled != newBatterySaverEnabled) {
+ mIsBatterySaverEnabled = newBatterySaverEnabled;
if (newBatterySaverEnabled) {
mBatterySaverEnabledCount++;
mLastBatterySaverEnabledTime = injectCurrentTime();
} else {
- mLastBatterySaverEnabledTime = 0;
+ mLastBatterySaverDisabledTime = injectCurrentTime();
}
}
@@ -391,25 +398,35 @@
indent = indent + " ";
+ final long now = System.currentTimeMillis();
+ final long nowElapsed = injectCurrentTime();
+ final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
pw.print(indent);
- pw.print("Battery Saver state: ");
- if (mLastBatterySaverEnabledTime == 0) {
- pw.print("OFF");
- } else {
- pw.print("ON since ");
-
- final long now = System.currentTimeMillis();
- final long nowElapsed = injectCurrentTime();
-
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ pw.print("Battery Saver is currently: ");
+ pw.println(mIsBatterySaverEnabled ? "ON" : "OFF");
+ if (mLastBatterySaverEnabledTime > 0) {
+ pw.print(indent);
+ pw.print(" ");
+ pw.print("Last ON time: ");
pw.print(sdf.format(new Date(now - nowElapsed + mLastBatterySaverEnabledTime)));
-
pw.print(" ");
TimeUtils.formatDuration(mLastBatterySaverEnabledTime, nowElapsed, pw);
+ pw.println();
}
- pw.println();
+
+ if (mLastBatterySaverDisabledTime > 0) {
+ pw.print(indent);
+ pw.print(" ");
+ pw.print("Last OFF time: ");
+ pw.print(sdf.format(new Date(now - nowElapsed + mLastBatterySaverDisabledTime)));
+ pw.print(" ");
+ TimeUtils.formatDuration(mLastBatterySaverDisabledTime, nowElapsed, pw);
+ pw.println();
+ }
pw.print(indent);
+ pw.print(" ");
pw.print("Times enabled: ");
pw.println(mBatterySaverEnabledCount);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index f17bfa4..1a95fdd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -37,12 +37,15 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.servertransaction.DestroyActivityItem;
import android.content.pm.ActivityInfo;
+import android.os.Debug;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
@@ -518,4 +521,37 @@
assertTrue(mTask.mActivities.isEmpty());
assertTrue(mStack.getAllTasks().isEmpty());
}
+
+ @Test
+ public void testShouldSleepActivities() throws Exception {
+ // When focused activity and keyguard is going away, we should not sleep regardless
+ // of the display state
+ verifyShouldSleepActivities(true /* focusedStack */, true /*keyguardGoingAway*/,
+ true /* displaySleeping */, false /* expected*/);
+
+ // When not the focused stack, defer to display sleeping state.
+ verifyShouldSleepActivities(false /* focusedStack */, true /*keyguardGoingAway*/,
+ true /* displaySleeping */, true /* expected*/);
+
+ // If keyguard is going away, defer to the display sleeping state.
+ verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
+ true /* displaySleeping */, true /* expected*/);
+ verifyShouldSleepActivities(true /* focusedStack */, false /*keyguardGoingAway*/,
+ false /* displaySleeping */, false /* expected*/);
+ }
+
+ private void verifyShouldSleepActivities(boolean focusedStack,
+ boolean keyguardGoingAway, boolean displaySleeping, boolean expected) {
+ mSupervisor.mFocusedStack = focusedStack ? mStack : null;
+
+ final ActivityDisplay display = mock(ActivityDisplay.class);
+ final KeyguardController keyguardController = mSupervisor.getKeyguardController();
+
+ doReturn(display).when(mSupervisor).getActivityDisplay(anyInt());
+ doReturn(keyguardGoingAway).when(keyguardController).isKeyguardGoingAway();
+ doReturn(displaySleeping).when(display).isSleeping();
+
+ assertEquals(expected, mStack.shouldSleepActivities());
+ }
+
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 3041a5f..c130592 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -316,6 +316,7 @@
@Override
final protected ActivityStackSupervisor createStackSupervisor() {
final ActivityStackSupervisor supervisor = spy(createTestSupervisor());
+ final KeyguardController keyguardController = mock(KeyguardController.class);
// No home stack is set.
doNothing().when(supervisor).moveHomeStackToFront(any());
@@ -330,6 +331,7 @@
doNothing().when(supervisor).scheduleIdleTimeoutLocked(any());
// unit test version does not handle launch wake lock
doNothing().when(supervisor).acquireLaunchWakelock();
+ doReturn(keyguardController).when(supervisor).getKeyguardController();
supervisor.initialize();
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
new file mode 100644
index 0000000..6b52ee5
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/usage/AppTimeLimitControllerTests.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2018 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.usage;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.PendingIntent;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class AppTimeLimitControllerTests {
+
+ private static final String PKG_SOC1 = "package.soc1";
+ private static final String PKG_SOC2 = "package.soc2";
+ private static final String PKG_GAME1 = "package.game1";
+ private static final String PKG_GAME2 = "package.game2";
+ private static final String PKG_PROD = "package.prod";
+
+ private static final int UID = 10100;
+ private static final int USER_ID = 10;
+ private static final int OBS_ID1 = 1;
+ private static final int OBS_ID2 = 2;
+ private static final int OBS_ID3 = 3;
+
+ private static final long TIME_30_MIN = 30 * 60_1000L;
+ private static final long TIME_10_MIN = 10 * 60_1000L;
+
+ private static final String[] GROUP1 = {
+ PKG_SOC1, PKG_GAME1, PKG_PROD
+ };
+
+ private static final String[] GROUP_SOC = {
+ PKG_SOC1, PKG_SOC2
+ };
+
+ private static final String[] GROUP_GAME = {
+ PKG_GAME1, PKG_GAME2
+ };
+
+ private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+ private AppTimeLimitController mController;
+
+ private HandlerThread mThread;
+
+ private long mUptimeMillis;
+
+ AppTimeLimitController.OnLimitReachedListener mListener
+ = new AppTimeLimitController.OnLimitReachedListener() {
+
+ @Override
+ public void onLimitReached(int observerId, int userId, long timeLimit, long timeElapsed,
+ PendingIntent callbackIntent) {
+ mCountDownLatch.countDown();
+ }
+ };
+
+ class MyAppTimeLimitController extends AppTimeLimitController {
+ MyAppTimeLimitController(AppTimeLimitController.OnLimitReachedListener listener,
+ Looper looper) {
+ super(listener, looper);
+ }
+
+ @Override
+ protected long getUptimeMillis() {
+ return mUptimeMillis;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ mThread = new HandlerThread("Test");
+ mThread.start();
+ mController = new MyAppTimeLimitController(mListener, mThread.getLooper());
+ }
+
+ @After
+ public void tearDown() {
+ mThread.quit();
+ }
+
+ /** Verify observer is added */
+ @Test
+ public void testAddObserver() {
+ addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
+ assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
+ addObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN);
+ assertTrue("Observer wasn't added", hasObserver(OBS_ID2));
+ assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
+ }
+
+ /** Verify observer is removed */
+ @Test
+ public void testRemoveObserver() {
+ addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
+ assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
+ mController.removeObserver(UID, OBS_ID1, USER_ID);
+ assertFalse("Observer wasn't removed", hasObserver(OBS_ID1));
+ }
+
+ /** Re-adding an observer should result in only one copy */
+ @Test
+ public void testObserverReAdd() {
+ addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
+ assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
+ addObserver(OBS_ID1, GROUP1, TIME_10_MIN);
+ assertTrue("Observer wasn't added",
+ mController.getObserverGroup(OBS_ID1, USER_ID).timeLimit == TIME_10_MIN);
+ mController.removeObserver(UID, OBS_ID1, USER_ID);
+ assertFalse("Observer wasn't removed", hasObserver(OBS_ID1));
+ }
+
+ /** Verify that usage across different apps within a group are added up */
+ @Test
+ public void testAccumulation() throws Exception {
+ setTime(0L);
+ addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
+ moveToForeground(PKG_SOC1);
+ // Add 10 mins
+ setTime(TIME_10_MIN);
+ moveToBackground(PKG_SOC1);
+
+ long timeRemaining = mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining;
+ assertEquals(TIME_10_MIN * 2, timeRemaining);
+
+ moveToForeground(PKG_SOC1);
+ setTime(TIME_10_MIN * 2);
+ moveToBackground(PKG_SOC1);
+
+ timeRemaining = mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining;
+ assertEquals(TIME_10_MIN, timeRemaining);
+
+ setTime(TIME_30_MIN);
+
+ assertFalse(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS));
+
+ // Add a different package in the group
+ moveToForeground(PKG_GAME1);
+ setTime(TIME_30_MIN + TIME_10_MIN);
+ moveToBackground(PKG_GAME1);
+
+ assertEquals(0, mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining);
+ assertTrue(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS));
+ }
+
+ /** Verify that time limit does not get triggered due to a different app */
+ @Test
+ public void testTimeoutOtherApp() throws Exception {
+ setTime(0L);
+ addObserver(OBS_ID1, GROUP1, 4_000L);
+ moveToForeground(PKG_SOC2);
+ assertFalse(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS));
+ setTime(6_000L);
+ moveToBackground(PKG_SOC2);
+ assertFalse(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS));
+ }
+
+ /** Verify the timeout message is delivered at the right time */
+ @Test
+ public void testTimeout() throws Exception {
+ setTime(0L);
+ addObserver(OBS_ID1, GROUP1, 4_000L);
+ moveToForeground(PKG_SOC1);
+ setTime(6_000L);
+ assertTrue(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS));
+ moveToBackground(PKG_SOC1);
+ // Verify that the observer was removed
+ assertFalse(hasObserver(OBS_ID1));
+ }
+
+ /** If an app was already running, make sure it is partially counted towards the time limit */
+ @Test
+ public void testAlreadyRunning() throws Exception {
+ setTime(TIME_10_MIN);
+ moveToForeground(PKG_GAME1);
+ setTime(TIME_30_MIN);
+ addObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN);
+ setTime(TIME_30_MIN + TIME_10_MIN);
+ moveToBackground(PKG_GAME1);
+ assertFalse(mCountDownLatch.await(1000L, TimeUnit.MILLISECONDS));
+
+ moveToForeground(PKG_GAME2);
+ setTime(TIME_30_MIN + TIME_30_MIN);
+ moveToBackground(PKG_GAME2);
+ assertTrue(mCountDownLatch.await(1000L, TimeUnit.MILLISECONDS));
+ // Verify that the observer was removed
+ assertFalse(hasObserver(OBS_ID2));
+ }
+
+ /** If watched app is already running, verify the timeout callback happens at the right time */
+ @Test
+ public void testAlreadyRunningTimeout() throws Exception {
+ setTime(0);
+ moveToForeground(PKG_SOC1);
+ setTime(TIME_10_MIN);
+ // 10 second time limit
+ addObserver(OBS_ID1, GROUP_SOC, 10_000L);
+ setTime(TIME_10_MIN + 5_000L);
+ // Shouldn't call back in 6 seconds
+ assertFalse(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS));
+ setTime(TIME_10_MIN + 10_000L);
+ // Should call back by 11 seconds (6 earlier + 5 now)
+ assertTrue(mCountDownLatch.await(5_000L, TimeUnit.MILLISECONDS));
+ // Verify that the observer was removed
+ assertFalse(hasObserver(OBS_ID1));
+ }
+
+ private void moveToForeground(String packageName) {
+ mController.moveToForeground(packageName, "class", USER_ID);
+ }
+
+ private void moveToBackground(String packageName) {
+ mController.moveToBackground(packageName, "class", USER_ID);
+ }
+
+ private void addObserver(int observerId, String[] packages, long timeLimit) {
+ mController.addObserver(UID, observerId, packages, timeLimit, null, USER_ID);
+ }
+
+ /** Is there still an observer by that id */
+ private boolean hasObserver(int observerId) {
+ return mController.getObserverGroup(observerId, USER_ID) != null;
+ }
+
+ private void setTime(long time) {
+ mUptimeMillis = time;
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
new file mode 100644
index 0000000..9cd0593
--- /dev/null
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -0,0 +1,464 @@
+/**
+ * Copyright (C) 2018 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.usage;
+
+import android.annotation.UserIdInt;
+import android.app.PendingIntent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Monitors and informs of any app time limits exceeded. It must be informed when an app
+ * enters the foreground and exits. Used by UsageStatsService. Manages multiple users.
+ *
+ * Test: atest FrameworksServicesTests:AppTimeLimitControllerTests
+ * Test: manual: frameworks/base/tests/UsageStatsTest
+ */
+public class AppTimeLimitController {
+
+ private static final String TAG = "AppTimeLimitController";
+
+ private static final boolean DEBUG = false;
+
+ /** Lock class for this object */
+ private static class Lock {}
+
+ /** Lock object for the data in this class. */
+ private final Lock mLock = new Lock();
+
+ private final MyHandler mHandler;
+
+ private OnLimitReachedListener mListener;
+
+ @GuardedBy("mLock")
+ private final SparseArray<UserData> mUsers = new SparseArray<>();
+
+ private static class UserData {
+ /** userId of the user */
+ private @UserIdInt int userId;
+
+ /** The app that is currently in the foreground */
+ private String currentForegroundedPackage;
+
+ /** The time when the current app came to the foreground */
+ private long currentForegroundedTime;
+
+ /** The last app that was in the background */
+ private String lastBackgroundedPackage;
+
+ /** Map from package name for quick lookup */
+ private ArrayMap<String, ArrayList<TimeLimitGroup>> packageMap = new ArrayMap<>();
+
+ /** Map of observerId to details of the time limit group */
+ private SparseArray<TimeLimitGroup> groups = new SparseArray<>();
+
+ UserData(@UserIdInt int userId) {
+ this.userId = userId;
+ }
+ }
+
+ /**
+ * Listener interface for being informed when an app group's time limit is reached.
+ */
+ public interface OnLimitReachedListener {
+ /**
+ * Time limit for a group, keyed by the observerId, has been reached.
+ * @param observerId The observerId of the group whose limit was reached
+ * @param userId The userId
+ * @param timeLimit The original time limit in milliseconds
+ * @param timeElapsed How much time was actually spent on apps in the group, in milliseconds
+ * @param callbackIntent The PendingIntent to send when the limit is reached
+ */
+ public void onLimitReached(int observerId, @UserIdInt int userId, long timeLimit,
+ long timeElapsed, PendingIntent callbackIntent);
+ }
+
+ static class TimeLimitGroup {
+ int requestingUid;
+ int observerId;
+ String[] packages;
+ long timeLimit;
+ long timeRequested;
+ long timeRemaining;
+ PendingIntent callbackIntent;
+ String currentPackage;
+ long timeCurrentPackageStarted;
+ int userId;
+ }
+
+ class MyHandler extends Handler {
+
+ static final int MSG_CHECK_TIMEOUT = 1;
+ static final int MSG_INFORM_LISTENER = 2;
+
+ MyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CHECK_TIMEOUT:
+ checkTimeout((TimeLimitGroup) msg.obj);
+ break;
+ case MSG_INFORM_LISTENER:
+ informListener((TimeLimitGroup) msg.obj);
+ break;
+ default:
+ super.handleMessage(msg);
+ break;
+ }
+ }
+ }
+
+ public AppTimeLimitController(OnLimitReachedListener listener, Looper looper) {
+ mHandler = new MyHandler(looper);
+ mListener = listener;
+ }
+
+ /** Overrideable by a test */
+ @VisibleForTesting
+ protected long getUptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+
+ /** Returns an existing UserData object for the given userId, or creates one */
+ UserData getOrCreateUserDataLocked(int userId) {
+ UserData userData = mUsers.get(userId);
+ if (userData == null) {
+ userData = new UserData(userId);
+ mUsers.put(userId, userData);
+ }
+ return userData;
+ }
+
+ /** Clean up data if user is removed */
+ public void onUserRemoved(int userId) {
+ synchronized (mLock) {
+ // TODO: Remove any inflight delayed messages
+ mUsers.remove(userId);
+ }
+ }
+
+ /**
+ * Registers an observer with the given details. Existing observer with the same observerId
+ * is removed.
+ */
+ public void addObserver(int requestingUid, int observerId, String[] packages, long timeLimit,
+ PendingIntent callbackIntent, @UserIdInt int userId) {
+ synchronized (mLock) {
+ UserData user = getOrCreateUserDataLocked(userId);
+
+ removeObserverLocked(user, requestingUid, observerId);
+
+ TimeLimitGroup group = new TimeLimitGroup();
+ group.observerId = observerId;
+ group.callbackIntent = callbackIntent;
+ group.packages = packages;
+ group.timeLimit = timeLimit;
+ group.timeRemaining = group.timeLimit;
+ group.timeRequested = getUptimeMillis();
+ group.requestingUid = requestingUid;
+ group.timeCurrentPackageStarted = -1L;
+ group.userId = userId;
+
+ user.groups.append(observerId, group);
+
+ addGroupToPackageMapLocked(user, packages, group);
+
+ if (DEBUG) {
+ Slog.d(TAG, "addObserver " + packages + " for " + timeLimit);
+ }
+ // Handle the case where a target package is already in the foreground when observer
+ // is added.
+ if (user.currentForegroundedPackage != null && inPackageList(group.packages,
+ user.currentForegroundedPackage)) {
+ group.timeCurrentPackageStarted = group.timeRequested;
+ group.currentPackage = user.currentForegroundedPackage;
+ if (group.timeRemaining > 0) {
+ postCheckTimeoutLocked(group, group.timeRemaining);
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove a registered observer by observerId and calling uid.
+ * @param requestingUid The calling uid
+ * @param observerId The unique observer id for this user
+ * @param userId The user id of the observer
+ */
+ public void removeObserver(int requestingUid, int observerId, @UserIdInt int userId) {
+ synchronized (mLock) {
+ UserData user = getOrCreateUserDataLocked(userId);
+ removeObserverLocked(user, requestingUid, observerId);
+ }
+ }
+
+ @VisibleForTesting
+ TimeLimitGroup getObserverGroup(int observerId, int userId) {
+ synchronized (mLock) {
+ return getOrCreateUserDataLocked(userId).groups.get(observerId);
+ }
+ }
+
+ private static boolean inPackageList(String[] packages, String packageName) {
+ return ArrayUtils.contains(packages, packageName);
+ }
+
+ @GuardedBy("mLock")
+ private void removeObserverLocked(UserData user, int requestingUid, int observerId) {
+ TimeLimitGroup group = user.groups.get(observerId);
+ if (group != null && group.requestingUid == requestingUid) {
+ removeGroupFromPackageMapLocked(user, group);
+ user.groups.remove(observerId);
+ mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group);
+ }
+ }
+
+ /**
+ * Called when an app has moved to the foreground.
+ * @param packageName The app that is foregrounded
+ * @param className The className of the activity
+ * @param userId The user
+ */
+ public void moveToForeground(String packageName, String className, int userId) {
+ synchronized (mLock) {
+ UserData user = getOrCreateUserDataLocked(userId);
+ if (DEBUG) Slog.d(TAG, "Setting mCurrentForegroundedPackage to " + packageName);
+ // Note the current foreground package
+ user.currentForegroundedPackage = packageName;
+ user.currentForegroundedTime = getUptimeMillis();
+
+ // Check if the last package that was backgrounded is the same as this one
+ if (!TextUtils.equals(packageName, user.lastBackgroundedPackage)) {
+ // TODO: Move this logic up to usage stats to persist there.
+ incTotalLaunchesLocked(user, packageName);
+ }
+
+ // Check if any of the groups need to watch for this package
+ maybeWatchForPackageLocked(user, packageName, user.currentForegroundedTime);
+ }
+ }
+
+ /**
+ * Called when an app is sent to the background.
+ *
+ * @param packageName
+ * @param className
+ * @param userId
+ */
+ public void moveToBackground(String packageName, String className, int userId) {
+ synchronized (mLock) {
+ UserData user = getOrCreateUserDataLocked(userId);
+ user.lastBackgroundedPackage = packageName;
+ if (!TextUtils.equals(user.currentForegroundedPackage, packageName)) {
+ Slog.w(TAG, "Eh? Last foregrounded package = " + user.currentForegroundedPackage
+ + " and now backgrounded = " + packageName);
+ return;
+ }
+ final long stopTime = getUptimeMillis();
+
+ // Add up the usage time to all groups that contain the package
+ ArrayList<TimeLimitGroup> groups = user.packageMap.get(packageName);
+ if (groups != null) {
+ final int size = groups.size();
+ for (int i = 0; i < size; i++) {
+ final TimeLimitGroup group = groups.get(i);
+ // Don't continue to send
+ if (group.timeRemaining <= 0) continue;
+
+ final long startTime = Math.max(user.currentForegroundedTime,
+ group.timeRequested);
+ long diff = stopTime - startTime;
+ group.timeRemaining -= diff;
+ if (group.timeRemaining <= 0) {
+ if (DEBUG) Slog.d(TAG, "MTB informing group obs=" + group.observerId);
+ postInformListenerLocked(group);
+ }
+ // Reset indicators that observer was added when package was already fg
+ group.currentPackage = null;
+ group.timeCurrentPackageStarted = -1L;
+ mHandler.removeMessages(MyHandler.MSG_CHECK_TIMEOUT, group);
+ }
+ }
+ user.currentForegroundedPackage = null;
+ }
+ }
+
+ private void postInformListenerLocked(TimeLimitGroup group) {
+ mHandler.sendMessage(mHandler.obtainMessage(MyHandler.MSG_INFORM_LISTENER,
+ group));
+ }
+
+ /**
+ * Inform the observer and unregister it, as the limit has been reached.
+ * @param group the observed group
+ */
+ private void informListener(TimeLimitGroup group) {
+ if (mListener != null) {
+ mListener.onLimitReached(group.observerId, group.userId, group.timeLimit,
+ group.timeLimit - group.timeRemaining, group.callbackIntent);
+ }
+ // Unregister since the limit has been met and observer was informed.
+ synchronized (mLock) {
+ UserData user = getOrCreateUserDataLocked(group.userId);
+ removeObserverLocked(user, group.requestingUid, group.observerId);
+ }
+ }
+
+ /** Check if any of the groups care about this package and set up delayed messages */
+ @GuardedBy("mLock")
+ private void maybeWatchForPackageLocked(UserData user, String packageName, long uptimeMillis) {
+ ArrayList<TimeLimitGroup> groups = user.packageMap.get(packageName);
+ if (groups == null) return;
+
+ final int size = groups.size();
+ for (int i = 0; i < size; i++) {
+ TimeLimitGroup group = groups.get(i);
+ if (group.timeRemaining > 0) {
+ group.timeCurrentPackageStarted = uptimeMillis;
+ group.currentPackage = packageName;
+ if (DEBUG) {
+ Slog.d(TAG, "Posting timeout for " + packageName + " for "
+ + group.timeRemaining + "ms");
+ }
+ postCheckTimeoutLocked(group, group.timeRemaining);
+ }
+ }
+ }
+
+ private void addGroupToPackageMapLocked(UserData user, String[] packages,
+ TimeLimitGroup group) {
+ for (int i = 0; i < packages.length; i++) {
+ ArrayList<TimeLimitGroup> list = user.packageMap.get(packages[i]);
+ if (list == null) {
+ list = new ArrayList<>();
+ user.packageMap.put(packages[i], list);
+ }
+ list.add(group);
+ }
+ }
+
+ /**
+ * Remove the group reference from the package to group mapping, which is 1 to many.
+ * @param group The group to remove from the package map.
+ */
+ private void removeGroupFromPackageMapLocked(UserData user, TimeLimitGroup group) {
+ final int mapSize = user.packageMap.size();
+ for (int i = 0; i < mapSize; i++) {
+ ArrayList<TimeLimitGroup> list = user.packageMap.valueAt(i);
+ list.remove(group);
+ }
+ }
+
+ private void postCheckTimeoutLocked(TimeLimitGroup group, long timeout) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MyHandler.MSG_CHECK_TIMEOUT, group),
+ timeout);
+ }
+
+ /**
+ * See if the given group has reached the timeout if the current foreground app is included
+ * and it exceeds the time remaining.
+ * @param group the group of packages to check
+ */
+ void checkTimeout(TimeLimitGroup group) {
+ // For each package in the group, check if any of the currently foregrounded apps are adding
+ // up to hit the limit and inform the observer
+ synchronized (mLock) {
+ UserData user = getOrCreateUserDataLocked(group.userId);
+ // This group doesn't exist anymore, nothing to see here.
+ if (user.groups.get(group.observerId) != group) return;
+
+ if (DEBUG) Slog.d(TAG, "checkTimeout timeRemaining=" + group.timeRemaining);
+
+ // Already reached the limit, no need to report again
+ if (group.timeRemaining <= 0) return;
+
+ if (DEBUG) {
+ Slog.d(TAG, "checkTimeout foregroundedPackage="
+ + user.currentForegroundedPackage);
+ }
+
+ if (inPackageList(group.packages, user.currentForegroundedPackage)) {
+ if (DEBUG) {
+ Slog.d(TAG, "checkTimeout package in foreground="
+ + user.currentForegroundedPackage);
+ }
+ if (group.timeCurrentPackageStarted < 0) {
+ Slog.w(TAG, "startTime was not set correctly for " + group);
+ }
+ final long timeInForeground = getUptimeMillis() - group.timeCurrentPackageStarted;
+ if (group.timeRemaining <= timeInForeground) {
+ if (DEBUG) Slog.d(TAG, "checkTimeout : Time limit reached");
+ // Hit the limit, set timeRemaining to zero to avoid checking again
+ group.timeRemaining -= timeInForeground;
+ postInformListenerLocked(group);
+ // Reset
+ group.timeCurrentPackageStarted = -1L;
+ group.currentPackage = null;
+ } else {
+ if (DEBUG) Slog.d(TAG, "checkTimeout : Some more time remaining");
+ postCheckTimeoutLocked(group, group.timeRemaining - timeInForeground);
+ }
+ }
+ }
+ }
+
+ private void incTotalLaunchesLocked(UserData user, String packageName) {
+ // TODO: Inform UsageStatsService and aggregate the counter per app
+ }
+
+ void dump(PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println("\n App Time Limits");
+ int nUsers = mUsers.size();
+ for (int i = 0; i < nUsers; i++) {
+ UserData user = mUsers.valueAt(i);
+ pw.print(" User "); pw.println(user.userId);
+ int nGroups = user.groups.size();
+ for (int j = 0; j < nGroups; j++) {
+ TimeLimitGroup group = user.groups.valueAt(j);
+ pw.print(" Group id="); pw.print(group.observerId);
+ pw.print(" timeLimit="); pw.print(group.timeLimit);
+ pw.print(" remaining="); pw.print(group.timeRemaining);
+ pw.print(" currentPackage="); pw.print(group.currentPackage);
+ pw.print(" timeCurrentPkgStarted="); pw.print(group.timeCurrentPackageStarted);
+ pw.print(" packages="); pw.println(Arrays.toString(group.packages));
+ }
+ pw.println();
+ pw.print(" currentForegroundedPackage=");
+ pw.println(user.currentForegroundedPackage);
+ pw.print(" lastBackgroundedPackage="); pw.println(user.lastBackgroundedPackage);
+ }
+ }
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 9be9f3f..b144545c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -20,6 +20,7 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.IUidObserver;
+import android.app.PendingIntent;
import android.app.usage.AppStandbyInfo;
import android.app.usage.ConfigurationStats;
import android.app.usage.IUsageStatsManager;
@@ -72,6 +73,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.TimeUnit;
/**
* A service that collects, aggregates, and persists application usage data.
@@ -117,6 +119,8 @@
AppStandbyController mAppStandby;
+ AppTimeLimitController mAppTimeLimit;
+
private UsageStatsManagerInternal.AppIdleStateChangeListener mStandbyChangeListener =
new UsageStatsManagerInternal.AppIdleStateChangeListener() {
@Override
@@ -151,6 +155,20 @@
mAppStandby = new AppStandbyController(getContext(), BackgroundThread.get().getLooper());
+ mAppTimeLimit = new AppTimeLimitController(
+ (observerId, userId, timeLimit, timeElapsed, callbackIntent) -> {
+ Intent intent = new Intent();
+ intent.putExtra(UsageStatsManager.EXTRA_OBSERVER_ID, observerId);
+ intent.putExtra(UsageStatsManager.EXTRA_TIME_LIMIT, timeLimit);
+ intent.putExtra(UsageStatsManager.EXTRA_TIME_USED, timeElapsed);
+ try {
+ callbackIntent.send(getContext(), 0, intent);
+ } catch (PendingIntent.CanceledException e) {
+ Slog.w(TAG, "Couldn't deliver callback: "
+ + callbackIntent);
+ }
+ }, mHandler.getLooper());
+
mAppStandby.addListener(mStandbyChangeListener);
File systemDataDir = new File(Environment.getDataDirectory(), "system");
mUsageStatsDir = new File(systemDataDir, "usagestats");
@@ -374,6 +392,16 @@
service.reportEvent(event);
mAppStandby.reportEvent(event, elapsedRealtime, userId);
+ switch (event.mEventType) {
+ case Event.MOVE_TO_FOREGROUND:
+ mAppTimeLimit.moveToForeground(event.getPackageName(), event.getClassName(),
+ userId);
+ break;
+ case Event.MOVE_TO_BACKGROUND:
+ mAppTimeLimit.moveToBackground(event.getPackageName(), event.getClassName(),
+ userId);
+ break;
+ }
}
}
@@ -394,6 +422,7 @@
Slog.i(TAG, "Removing user " + userId + " and all data.");
mUserState.remove(userId);
mAppStandby.onUserRemoved(userId);
+ mAppTimeLimit.onUserRemoved(userId);
cleanUpRemovedUsersLocked();
}
}
@@ -549,6 +578,8 @@
pw.println();
mAppStandby.dumpState(args, pw);
}
+
+ mAppTimeLimit.dump(pw);
}
}
@@ -927,6 +958,60 @@
mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
}
+
+ @Override
+ public void registerAppUsageObserver(int observerId,
+ String[] packages, long timeLimitMs, PendingIntent
+ callbackIntent, String callingPackage) {
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException("Caller doesn't have PACKAGE_USAGE_STATS permission");
+ }
+
+ if (packages == null || packages.length == 0) {
+ throw new IllegalArgumentException("Must specify at least one package");
+ }
+ if (timeLimitMs <= 0) {
+ throw new IllegalArgumentException("Time limit must be > 0");
+ }
+ if (callbackIntent == null) {
+ throw new NullPointerException("callbackIntent can't be null");
+ }
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ UsageStatsService.this.registerAppUsageObserver(callingUid, observerId,
+ packages, timeLimitMs, callbackIntent, userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void unregisterAppUsageObserver(int observerId, String callingPackage) {
+ if (!hasPermission(callingPackage)) {
+ throw new SecurityException("Caller doesn't have PACKAGE_USAGE_STATS permission");
+ }
+
+ final int callingUid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(callingUid);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ UsageStatsService.this.unregisterAppUsageObserver(callingUid, observerId, userId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ void registerAppUsageObserver(int callingUid, int observerId, String[] packages,
+ long timeLimitMs, PendingIntent callbackIntent, int userId) {
+ mAppTimeLimit.addObserver(callingUid, observerId, packages, timeLimitMs, callbackIntent,
+ userId);
+ }
+
+ void unregisterAppUsageObserver(int callingUid, int observerId, int userId) {
+ mAppTimeLimit.removeObserver(callingUid, observerId, userId);
}
/**
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 4f78c4c..f1653ce 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3165,8 +3165,8 @@
values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology());
values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology());
values.put(CSS_INDICATOR, state.getCssIndicator());
- values.put(NETWORK_ID, state.getNetworkId());
- values.put(SYSTEM_ID, state.getSystemId());
+ values.put(NETWORK_ID, state.getCdmaNetworkId());
+ values.put(SYSTEM_ID, state.getCdmaSystemId());
values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator());
values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator());
values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
@@ -3296,13 +3296,13 @@
public static final String CSS_INDICATOR = "css_indicator";
/**
- * This is the same as {@link ServiceState#getNetworkId()}.
+ * This is the same as {@link ServiceState#getCdmaNetworkId()}.
* @hide
*/
public static final String NETWORK_ID = "network_id";
/**
- * This is the same as {@link ServiceState#getSystemId()}.
+ * This is the same as {@link ServiceState#getCdmaSystemId()}.
* @hide
*/
public static final String SYSTEM_ID = "system_id";
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index a9c1cf6..9c831b9 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -221,7 +221,7 @@
public static final int ROAMING_TYPE_INTERNATIONAL = 3;
/**
- * Unknown ID. Could be returned by {@link #getNetworkId()} or {@link #getSystemId()}
+ * Unknown ID. Could be returned by {@link #getCdmaNetworkId()} or {@link #getCdmaSystemId()}
*/
public static final int UNKNOWN_ID = -1;
@@ -1222,7 +1222,7 @@
/** @hide */
@TestApi
- public void setSystemAndNetworkId(int systemId, int networkId) {
+ public void setCdmaSystemAndNetworkId(int systemId, int networkId) {
this.mSystemId = systemId;
this.mNetworkId = networkId;
}
@@ -1388,7 +1388,7 @@
* within a wireless system. (Defined in 3GPP2 C.S0023 3.4.8)
* @return The CDMA NID or {@link #UNKNOWN_ID} if not available.
*/
- public int getNetworkId() {
+ public int getCdmaNetworkId() {
return this.mNetworkId;
}
@@ -1397,7 +1397,7 @@
* system. (Defined in 3GPP2 C.S0023 3.4.8)
* @return The CDMA SID or {@link #UNKNOWN_ID} if not available.
*/
- public int getSystemId() {
+ public int getCdmaSystemId() {
return this.mSystemId;
}
diff --git a/tests/UsageStatsTest/AndroidManifest.xml b/tests/UsageStatsTest/AndroidManifest.xml
index c27be7b..66af454 100644
--- a/tests/UsageStatsTest/AndroidManifest.xml
+++ b/tests/UsageStatsTest/AndroidManifest.xml
@@ -21,5 +21,6 @@
</activity>
<activity android:name=".UsageLogActivity" />
+
</application>
</manifest>
diff --git a/tests/UsageStatsTest/res/menu/main.xml b/tests/UsageStatsTest/res/menu/main.xml
index 4ccbc81..612267c 100644
--- a/tests/UsageStatsTest/res/menu/main.xml
+++ b/tests/UsageStatsTest/res/menu/main.xml
@@ -4,4 +4,6 @@
android:title="View Log"/>
<item android:id="@+id/call_is_app_inactive"
android:title="Call isAppInactive()"/>
+ <item android:id="@+id/set_app_limit"
+ android:title="Set App Limit" />
</menu>
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
index 9429d9b..3d8ce21 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageStatsActivity.java
@@ -18,6 +18,7 @@
import android.app.AlertDialog;
import android.app.ListActivity;
+import android.app.PendingIntent;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
@@ -36,14 +37,17 @@
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.TextView;
+import android.widget.Toast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
public class UsageStatsActivity extends ListActivity {
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
+ private static final String EXTRA_KEY_TIMEOUT = "com.android.tests.usagestats.extra.TIMEOUT";
private UsageStatsManager mUsageStatsManager;
private Adapter mAdapter;
private Comparator<UsageStats> mComparator = new Comparator<UsageStats>() {
@@ -59,6 +63,20 @@
mUsageStatsManager = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
mAdapter = new Adapter();
setListAdapter(mAdapter);
+ Bundle extras = getIntent().getExtras();
+ if (extras != null && extras.containsKey(UsageStatsManager.EXTRA_TIME_USED)) {
+ System.err.println("UsageStatsActivity " + extras);
+ Toast.makeText(this, "Timeout of observed app\n" + extras, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ Bundle extras = intent.getExtras();
+ if (extras != null && extras.containsKey(UsageStatsManager.EXTRA_TIME_USED)) {
+ System.err.println("UsageStatsActivity " + extras);
+ Toast.makeText(this, "Timeout of observed app\n" + extras, Toast.LENGTH_SHORT).show();
+ }
}
@Override
@@ -77,7 +95,9 @@
case R.id.call_is_app_inactive:
callIsAppInactive();
return true;
-
+ case R.id.set_app_limit:
+ callSetAppLimit();
+ return true;
default:
return super.onOptionsItemSelected(item);
}
@@ -116,6 +136,40 @@
builder.show();
}
+ private void callSetAppLimit() {
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Enter package name");
+ final EditText input = new EditText(this);
+ input.setInputType(InputType.TYPE_CLASS_TEXT);
+ input.setHint("com.android.tests.usagestats");
+ builder.setView(input);
+
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final String packageName = input.getText().toString().trim();
+ if (!TextUtils.isEmpty(packageName)) {
+ String[] packages = packageName.split(",");
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setClass(UsageStatsActivity.this, UsageStatsActivity.class);
+ intent.setPackage(getPackageName());
+ intent.putExtra(EXTRA_KEY_TIMEOUT, true);
+ mUsageStatsManager.registerAppUsageObserver(1, packages,
+ 30, TimeUnit.SECONDS, PendingIntent.getActivity(UsageStatsActivity.this,
+ 1, intent, 0));
+ }
+ }
+ });
+ builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ builder.show();
+ }
+
private void showInactive(String packageName) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 6865f77..21ae3a9 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -529,91 +529,6 @@
/** @hide **/
public static int INVALID_RSSI = -127;
- /**
- * @hide
- * A summary of the RSSI and Band status for that configuration
- * This is used as a temporary value by the auto-join controller
- */
- public static final class Visibility {
- public int rssi5; // strongest 5GHz RSSI
- public int rssi24; // strongest 2.4GHz RSSI
- public int num5; // number of BSSIDs on 5GHz
- public int num24; // number of BSSIDs on 2.4GHz
- public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen)
- public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
- public String BSSID24;
- public String BSSID5;
- public int score; // Debug only, indicate last score used for autojoin/cell-handover
- public int currentNetworkBoost; // Debug only, indicate boost applied to RSSI if current
- public int bandPreferenceBoost; // Debug only, indicate boost applied to RSSI if current
- public int lastChoiceBoost; // Debug only, indicate last choice applied to this configuration
- public String lastChoiceConfig; // Debug only, indicate last choice applied to this configuration
-
- public Visibility() {
- rssi5 = INVALID_RSSI;
- rssi24 = INVALID_RSSI;
- }
-
- public Visibility(Visibility source) {
- rssi5 = source.rssi5;
- rssi24 = source.rssi24;
- age24 = source.age24;
- age5 = source.age5;
- num24 = source.num24;
- num5 = source.num5;
- BSSID5 = source.BSSID5;
- BSSID24 = source.BSSID24;
- }
-
- @Override
- public String toString() {
- StringBuilder sbuf = new StringBuilder();
- sbuf.append("[");
- if (rssi24 > INVALID_RSSI) {
- sbuf.append(Integer.toString(rssi24));
- sbuf.append(",");
- sbuf.append(Integer.toString(num24));
- if (BSSID24 != null) sbuf.append(",").append(BSSID24);
- }
- sbuf.append("; ");
- if (rssi5 > INVALID_RSSI) {
- sbuf.append(Integer.toString(rssi5));
- sbuf.append(",");
- sbuf.append(Integer.toString(num5));
- if (BSSID5 != null) sbuf.append(",").append(BSSID5);
- }
- if (score != 0) {
- sbuf.append("; ").append(score);
- sbuf.append(", ").append(currentNetworkBoost);
- sbuf.append(", ").append(bandPreferenceBoost);
- if (lastChoiceConfig != null) {
- sbuf.append(", ").append(lastChoiceBoost);
- sbuf.append(", ").append(lastChoiceConfig);
- }
- }
- sbuf.append("]");
- return sbuf.toString();
- }
- }
-
- /** @hide
- * Cache the visibility status of this configuration.
- * Visibility can change at any time depending on scan results availability.
- * Owner of the WifiConfiguration is responsible to set this field based on
- * recent scan results.
- ***/
- public Visibility visibility;
-
- /** @hide
- * calculate and set Visibility for that configuration.
- *
- * age in milliseconds: we will consider only ScanResults that are more recent,
- * i.e. younger.
- ***/
- public void setVisibility(Visibility status) {
- visibility = status;
- }
-
// States for the userApproved field
/**
* @hide
@@ -2178,9 +2093,6 @@
meteredHint = source.meteredHint;
meteredOverride = source.meteredOverride;
useExternalScores = source.useExternalScores;
- if (source.visibility != null) {
- visibility = new Visibility(source.visibility);
- }
didSelfAdd = source.didSelfAdd;
lastConnectUid = source.lastConnectUid;