Merge "Add API for checking which CA certs were installed by the DO/PO"
diff --git a/api/current.txt b/api/current.txt
index 6e054fc..c84d464 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5519,12 +5519,14 @@
public final class NotificationChannelGroup implements android.os.Parcelable {
ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+ ctor public NotificationChannelGroup(java.lang.String, int);
ctor protected NotificationChannelGroup(android.os.Parcel);
method public android.app.NotificationChannelGroup clone();
method public int describeContents();
method public java.util.List<android.app.NotificationChannel> getChannels();
method public java.lang.String getId();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
}
@@ -8451,8 +8453,10 @@
field public static final java.lang.String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
field public static final java.lang.String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
field public static final java.lang.String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
+ field public static final java.lang.String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
field public static final java.lang.String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
field public static final java.lang.String EXTRA_SIZE = "android.content.extra.SIZE";
+ field public static final java.lang.String EXTRA_TOTAL_SIZE = "android.content.extra.TOTAL_SIZE";
field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
field public static final java.lang.String QUERY_ARG_LIMIT = "android:query-page-limit";
@@ -8463,7 +8467,6 @@
field public static final java.lang.String QUERY_ARG_SQL_SELECTION = "android:query-sql-selection";
field public static final java.lang.String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-sql-selection-args";
field public static final java.lang.String QUERY_ARG_SQL_SORT_ORDER = "android:query-sql-sort-order";
- field public static final java.lang.String QUERY_RESULT_SIZE = "android:query-result-size";
field public static final int QUERY_SORT_DIRECTION_ASCENDING = 0; // 0x0
field public static final int QUERY_SORT_DIRECTION_DESCENDING = 1; // 0x1
field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
diff --git a/api/system-current.txt b/api/system-current.txt
index 0cef28e..658a56a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5712,6 +5712,7 @@
public final class NotificationChannelGroup implements android.os.Parcelable {
ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+ ctor public NotificationChannelGroup(java.lang.String, int);
ctor protected NotificationChannelGroup(android.os.Parcel);
method public void addChannel(android.app.NotificationChannel);
method public android.app.NotificationChannelGroup clone();
@@ -5719,6 +5720,7 @@
method public java.util.List<android.app.NotificationChannel> getChannels();
method public java.lang.String getId();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public org.json.JSONObject toJson() throws org.json.JSONException;
method public void writeToParcel(android.os.Parcel, int);
method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
@@ -6947,26 +6949,64 @@
public class BackupManagerMonitor {
ctor public BackupManagerMonitor();
method public void onEvent(android.os.Bundle);
+ field public static final java.lang.String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
field public static final java.lang.String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY";
field public static final java.lang.String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_NAME = "android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
+ field public static final java.lang.String EXTRA_LOG_EXCEPTION_FULL_BACKUP = "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP";
+ field public static final java.lang.String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY";
+ field public static final java.lang.String EXTRA_LOG_MANIFEST_PACKAGE_NAME = "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME";
field public static final java.lang.String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION";
+ field public static final java.lang.String EXTRA_LOG_POLICY_ALLOW_APKS = "android.app.backup.extra.LOG_POLICY_ALLOW_APKS";
+ field public static final java.lang.String EXTRA_LOG_PREFLIGHT_ERROR = "android.app.backup.extra.LOG_PREFLIGHT_ERROR";
+ field public static final java.lang.String EXTRA_LOG_RESTORE_ANYWAY = "android.app.backup.extra.LOG_RESTORE_ANYWAY";
+ field public static final java.lang.String EXTRA_LOG_RESTORE_VERSION = "android.app.backup.extra.LOG_RESTORE_VERSION";
+ field public static final java.lang.String EXTRA_LOG_WIDGET_PACKAGE_NAME = "android.app.backup.extra.LOG_WIDGET_PACKAGE_NAME";
field public static final int LOG_EVENT_CATEGORY_AGENT = 2; // 0x2
field public static final int LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY = 3; // 0x3
field public static final int LOG_EVENT_CATEGORY_TRANSPORT = 1; // 0x1
+ field public static final int LOG_EVENT_ID_APK_NOT_INSTALLED = 40; // 0x28
field public static final int LOG_EVENT_ID_APP_HAS_NO_AGENT = 28; // 0x1c
+ field public static final int LOG_EVENT_ID_BACKUP_DISABLED = 13; // 0xd
+ field public static final int LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK = 41; // 0x29
field public static final int LOG_EVENT_ID_CANT_FIND_AGENT = 30; // 0x1e
- field public static final int LOG_EVENT_ID_FULL_BACKUP_TIMEOUT = 4; // 0x4
+ field public static final int LOG_EVENT_ID_CORRUPT_MANIFEST = 46; // 0x2e
+ field public static final int LOG_EVENT_ID_DEVICE_NOT_PROVISIONED = 14; // 0xe
+ field public static final int LOG_EVENT_ID_ERROR_PREFLIGHT = 16; // 0x10
+ field public static final int LOG_EVENT_ID_EXCEPTION_FULL_BACKUP = 19; // 0x13
+ field public static final int LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE = 43; // 0x2b
+ field public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4; // 0x4
+ field public static final int LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE = 39; // 0x27
+ field public static final int LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH = 37; // 0x25
field public static final int LOG_EVENT_ID_FULL_RESTORE_TIMEOUT = 45; // 0x2d
- field public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_TIMEOUT = 21; // 0x15
+ field public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5; // 0x5
+ field public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL = 21; // 0x15
field public static final int LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT = 31; // 0x1f
+ field public static final int LOG_EVENT_ID_LOST_TRANSPORT = 25; // 0x19
+ field public static final int LOG_EVENT_ID_MISSING_SIGNATURE = 42; // 0x2a
+ field public static final int LOG_EVENT_ID_NO_DATA_TO_SEND = 7; // 0x7
field public static final int LOG_EVENT_ID_NO_PACKAGES = 49; // 0x31
+ field public static final int LOG_EVENT_ID_NO_PM_METADATA_RECEIVED = 23; // 0x17
field public static final int LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE = 22; // 0x16
+ field public static final int LOG_EVENT_ID_PACKAGE_INELIGIBLE = 9; // 0x9
+ field public static final int LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT = 10; // 0xa
field public static final int LOG_EVENT_ID_PACKAGE_NOT_FOUND = 12; // 0xc
field public static final int LOG_EVENT_ID_PACKAGE_NOT_PRESENT = 26; // 0x1a
+ field public static final int LOG_EVENT_ID_PACKAGE_STOPPED = 11; // 0xb
field public static final int LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT = 15; // 0xf
+ field public static final int LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA = 24; // 0x18
+ field public static final int LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT = 18; // 0x12
+ field public static final int LOG_EVENT_ID_RESTORE_ANY_VERSION = 34; // 0x22
+ field public static final int LOG_EVENT_ID_RESTORE_VERSION_HIGHER = 27; // 0x1b
+ field public static final int LOG_EVENT_ID_SIGNATURE_MISMATCH = 29; // 0x1d
+ field public static final int LOG_EVENT_ID_SYSTEM_APP_NO_AGENT = 38; // 0x26
+ field public static final int LOG_EVENT_ID_TRANSPORT_IS_NULL = 50; // 0x32
+ field public static final int LOG_EVENT_ID_UNKNOWN_VERSION = 44; // 0x2c
+ field public static final int LOG_EVENT_ID_VERSIONS_MATCH = 35; // 0x23
field public static final int LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER = 36; // 0x24
+ field public static final int LOG_EVENT_ID_WIDGET_METADATA_MISMATCH = 47; // 0x2f
+ field public static final int LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION = 48; // 0x30
}
public abstract class BackupObserver {
@@ -8903,8 +8943,10 @@
field public static final java.lang.String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
field public static final java.lang.String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
field public static final java.lang.String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
+ field public static final java.lang.String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
field public static final java.lang.String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
field public static final java.lang.String EXTRA_SIZE = "android.content.extra.SIZE";
+ field public static final java.lang.String EXTRA_TOTAL_SIZE = "android.content.extra.TOTAL_SIZE";
field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
field public static final java.lang.String QUERY_ARG_LIMIT = "android:query-page-limit";
@@ -8915,7 +8957,6 @@
field public static final java.lang.String QUERY_ARG_SQL_SELECTION = "android:query-sql-selection";
field public static final java.lang.String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-sql-selection-args";
field public static final java.lang.String QUERY_ARG_SQL_SORT_ORDER = "android:query-sql-sort-order";
- field public static final java.lang.String QUERY_RESULT_SIZE = "android:query-result-size";
field public static final int QUERY_SORT_DIRECTION_ASCENDING = 0; // 0x0
field public static final int QUERY_SORT_DIRECTION_DESCENDING = 1; // 0x1
field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
diff --git a/api/test-current.txt b/api/test-current.txt
index 5721b3d..e496a96 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5529,12 +5529,14 @@
public final class NotificationChannelGroup implements android.os.Parcelable {
ctor public NotificationChannelGroup(java.lang.String, java.lang.CharSequence);
+ ctor public NotificationChannelGroup(java.lang.String, int);
ctor protected NotificationChannelGroup(android.os.Parcel);
method public android.app.NotificationChannelGroup clone();
method public int describeContents();
method public java.util.List<android.app.NotificationChannel> getChannels();
method public java.lang.String getId();
method public java.lang.CharSequence getName();
+ method public int getNameResId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
}
@@ -8479,8 +8481,10 @@
field public static final java.lang.String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
field public static final java.lang.String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
field public static final java.lang.String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
+ field public static final java.lang.String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
field public static final java.lang.String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
field public static final java.lang.String EXTRA_SIZE = "android.content.extra.SIZE";
+ field public static final java.lang.String EXTRA_TOTAL_SIZE = "android.content.extra.TOTAL_SIZE";
field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
field public static final java.lang.String QUERY_ARG_LIMIT = "android:query-page-limit";
@@ -8491,7 +8495,6 @@
field public static final java.lang.String QUERY_ARG_SQL_SELECTION = "android:query-sql-selection";
field public static final java.lang.String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-sql-selection-args";
field public static final java.lang.String QUERY_ARG_SQL_SORT_ORDER = "android:query-sql-sort-order";
- field public static final java.lang.String QUERY_RESULT_SIZE = "android:query-result-size";
field public static final int QUERY_SORT_DIRECTION_ASCENDING = 0; // 0x0
field public static final int QUERY_SORT_DIRECTION_DESCENDING = 1; // 0x1
field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 8538330..dad2061 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -522,6 +522,7 @@
void startLocalVoiceInteraction(in IBinder token, in Bundle options);
void stopLocalVoiceInteraction(in IBinder token);
boolean supportsLocalVoiceInteraction();
+ void notifyPinnedStackAnimationStarted();
void notifyPinnedStackAnimationEnded();
void removeStack(int stackId);
void makePackageIdle(String packageName, int userId);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 9834350..d8d4bb9 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -38,6 +38,11 @@
void onPinnedActivityRestartAttempt(String launchedFromPackage);
/**
+ * Called whenever the pinned stack is starting animating a resize.
+ */
+ void onPinnedStackAnimationStarted();
+
+ /**
* Called whenever the pinned stack is done animating a resize.
*/
void onPinnedStackAnimationEnded();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 34a45dd..3fc459e 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4177,7 +4177,7 @@
}
RemoteViews header = makeNotificationHeader();
-
+ header.setBoolean(R.id.notification_header, "setAcceptAllTouches", true);
if (summary != null) {
mN.extras.putCharSequence(EXTRA_SUB_TEXT, summary);
} else {
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 8854adc..288d39a 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -15,6 +15,7 @@
*/
package android.app;
+import android.annotation.StringRes;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Parcel;
@@ -40,23 +41,38 @@
private static final String TAG_GROUP = "channelGroup";
private static final String ATT_NAME = "name";
+ private static final String ATT_NAME_RES_ID = "name_res_id";
private static final String ATT_ID = "id";
private final String mId;
private CharSequence mName;
+ private int mNameResId = 0;
private List<NotificationChannel> mChannels = new ArrayList<>();
/**
* Creates a notification channel.
*
* @param id The id of the group. Must be unique per package.
- * @param name The user visible name of the group.
+ * @param name The user visible name of the group. Unchangeable once created; use this
+ * constructor if the group represents something user-defined that does not
+ * need to be translated.
*/
public NotificationChannelGroup(String id, CharSequence name) {
this.mId = id;
this.mName = name;
}
+ /**
+ * Creates a notification channel.
+ *
+ * @param id The id of the group. Must be unique per package.
+ * @param nameResId String resource id of the user visible name of the group.
+ */
+ public NotificationChannelGroup(String id, @StringRes int nameResId) {
+ this.mId = id;
+ this.mNameResId = nameResId;
+ }
+
protected NotificationChannelGroup(Parcel in) {
if (in.readByte() != 0) {
mId = in.readString();
@@ -64,6 +80,7 @@
mId = null;
}
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mNameResId = in.readInt();
in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
}
@@ -76,6 +93,7 @@
dest.writeByte((byte) 0);
}
TextUtils.writeToParcel(mName, dest, flags);
+ dest.writeInt(mNameResId);
dest.writeParcelableList(mChannels, flags);
}
@@ -93,6 +111,13 @@
return mName;
}
+ /**
+ * Returns the resource id of the user visible name of this group.
+ */
+ public @StringRes int getNameResId() {
+ return mNameResId;
+ }
+
/*
* Returns the list of channels that belong to this group
*
@@ -119,7 +144,12 @@
out.startTag(null, TAG_GROUP);
out.attribute(null, ATT_ID, getId());
- out.attribute(null, ATT_NAME, getName().toString());
+ if (getName() != null) {
+ out.attribute(null, ATT_NAME, getName().toString());
+ }
+ if (getNameResId() != 0) {
+ out.attribute(null, ATT_NAME_RES_ID, Integer.toString(getNameResId()));
+ }
out.endTag(null, TAG_GROUP);
}
@@ -132,6 +162,7 @@
JSONObject record = new JSONObject();
record.put(ATT_ID, getId());
record.put(ATT_NAME, getName());
+ record.put(ATT_NAME_RES_ID, getNameResId());
return record;
}
@@ -160,6 +191,7 @@
NotificationChannelGroup that = (NotificationChannelGroup) o;
+ if (getNameResId() != that.getNameResId()) return false;
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
@@ -171,13 +203,18 @@
@Override
public NotificationChannelGroup clone() {
- return new NotificationChannelGroup(getId(), getName());
+ if (getName() != null) {
+ return new NotificationChannelGroup(getId(), getName());
+ } else {
+ return new NotificationChannelGroup(getId(), getNameResId());
+ }
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + getNameResId();
result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0);
return result;
}
@@ -187,6 +224,8 @@
return "NotificationChannelGroup{" +
"mId='" + mId + '\'' +
", mName=" + mName +
+ ", mNameResId=" + mNameResId +
+ ", mChannels=" + mChannels +
'}';
}
}
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 5a0845f..7a569fc 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -39,6 +39,10 @@
}
@Override
+ public void onPinnedStackAnimationStarted() throws RemoteException {
+ }
+
+ @Override
public void onPinnedStackAnimationEnded() throws RemoteException {
}
diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java
index d2a623e..ebad16e 100644
--- a/core/java/android/app/backup/BackupManagerMonitor.java
+++ b/core/java/android/app/backup/BackupManagerMonitor.java
@@ -54,26 +54,118 @@
public static final String EXTRA_LOG_EVENT_CATEGORY =
"android.app.backup.extra.LOG_EVENT_CATEGORY";
+
/**
- * string: when we have event of id LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER we send the version
+ * boolean: when we have an event with id LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL we record if
+ * the call was to cancel backup of all packages
+ */
+ public static final String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
+
+ /**
+ * string: when we have an event with id LOG_EVENT_ID_ILLEGAL_KEY we send the key that was used
+ * by the app
+ */
+ public static final String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY";
+
+ /**
+ * long: when we have an event with id LOG_EVENT_ID_ERROR_PREFLIGHT we send the error code that
+ * was returned by the transport during preflight
+ */
+ public static final String EXTRA_LOG_PREFLIGHT_ERROR =
+ "android.app.backup.extra.LOG_PREFLIGHT_ERROR";
+
+ /**
+ * string: when we have an event with id LOG_EVENT_ID_EXCEPTION_FULL_BACKUP we send the
+ * exception's stacktrace
+ */
+ public static final String EXTRA_LOG_EXCEPTION_FULL_BACKUP =
+ "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP";
+
+ /**
+ * int: when we have an event with id LOG_EVENT_ID_RESTORE_VERSION_HIGHER we send the
+ * restore package version
+ */
+ public static final String EXTRA_LOG_RESTORE_VERSION =
+ "android.app.backup.extra.LOG_RESTORE_VERSION";
+
+ /**
+ * boolean: when we have an event with id LOG_EVENT_ID_RESTORE_VERSION_HIGHER we record if
+ * ApplicationInfo.FLAG_RESTORE_ANY_VERSION flag is set
+ */
+ public static final String EXTRA_LOG_RESTORE_ANYWAY =
+ "android.app.backup.extra.LOG_RESTORE_ANYWAY";
+
+
+ /**
+ * boolean: when we have an event with id LOG_EVENT_ID_APK_NOT_INSTALLED we record if
+ * the policy allows to install apks provided with the dataset
+ */
+ public static final String EXTRA_LOG_POLICY_ALLOW_APKS =
+ "android.app.backup.extra.LOG_POLICY_ALLOW_APKS";
+
+
+ /**
+ * string: when we have an event with id LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE we record the
+ * package name provided in the restore manifest
+ */
+ public static final String EXTRA_LOG_MANIFEST_PACKAGE_NAME =
+ "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME";
+
+ /**
+ * string: when we have an event with id LOG_EVENT_ID_WIDGET_METADATA_MISMATCH we record the
+ * package name provided in the widget metadata
+ */
+ public static final String EXTRA_LOG_WIDGET_PACKAGE_NAME =
+ "android.app.backup.extra.LOG_WIDGET_PACKAGE_NAME";
+
+ /**
+ * int: when we have event of id LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER we send the version
* of the backup.
*/
- public static final String EXTRA_LOG_OLD_VERSION =
- "android.app.backup.extra.LOG_OLD_VERSION";
+ public static final String EXTRA_LOG_OLD_VERSION = "android.app.backup.extra.LOG_OLD_VERSION";
// TODO complete this list with all log messages. And document properly.
- public static final int LOG_EVENT_ID_FULL_BACKUP_TIMEOUT = 4;
+ public static final int LOG_EVENT_ID_FULL_BACKUP_CANCEL = 4;
+ public static final int LOG_EVENT_ID_ILLEGAL_KEY = 5;
+ public static final int LOG_EVENT_ID_NO_DATA_TO_SEND = 7;
+ public static final int LOG_EVENT_ID_PACKAGE_INELIGIBLE = 9;
+ public static final int LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT = 10;
+ public static final int LOG_EVENT_ID_PACKAGE_STOPPED = 11;
public static final int LOG_EVENT_ID_PACKAGE_NOT_FOUND = 12;
+ public static final int LOG_EVENT_ID_BACKUP_DISABLED = 13;
+ public static final int LOG_EVENT_ID_DEVICE_NOT_PROVISIONED = 14;
public static final int LOG_EVENT_ID_PACKAGE_TRANSPORT_NOT_PRESENT = 15;
- public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_TIMEOUT = 21;
+ public static final int LOG_EVENT_ID_ERROR_PREFLIGHT = 16;
+ public static final int LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT = 18;
+ public static final int LOG_EVENT_ID_EXCEPTION_FULL_BACKUP = 19;
+ public static final int LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL = 21;
public static final int LOG_EVENT_ID_NO_RESTORE_METADATA_AVAILABLE = 22;
+ public static final int LOG_EVENT_ID_NO_PM_METADATA_RECEIVED = 23;
+ public static final int LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA = 24;
+ public static final int LOG_EVENT_ID_LOST_TRANSPORT = 25;
public static final int LOG_EVENT_ID_PACKAGE_NOT_PRESENT = 26;
+ public static final int LOG_EVENT_ID_RESTORE_VERSION_HIGHER = 27;
public static final int LOG_EVENT_ID_APP_HAS_NO_AGENT = 28;
+ public static final int LOG_EVENT_ID_SIGNATURE_MISMATCH = 29;
public static final int LOG_EVENT_ID_CANT_FIND_AGENT = 30;
public static final int LOG_EVENT_ID_KEY_VALUE_RESTORE_TIMEOUT = 31;
+ public static final int LOG_EVENT_ID_RESTORE_ANY_VERSION = 34;
+ public static final int LOG_EVENT_ID_VERSIONS_MATCH = 35;
public static final int LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER = 36;
+ public static final int LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH = 37;
+ public static final int LOG_EVENT_ID_SYSTEM_APP_NO_AGENT = 38;
+ public static final int LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE = 39;
+ public static final int LOG_EVENT_ID_APK_NOT_INSTALLED = 40;
+ public static final int LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK = 41;
+ public static final int LOG_EVENT_ID_MISSING_SIGNATURE = 42;
+ public static final int LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE = 43;
+ public static final int LOG_EVENT_ID_UNKNOWN_VERSION = 44;
public static final int LOG_EVENT_ID_FULL_RESTORE_TIMEOUT = 45;
+ public static final int LOG_EVENT_ID_CORRUPT_MANIFEST = 46;
+ public static final int LOG_EVENT_ID_WIDGET_METADATA_MISMATCH = 47;
+ public static final int LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION = 48;
public static final int LOG_EVENT_ID_NO_PACKAGES = 49;
+ public static final int LOG_EVENT_ID_TRANSPORT_IS_NULL = 50;
diff --git a/core/java/android/app/usage/CacheQuotaHint.java b/core/java/android/app/usage/CacheQuotaHint.java
index 4b6f99b..1d5c2b0 100644
--- a/core/java/android/app/usage/CacheQuotaHint.java
+++ b/core/java/android/app/usage/CacheQuotaHint.java
@@ -24,8 +24,10 @@
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
- * CacheQuotaRequest represents a triplet of a uid, the volume UUID it is stored upon, and
+ * CacheQuotaHint represents a triplet of a uid, the volume UUID it is stored upon, and
* its usage stats. When processed, it obtains a cache quota as defined by the system which
* allows apps to understand how much cache to use.
* {@hide}
@@ -78,6 +80,23 @@
return 0;
}
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof CacheQuotaHint) {
+ final CacheQuotaHint other = (CacheQuotaHint) o;
+ return Objects.equals(mUuid, other.mUuid)
+ && Objects.equals(mUsageStats, other.mUsageStats)
+ && mUid == other.mUid && mQuota == other.mQuota;
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(this.mUuid, this.mUid, this.mUsageStats, this.mQuota);
+ }
+
public static final class Builder {
private String mUuid;
private int mUid;
@@ -100,7 +119,7 @@
}
public @NonNull Builder setUid(int uid) {
- Preconditions.checkArgumentPositive(uid, "Proposed uid was not positive.");
+ Preconditions.checkArgumentNonnegative(uid, "Proposed uid was negative.");
mUid = uid;
return this;
}
@@ -117,7 +136,6 @@
}
public @NonNull CacheQuotaHint build() {
- Preconditions.checkNotNull(mUsageStats);
return new CacheQuotaHint(this);
}
}
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
index 4252482..7d8459c 100644
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ b/core/java/android/bluetooth/BluetoothMapClient.java
@@ -50,6 +50,12 @@
public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
"android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
+ /* Extras used in ACTION_MESSAGE_RECEIVED intent */
+ public static final String EXTRA_SENDER_CONTACT_URI =
+ "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_URI";
+ public static final String EXTRA_SENDER_CONTACT_NAME =
+ "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
+
private IBluetoothMapClient mService;
private final Context mContext;
private ServiceListener mServiceListener;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9958a79..5579c9a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -307,6 +307,18 @@
*/
public static final String QUERY_ARG_SORT_COLLATION = "android:query-sort-collation";
+ /**
+ * Allows provider to report back to client which keys were honored.
+ *
+ * Key identifying a {@code String[]} containing all QUERY_ARG_SORT* arguments
+ * honored by the provider. Include this in {@link Cursor} extras {@link Bundle}
+ * when any QUERY_ARG_SORT* value was honored during the preparation of the
+ * results {@link Cursor}.
+ *
+ * @see #QUERY_ARG_SORT_COLUMNS, #QUERY_ARG_SORT_DIRECTION, #QUERY_ARG_SORT_COLLATION.
+ */
+ public static final String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
+
/** @hide */
@IntDef(flag = false, value = {
QUERY_SORT_DIRECTION_ASCENDING,
@@ -354,8 +366,9 @@
public static final String QUERY_ARG_LIMIT = "android:query-page-limit";
/**
- * Added to {@link Cursor} extras {@link Bundle} to indicate size of the
- * full, un-offset, un-limited recordset.
+ * Added to {@link Cursor} extras {@link Bundle} to indicate total size of
+ * recordset when paging is active. Providers must include this when
+ * implementing paging support.
*
* <p>When full size of the recordset is unknown a provider may return -1
* to indicate this.
@@ -364,7 +377,7 @@
* send content change notification once (if) full recordset size becomes
* known.
*/
- public static final String QUERY_RESULT_SIZE = "android:query-result-size";
+ public static final String EXTRA_TOTAL_SIZE = "android.content.extra.TOTAL_SIZE";
/**
* This is the Android platform's base MIME type for a content: URI
@@ -704,6 +717,13 @@
* <li>Provide an explicit projection, to prevent reading data from storage
* that aren't going to be used.
*
+ * Provider must identify which QUERY_ARG_SORT* arguments were honored during
+ * the preparation of the result set by including the respective argument keys
+ * in the {@link Cursor} extras {@link Bundle}. See {@link #EXTRA_HONORED_ARGS}
+ * for details.
+ *
+ * @see #QUERY_ARG_SORT_COLUMNS, #QUERY_ARG_SORT_DIRECTION, #QUERY_ARG_SORT_COLLATION.
+ *
* @param uri The URI, using the content:// scheme, for the content to
* retrieve.
* @param projection A list of which columns to return. Passing null will
@@ -3037,17 +3057,19 @@
query += " COLLATE NOCASE";
}
- switch (queryArgs.getInt(
- QUERY_ARG_SORT_DIRECTION, Integer.MIN_VALUE)) {
- case QUERY_SORT_DIRECTION_ASCENDING:
- query += " ASC";
- break;
- case QUERY_SORT_DIRECTION_DESCENDING:
- query += " DESC";
- break;
- default:
- throw new IllegalArgumentException("Unsupported sort direction value."
- + " See ContentResolver documentation for details.");
+ int sortDir = queryArgs.getInt(QUERY_ARG_SORT_DIRECTION, Integer.MIN_VALUE);
+ if (sortDir != Integer.MIN_VALUE) {
+ switch (sortDir) {
+ case QUERY_SORT_DIRECTION_ASCENDING:
+ query += " ASC";
+ break;
+ case QUERY_SORT_DIRECTION_DESCENDING:
+ query += " DESC";
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported sort direction value."
+ + " See ContentResolver documentation for details.");
+ }
}
return query;
}
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 71a0349..33b5903 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -119,6 +119,9 @@
* <p>Location should specify a document URI or a tree URI with document ID. If
* this URI identifies a non-directory, document navigator will attempt to use the parent
* of the document as the initial location.
+ *
+ * <p>The initial location is system specific if this extra is missing or document navigator
+ * failed to locate the desired initial location.
*/
public static final String EXTRA_INITIAL_URI = "android.provider.extra.INITIAL_URI";
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index c3d3f39..16d4666 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -94,6 +94,7 @@
}
}
};
+ private boolean mAcceptAllTouches;
public NotificationHeaderView(Context context) {
this(context, null);
@@ -374,6 +375,8 @@
case MotionEvent.ACTION_DOWN:
mTrackGesture = false;
if (isInside(x, y)) {
+ mDownX = x;
+ mDownY = y;
mTrackGesture = true;
return true;
}
@@ -396,11 +399,12 @@
}
private boolean isInside(float x, float y) {
+ if (mAcceptAllTouches) {
+ return true;
+ }
for (int i = 0; i < mTouchRects.size(); i++) {
Rect r = mTouchRects.get(i);
if (r.contains((int) x, (int) y)) {
- mDownX = x;
- mDownY = y;
return true;
}
}
@@ -433,4 +437,9 @@
}
return mTouchListener.isInside(x, y);
}
+
+ @RemotableViewMethod
+ public void setAcceptAllTouches(boolean acceptAllTouches) {
+ mAcceptAllTouches = acceptAllTouches;
+ }
}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 3ede2ee..1b1f28c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -139,16 +139,27 @@
ANativeActivity_setWindowFlags;
ANativeActivity_setWindowFormat;
ANativeActivity_showSoftInput;
- ANativeWindow_acquire; # removed=26
- ANativeWindow_fromSurface; # removed=26
- ANativeWindow_fromSurfaceTexture; # removed=26
- ANativeWindow_getFormat; # removed=26
- ANativeWindow_getHeight; # removed=26
- ANativeWindow_getWidth; # removed=26
- ANativeWindow_lock; # removed=26
- ANativeWindow_release; # removed=26
- ANativeWindow_setBuffersGeometry; # removed=26
- ANativeWindow_unlockAndPost; # removed=26
+ AHardwareBuffer_acquire; # introduced=26
+ AHardwareBuffer_allocate; # introduced=26
+ AHardwareBuffer_describe; # introduced=26
+ AHardwareBuffer_fromHardwareBuffer; # introduced=26
+ AHardwareBuffer_getNativeHandle; # introduced=26
+ AHardwareBuffer_lock; # introduced=26
+ AHardwareBuffer_recvHandleFromUnixSocket; # introduced=26
+ AHardwareBuffer_release; # introduced=26
+ AHardwareBuffer_sendHandleToUnixSocket; # introduced=26
+ AHardwareBuffer_toHardwareBuffer; # introduced=26
+ AHardwareBuffer_unlock; # introduced=26
+ ANativeWindow_acquire;
+ ANativeWindow_fromSurface;
+ ANativeWindow_fromSurfaceTexture; # introduced-arm=13 introduced-mips=13 introduced-x86=13
+ ANativeWindow_getFormat;
+ ANativeWindow_getHeight;
+ ANativeWindow_getWidth;
+ ANativeWindow_lock;
+ ANativeWindow_release;
+ ANativeWindow_setBuffersGeometry;
+ ANativeWindow_unlockAndPost;
AObbInfo_delete;
AObbInfo_getFlags;
AObbInfo_getPackageName;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
new file mode 100644
index 0000000..ec8e956
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/PermissionsSummaryHelper.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.settingslib.applications;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.permission.RuntimePermissionPresentationInfo;
+import android.content.pm.permission.RuntimePermissionPresenter;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class PermissionsSummaryHelper {
+
+ public static void getPermissionSummary(Context context, String pkg,
+ final PermissionsResultCallback callback) {
+ final RuntimePermissionPresenter presenter =
+ RuntimePermissionPresenter.getInstance(context);
+ presenter.getAppPermissions(pkg, new RuntimePermissionPresenter.OnResultCallback() {
+ @Override
+ public void onGetAppPermissions(
+ @NonNull List<RuntimePermissionPresentationInfo> permissions) {
+ final int permissionCount = permissions.size();
+
+ int grantedStandardCount = 0;
+ int grantedAdditionalCount = 0;
+ int requestedCount = 0;
+ List<CharSequence> grantedStandardLabels = new ArrayList<>();
+
+ for (int i = 0; i < permissionCount; i++) {
+ RuntimePermissionPresentationInfo permission = permissions.get(i);
+ requestedCount++;
+ if (permission.isGranted()) {
+ if (permission.isStandard()) {
+ grantedStandardLabels.add(permission.getLabel());
+ grantedStandardCount++;
+ } else {
+ grantedAdditionalCount++;
+ }
+ }
+ }
+
+ Collator collator = Collator.getInstance();
+ collator.setStrength(Collator.PRIMARY);
+ Collections.sort(grantedStandardLabels, collator);
+
+ callback.onPermissionSummaryResult(grantedStandardCount, requestedCount,
+ grantedAdditionalCount, grantedStandardLabels);
+ }
+ }, null);
+ }
+
+ public static abstract class PermissionsResultCallback {
+ public void onAppWithPermissionsCountsResult(int standardGrantedPermissionAppCount,
+ int standardUsedPermissionAppCount) {
+ /* do nothing - stub */
+ }
+
+ public void onPermissionSummaryResult(int standardGrantedPermissionCount,
+ int requestedPermissionCount, int additionalGrantedPermissionCount,
+ List<CharSequence> grantedGroupLabels) {
+ /* do nothing - stub */
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemBars.java b/packages/SystemUI/src/com/android/systemui/SystemBars.java
index 6623cabe..b5093b3 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemBars.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemBars.java
@@ -43,13 +43,6 @@
}
@Override
- protected void onConfigurationChanged(Configuration newConfig) {
- if (mStatusBar != null) {
- mStatusBar.onConfigurationChanged(newConfig);
- }
- }
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mStatusBar != null) {
mStatusBar.dump(fd, pw, args);
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 ae402ef..e7256d1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -71,8 +71,15 @@
}
@Override
+ public void onPinnedStackAnimationStarted() {
+ // Disable touches while the animation is running
+ mTouchHandler.setTouchEnabled(false);
+ }
+
+ @Override
public void onPinnedStackAnimationEnded() {
- // TODO(winsonc): Disable touch interaction with the PiP until the animation ends
+ // Re-enable touches after the animation completes
+ mTouchHandler.setTouchEnabled(true);
}
@Override
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 d832810..4100b66 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -181,6 +181,10 @@
registerInputConsumer();
}
+ public void setTouchEnabled(boolean enabled) {
+ mTouchState.setAllowTouches(enabled);
+ }
+
public void onActivityPinned() {
// Reset some states once we are pinned
if (mIsTappingThrough) {
@@ -294,6 +298,7 @@
// Fall through to clean up
}
case MotionEvent.ACTION_CANCEL: {
+ mTouchState.reset();
break;
}
}
@@ -418,6 +423,10 @@
@Override
public void onDown(PipTouchState touchState) {
+ if (!touchState.isUserInteracting()) {
+ return;
+ }
+
if (ENABLE_DRAG_TO_DISMISS) {
mDismissViewController.createDismissTarget();
mHandler.postDelayed(mShowDismissAffordance, SHOW_DISMISS_AFFORDANCE_DELAY);
@@ -426,6 +435,10 @@
@Override
boolean onMove(PipTouchState touchState) {
+ if (!touchState.isUserInteracting()) {
+ return false;
+ }
+
if (touchState.startedDragging()) {
mSavedSnapFraction = -1f;
}
@@ -458,6 +471,10 @@
@Override
public boolean onUp(PipTouchState touchState) {
+ if (!touchState.isUserInteracting()) {
+ return false;
+ }
+
try {
if (ENABLE_DRAG_TO_DISMISS) {
mHandler.removeCallbacks(mShowDismissAffordance);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
index 702ad0a..a317dc3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchState.java
@@ -37,6 +37,7 @@
private final PointF mLastTouch = new PointF();
private final PointF mLastDelta = new PointF();
private final PointF mVelocity = new PointF();
+ private boolean mAllowTouches = true;
private boolean mIsUserInteracting = false;
private boolean mIsDragging = false;
private boolean mStartedDragging = false;
@@ -48,23 +49,41 @@
}
/**
+ * Resets this state.
+ */
+ public void reset() {
+ mAllowDraggingOffscreen = false;
+ mIsDragging = false;
+ mStartedDragging = false;
+ mIsUserInteracting = false;
+ }
+
+ /**
* Processess a given touch event and updates the state.
*/
public void onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
+ if (!mAllowTouches) {
+ return;
+ }
+
// Initialize the velocity tracker
initOrResetVelocityTracker();
+
mActivePointerId = ev.getPointerId(0);
mLastTouch.set(ev.getX(), ev.getY());
mDownTouch.set(mLastTouch);
- mIsDragging = false;
- mStartedDragging = false;
mAllowDraggingOffscreen = true;
mIsUserInteracting = true;
break;
}
case MotionEvent.ACTION_MOVE: {
+ // Skip event if we did not start processing this touch gesture
+ if (!mIsUserInteracting) {
+ break;
+ }
+
// Update the velocity tracker
mVelocityTracker.addMovement(ev);
int pointerIndex = ev.findPointerIndex(mActivePointerId);
@@ -86,6 +105,11 @@
break;
}
case MotionEvent.ACTION_POINTER_UP: {
+ // Skip event if we did not start processing this touch gesture
+ if (!mIsUserInteracting) {
+ break;
+ }
+
// Update the velocity tracker
mVelocityTracker.addMovement(ev);
@@ -100,6 +124,11 @@
break;
}
case MotionEvent.ACTION_UP: {
+ // Skip event if we did not start processing this touch gesture
+ if (!mIsUserInteracting) {
+ break;
+ }
+
// Update the velocity tracker
mVelocityTracker.addMovement(ev);
mVelocityTracker.computeCurrentVelocity(1000,
@@ -112,7 +141,6 @@
// Fall through to clean up
}
case MotionEvent.ACTION_CANCEL: {
- mIsUserInteracting = false;
recycleVelocityTracker();
break;
}
@@ -171,6 +199,19 @@
}
/**
+ * Sets whether touching is currently allowed.
+ */
+ public void setAllowTouches(boolean allowTouches) {
+ mAllowTouches = allowTouches;
+
+ // If the user happens to touch down before this is sent from the system during a transition
+ // then block any additional handling by resetting the state now
+ if (mIsUserInteracting) {
+ reset();
+ }
+ }
+
+ /**
* Disallows dragging offscreen for the duration of the current gesture.
*/
public void setDisallowDraggingOffscreen() {
@@ -202,6 +243,7 @@
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mAllowTouches=" + mAllowTouches);
pw.println(innerPrefix + "mDownTouch=" + mDownTouch);
pw.println(innerPrefix + "mDownDelta=" + mDownDelta);
pw.println(innerPrefix + "mLastTouch=" + mLastTouch);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 428fe9b..7d13f76 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -84,7 +84,6 @@
mLabel = (TextView) mLabelContainer.findViewById(R.id.tile_label);
mPadLock = (ImageView) mLabelContainer.findViewById(R.id.restricted_padlock);
- mLabelContainer.setBackground(newTileBackground());
addView(mLabelContainer);
}
@@ -102,6 +101,11 @@
mLabel.setText(state.label);
}
mDivider.setVisibility(state.dualTarget ? View.VISIBLE : View.INVISIBLE);
+ if (state.dualTarget != mLabelContainer.isClickable()) {
+ mLabelContainer.setClickable(state.dualTarget);
+ mLabelContainer.setLongClickable(state.dualTarget);
+ mLabelContainer.setBackground(state.dualTarget ? newTileBackground() : null);
+ }
mLabel.setEnabled(!state.disabledByPolicy);
mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
}
@@ -110,7 +114,9 @@
public void init(OnClickListener click, OnClickListener secondaryClick,
OnLongClickListener longClick) {
super.init(click, secondaryClick, longClick);
- mLabelContainer.setClickable(true);
mLabelContainer.setOnClickListener(secondaryClick);
+ mLabelContainer.setOnLongClickListener(longClick);
+ mLabelContainer.setClickable(false);
+ mLabelContainer.setLongClickable(false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index b28b0e7..a76299d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -288,7 +288,7 @@
drawable = mTile.getIcon().loadDrawable(mContext);
} catch (Exception e) {
Log.w(TAG, "Invalid icon, forcing into unavailable state");
- tileState = Tile.STATE_UNAVAILABLE;
+ state.state = Tile.STATE_UNAVAILABLE;
drawable = mDefaultIcon.loadDrawable(mContext);
}
state.icon = new DrawableIcon(drawable);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index cda902b..1042356 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -154,6 +154,7 @@
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
public void onActivityPinned() { }
public void onPinnedActivityRestartAttempt(String launchedFromPackage) { }
+ public void onPinnedStackAnimationStarted() { }
public void onPinnedStackAnimationEnded() { }
public void onActivityForcedResizable(String packageName, int taskId) { }
public void onActivityDismissingDockedStack() { }
@@ -206,6 +207,12 @@
}
@Override
+ public void onPinnedStackAnimationStarted() throws RemoteException {
+ mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_STARTED);
+ mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_STARTED);
+ }
+
+ @Override
public void onPinnedStackAnimationEnded() throws RemoteException {
mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED);
mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED);
@@ -1219,6 +1226,7 @@
private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
private static final int ON_TASK_PROFILE_LOCKED = 8;
+ private static final int ON_PINNED_STACK_ANIMATION_STARTED = 9;
@Override
public void handleMessage(Message msg) {
@@ -1248,6 +1256,12 @@
}
break;
}
+ case ON_PINNED_STACK_ANIMATION_STARTED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onPinnedStackAnimationStarted();
+ }
+ break;
+ }
case ON_PINNED_STACK_ANIMATION_ENDED: {
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 807d902..af464c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -154,7 +154,12 @@
iNotificationManager.getNotificationChannelGroupForPackage(
channel.getGroup(), pkg, appUid);
if (notificationChannelGroup != null) {
- groupName = notificationChannelGroup.getName();
+ if (info != null && notificationChannelGroup.getNameResId() != 0) {
+ groupName = pm.getText(pkg, notificationChannelGroup.getNameResId(), info);
+ }
+ if (notificationChannelGroup.getName() != null) {
+ groupName = notificationChannelGroup.getName();
+ }
}
} catch (RemoteException e) {
Log.e(TAG, e.toString());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 36ed551..8da17fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -41,7 +41,8 @@
* A notification shelf view that is placed inside the notification scroller. It manages the
* overflow icons that don't fit into the regular list anymore.
*/
-public class NotificationShelf extends ActivatableNotificationView {
+public class NotificationShelf extends ActivatableNotificationView implements
+ View.OnLayoutChangeListener {
public static final boolean SHOW_AMBIENT_ICONS = true;
private static final boolean USE_ANIMATIONS_WHEN_OPENING =
@@ -494,6 +495,10 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
+ updateRelativeOffset();
+ }
+
+ private void updateRelativeOffset() {
mCollapsedIcons.getLocationOnScreen(mTmp);
mRelativeOffset = mTmp[0];
getLocationOnScreen(mTmp);
@@ -560,6 +565,7 @@
public void setCollapsedIcons(NotificationIconContainer collapsedIcons) {
mCollapsedIcons = collapsedIcons;
+ mCollapsedIcons.addOnLayoutChangeListener(this);
}
public void setStatusBarState(int statusBarState) {
@@ -595,6 +601,12 @@
}
}
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ updateRelativeOffset();
+ }
+
private class ShelfState extends ExpandableViewState {
private float openedAmount;
private boolean hasItemsInStableShelf;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index aec9a4b..1101701 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -612,8 +612,10 @@
}
public void setIconAppearAmount(float iconAppearAmount) {
- mIconAppearAmount = iconAppearAmount;
- invalidate();
+ if (mIconAppearAmount != iconAppearAmount) {
+ mIconAppearAmount = iconAppearAmount;
+ invalidate();
+ }
}
public float getIconAppearAmount() {
@@ -625,8 +627,10 @@
}
public void setDotAppearAmount(float dotAppearAmount) {
- mDotAppearAmount = dotAppearAmount;
- invalidate();
+ if (mDotAppearAmount != dotAppearAmount) {
+ mDotAppearAmount = dotAppearAmount;
+ invalidate();
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 1f56c56..6cd3eae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -153,7 +153,7 @@
}
private boolean shouldHideNotificationIcons() {
- return !mStatusBar.isClosed() && mStatusBarComponent.shouldHideNotificationIcons();
+ return !mStatusBar.isClosed() && mStatusBarComponent.hideStatusBarIconsWhenExpanded();
}
public void hideSystemIconArea(boolean animate) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 707997d..4581204 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -79,7 +79,9 @@
for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
View child = mNotificationIcons.getChildAt(i);
child.setLayoutParams(params);
- child = mShelfIcons.getChildAt(i);
+ }
+ for (int i = 0; i < mShelfIcons.getChildCount(); i++) {
+ View child = mShelfIcons.getChildAt(i);
child.setLayoutParams(params);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 468fb57..e6d3168 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -26,7 +26,6 @@
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
@@ -47,7 +46,6 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.DejankUtils;
-import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -179,7 +177,7 @@
private boolean mKeyguardStatusViewAnimating;
private ValueAnimator mQsSizeChangeAnimator;
- private boolean mShadeEmpty;
+ private boolean mShowEmptyShadeView;
private boolean mQsScrimEnabled = true;
private boolean mLastAnnouncementWasQuickSettings;
@@ -211,11 +209,12 @@
}
};
private NotificationGroupManager mGroupManager;
- private boolean mOpening;
+ private boolean mShowIconsWhenExpanded;
private int mIndicationBottomPadding;
private boolean mIsFullWidth;
private boolean mDark;
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
+ private boolean mNoVisibleNotifications = true;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -1518,7 +1517,7 @@
// it in expanded QS state as well so we don't run into troubles when fading the view in/out
// and expanding/collapsing the whole panel from/to quick settings.
if (mNotificationStackScroller.getNotGoneChildCount() == 0
- && mShadeEmpty) {
+ && mShowEmptyShadeView) {
notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight();
}
int maxQsHeight = mQsMaxExpansionHeight;
@@ -2118,15 +2117,15 @@
return mDozing;
}
- public void setShadeEmpty(boolean shadeEmpty) {
- mShadeEmpty = shadeEmpty;
+ public void showEmptyShadeView(boolean emptyShadeViewVisible) {
+ mShowEmptyShadeView = emptyShadeViewVisible;
updateEmptyShadeView();
}
private void updateEmptyShadeView() {
// Hide "No notifications" in QS.
- mNotificationStackScroller.updateEmptyShadeView(mShadeEmpty && !mQsExpanded);
+ mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
}
public void setQsScrimEnabled(boolean qsScrimEnabled) {
@@ -2306,7 +2305,7 @@
}
mNotificationStackScroller.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
- setOpening(isFullWidth() && expandedHeight < getOpeningHeight());
+ updateStatusBarIcons();
}
/**
@@ -2317,13 +2316,21 @@
return mIsFullWidth;
}
- private void setOpening(boolean opening) {
- if (opening != mOpening) {
- mOpening = opening;
+ private void updateStatusBarIcons() {
+ boolean showIconsWhenExpanded = isFullWidth() && getExpandedHeight() < getOpeningHeight();
+ if (showIconsWhenExpanded && mNoVisibleNotifications && isOnKeyguard()) {
+ showIconsWhenExpanded = false;
+ }
+ if (showIconsWhenExpanded != mShowIconsWhenExpanded) {
+ mShowIconsWhenExpanded = showIconsWhenExpanded;
mStatusBar.recomputeDisableFlags(false);
}
}
+ private boolean isOnKeyguard() {
+ return mStatusBar.getBarState() == StatusBarState.KEYGUARD;
+ }
+
public void setPanelScrimMinFraction(float minFraction) {
mBar.panelScrimMinFractionChanged(minFraction);
}
@@ -2426,12 +2433,8 @@
mGroupManager = groupManager;
}
- public boolean shouldHideNotificationIcons() {
- return !isFullWidth() || (!mOpening && !isFullyCollapsed());
- }
-
- public boolean shouldAnimateIconHiding() {
- return !isFullWidth();
+ public boolean hideStatusBarIconsWhenExpanded() {
+ return !isFullWidth() || !mShowIconsWhenExpanded;
}
private final FragmentListener mFragmentListener = new FragmentListener() {
@@ -2473,4 +2476,8 @@
mKeyguardStatusView.setDark(dark);
positionClockAndNotifications();
}
+
+ public void setNoVisibleNotifications(boolean noNotifications) {
+ mNoVisibleNotifications = noNotifications;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 9e93ed3..bb6c8f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
import android.app.AlarmManager;
@@ -25,8 +24,6 @@
import android.app.AppGlobals;
import android.app.Notification;
import android.app.Notification.Action;
-import android.app.Notification.BigTextStyle;
-import android.app.Notification.Style;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.SynchronousUserSwitchObserver;
@@ -37,7 +34,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.graphics.drawable.Icon;
import android.media.AudioManager;
@@ -51,7 +47,6 @@
import android.provider.Settings.Global;
import android.service.notification.StatusBarNotification;
import android.telecom.TelecomManager;
-import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -61,11 +56,9 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.R.string;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.statusbar.CommandQueue;
@@ -87,9 +80,6 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.NotificationChannels;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* This class contains all of the policy about which icons are installed in the status
* bar at boot time. It goes through the normal API for icons, even though it probably
@@ -137,8 +127,6 @@
private boolean mVolumeVisible;
private boolean mCurrentUserSetup;
- private int mZen;
-
private boolean mManagedProfileFocused = false;
private boolean mManagedProfileIconVisible = false;
private boolean mManagedProfileInQuietMode = false;
@@ -275,14 +263,14 @@
@Override
public void onZenChanged(int zen) {
- mZen = zen;
updateVolumeZen();
}
private void updateAlarm() {
final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
- final boolean zenNone = mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
+ int zen = mZenController.getZen();
+ final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
mIconController.setIcon(mSlotAlarmClock, zenNone ? R.drawable.stat_sys_alarm_dim
: R.drawable.stat_sys_alarm, null);
mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm);
@@ -323,17 +311,18 @@
boolean volumeVisible = false;
int volumeIconId = 0;
String volumeDescription = null;
+ int zen = mZenController.getZen();
if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
- zenVisible = mZen != Global.ZEN_MODE_OFF;
- zenIconId = mZen == Global.ZEN_MODE_NO_INTERRUPTIONS
+ zenVisible = zen != Global.ZEN_MODE_OFF;
+ zenIconId = zen == Global.ZEN_MODE_NO_INTERRUPTIONS
? R.drawable.stat_sys_dnd_total_silence : R.drawable.stat_sys_dnd;
zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
- } else if (mZen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+ } else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
zenVisible = true;
zenIconId = R.drawable.stat_sys_zen_none;
zenDescription = mContext.getString(R.string.interruption_level_none);
- } else if (mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+ } else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
zenVisible = true;
zenIconId = R.drawable.stat_sys_zen_important;
zenDescription = mContext.getString(R.string.interruption_level_priority);
@@ -344,7 +333,7 @@
volumeVisible = true;
volumeIconId = R.drawable.stat_sys_ringer_silent;
volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
- } else if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS && mZen != Global.ZEN_MODE_ALARMS &&
+ } else if (zen != Global.ZEN_MODE_NO_INTERRUPTIONS && zen != Global.ZEN_MODE_ALARMS &&
audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
volumeVisible = true;
volumeIconId = R.drawable.stat_sys_ringer_vibrate;
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 53d2d73..c90d493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -172,7 +172,6 @@
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
@@ -717,7 +716,7 @@
private LogMaker mStatusBarStateLog;
private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
private NotificationIconAreaController mNotificationIconAreaController;
- private ConfigurationListener mDensityChangeListener;
+ private ConfigurationListener mConfigurationListener;
private InflationExceptionHandler mInflationExceptionHandler = this::handleInflationException;
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
@@ -945,13 +944,18 @@
Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
- mDensityChangeListener = new ConfigurationListener() {
+ mConfigurationListener = new ConfigurationListener() {
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ StatusBar.this.onConfigurationChanged(newConfig);
+ }
+
@Override
public void onDensityOrFontScaleChanged() {
StatusBar.this.onDensityOrFontScaleChanged();
}
};
- Dependency.get(ConfigurationController.class).addCallback(mDensityChangeListener);
+ Dependency.get(ConfigurationController.class).addCallback(mConfigurationListener);
}
protected void createIconController() {
@@ -2034,10 +2038,10 @@
}
private void updateEmptyShadeView() {
- boolean showEmptyShade =
+ boolean showEmptyShadeView =
mState != StatusBarState.KEYGUARD &&
mNotificationData.getActiveNotifications().size() == 0;
- mNotificationPanel.setShadeEmpty(showEmptyShade);
+ mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
}
private void updateSpeedBumpIndex() {
@@ -2720,8 +2724,8 @@
return mLaunchTransitionFadingAway;
}
- public boolean shouldHideNotificationIcons() {
- return mNotificationPanel.shouldHideNotificationIcons();
+ public boolean hideStatusBarIconsWhenExpanded() {
+ return mNotificationPanel.hideStatusBarIconsWhenExpanded();
}
/**
@@ -2963,7 +2967,7 @@
runPostCollapseRunnables();
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
showBouncerIfKeyguard();
- recomputeDisableFlags(shouldAnimatIconHiding() /* animate */);
+ recomputeDisableFlags(mNotificationPanel.hideStatusBarIconsWhenExpanded() /* animate */);
// Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
// the bouncer appear animation.
@@ -2972,10 +2976,6 @@
}
}
- private boolean shouldAnimatIconHiding() {
- return mNotificationPanel.shouldAnimateIconHiding();
- }
-
public boolean interceptTouchEvent(MotionEvent event) {
if (DEBUG_GESTURES) {
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
@@ -3910,7 +3910,7 @@
}
Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null);
mDeviceProvisionedController.removeCallback(mUserSetupObserver);
- Dependency.get(ConfigurationController.class).removeCallback(mDensityChangeListener);
+ Dependency.get(ConfigurationController.class).removeCallback(mConfigurationListener);
}
private boolean mDemoModeAllowed;
@@ -6570,6 +6570,7 @@
}
}
}
+ mNotificationPanel.setNoVisibleNotifications(visibleNotifications == 0);
mStackScroller.changeViewPosition(mDismissView, mStackScroller.getChildCount() - 1);
mStackScroller.changeViewPosition(mEmptyShadeView, mStackScroller.getChildCount() - 2);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 9a3fabb..92f8c7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -100,10 +100,6 @@
mNotificationChannel = new NotificationChannel(
TEST_CHANNEL, TEST_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
when(mMockStatusBarNotification.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
- when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME),
- eq(R.string.notification_menu_accessibility), anyObject())).thenReturn(
- getContext().getString(R.string.notification_menu_accessibility));
-
when(mMockINotificationManager.getNumNotificationChannelsForPackage(
eq(TEST_PACKAGE_NAME), anyInt(), anyBoolean())).thenReturn(1);
}
@@ -174,6 +170,28 @@
@Test
@UiThreadTest
+ public void testBindNotification_SetsGroupName_resId() throws Exception {
+ when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME),
+ eq(R.string.legacy_vpn_name), anyObject())).thenReturn(
+ getContext().getString(R.string.legacy_vpn_name));
+ mNotificationChannel.setGroup("test_group_id");
+ final NotificationChannelGroup notificationChannelGroup =
+ new NotificationChannelGroup("test_group_id", R.string.legacy_vpn_name);
+ when(mMockINotificationManager.getNotificationChannelGroupForPackage(
+ eq("test_group_id"), eq(TEST_PACKAGE_NAME), anyInt()))
+ .thenReturn(notificationChannelGroup);
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ mMockStatusBarNotification, mNotificationChannel, null, null, null);
+ final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name);
+ assertEquals(View.VISIBLE, groupNameView.getVisibility());
+ assertEquals(mContext.getString(R.string.legacy_vpn_name), groupNameView.getText());
+ final TextView groupDividerView =
+ (TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider);
+ assertEquals(View.VISIBLE, groupDividerView.getVisibility());
+ }
+
+ @Test
+ @UiThreadTest
public void testBindNotification_SetsTextChannelName() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
mMockStatusBarNotification, mNotificationChannel, null, null, null);
@@ -184,6 +202,9 @@
@Test
@UiThreadTest
public void testBindNotification_SetsTextChannelName_resId() throws Exception {
+ when(mMockPackageManager.getText(eq(TEST_PACKAGE_NAME),
+ eq(R.string.notification_menu_accessibility), anyObject())).thenReturn(
+ getContext().getString(R.string.notification_menu_accessibility));
NotificationChannel notificationChannelResId = new NotificationChannel(
TEST_CHANNEL, R.string.notification_menu_accessibility,
NotificationManager.IMPORTANCE_LOW);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 4f8b8af..2d947a4 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -16,9 +16,23 @@
package com.android.server.backup;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER;
-import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY;
+import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
+import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_OLD_VERSION;
+import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_POLICY_ALLOW_APKS;
+import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_MANIFEST_PACKAGE_NAME;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_SYSTEM_APP_NO_AGENT;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_APK_NOT_INSTALLED;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_MISSING_SIGNATURE;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_RESTORE_ANY_VERSION;
+import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSIONS_MATCH;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND;
import android.app.ActivityManager;
@@ -2374,6 +2388,8 @@
IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
if (transport == null) {
sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
+ monitor = monitorEvent(monitor, BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_IS_NULL,
+ null, BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
return BackupManager.ERROR_TRANSPORT_ABORTED;
}
@@ -3338,6 +3354,14 @@
addBackupTrace("illegal key " + key + " from " + pkgName);
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, pkgName,
"bad key");
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_ILLEGAL_KEY,
+ mCurrentPackage,
+ BackupManagerMonitor
+ .LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ putMonitoringExtra(null,
+ BackupManagerMonitor.EXTRA_LOG_ILLEGAL_KEY,
+ key));
mBackupHandler.removeMessages(MSG_BACKUP_OPERATION_TIMEOUT);
sendBackupOnPackageResult(mObserver, pkgName,
BackupManager.ERROR_AGENT_FAILURE);
@@ -3407,6 +3431,11 @@
if (MORE_DEBUG) Slog.i(TAG,
"no backup data written; not calling transport");
addBackupTrace("no data to send");
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_NO_DATA_TO_SEND,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
}
if (mStatus == BackupTransport.TRANSPORT_OK) {
@@ -3502,8 +3531,10 @@
Slog.e(TAG, "Cancel backing up " + mCurrentPackage.packageName);
EventLog.writeEvent(EventLogTags.BACKUP_AGENT_FAILURE, mCurrentPackage.packageName);
mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_TIMEOUT,
- mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
+ BackupManagerMonitor.LOG_EVENT_ID_KEY_VALUE_BACKUP_CANCEL,
+ mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ putMonitoringExtra(null, BackupManagerMonitor.EXTRA_LOG_CANCEL_ALL,
+ mCancelAll));
addBackupTrace(
"cancel of " + mCurrentPackage.packageName + ", cancelAll=" + cancelAll);
errorCleanup();
@@ -4593,6 +4624,11 @@
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring ineligible package " + pkg);
}
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_INELIGIBLE,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
@@ -4603,6 +4639,11 @@
Slog.d(TAG, "Ignoring full-data backup of key/value participant "
+ pkg);
}
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_KEY_VALUE_PARTICIPANT,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
@@ -4613,6 +4654,11 @@
if (MORE_DEBUG) {
Slog.d(TAG, "Ignoring stopped package " + pkg);
}
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_STOPPED,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
sendBackupOnPackageResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
@@ -4620,7 +4666,7 @@
mPackages.add(info);
} catch (NameNotFoundException e) {
Slog.i(TAG, "Requested package " + pkg + " not found; ignoring");
- monitor = monitorEvent(monitor,
+ mMonitor = monitorEvent(mMonitor,
BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_NOT_FOUND,
mCurrentPackage,
BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
@@ -4696,9 +4742,17 @@
if (!mEnabled || !mProvisioned) {
// Backups are globally disabled, so don't proceed.
if (DEBUG) {
- Slog.i(TAG, "full backup requested but e=" + mEnabled
- + " p=" + mProvisioned + "; ignoring");
+ Slog.i(TAG, "full backup requested but enabled=" + mEnabled
+ + " provisioned=" + mProvisioned + "; ignoring");
}
+ int monitoringEvent;
+ if (!mEnabled) {
+ monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED;
+ } else {
+ monitoringEvent = BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED;
+ }
+ mMonitor = monitorEvent(mMonitor, monitoringEvent, null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
mUpdateSchedule = false;
backupRunStatus = BackupManager.ERROR_BACKUP_NOT_ALLOWED;
return;
@@ -4722,7 +4776,8 @@
PackageInfo currentPackage = mPackages.get(i);
String packageName = currentPackage.packageName;
if (DEBUG) {
- Slog.i(TAG, "Initiating full-data transport backup of " + packageName);
+ Slog.i(TAG, "Initiating full-data transport backup of " + packageName
+ + " token: " + mCurrentOpToken);
}
EventLog.writeEvent(EventLogTags.FULL_BACKUP_PACKAGE, packageName);
@@ -4781,6 +4836,13 @@
+ packageName + ": " + preflightResult
+ ", not running backup.");
}
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_ERROR_PREFLIGHT,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ putMonitoringExtra(null,
+ BackupManagerMonitor.EXTRA_LOG_PREFLIGHT_ERROR,
+ preflightResult));
backupPackageStatus = (int) preflightResult;
} else {
int nRead = 0;
@@ -4808,6 +4870,11 @@
if (backupPackageStatus == BackupTransport.TRANSPORT_QUOTA_EXCEEDED) {
Slog.w(TAG, "Package hit quota limit in-flight " + packageName
+ ": " + totalRead + " of " + quota);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_QUOTA_HIT_PREFLIGHT,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ null);
mBackupRunner.sendQuotaExceeded(totalRead, quota);
}
}
@@ -4942,6 +5009,14 @@
} catch (Exception e) {
backupRunStatus = BackupManager.ERROR_TRANSPORT_ABORTED;
Slog.w(TAG, "Exception trying full transport backup", e);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_EXCEPTION_FULL_BACKUP,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ putMonitoringExtra(null,
+ BackupManagerMonitor.EXTRA_LOG_EXCEPTION_FULL_BACKUP,
+ Log.getStackTraceString(e)));
+
} finally {
if (mCancelAll) {
@@ -5221,7 +5296,7 @@
}
mMonitor = monitorEvent(mMonitor,
- BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_TIMEOUT,
+ BackupManagerMonitor.LOG_EVENT_ID_FULL_BACKUP_CANCEL,
mCurrentPackage, BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, null);
mIsCancelled = true;
// Cancel tasks spun off by this task.
@@ -6309,9 +6384,29 @@
} else {
Slog.w(TAG, "Metadata mismatch: package " + info.packageName
+ " but widget data for " + pkg);
+
+ Bundle monitoringExtras = putMonitoringExtra(null,
+ EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
+ monitoringExtras = putMonitoringExtra(monitoringExtras,
+ BackupManagerMonitor.EXTRA_LOG_WIDGET_PACKAGE_NAME, pkg);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_WIDGET_METADATA_MISMATCH,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
}
} else {
Slog.w(TAG, "Unsupported metadata version " + version);
+
+ Bundle monitoringExtras = putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME,
+ info.packageName);
+ monitoringExtras = putMonitoringExtra(monitoringExtras,
+ EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_WIDGET_UNKNOWN_VERSION,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
}
}
@@ -6386,10 +6481,20 @@
if ((pkgInfo.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
Slog.i(TAG, "Package has restoreAnyVersion; taking data");
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_RESTORE_ANY_VERSION,
+ pkgInfo,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
policy = RestorePolicy.ACCEPT;
} else if (pkgInfo.versionCode >= version) {
Slog.i(TAG, "Sig + version match; taking data");
policy = RestorePolicy.ACCEPT;
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_VERSIONS_MATCH,
+ pkgInfo,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
} else {
// The data is from a newer version of the app than
// is presently installed. That means we can only
@@ -6403,30 +6508,43 @@
} else {
Slog.i(TAG, "Data requires newer version "
+ version + "; ignoring");
- ArrayList<Pair<String, String>> list =
- new ArrayList<>();
- list.add(new Pair<String, String>(
- EXTRA_LOG_OLD_VERSION,
- Integer.toString(version)));
mMonitor = monitorEvent(mMonitor,
LOG_EVENT_ID_VERSION_OF_BACKUP_OLDER,
pkgInfo,
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
- list);
+ putMonitoringExtra(null,
+ EXTRA_LOG_OLD_VERSION,
+ version));
+
policy = RestorePolicy.IGNORE;
}
}
} else {
Slog.w(TAG, "Restore manifest signatures do not match "
+ "installed application for " + info.packageName);
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_FULL_RESTORE_SIGNATURE_MISMATCH,
+ pkgInfo,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
}
} else {
Slog.w(TAG, "Package " + info.packageName
+ " is system level with no agent");
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_SYSTEM_APP_NO_AGENT,
+ pkgInfo,
+ LOG_EVENT_CATEGORY_AGENT,
+ null);
}
} else {
if (DEBUG) Slog.i(TAG, "Restore manifest from "
+ info.packageName + " but allowBackup=false");
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_FULL_RESTORE_ALLOW_BACKUP_FALSE,
+ pkgInfo,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ null);
}
} catch (NameNotFoundException e) {
// Okay, the target app isn't installed. We can process
@@ -6439,26 +6557,71 @@
} else {
policy = RestorePolicy.IGNORE;
}
+ Bundle monitoringExtras = putMonitoringExtra(null,
+ EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
+ monitoringExtras = putMonitoringExtra(monitoringExtras,
+ EXTRA_LOG_POLICY_ALLOW_APKS, mAllowApks);
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_APK_NOT_INSTALLED,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
}
if (policy == RestorePolicy.ACCEPT_IF_APK && !hasApk) {
Slog.i(TAG, "Cannot restore package " + info.packageName
+ " without the matching .apk");
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_CANNOT_RESTORE_WITHOUT_APK,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ putMonitoringExtra(null,
+ EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
}
} else {
Slog.i(TAG, "Missing signature on backed-up package "
+ info.packageName);
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_MISSING_SIGNATURE,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ putMonitoringExtra(null,
+ EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
}
} else {
Slog.i(TAG, "Expected package " + info.packageName
+ " but restore manifest claims " + manifestPackage);
+ Bundle monitoringExtras = putMonitoringExtra(null,
+ EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
+ monitoringExtras = putMonitoringExtra(monitoringExtras,
+ EXTRA_LOG_MANIFEST_PACKAGE_NAME, manifestPackage);
+ mMonitor = monitorEvent(mMonitor,
+ LOG_EVENT_ID_EXPECTED_DIFFERENT_PACKAGE,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
}
} else {
Slog.i(TAG, "Unknown restore manifest version " + version
+ " for package " + info.packageName);
+ Bundle monitoringExtras = putMonitoringExtra(null,
+ EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName);
+ monitoringExtras = putMonitoringExtra(monitoringExtras,
+ EXTRA_LOG_EVENT_PACKAGE_VERSION, version);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_VERSION,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
+
}
} catch (NumberFormatException e) {
Slog.w(TAG, "Corrupt restore manifest for package " + info.packageName);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_CORRUPT_MANIFEST,
+ null,
+ LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ putMonitoringExtra(null, EXTRA_LOG_EVENT_PACKAGE_NAME, info.packageName));
} catch (IllegalArgumentException e) {
Slog.w(TAG, e.getMessage());
}
@@ -8557,7 +8720,12 @@
return;
}
if (!PACKAGE_MANAGER_SENTINEL.equals(desc.getPackageName())) {
- Slog.e(TAG, "Required metadata but got " + desc.getPackageName());
+ Slog.e(TAG, "Required package metadata but got "
+ + desc.getPackageName());
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_NO_PM_METADATA_RECEIVED,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
mStatus = BackupTransport.TRANSPORT_ERROR;
executeNextState(UnifiedRestoreState.FINAL);
return;
@@ -8585,7 +8753,11 @@
// signature/version verification etc, so we simply do not proceed with
// the restore operation.
if (!mPmAgent.hasMetadata()) {
- Slog.e(TAG, "No restore metadata available, so not restoring");
+ Slog.e(TAG, "PM agent has no metadata, so not restoring");
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
PACKAGE_MANAGER_SENTINEL,
"Package manager restore metadata missing");
@@ -8601,6 +8773,10 @@
} catch (Exception e) {
// If we lost the transport at any time, halt
Slog.e(TAG, "Unable to contact transport for restore: " + e.getMessage());
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_LOST_TRANSPORT,
+ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT, null);
mStatus = BackupTransport.TRANSPORT_ERROR;
mBackupHandler.removeMessages(MSG_BACKUP_RESTORE_STEP, this);
executeNextState(UnifiedRestoreState.FINAL);
@@ -8670,17 +8846,37 @@
// handle this case, we do not attempt the restore.
if ((mCurrentPackage.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
- String message = "Version " + metaInfo.versionCode
+ String message = "Source version " + metaInfo.versionCode
+ " > installed version " + mCurrentPackage.versionCode;
Slog.w(TAG, "Package " + pkgName + ": " + message);
+ Bundle monitoringExtras = putMonitoringExtra(null,
+ BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
+ metaInfo.versionCode);
+ monitoringExtras = putMonitoringExtra(monitoringExtras,
+ BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, false);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
pkgName, message);
nextState = UnifiedRestoreState.RUNNING_QUEUE;
return;
} else {
- if (DEBUG) Slog.v(TAG, "Version " + metaInfo.versionCode
- + " > installed " + mCurrentPackage.versionCode
+ if (DEBUG) Slog.v(TAG, "Source version " + metaInfo.versionCode
+ + " > installed version " + mCurrentPackage.versionCode
+ " but restoreAnyVersion");
+ Bundle monitoringExtras = putMonitoringExtra(null,
+ BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
+ metaInfo.versionCode);
+ monitoringExtras = putMonitoringExtra(monitoringExtras,
+ BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY, true);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
}
}
@@ -8739,6 +8935,9 @@
Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
Slog.w(TAG, "Signature mismatch restoring " + packageName);
+ mMonitor = monitorEvent(mMonitor,
+ BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY, null);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName,
"Signature mismatch");
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
@@ -11035,23 +11234,54 @@
}
}
+ private Bundle putMonitoringExtra(Bundle extras, String key, String value) {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putString(key, value);
+ return extras;
+ }
+
+ private Bundle putMonitoringExtra(Bundle extras, String key, int value) {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putInt(key, value);
+ return extras;
+ }
+
+ private Bundle putMonitoringExtra(Bundle extras, String key, long value) {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putLong(key, value);
+ return extras;
+ }
+
+
+ private Bundle putMonitoringExtra(Bundle extras, String key, boolean value) {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putBoolean(key, value);
+ return extras;
+ }
+
private static IBackupManagerMonitor monitorEvent(IBackupManagerMonitor monitor, int id,
- PackageInfo pkg, int category, ArrayList<Pair<String, String>> extras) {
+ PackageInfo pkg, int category, Bundle extras) {
if (monitor != null) {
try {
Bundle bundle = new Bundle();
bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, id);
bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, category);
if (pkg != null) {
- bundle.putString(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME,
+ bundle.putString(EXTRA_LOG_EVENT_PACKAGE_NAME,
pkg.packageName);
bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION,
pkg.versionCode);
}
if (extras != null) {
- for (Pair<String,String> pair : extras) {
- bundle.putString(pair.first, pair.second);
- }
+ bundle.putAll(extras);
}
monitor.onEvent(bundle);
return monitor;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e9e73cc..54ee5dc 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12111,6 +12111,12 @@
mRecentTasks.notifyTaskPersisterLocked(task, flush);
}
+ /** Notifies all listeners when the pinned stack animation starts. */
+ @Override
+ public void notifyPinnedStackAnimationStarted() {
+ mTaskChangeNotificationController.notifyPinnedStackAnimationStarted();
+ }
+
/** Notifies all listeners when the pinned stack animation ends. */
@Override
public void notifyPinnedStackAnimationEnded() {
@@ -19013,8 +19019,7 @@
return ActivityManager.BROADCAST_SUCCESS;
}
- final void addBroadcastStatLocked(String action, String srcPackage, int receiveCount,
- int skipCount, long dispatchTime) {
+ final void rotateBroadcastStatsIfNeededLocked() {
final long now = SystemClock.elapsedRealtime();
if (mCurBroadcastStats == null ||
(mCurBroadcastStats.mStartRealtime +(24*60*60*1000) < now)) {
@@ -19025,9 +19030,19 @@
}
mCurBroadcastStats = new BroadcastStats();
}
+ }
+
+ final void addBroadcastStatLocked(String action, String srcPackage, int receiveCount,
+ int skipCount, long dispatchTime) {
+ rotateBroadcastStatsIfNeededLocked();
mCurBroadcastStats.addBroadcast(action, srcPackage, receiveCount, skipCount, dispatchTime);
}
+ final void addBackgroundCheckViolationLocked(String action, String targetPackage) {
+ rotateBroadcastStatsIfNeededLocked();
+ mCurBroadcastStats.addBackgroundCheckViolation(action, targetPackage);
+ }
+
final Intent verifyBroadcastLocked(Intent intent) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 2e33c62..b9ae4fd 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1561,9 +1561,13 @@
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
// The caller has requested to completely replace any existing task with its new
// activity. Well that should not be too hard...
- intentActivity.task.performClearTaskLocked();
- intentActivity.task.setIntent(mStartActivity);
+ // Note: we must persist the {@link TaskRecord} first as intentActivity could be
+ // removed from calling performClearTaskLocked (For example, if it is being brought out
+ // of history or if it is finished immediately), thus disassociating the task.
mReuseTask = intentActivity.task;
+ mReuseTask.performClearTaskLocked();
+ mReuseTask.setIntent(mStartActivity);
+
// When we clear the task - focus will be adjusted, which will bring another task
// to top before we launch the activity we need. This will temporary swap their
// mTaskToReturnTo values and we don't want to overwrite them accidentally.
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 75b5929..c9d19cb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1195,6 +1195,8 @@
&& r.intent.getPackage() == null
&& ((r.intent.getFlags()
& Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0))) {
+ mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
+ component.getPackageName());
Slog.w(TAG, "Background execution not allowed: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
diff --git a/services/core/java/com/android/server/am/BroadcastStats.java b/services/core/java/com/android/server/am/BroadcastStats.java
index fdbaada..fd24582 100644
--- a/services/core/java/com/android/server/am/BroadcastStats.java
+++ b/services/core/java/com/android/server/am/BroadcastStats.java
@@ -47,6 +47,7 @@
static final class ActionEntry {
final String mAction;
final ArrayMap<String, PackageEntry> mPackages = new ArrayMap<>();
+ final ArrayMap<String, ViolationEntry> mBackgroundCheckViolations = new ArrayMap<>();
int mReceiveCount;
int mSkipCount;
long mTotalDispatchTime;
@@ -61,6 +62,10 @@
int mSendCount;
}
+ static final class ViolationEntry {
+ int mCount;
+ }
+
public BroadcastStats() {
mStartRealtime = SystemClock.elapsedRealtime();
mStartUptime = SystemClock.uptimeMillis();
@@ -87,6 +92,20 @@
pe.mSendCount++;
}
+ public void addBackgroundCheckViolation(String action, String targetPackage) {
+ ActionEntry ae = mActions.get(action);
+ if (ae == null) {
+ ae = new ActionEntry(action);
+ mActions.put(action, ae);
+ }
+ ViolationEntry ve = ae.mBackgroundCheckViolations.get(targetPackage);
+ if (ve == null) {
+ ve = new ViolationEntry();
+ ae.mBackgroundCheckViolations.put(targetPackage, ve);
+ }
+ ve.mCount++;
+ }
+
public boolean dumpStats(PrintWriter pw, String prefix, String dumpPackage) {
boolean printedSomething = false;
ArrayList<ActionEntry> actions = new ArrayList<>(mActions.size());
@@ -123,6 +142,15 @@
pw.print(pe.mSendCount);
pw.println(" times");
}
+ for (int j=ae.mBackgroundCheckViolations.size()-1; j>=0; j--) {
+ pw.print(prefix);
+ pw.print(" Bg Check Violation ");
+ pw.print(ae.mBackgroundCheckViolations.keyAt(j));
+ pw.print(": ");
+ ViolationEntry ve = ae.mBackgroundCheckViolations.valueAt(j);
+ pw.print(ve.mCount);
+ pw.println(" times");
+ }
}
return printedSomething;
}
@@ -158,6 +186,14 @@
pw.print(pe.mSendCount);
pw.println();
}
+ for (int j=ae.mBackgroundCheckViolations.size()-1; j>=0; j--) {
+ pw.print("v,");
+ pw.print(ae.mBackgroundCheckViolations.keyAt(j));
+ ViolationEntry ve = ae.mBackgroundCheckViolations.valueAt(j);
+ pw.print(",");
+ pw.print(ve.mCount);
+ pw.println();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index 9dfc7cd..9a98bc6 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -46,6 +46,7 @@
static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
+ static final int NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG = 16;
// Delay in notifying task stack change listeners (in millis)
static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -100,6 +101,10 @@
l.onPinnedActivityRestartAttempt((String) m.obj);
};
+ private final TaskStackConsumer mNotifyPinnedStackAnimationStarted = (l, m) -> {
+ l.onPinnedStackAnimationStarted();
+ };
+
private final TaskStackConsumer mNotifyPinnedStackAnimationEnded = (l, m) -> {
l.onPinnedStackAnimationEnded();
};
@@ -166,6 +171,9 @@
case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
forAllRemoteListeners(mNotifyPinnedActivityRestartAttempt, msg);
break;
+ case NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG:
+ forAllRemoteListeners(mNotifyPinnedStackAnimationStarted, msg);
+ break;
case NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG:
forAllRemoteListeners(mNotifyPinnedStackAnimationEnded, msg);
break;
@@ -276,6 +284,15 @@
msg.sendToTarget();
}
+ /** Notifies all listeners when the pinned stack animation starts. */
+ void notifyPinnedStackAnimationStarted() {
+ mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG);
+ final Message msg =
+ mHandler.obtainMessage(NOTIFY_PINNED_STACK_ANIMATION_STARTED_LISTENERS_MSG);
+ forAllLocalListeners(mNotifyPinnedStackAnimationStarted, msg);
+ msg.sendToTarget();
+ }
+
/** Notifies all listeners when the pinned stack animation ends. */
void notifyPinnedStackAnimationEnded() {
mHandler.removeMessages(NOTIFY_PINNED_STACK_ANIMATION_ENDED_LISTENERS_MSG);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index e72f7ff..476eb10 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -192,9 +192,14 @@
if (TAG_GROUP.equals(tagName)) {
String id = parser.getAttributeValue(null, ATT_ID);
CharSequence groupName = parser.getAttributeValue(null, ATT_NAME);
+ int groupNameRes = safeInt(parser, ATT_NAME_RES_ID, 0);
if (!TextUtils.isEmpty(id)) {
- final NotificationChannelGroup group =
- new NotificationChannelGroup(id, groupName);
+ NotificationChannelGroup group = null;
+ if (groupName != null) {
+ group = new NotificationChannelGroup(id, groupName);
+ } else {
+ group = new NotificationChannelGroup(id, groupNameRes);
+ }
r.groups.put(id, group);
}
}
@@ -202,7 +207,7 @@
if (TAG_CHANNEL.equals(tagName)) {
String id = parser.getAttributeValue(null, ATT_ID);
CharSequence channelName = parser.getAttributeValue(null, ATT_NAME);
- int channelNameRes = safeInt(parser, ATT_NAME_RES_ID, -1);
+ int channelNameRes = safeInt(parser, ATT_NAME_RES_ID, 0);
int channelImportance =
safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
@@ -473,7 +478,8 @@
Preconditions.checkNotNull(pkg);
Preconditions.checkNotNull(group);
Preconditions.checkNotNull(group.getId());
- Preconditions.checkNotNull(group.getName());
+ Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName())
+ || group.getNameResId() != 0);
Record r = getOrCreateRecord(pkg, uid);
if (r == null) {
throw new IllegalArgumentException("Invalid package");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index caacc46..a4d35a1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -15919,14 +15919,6 @@
final PackageSetting ps = mSettings.mPackages.get(pkgName);
- // don't allow an upgrade from full to ephemeral
- if (isInstantApp && !ps.getInstantApp(user.getIdentifier())) {
- // can't downgrade from full to instant
- Slog.w(TAG, "Can't replace app with instant app: " + pkgName);
- res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
- return;
- }
-
// verify signatures are valid
if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
if (!checkUpgradeKeySetLP(ps, pkg)) {
@@ -15984,6 +15976,27 @@
// In case of rollback, remember per-user/profile install state
allUsers = sUserManager.getUserIds();
installedUsers = ps.queryInstalledUsers(allUsers, true);
+
+ // don't allow an upgrade from full to ephemeral
+ if (isInstantApp) {
+ if (user == null || user.getIdentifier() == UserHandle.USER_ALL) {
+ for (int currentUser : allUsers) {
+ if (!ps.getInstantApp(currentUser)) {
+ // can't downgrade from full to instant
+ Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
+ + " for user: " + currentUser);
+ res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+ return;
+ }
+ }
+ } else if (!ps.getInstantApp(user.getIdentifier())) {
+ // can't downgrade from full to instant
+ Slog.w(TAG, "Can't replace full app with instant app: " + pkgName
+ + " for user: " + user.getIdentifier());
+ res.setReturnCode(PackageManager.INSTALL_FAILED_INSTANT_APP_INVALID);
+ return;
+ }
+ }
}
// Update what is removed
diff --git a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
index 10d30aa..c064392 100644
--- a/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
+++ b/services/core/java/com/android/server/storage/CacheQuotaStrategy.java
@@ -34,21 +34,37 @@
import android.content.pm.UserInfo;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.format.DateUtils;
+import android.util.Pair;
import android.util.Slog;
+import android.util.Xml;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.server.pm.Installer;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
-
/**
* CacheQuotaStrategy is a strategy for determining cache quotas using usage stats and foreground
* time using the calculation as defined in the refuel rocket.
@@ -58,17 +74,28 @@
private final Object mLock = new Object();
+ // XML Constants
+ private static final String CACHE_INFO_TAG = "cache-info";
+ private static final String ATTR_PREVIOUS_BYTES = "previousBytes";
+ private static final String TAG_QUOTA = "quota";
+ private static final String ATTR_UUID = "uuid";
+ private static final String ATTR_UID = "uid";
+ private static final String ATTR_QUOTA_IN_BYTES = "bytes";
+
private final Context mContext;
private final UsageStatsManagerInternal mUsageStats;
private final Installer mInstaller;
private ServiceConnection mServiceConnection;
private ICacheQuotaService mRemoteService;
+ private AtomicFile mPreviousValuesFile;
public CacheQuotaStrategy(
Context context, UsageStatsManagerInternal usageStatsManager, Installer installer) {
mContext = Preconditions.checkNotNull(context);
mUsageStats = Preconditions.checkNotNull(usageStatsManager);
mInstaller = Preconditions.checkNotNull(installer);
+ mPreviousValuesFile = new AtomicFile(new File(
+ new File(Environment.getDataDirectory(), "system"), "cachequota.xml"));
}
/**
@@ -128,7 +155,7 @@
}
/**
- * Returns a list of CacheQuotaRequests which do not have their quotas filled out for apps
+ * Returns a list of CacheQuotaHints which do not have their quotas filled out for apps
* which have been used in the last year.
*/
private List<CacheQuotaHint> getUnfulfilledRequests() {
@@ -176,6 +203,11 @@
final List<CacheQuotaHint> processedRequests =
data.getParcelableArrayList(
CacheQuotaService.REQUEST_LIST_KEY);
+ pushProcessedQuotas(processedRequests);
+ writeXmlToFile(processedRequests);
+ }
+
+ private void pushProcessedQuotas(List<CacheQuotaHint> processedRequests) {
final int requestSize = processedRequests.size();
for (int i = 0; i < requestSize; i++) {
CacheQuotaHint request = processedRequests.get(i);
@@ -200,8 +232,10 @@
}
private void disconnectService() {
- mContext.unbindService(mServiceConnection);
- mServiceConnection = null;
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ mServiceConnection = null;
+ }
}
private ComponentName getServiceComponentName() {
@@ -223,4 +257,131 @@
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
return new ComponentName(serviceInfo.packageName, serviceInfo.name);
}
+
+ private void writeXmlToFile(List<CacheQuotaHint> processedRequests) {
+ FileOutputStream fileStream = null;
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ fileStream = mPreviousValuesFile.startWrite();
+ out.setOutput(fileStream, StandardCharsets.UTF_8.name());
+ saveToXml(out, processedRequests, 0);
+ mPreviousValuesFile.finishWrite(fileStream);
+ } catch (Exception e) {
+ Slog.e(TAG, "An error occurred while writing the cache quota file.", e);
+ mPreviousValuesFile.failWrite(fileStream);
+ }
+ }
+
+ /**
+ * Initializes the quotas from the file.
+ * @return the number of bytes that were free on the device when the quotas were last calced.
+ */
+ public long setupQuotasFromFile() throws IOException {
+ FileInputStream stream;
+ try {
+ stream = mPreviousValuesFile.openRead();
+ } catch (FileNotFoundException e) {
+ // The file may not exist yet -- this isn't truly exceptional.
+ return -1;
+ }
+
+ Pair<Long, List<CacheQuotaHint>> cachedValues = null;
+ try {
+ cachedValues = readFromXml(stream);
+ } catch (XmlPullParserException e) {
+ throw new IllegalStateException(e.getMessage());
+ }
+
+ if (cachedValues == null) {
+ Slog.e(TAG, "An error occurred while parsing the cache quota file.");
+ return -1;
+ }
+ pushProcessedQuotas(cachedValues.second);
+ return cachedValues.first;
+ }
+
+ @VisibleForTesting
+ static void saveToXml(XmlSerializer out,
+ List<CacheQuotaHint> requests, long bytesWhenCalculated) throws IOException {
+ out.startDocument(null, true);
+ out.startTag(null, CACHE_INFO_TAG);
+ int requestSize = requests.size();
+ out.attribute(null, ATTR_PREVIOUS_BYTES, Long.toString(bytesWhenCalculated));
+
+ for (int i = 0; i < requestSize; i++) {
+ CacheQuotaHint request = requests.get(i);
+ out.startTag(null, TAG_QUOTA);
+ String uuid = request.getVolumeUuid();
+ if (uuid != null) {
+ out.attribute(null, ATTR_UUID, request.getVolumeUuid());
+ }
+ out.attribute(null, ATTR_UID, Integer.toString(request.getUid()));
+ out.attribute(null, ATTR_QUOTA_IN_BYTES, Long.toString(request.getQuota()));
+ out.endTag(null, TAG_QUOTA);
+ }
+ out.endTag(null, CACHE_INFO_TAG);
+ out.endDocument();
+ }
+
+ protected static Pair<Long, List<CacheQuotaHint>> readFromXml(InputStream inputStream)
+ throws XmlPullParserException, IOException {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(inputStream, StandardCharsets.UTF_8.name());
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.START_TAG &&
+ eventType != XmlPullParser.END_DOCUMENT) {
+ eventType = parser.next();
+ }
+
+ if (eventType == XmlPullParser.END_DOCUMENT) {
+ Slog.d(TAG, "No quotas found in quota file.");
+ return null;
+ }
+
+ String tagName = parser.getName();
+ if (!CACHE_INFO_TAG.equals(tagName)) {
+ throw new IllegalStateException("Invalid starting tag.");
+ }
+
+ final List<CacheQuotaHint> quotas = new ArrayList<>();
+ long previousBytes;
+ try {
+ previousBytes = Long.parseLong(parser.getAttributeValue(
+ null, ATTR_PREVIOUS_BYTES));
+ } catch (NumberFormatException e) {
+ throw new IllegalStateException(
+ "Previous bytes formatted incorrectly; aborting quota read.");
+ }
+
+ eventType = parser.next();
+ do {
+ if (eventType == XmlPullParser.START_TAG) {
+ tagName = parser.getName();
+ if (TAG_QUOTA.equals(tagName)) {
+ CacheQuotaHint request = getRequestFromXml(parser);
+ if (request == null) {
+ continue;
+ }
+ quotas.add(request);
+ }
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+ return new Pair<>(previousBytes, quotas);
+ }
+
+ @VisibleForTesting
+ static CacheQuotaHint getRequestFromXml(XmlPullParser parser) {
+ try {
+ String uuid = parser.getAttributeValue(null, ATTR_UUID);
+ int uid = Integer.parseInt(parser.getAttributeValue(null, ATTR_UID));
+ long bytes = Long.parseLong(parser.getAttributeValue(null, ATTR_QUOTA_IN_BYTES));
+ return new CacheQuotaHint.Builder()
+ .setVolumeUuid(uuid).setUid(uid).setQuota(bytes).build();
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Invalid cache quota request, skipping.");
+ return null;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f5ccf08..647adbf 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -84,8 +84,6 @@
final boolean mVoiceInteraction;
- // TODO: Use getParent instead?
- private Task mTask;
/** @see WindowContainer#fillsParent() */
private boolean mFillsParent;
boolean layoutConfigChanges;
@@ -411,7 +409,7 @@
}
boolean windowsAreFocusable() {
- return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
+ return StackId.canReceiveKeys(getTask().mStack.mStackId) || mAlwaysFocusable;
}
AppWindowContainerController getController() {
@@ -467,7 +465,7 @@
getController().removeStartingWindow();
}
- final TaskStack stack = mTask.mStack;
+ final TaskStack stack = getTask().mStack;
if (delayed && !isEmpty()) {
// set the token aside because it has an active animation to be finished
if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
@@ -667,20 +665,7 @@
}
Task getTask() {
- return mTask;
- }
-
- /**
- * Sets the associated task, cleaning up dependencies when unset.
- */
- void setTask(Task task) {
- // Note: the following code assumes that the previous task's stack is the same as the
- // new task's stack.
- if (!mReparenting && mTask != null && mTask.mStack != null) {
- mTask.mStack.mExitingAppTokens.remove(this);
- }
-
- mTask = task;
+ return (Task) getParent();
}
@Override
@@ -690,10 +675,15 @@
// When the associated task is {@code null}, the {@link AppWindowToken} can no longer
// access visual elements like the {@link DisplayContent}. We must remove any associations
// such as animations.
- if (!mReparenting && mTask == null) {
- // It is possible we have been marked as a closing app earlier. We must remove ourselves
- // from this list so we do not participate in any future animations.
- mService.mClosingApps.remove(this);
+ if (!mReparenting) {
+ final Task task = getTask();
+ if (task == null) {
+ // It is possible we have been marked as a closing app earlier. We must remove ourselves
+ // from this list so we do not participate in any future animations.
+ mService.mClosingApps.remove(this);
+ } else if (task.mStack != null) {
+ task.mStack.mExitingAppTokens.remove(this);
+ }
}
}
@@ -885,19 +875,20 @@
}
void reparent(Task task, int position) {
- if (task == mTask) {
+ final Task currentTask = getTask();
+ if (task == currentTask) {
throw new IllegalArgumentException(
- "window token=" + this + " already child of task=" + mTask);
+ "window token=" + this + " already child of task=" + currentTask);
}
- if (mTask.mStack != task.mStack) {
+ if (currentTask.mStack != task.mStack) {
throw new IllegalArgumentException(
- "window token=" + this + " current task=" + mTask
+ "window token=" + this + " current task=" + currentTask
+ " belongs to a different stack than " + task);
}
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
- + " from task=" + mTask);
+ + " from task=" + currentTask);
final DisplayContent prevDisplayContent = getDisplayContent();
mReparenting = true;
@@ -917,9 +908,11 @@
}
private boolean canFreezeBounds() {
+ final Task task = getTask();
+
// For freeform windows, we can't freeze the bounds at the moment because this would make
// the resizing unresponsive.
- return mTask != null && !mTask.inFreeformWorkspace();
+ return task != null && !task.inFreeformWorkspace();
}
/**
@@ -929,16 +922,17 @@
* with a queue.
*/
private void freezeBounds() {
- mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
+ final Task task = getTask();
+ mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
- if (mTask.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
+ if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
// We didn't call prepareFreezingBounds on the task, so use the current value.
- mFrozenMergedConfig.offer(new Configuration(mTask.getConfiguration()));
+ mFrozenMergedConfig.offer(new Configuration(task.getConfiguration()));
} else {
- mFrozenMergedConfig.offer(new Configuration(mTask.mPreparedFrozenMergedConfig));
+ mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
}
// Calling unset() to make it equal to Configuration.EMPTY.
- mTask.mPreparedFrozenMergedConfig.unset();
+ task.mPreparedFrozenMergedConfig.unset();
}
/**
@@ -1463,7 +1457,7 @@
if (appToken != null) {
pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
}
- pw.print(prefix); pw.print("task="); pw.println(mTask);
+ pw.print(prefix); pw.print("task="); pw.println(getTask());
pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
pw.print(" mOrientation="); pw.println(mOrientation);
pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 07eb88d..99c085f 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -133,7 +133,6 @@
void addChild(AppWindowToken wtoken, int position) {
position = getAdjustedAddPosition(position);
super.addChild(wtoken, position);
- wtoken.setTask(this);
mDeferRemoval = false;
}
@@ -244,8 +243,6 @@
removeIfPossible();
}
}
-
- token.setTask(null /*task*/);
}
void setSendingToBottom(boolean toBottom) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 6cc2efb..7588b71 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1439,6 +1439,14 @@
mBoundsAnimating = true;
mBoundsAnimatingToFullscreen = toFullscreen;
}
+
+ if (mStackId == PINNED_STACK_ID) {
+ try {
+ mService.mActivityManager.notifyPinnedStackAnimationStarted();
+ } catch (RemoteException e) {
+ // I don't believe you...
+ }
+ }
}
@Override // AnimatesBounds
@@ -1448,6 +1456,7 @@
mBoundsAnimationTarget.setEmpty();
mService.requestTraversal();
}
+
if (mStackId == PINNED_STACK_ID) {
try {
mService.mActivityManager.notifyPinnedStackAnimationEnded();
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index ffb0a9e..25c29ee 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -209,6 +209,12 @@
assertEquals(expected.getLightColor(), actual.getLightColor());
}
+ private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) {
+ assertEquals(expected.getId(), actual.getId());
+ assertEquals(expected.getName(), actual.getName());
+ assertEquals(expected.getNameResId(), actual.getNameResId());
+ }
+
@Test
public void testFindAfterRankingWithASplitGroup() throws Exception {
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -262,8 +268,10 @@
@Test
public void testChannelXml() throws Exception {
int nameResId = 924896;
+ int groupNameResId = 426272;
- NotificationChannelGroup ncg = new NotificationChannelGroup("1", "2");
+ NotificationChannelGroup ncg = new NotificationChannelGroup("1", groupNameResId);
+ NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
NotificationChannel channel2 =
@@ -278,6 +286,7 @@
channel2.setLightColor(Color.BLUE);
mHelper.createNotificationChannelGroup(pkg, uid, ncg, true);
+ mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true);
mHelper.createNotificationChannel(pkg, uid, channel1, true);
mHelper.createNotificationChannel(pkg, uid, channel2, false);
@@ -308,7 +317,9 @@
for (NotificationChannelGroup actual : actualGroups) {
if (ncg.getId().equals(actual.getId())) {
foundNcg = true;
- break;
+ compareGroups(ncg, actual);
+ } else if (ncg2.getId().equals(actual.getId())) {
+ compareGroups(ncg2, actual);
}
}
assertTrue(foundNcg);
diff --git a/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
new file mode 100644
index 0000000..1d62e01
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/storage/CacheQuotaStrategyTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 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.storage;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.usage.CacheQuotaHint;
+import android.test.AndroidTestCase;
+import android.util.Pair;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.ByteArrayInputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class CacheQuotaStrategyTest extends AndroidTestCase {
+ StringWriter mWriter;
+ FastXmlSerializer mOut;
+
+ @Before
+ public void setUp() throws Exception {
+ mWriter = new StringWriter();
+ mOut = new FastXmlSerializer();
+ mOut.setOutput(mWriter);
+ }
+
+ @Test
+ public void testEmptyWrite() throws Exception {
+ CacheQuotaStrategy.saveToXml(mOut, new ArrayList<>(), 0);
+ mOut.flush();
+
+ assertThat(mWriter.toString()).isEqualTo(
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
+ "<cache-info previousBytes=\"0\" />\n");
+ }
+
+ @Test
+ public void testWriteOneQuota() throws Exception {
+ ArrayList<CacheQuotaHint> requests = new ArrayList<>();
+ requests.add(buildCacheQuotaHint("uuid", 0, 100));
+
+ CacheQuotaStrategy.saveToXml(mOut, requests, 1000);
+ mOut.flush();
+
+ assertThat(mWriter.toString()).isEqualTo(
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
+ "<cache-info previousBytes=\"1000\">\n"
+ + "<quota uuid=\"uuid\" uid=\"0\" bytes=\"100\" />\n"
+ + "</cache-info>\n");
+ }
+
+ @Test
+ public void testWriteMultipleQuotas() throws Exception {
+ ArrayList<CacheQuotaHint> requests = new ArrayList<>();
+ requests.add(buildCacheQuotaHint("uuid", 0, 100));
+ requests.add(buildCacheQuotaHint("uuid2", 10, 250));
+
+ CacheQuotaStrategy.saveToXml(mOut, requests, 1000);
+ mOut.flush();
+
+ assertThat(mWriter.toString()).isEqualTo(
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
+ "<cache-info previousBytes=\"1000\">\n"
+ + "<quota uuid=\"uuid\" uid=\"0\" bytes=\"100\" />\n"
+ + "<quota uuid=\"uuid2\" uid=\"10\" bytes=\"250\" />\n"
+ + "</cache-info>\n");
+ }
+
+ @Test
+ public void testNullUuidDoesntCauseCrash() throws Exception {
+ ArrayList<CacheQuotaHint> requests = new ArrayList<>();
+ requests.add(buildCacheQuotaHint(null, 0, 100));
+ requests.add(buildCacheQuotaHint(null, 10, 250));
+
+ CacheQuotaStrategy.saveToXml(mOut, requests, 1000);
+ mOut.flush();
+
+ assertThat(mWriter.toString()).isEqualTo(
+ "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" +
+ "<cache-info previousBytes=\"1000\">\n"
+ + "<quota uid=\"0\" bytes=\"100\" />\n"
+ + "<quota uid=\"10\" bytes=\"250\" />\n"
+ + "</cache-info>\n");
+ }
+
+ @Test
+ public void testReadMultipleQuotas() throws Exception {
+ String input = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<cache-info previousBytes=\"1000\">\n"
+ + "<quota uuid=\"uuid\" uid=\"0\" bytes=\"100\" />\n"
+ + "<quota uuid=\"uuid2\" uid=\"10\" bytes=\"250\" />\n"
+ + "</cache-info>\n";
+
+ Pair<Long, List<CacheQuotaHint>> output =
+ CacheQuotaStrategy.readFromXml(new ByteArrayInputStream(input.getBytes("UTF-8")));
+
+ assertThat(output.first).isEqualTo(1000);
+ assertThat(output.second).containsExactly(buildCacheQuotaHint("uuid", 0, 100),
+ buildCacheQuotaHint("uuid2", 10, 250));
+ }
+
+ private CacheQuotaHint buildCacheQuotaHint(String volumeUuid, int uid, long quota) {
+ return new CacheQuotaHint.Builder()
+ .setVolumeUuid(volumeUuid).setUid(uid).setQuota(quota).build();
+ }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 440362d..18c48b7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -158,21 +158,6 @@
return win;
}
- /**
- * Creates a window for a task on a the given {@param stackId}.
- */
- private WindowState createStackWindow(int stackId, String name) {
- final StackWindowController stackController = createStackControllerOnStackOnDisplay(stackId,
- sDisplayContent);
- final TestTaskWindowContainerController taskController =
- new TestTaskWindowContainerController(stackController);
- TestAppWindowToken appWinToken = new TestAppWindowToken(sDisplayContent);
- appWinToken.setTask(taskController.mContainer);
- final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, name);
- win.mAppToken = appWinToken;
- return win;
- }
-
/** Asserts that the first entry is greater than the second entry. */
void assertGreaterThan(int first, int second) throws Exception {
Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index ed1530a..89e68a6 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -55,6 +55,8 @@
import com.android.server.pm.Installer.InstallerException;
import com.android.server.storage.CacheQuotaStrategy;
+import java.io.IOException;
+
public class StorageStatsService extends IStorageStatsManager.Stub {
private static final String TAG = "StorageStatsService";
@@ -97,7 +99,7 @@
invalidateMounts();
mHandler = new H(IoThread.get().getLooper());
- mHandler.sendEmptyMessageDelayed(H.MSG_CHECK_STORAGE_DELTA, DELAY_IN_MILLIS);
+ mHandler.sendEmptyMessageDelayed(H.MSG_LOAD_CACHED_QUOTAS_FROM_FILE, DELAY_IN_MILLIS);
mStorage.registerListener(new StorageEventListener() {
@Override
@@ -343,12 +345,14 @@
private class H extends Handler {
private static final int MSG_CHECK_STORAGE_DELTA = 100;
+ private static final int MSG_LOAD_CACHED_QUOTAS_FROM_FILE = 101;
/**
* By only triggering a re-calculation after the storage has changed sizes, we can avoid
* recalculating quotas too often. Minimum change delta defines the percentage of change
* we need to see before we recalculate.
*/
private static final double MINIMUM_CHANGE_DELTA = 0.05;
+ private static final int UNSET = -1;
private static final boolean DEBUG = false;
private final StatFs mStats;
@@ -361,7 +365,6 @@
mStats = new StatFs(Environment.getDataDirectory().getAbsolutePath());
mPreviousBytes = mStats.getFreeBytes();
mMinimumThresholdBytes = mStats.getTotalBytes() * MINIMUM_CHANGE_DELTA;
- // TODO: Load cache quotas from a file to avoid re-doing work.
}
public void handleMessage(Message msg) {
@@ -378,7 +381,26 @@
long bytesDelta = Math.abs(mPreviousBytes - mStats.getFreeBytes());
if (bytesDelta > mMinimumThresholdBytes) {
mPreviousBytes = mStats.getFreeBytes();
- recalculateQuotas();
+ recalculateQuotas(getInitializedStrategy());
+ }
+ sendEmptyMessageDelayed(MSG_CHECK_STORAGE_DELTA, DELAY_IN_MILLIS);
+ break;
+ }
+ case MSG_LOAD_CACHED_QUOTAS_FROM_FILE: {
+ CacheQuotaStrategy strategy = getInitializedStrategy();
+ mPreviousBytes = UNSET;
+ try {
+ mPreviousBytes = strategy.setupQuotasFromFile();
+ } catch (IOException e) {
+ Slog.e(TAG, "An error occurred while reading the cache quota file.", e);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "Cache quota XML file is malformed?", e);
+ }
+
+ // If errors occurred getting the quotas from disk, let's re-calc them.
+ if (mPreviousBytes < 0) {
+ mPreviousBytes = mStats.getFreeBytes();
+ recalculateQuotas(strategy);
}
sendEmptyMessageDelayed(MSG_CHECK_STORAGE_DELTA, DELAY_IN_MILLIS);
break;
@@ -391,17 +413,18 @@
}
}
- private void recalculateQuotas() {
+ private void recalculateQuotas(CacheQuotaStrategy strategy) {
if (DEBUG) {
Slog.v(TAG, ">>> recalculating quotas ");
}
+ strategy.recalculateQuotas();
+ }
+
+ private CacheQuotaStrategy getInitializedStrategy() {
UsageStatsManagerInternal usageStatsManager =
LocalServices.getService(UsageStatsManagerInternal.class);
- CacheQuotaStrategy strategy = new CacheQuotaStrategy(
- mContext, usageStatsManager, mInstaller);
- // TODO: Save cache quotas to an XML file.
- strategy.recalculateQuotas();
+ return new CacheQuotaStrategy(mContext, usageStatsManager, mInstaller);
}
}
diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp
index ffc2de1..ec3d75e 100644
--- a/tools/aapt2/flatten/XmlFlattener_test.cpp
+++ b/tools/aapt2/flatten/XmlFlattener_test.cpp
@@ -76,7 +76,7 @@
<View xmlns:test="http://com.test"
attr="hey">
<Layout test:hello="hi" />
- <Layout>Some text</Layout>
+ <Layout>Some text\\</Layout>
</View>)EOF");
android::ResXMLTree tree;
@@ -128,7 +128,7 @@
ASSERT_EQ(tree.next(), android::ResXMLTree::TEXT);
const char16_t* text = tree.getText(&len);
- EXPECT_EQ(StringPiece16(text, len), u"Some text");
+ EXPECT_EQ(StringPiece16(text, len), u"Some text\\");
ASSERT_EQ(tree.next(), android::ResXMLTree::END_TAG);
ASSERT_EQ(tree.getElementNamespace(&len), nullptr);
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index f8fa80e..7210d21 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -164,6 +164,7 @@
StringBuilder& Append(const android::StringPiece& str);
const std::string& ToString() const;
const std::string& Error() const;
+ bool IsEmpty() const;
// When building StyledStrings, we need UTF-16 indices into the string,
// which is what the Java layer expects when dealing with java
@@ -185,6 +186,8 @@
inline const std::string& StringBuilder::Error() const { return error_; }
+inline bool StringBuilder::IsEmpty() const { return str_.empty(); }
+
inline size_t StringBuilder::Utf16Len() const { return utf16_len_; }
inline StringBuilder::operator bool() const { return error_.empty(); }
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index fab2f19..d9ea1bc 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -18,7 +18,6 @@
#include <expat.h>
-#include <cassert>
#include <memory>
#include <stack>
#include <string>
@@ -41,6 +40,8 @@
std::unique_ptr<xml::Node> root;
std::stack<xml::Node*> node_stack;
std::string pending_comment;
+ std::unique_ptr<xml::Text> last_text_node;
+ util::StringBuilder pending_text;
};
/**
@@ -62,6 +63,19 @@
}
}
+static void FinishPendingText(Stack* stack) {
+ if (stack->last_text_node != nullptr) {
+ if (!stack->pending_text.IsEmpty()) {
+ stack->last_text_node->text = stack->pending_text.ToString();
+ stack->pending_text = {};
+ stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
+ } else {
+ // Drop an empty text node.
+ stack->last_text_node = nullptr;
+ }
+ }
+}
+
static void AddToStack(Stack* stack, XML_Parser parser,
std::unique_ptr<Node> node) {
node->line_number = XML_GetCurrentLineNumber(parser);
@@ -83,6 +97,7 @@
const char* uri) {
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
+ FinishPendingText(stack);
std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
if (prefix) {
@@ -99,6 +114,7 @@
static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix) {
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
+ FinishPendingText(stack);
CHECK(!stack->node_stack.empty());
stack->node_stack.pop();
@@ -113,6 +129,7 @@
const char** attrs) {
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
+ FinishPendingText(stack);
std::unique_ptr<Element> el = util::make_unique<Element>();
SplitName(name, &el->namespace_uri, &el->name);
@@ -120,7 +137,9 @@
while (*attrs) {
Attribute attribute;
SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
- attribute.value = *attrs++;
+ util::StringBuilder builder;
+ builder.Append(*attrs++);
+ attribute.value = builder.ToString();
// Insert in sorted order.
auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(),
@@ -135,41 +154,38 @@
static void XMLCALL EndElementHandler(void* user_data, const char* name) {
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
+ FinishPendingText(stack);
CHECK(!stack->node_stack.empty());
// stack->nodeStack.top()->comment = std::move(stack->pendingComment);
stack->node_stack.pop();
}
-static void XMLCALL CharacterDataHandler(void* user_data, const char* s,
- int len) {
+static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
- if (!s || len <= 0) {
+ const StringPiece str(s, len);
+ if (str.empty()) {
return;
}
// See if we can just append the text to a previous text node.
- if (!stack->node_stack.empty()) {
- Node* currentParent = stack->node_stack.top();
- if (!currentParent->children.empty()) {
- Node* last_child = currentParent->children.back().get();
- if (Text* text = NodeCast<Text>(last_child)) {
- text->text.append(s, len);
- return;
- }
- }
+ if (stack->last_text_node != nullptr) {
+ stack->pending_text.Append(str);
+ return;
}
- std::unique_ptr<Text> text = util::make_unique<Text>();
- text->text.assign(s, len);
- AddToStack(stack, parser, std::move(text));
+ stack->last_text_node = util::make_unique<Text>();
+ stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
+ stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
+ stack->pending_text.Append(str);
}
static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
+ FinishPendingText(stack);
if (!stack->pending_comment.empty()) {
stack->pending_comment += '\n';
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index a414afe..0fc3cec6 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -49,4 +49,23 @@
EXPECT_EQ(ns->namespace_prefix, "android");
}
+TEST(XmlDomTest, HandleEscapes) {
+ std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(
+ R"EOF(<shortcode pattern="\\d{5}">\\d{5}</shortcode>)EOF");
+
+ xml::Element* el = xml::FindRootElement(doc->root.get());
+ ASSERT_NE(nullptr, el);
+
+ xml::Attribute* attr = el->FindAttribute({}, "pattern");
+ ASSERT_NE(nullptr, attr);
+
+ EXPECT_EQ("\\d{5}", attr->value);
+
+ ASSERT_EQ(1u, el->children.size());
+
+ xml::Text* text = xml::NodeCast<xml::Text>(el->children[0].get());
+ ASSERT_NE(nullptr, text);
+ EXPECT_EQ("\\d{5}", text->text);
+}
+
} // namespace aapt
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index a4ab64f..a1099f8 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -376,7 +376,9 @@
/**
* Flag indicating if this network is provided by a home Passpoint provider or a roaming
- * Passpoint provider.
+ * Passpoint provider. This flag will be {@code true} if this network is provided by
+ * a home Passpoint provider and {@code false} if is provided by a roaming Passpoint provider
+ * or is a non-Passpoint network.
*/
public boolean isHomeProviderNetwork;