Merge "Update doc of ACTION_PROVISION_MANAGED_DEVICE" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index d5685a6..3e0a1b3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4000,6 +4000,7 @@
public deprecated class AssistContent {
ctor public AssistContent();
method public android.content.ClipData getClipData();
+ method public android.os.Bundle getExtras();
method public android.net.Uri getWebUri();
method public boolean isAppProvidedIntent();
method public void setClipData(android.content.ClipData);
@@ -4058,6 +4059,7 @@
}
public static class AssistStructure.WindowNode {
+ method public int getDisplayId();
method public int getHeight();
method public int getLeft();
method public android.app.AssistStructure.ViewNode getRootViewNode();
@@ -8457,8 +8459,6 @@
field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
field public static final int NO_MATCH_DATA = -2; // 0xfffffffe
field public static final int NO_MATCH_TYPE = -1; // 0xffffffff
- field public static final java.lang.String SCHEME_HTTP = "http";
- field public static final java.lang.String SCHEME_HTTPS = "https";
field public static final int SYSTEM_HIGH_PRIORITY = 1000; // 0x3e8
field public static final int SYSTEM_LOW_PRIORITY = -1000; // 0xfffffc18
}
@@ -37054,6 +37054,7 @@
public abstract class ViewStructure {
ctor public ViewStructure();
+ method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewAssistStructure asyncNewChild(int);
method public abstract int getChildCount();
diff --git a/api/system-current.txt b/api/system-current.txt
index fbf8d1d..a61b9fb53 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4096,6 +4096,7 @@
public deprecated class AssistContent {
ctor public AssistContent();
method public android.content.ClipData getClipData();
+ method public android.os.Bundle getExtras();
method public android.net.Uri getWebUri();
method public boolean isAppProvidedIntent();
method public void setClipData(android.content.ClipData);
@@ -4154,6 +4155,7 @@
}
public static class AssistStructure.WindowNode {
+ method public int getDisplayId();
method public int getHeight();
method public int getLeft();
method public android.app.AssistStructure.ViewNode getRootViewNode();
@@ -8689,8 +8691,6 @@
field public static final int NO_MATCH_CATEGORY = -4; // 0xfffffffc
field public static final int NO_MATCH_DATA = -2; // 0xfffffffe
field public static final int NO_MATCH_TYPE = -1; // 0xffffffff
- field public static final java.lang.String SCHEME_HTTP = "http";
- field public static final java.lang.String SCHEME_HTTPS = "https";
field public static final int SYSTEM_HIGH_PRIORITY = 1000; // 0x3e8
field public static final int SYSTEM_LOW_PRIORITY = -1000; // 0xfffffc18
}
@@ -39331,6 +39331,7 @@
public abstract class ViewStructure {
ctor public ViewStructure();
+ method public abstract int addChildCount(int);
method public abstract void asyncCommit();
method public abstract android.view.ViewAssistStructure asyncNewChild(int);
method public abstract int getChildCount();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index da345a6..b65593d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2812,7 +2812,9 @@
* continues running even if the process is killed and restarted. To remove the watch,
* use {@link #clearWatchHeapLimit()}.
*
- * <p>This API only work if running on a debuggable (userdebug or eng) build.</p>
+ * <p>This API only work if the calling process has been marked as
+ * {@link ApplicationInfo#FLAG_DEBUGGABLE} or this is running on a debuggable
+ * (userdebug or eng) build.</p>
*
* <p>Callers can optionally implement {@link #ACTION_REPORT_HEAP_LIMIT} to directly
* handle heap limit reports themselves.</p>
diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java
index 173b237..0df9ce5 100644
--- a/core/java/android/app/AssistContent.java
+++ b/core/java/android/app/AssistContent.java
@@ -35,6 +35,7 @@
private Intent mIntent;
private ClipData mClipData;
private Uri mUri;
+ private final Bundle mExtras;
/**
* @hide
@@ -53,6 +54,7 @@
}
public AssistContent() {
+ mExtras = new Bundle();
}
/**
@@ -143,6 +145,13 @@
return mUri;
}
+ /**
+ * Return Bundle for extra vendor-specific data that can be modified and examined.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
/** @hide */
public AssistContent(Parcel in) {
if (in.readInt() != 0) {
@@ -155,6 +164,7 @@
mUri = Uri.CREATOR.createFromParcel(in);
}
mIsAppProvidedIntent = in.readInt() == 1;
+ mExtras = in.readBundle();
}
/** @hide */
@@ -178,5 +188,6 @@
dest.writeInt(0);
}
dest.writeInt(mIsAppProvidedIntent ? 1 : 0);
+ dest.writeBundle(mExtras);
}
}
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
index 0f69817..7f6dae5 100644
--- a/core/java/android/app/AssistStructure.java
+++ b/core/java/android/app/AssistStructure.java
@@ -131,6 +131,7 @@
final int mWidth;
final int mHeight;
final CharSequence mTitle;
+ final int mDisplayId;
final ViewNode mRoot;
WindowNode(AssistStructure assist, ViewRootImpl root) {
@@ -142,6 +143,7 @@
mWidth = rect.width();
mHeight = rect.height();
mTitle = root.getTitle();
+ mDisplayId = root.getDisplayId();
mRoot = new ViewNode();
ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
if ((root.getWindowFlags()&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
@@ -160,6 +162,7 @@
mWidth = in.readInt();
mHeight = in.readInt();
mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mDisplayId = in.readInt();
mRoot = new ViewNode(in, preader);
}
@@ -169,29 +172,58 @@
out.writeInt(mWidth);
out.writeInt(mHeight);
TextUtils.writeToParcel(mTitle, out, 0);
+ out.writeInt(mDisplayId);
mRoot.writeToParcel(out, pwriter);
}
+ /**
+ * Returns the left edge of the window, in pixels, relative to the left
+ * edge of the screen.
+ */
public int getLeft() {
return mX;
}
+ /**
+ * Returns the top edge of the window, in pixels, relative to the top
+ * edge of the screen.
+ */
public int getTop() {
return mY;
}
+ /**
+ * Returns the total width of the window in pixels.
+ */
public int getWidth() {
return mWidth;
}
+ /**
+ * Returns the total height of the window in pixels.
+ */
public int getHeight() {
return mHeight;
}
+ /**
+ * Returns the title associated with the window, if it has one.
+ */
public CharSequence getTitle() {
return mTitle;
}
+ /**
+ * Returns the ID of the display this window is on, for use with
+ * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
+ * Returns the {@link ViewNode} containing the root content of the window.
+ */
public ViewNode getRootViewNode() {
return mRoot;
}
@@ -325,146 +357,288 @@
}
}
+ /**
+ * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
+ */
public int getId() {
return mId;
}
+ /**
+ * If {@link #getId()} is a resource identifier, this is the package name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
public String getIdPackage() {
return mIdPackage;
}
+ /**
+ * If {@link #getId()} is a resource identifier, this is the type name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
public String getIdType() {
return mIdType;
}
+ /**
+ * If {@link #getId()} is a resource identifier, this is the entry name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
public String getIdEntry() {
return mIdEntry;
}
+ /**
+ * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
+ */
public int getLeft() {
return mX;
}
+ /**
+ * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
+ */
public int getTop() {
return mY;
}
+ /**
+ * Returns the current X scroll offset of this view, as per
+ * {@link android.view.View#getScrollX() View.getScrollX()}.
+ */
public int getScrollX() {
return mScrollX;
}
+ /**
+ * Returns the current Y scroll offset of this view, as per
+ * {@link android.view.View#getScrollX() View.getScrollY()}.
+ */
public int getScrollY() {
return mScrollY;
}
+ /**
+ * Returns the width of this view, in pixels.
+ */
public int getWidth() {
return mWidth;
}
+ /**
+ * Returns the height of this view, in pixels.
+ */
public int getHeight() {
return mHeight;
}
+ /**
+ * Returns the visibility mode of this view, as per
+ * {@link android.view.View#getVisibility() View.getVisibility()}.
+ */
public int getVisibility() {
return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
}
+ /**
+ * Returns true if assist data has been blocked starting at this node in the hierarchy.
+ */
public boolean isAssistBlocked() {
return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0;
}
+ /**
+ * Returns true if this node is in an enabled state.
+ */
public boolean isEnabled() {
return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
}
+ /**
+ * Returns true if this node is clickable by the user.
+ */
public boolean isClickable() {
return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
}
+ /**
+ * Returns true if this node can take input focus.
+ */
public boolean isFocusable() {
return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
}
+ /**
+ * Returns true if this node currently had input focus at the time that the
+ * structure was collected.
+ */
public boolean isFocused() {
return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
}
+ /**
+ * Returns true if this node currently had accessibility focus at the time that the
+ * structure was collected.
+ */
public boolean isAccessibilityFocused() {
return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
}
+ /**
+ * Returns true if this node represents something that is checkable by the user.
+ */
public boolean isCheckable() {
return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
}
+ /**
+ * Returns true if this node is currently in a checked state.
+ */
public boolean isChecked() {
return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
}
+ /**
+ * Returns true if this node has currently been selected by the user.
+ */
public boolean isSelected() {
return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
}
+ /**
+ * Returns true if this node has currently been activated by the user.
+ */
public boolean isActivated() {
return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
}
+ /**
+ * Returns true if this node is something the user can perform a long click/press on.
+ */
public boolean isLongClickable() {
return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
}
+ /**
+ * Returns true if this node is something the user can perform a context click on.
+ */
public boolean isContextClickable() {
return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
}
+ /**
+ * Returns the class name of the node's implementation, indicating its behavior.
+ * For example, a button will report "android.widget.Button" meaning it behaves
+ * like a {@link android.widget.Button}.
+ */
public String getClassName() {
return mClassName;
}
+ /**
+ * Returns any content description associated with the node, which semantically describes
+ * its purpose for accessibility and other uses.
+ */
public CharSequence getContentDescription() {
return mContentDescription;
}
+ /**
+ * Returns any text associated with the node that is displayed to the user, or null
+ * if there is none.
+ */
public CharSequence getText() {
return mText != null ? mText.mText : null;
}
+ /**
+ * If {@link #getText()} is non-null, this is where the current selection starts.
+ */
public int getTextSelectionStart() {
return mText != null ? mText.mTextSelectionStart : -1;
}
+ /**
+ * If {@link #getText()} is non-null, this is where the current selection starts.
+ * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
+ * indicating the cursor position.
+ */
public int getTextSelectionEnd() {
return mText != null ? mText.mTextSelectionEnd : -1;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text color associated with it.
+ * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned.
+ * Note that the text may also contain style spans that modify the color of specific
+ * parts of the text.
+ */
public int getTextColor() {
return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text background color associated
+ * with it.
+ * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
+ * Note that the text may also contain style spans that modify the color of specific
+ * parts of the text.
+ */
public int getTextBackgroundColor() {
return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
+ * with it.
+ * Note that the text may also contain style spans that modify the size of specific
+ * parts of the text.
+ */
public float getTextSize() {
return mText != null ? mText.mTextSize : 0;
}
+ /**
+ * If {@link #getText()} is non-null, this is the main text style associated
+ * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD},
+ * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or
+ * {@link #TEXT_STYLE_UNDERLINE}.
+ * Note that the text may also contain style spans that modify the style of specific
+ * parts of the text.
+ */
public int getTextStyle() {
return mText != null ? mText.mTextStyle : 0;
}
+ /**
+ * Return additional hint text associated with the node; this is typically used with
+ * a node that takes user input, describing to the user what the input means.
+ */
public String getHint() {
return mText != null ? mText.mHint : null;
}
+ /**
+ * Return a Bundle containing optional vendor-specific extension information.
+ */
public Bundle getExtras() {
return mExtras;
}
+ /**
+ * Return the number of children this node has.
+ */
public int getChildCount() {
return mChildren != null ? mChildren.length : 0;
}
+ /**
+ * Return a child of this node, given an index value from 0 to
+ * {@link #getChildCount()}-1.
+ */
public ViewNode getChildAt(int index) {
return mChildren[index];
}
@@ -663,6 +837,19 @@
}
@Override
+ public int addChildCount(int num) {
+ if (mNode.mChildren == null) {
+ setChildCount(num);
+ return 0;
+ }
+ final int start = mNode.mChildren.length;
+ ViewNode[] newArray = new ViewNode[start + num];
+ System.arraycopy(mNode.mChildren, 0, newArray, 0, start);
+ mNode.mChildren = newArray;
+ return start;
+ }
+
+ @Override
public int getChildCount() {
return mNode.mChildren != null ? mNode.mChildren.length : 0;
}
@@ -801,6 +988,9 @@
return assistBundle.getParcelable(ASSIST_KEY);
}
+ /**
+ * Return the activity this AssistStructure came from.
+ */
public ComponentName getActivityComponent() {
ensureData();
return mActivityComponent;
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 2ed8b0f..5327646 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -418,7 +418,7 @@
private int mNotificationVisibility = VISIBILITY_VISIBLE;
/**
- * @param uri the HTTP URI to download.
+ * @param uri the HTTP or HTTPS URI to download.
*/
public Request(Uri uri) {
if (uri == null) {
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index e15ac94..d12595f 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -16,6 +16,8 @@
package android.content;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
@@ -30,6 +32,7 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
@@ -109,14 +112,19 @@
}
/** See {@link ContentProvider#query ContentProvider.query} */
- public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) throws RemoteException {
+ public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder) throws RemoteException {
return query(url, projection, selection, selectionArgs, sortOrder, null);
}
/** See {@link ContentProvider#query ContentProvider.query} */
- public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
- String sortOrder, CancellationSignal cancellationSignal) throws RemoteException {
+ public @Nullable Cursor query(@NonNull Uri url, @Nullable String[] projection,
+ @Nullable String selection, @Nullable String[] selectionArgs,
+ @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
ICancellationSignal remoteCancellationSignal = null;
@@ -138,7 +146,9 @@
}
/** See {@link ContentProvider#getType ContentProvider.getType} */
- public String getType(Uri url) throws RemoteException {
+ public @Nullable String getType(@NonNull Uri url) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.getType(url);
@@ -153,7 +163,11 @@
}
/** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
- public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
+ public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
+
beforeRemote();
try {
return mContentProvider.getStreamTypes(url, mimeTypeFilter);
@@ -168,7 +182,9 @@
}
/** See {@link ContentProvider#canonicalize} */
- public final Uri canonicalize(Uri url) throws RemoteException {
+ public final @Nullable Uri canonicalize(@NonNull Uri url) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.canonicalize(mPackageName, url);
@@ -183,7 +199,9 @@
}
/** See {@link ContentProvider#uncanonicalize} */
- public final Uri uncanonicalize(Uri url) throws RemoteException {
+ public final @Nullable Uri uncanonicalize(@NonNull Uri url) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.uncanonicalize(mPackageName, url);
@@ -198,7 +216,10 @@
}
/** See {@link ContentProvider#insert ContentProvider.insert} */
- public Uri insert(Uri url, ContentValues initialValues) throws RemoteException {
+ public @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues initialValues)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.insert(mPackageName, url, initialValues);
@@ -213,7 +234,11 @@
}
/** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
- public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
+ public int bulkInsert(@NonNull Uri url, @NonNull ContentValues[] initialValues)
+ throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(initialValues, "initialValues");
+
beforeRemote();
try {
return mContentProvider.bulkInsert(mPackageName, url, initialValues);
@@ -228,8 +253,10 @@
}
/** See {@link ContentProvider#delete ContentProvider.delete} */
- public int delete(Uri url, String selection, String[] selectionArgs)
- throws RemoteException {
+ public int delete(@NonNull Uri url, @Nullable String selection,
+ @Nullable String[] selectionArgs) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
@@ -244,8 +271,10 @@
}
/** See {@link ContentProvider#update ContentProvider.update} */
- public int update(Uri url, ContentValues values, String selection,
- String[] selectionArgs) throws RemoteException {
+ public int update(@NonNull Uri url, @Nullable ContentValues values, @Nullable String selection,
+ @Nullable String[] selectionArgs) throws RemoteException {
+ Preconditions.checkNotNull(url, "url");
+
beforeRemote();
try {
return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
@@ -266,7 +295,7 @@
* you use the {@link ContentResolver#openFileDescriptor
* ContentResolver.openFileDescriptor} API instead.
*/
- public ParcelFileDescriptor openFile(Uri url, String mode)
+ public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode)
throws RemoteException, FileNotFoundException {
return openFile(url, mode, null);
}
@@ -278,8 +307,11 @@
* you use the {@link ContentResolver#openFileDescriptor
* ContentResolver.openFileDescriptor} API instead.
*/
- public ParcelFileDescriptor openFile(Uri url, String mode, CancellationSignal signal)
- throws RemoteException, FileNotFoundException {
+ public @Nullable ParcelFileDescriptor openFile(@NonNull Uri url, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(mode, "mode");
+
beforeRemote();
try {
ICancellationSignal remoteSignal = null;
@@ -306,7 +338,7 @@
* you use the {@link ContentResolver#openAssetFileDescriptor
* ContentResolver.openAssetFileDescriptor} API instead.
*/
- public AssetFileDescriptor openAssetFile(Uri url, String mode)
+ public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode)
throws RemoteException, FileNotFoundException {
return openAssetFile(url, mode, null);
}
@@ -318,8 +350,11 @@
* you use the {@link ContentResolver#openAssetFileDescriptor
* ContentResolver.openAssetFileDescriptor} API instead.
*/
- public AssetFileDescriptor openAssetFile(Uri url, String mode, CancellationSignal signal)
- throws RemoteException, FileNotFoundException {
+ public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri url, @NonNull String mode,
+ @Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
+ Preconditions.checkNotNull(url, "url");
+ Preconditions.checkNotNull(mode, "mode");
+
beforeRemote();
try {
ICancellationSignal remoteSignal = null;
@@ -340,15 +375,19 @@
}
/** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
- public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
- String mimeType, Bundle opts) throws RemoteException, FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mimeType, @Nullable Bundle opts)
+ throws RemoteException, FileNotFoundException {
return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
}
/** See {@link ContentProvider#openTypedAssetFile ContentProvider.openTypedAssetFile} */
- public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
- String mimeType, Bundle opts, CancellationSignal signal)
- throws RemoteException, FileNotFoundException {
+ public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
+ @NonNull String mimeType, @Nullable Bundle opts, @Nullable CancellationSignal signal)
+ throws RemoteException, FileNotFoundException {
+ Preconditions.checkNotNull(uri, "uri");
+ Preconditions.checkNotNull(mimeType, "mimeType");
+
beforeRemote();
try {
ICancellationSignal remoteSignal = null;
@@ -370,8 +409,11 @@
}
/** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
- throws RemoteException, OperationApplicationException {
+ public @NonNull ContentProviderResult[] applyBatch(
+ @NonNull ArrayList<ContentProviderOperation> operations)
+ throws RemoteException, OperationApplicationException {
+ Preconditions.checkNotNull(operations, "operations");
+
beforeRemote();
try {
return mContentProvider.applyBatch(mPackageName, operations);
@@ -386,7 +428,10 @@
}
/** See {@link ContentProvider#call(String, String, Bundle)} */
- public Bundle call(String method, String arg, Bundle extras) throws RemoteException {
+ public @Nullable Bundle call(@NonNull String method, @Nullable String arg,
+ @Nullable Bundle extras) throws RemoteException {
+ Preconditions.checkNotNull(method, "method");
+
beforeRemote();
try {
return mContentProvider.call(mPackageName, method, arg, extras);
@@ -436,7 +481,7 @@
* @return If the associated {@link ContentProvider} is local, returns it.
* Otherwise returns null.
*/
- public ContentProvider getLocalContentProvider() {
+ public @Nullable ContentProvider getLocalContentProvider() {
return ContentProvider.coerceToLocalContentProvider(mContentProvider);
}
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 33c0b87..08c5236 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -254,12 +254,14 @@
* HTTP scheme.
*
* @see #addDataScheme(String)
+ * @hide
*/
public static final String SCHEME_HTTP = "http";
/**
* HTTPS scheme.
*
* @see #addDataScheme(String)
+ * @hide
*/
public static final String SCHEME_HTTPS = "https";
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index a6efc58..f76192e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1177,8 +1177,13 @@
public static final int EVENT_ALARM = 0x000e;
// Record that we have decided we need to collect new stats data.
public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000f;
+ // Event for a package becoming inactive due to being unused for a period of time.
+ public static final int EVENT_PACKAGE_INACTIVE = 0x0010;
+ // Event for a package becoming active due to an interaction.
+ public static final int EVENT_PACKAGE_ACTIVE = 0x0011;
+
// Number of event types.
- public static final int EVENT_COUNT = 0x0010;
+ public static final int EVENT_COUNT = 0x0012;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -1835,12 +1840,12 @@
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
- "motion", "active", "pkginst", "pkgunin", "alarm", "stats"
+ "motion", "active", "pkginst", "pkgunin", "alarm", "stats", "inactive", "active"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
- "Esm", "Eac", "Epi", "Epu", "Eal", "Est"
+ "Esm", "Eac", "Epi", "Epu", "Eal", "Est", "Eai", "Eaa"
};
/**
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 8b18f32..7a1aa1e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -878,7 +878,10 @@
* off network access to apps. You can monitor for changes to this state with
* {@link #ACTION_DEVICE_IDLE_MODE_CHANGED}.
*
- * @return Returns true if currently in low power mode, else false.
+ * @return Returns true if currently in active device idle mode, else false. This is
+ * when idle mode restrictions are being actively applied; it will return false if the
+ * device is in a long-term idle mode but currently running a maintenance window where
+ * restrictions have been lifted.
*/
public boolean isDeviceIdleMode() {
try {
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
index 9eb22ef..890ea3d 100644
--- a/core/java/android/speech/tts/UtteranceProgressListener.java
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -61,16 +61,16 @@
/**
* Called when an utterance has been stopped while in progress or flushed from the
- * synthesis queue. This can happen if client calls {@link TextToSpeech#stop()}
- * or use {@link TextToSpeech#QUEUE_FLUSH} as an argument in
+ * synthesis queue. This can happen if a client calls {@link TextToSpeech#stop()}
+ * or uses {@link TextToSpeech#QUEUE_FLUSH} as an argument with the
* {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
*
* @param utteranceId the utterance ID of the utterance.
- * @param isStarted If true, then utterance was interrupted while being synthesized
- * and it's output is incomplete. If it's false, then utterance was flushed
+ * @param interrupted If true, then the utterance was interrupted while being synthesized
+ * and its output is incomplete. If false, then the utterance was flushed
* before the synthesis started.
*/
- public void onStop(String utteranceId, boolean isStarted) {
+ public void onStop(String utteranceId, boolean interrupted) {
}
/**
@@ -99,7 +99,7 @@
}
@Override
- public void onStop(String utteranceId, boolean isStarted) {
+ public void onStop(String utteranceId, boolean interrupted) {
listener.onUtteranceCompleted(utteranceId);
}
};
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d2ee0e5..0df8ea9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17175,21 +17175,6 @@
}
/**
- * If the view has a ColorDrawable background, returns the color of that
- * drawable.
- *
- * @return The color of the ColorDrawable background, if set, otherwise 0.
- * @hide
- */
- @ColorInt
- public int getBackgroundColor() {
- if (mBackground instanceof ColorDrawable) {
- return ((ColorDrawable) mBackground).getColor();
- }
- return 0;
- }
-
- /**
* Set the background to a given resource. The resource should refer to
* a Drawable object or 0 to remove the background.
* @param resid The identifier of the resource.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e2f42db..8b57d96 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -663,6 +663,10 @@
return mWindowAttributes.flags;
}
+ public int getDisplayId() {
+ return mDisplay.getDisplayId();
+ }
+
public CharSequence getTitle() {
return mWindowAttributes.getTitle();
}
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 8ceb166..d06cd83 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -201,6 +201,17 @@
public abstract void setChildCount(int num);
/**
+ * Add to this view's child count. This increases the current child count by
+ * <var>num</var> children beyond what was last set by {@link #setChildCount}
+ * or {@link #addChildCount}. The index at which the new child starts in the child
+ * array is returned.
+ *
+ * @param num The number of new children to add.
+ * @return Returns the index in the child array at which the new children start.
+ */
+ public abstract int addChildCount(int num);
+
+ /**
* Return the child count as set by {@link #setChildCount}.
*/
public abstract int getChildCount();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e43237a..cf6a018 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1162,6 +1162,10 @@
// We do not hide the span controllers, since they can be added when a new text is
// inserted into the text view (voice IME).
hideCursorControllers();
+ // Reset drag accelerator.
+ if (mSelectionModifierCursorController != null) {
+ mSelectionModifierCursorController.resetTouchOffsets();
+ }
stopTextActionMode();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 353901c..78b5d5d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8790,7 +8790,8 @@
@Override
public void onProvideStructure(ViewStructure structure) {
super.onProvideStructure(structure);
- final boolean isPassword = hasPasswordTransformationMethod();
+ final boolean isPassword = hasPasswordTransformationMethod()
+ || isPasswordInputType(getInputType());
if (!isPassword) {
structure.setText(getText(), getSelectionStart(), getSelectionEnd());
@@ -9244,25 +9245,25 @@
/**
* If provided, this ActionMode.Callback will be used to create the ActionMode when text
* insertion is initiated in this View.
- *
* The standard implementation populates the menu with a subset of Select All,
* Paste and Replace actions, depending on what this View supports.
*
- * A custom implementation can add new entries in the default menu in its
- * {@link android.view.ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method. The
- * default actions can also be removed from the menu using
+ * <p>A custom implementation can add new entries in the default menu in its
+ * {@link android.view.ActionMode.Callback#onPrepareActionMode(android.view.ActionMode,
+ * android.view.Menu)} method. The default actions can also be removed from the menu using
* {@link android.view.Menu#removeItem(int)} and passing {@link android.R.id#selectAll},
- * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.
+ * {@link android.R.id#paste} or {@link android.R.id#replaceText} ids as parameters.</p>
*
- * Returning false from
- * {@link android.view.ActionMode.Callback#onCreateActionMode(ActionMode, Menu)} will prevent
- * the action mode from being started.
+ * <p>Returning false from
+ * {@link android.view.ActionMode.Callback#onCreateActionMode(android.view.ActionMode,
+ * android.view.Menu)} will prevent the action mode from being started.</p>
*
- * Action click events should be handled by the custom implementation of
- * {@link android.view.ActionMode.Callback#onActionItemClicked(ActionMode, MenuItem)}.
+ * <p>Action click events should be handled by the custom implementation of
+ * {@link android.view.ActionMode.Callback#onActionItemClicked(android.view.ActionMode,
+ * android.view.MenuItem)}.</p>
*
- * Note that text insertion mode is not started when a TextView receives focus and the
- * {@link android.R.attr#selectAllOnFocus} flag has been set.
+ * <p>Note that text insertion mode is not started when a TextView receives focus and the
+ * {@link android.R.attr#selectAllOnFocus} flag has been set.</p>
*/
public void setCustomInsertionActionModeCallback(ActionMode.Callback actionModeCallback) {
createEditorIfNeeded();
diff --git a/core/res/res/drawable/floating_popup_background.xml b/core/res/res/drawable/floating_popup_background_dark.xml
similarity index 87%
copy from core/res/res/drawable/floating_popup_background.xml
copy to core/res/res/drawable/floating_popup_background_dark.xml
index b6700b3..ded1137 100644
--- a/core/res/res/drawable/floating_popup_background.xml
+++ b/core/res/res/drawable/floating_popup_background_dark.xml
@@ -16,8 +16,8 @@
*/
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?attr/colorBackgroundFloating" />
+ android:shape="rectangle">
+ <solid android:color="@color/background_floating_material_dark" />
<corners android:radius="2dp" />
</shape>
diff --git a/core/res/res/drawable/floating_popup_background.xml b/core/res/res/drawable/floating_popup_background_light.xml
similarity index 91%
rename from core/res/res/drawable/floating_popup_background.xml
rename to core/res/res/drawable/floating_popup_background_light.xml
index b6700b3..9c7a886 100644
--- a/core/res/res/drawable/floating_popup_background.xml
+++ b/core/res/res/drawable/floating_popup_background_light.xml
@@ -17,7 +17,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?attr/colorBackgroundFloating" />
+ <solid android:color="@color/background_floating_material_light" />
<corners android:radius="2dp" />
</shape>
diff --git a/core/res/res/drawable/ic_ab_back_material_dark.xml b/core/res/res/drawable/ic_ab_back_material_dark.xml
new file mode 100644
index 0000000..7cdd139
--- /dev/null
+++ b/core/res/res/drawable/ic_ab_back_material_dark.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:autoMirrored="true"
+ android:tint="@color/secondary_text_material_dark">
+ <path
+ android:pathData="M20,11L7.8,11l5.6,-5.6L12,4l-8,8l8,8l1.4,-1.4L7.8,13L20,13L20,11z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/ic_ab_back_material_light.xml b/core/res/res/drawable/ic_ab_back_material_light.xml
new file mode 100644
index 0000000..65dab81
--- /dev/null
+++ b/core/res/res/drawable/ic_ab_back_material_light.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:autoMirrored="true"
+ android:tint="@color/secondary_text_material_light">
+ <path
+ android:pathData="M20,11L7.8,11l5.6,-5.6L12,4l-8,8l8,8l1.4,-1.4L7.8,13L20,13L20,11z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_material.xml b/core/res/res/drawable/ic_menu_moreoverflow_material.xml
index 502ad69..3f53451 100644
--- a/core/res/res/drawable/ic_menu_moreoverflow_material.xml
+++ b/core/res/res/drawable/ic_menu_moreoverflow_material.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_material_dark.xml b/core/res/res/drawable/ic_menu_moreoverflow_material_dark.xml
new file mode 100644
index 0000000..fa350a6
--- /dev/null
+++ b/core/res/res/drawable/ic_menu_moreoverflow_material_dark.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="@color/secondary_text_material_dark">
+ <path
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/ic_menu_moreoverflow_material_light.xml b/core/res/res/drawable/ic_menu_moreoverflow_material_light.xml
new file mode 100644
index 0000000..7af234f
--- /dev/null
+++ b/core/res/res/drawable/ic_menu_moreoverflow_material_light.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="@color/secondary_text_material_light">
+ <path
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2S10.9,8 12,8zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,10 12,10zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2c1.1,0 2,-0.9 2,-2S13.1,16 12,16z"
+ android:fillColor="@color/white"/>
+</vector>
diff --git a/core/res/res/drawable/item_background_borderless_material_dark.xml b/core/res/res/drawable/item_background_borderless_material_dark.xml
new file mode 100644
index 0000000..685c52a
--- /dev/null
+++ b/core/res/res/drawable/item_background_borderless_material_dark.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_dark" />
diff --git a/core/res/res/drawable/item_background_borderless_material_light.xml b/core/res/res/drawable/item_background_borderless_material_light.xml
new file mode 100644
index 0000000..3ef6674
--- /dev/null
+++ b/core/res/res/drawable/item_background_borderless_material_light.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 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
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_light" />
diff --git a/core/res/res/drawable/item_background_material_dark.xml b/core/res/res/drawable/item_background_material_dark.xml
new file mode 100644
index 0000000..06eb531
--- /dev/null
+++ b/core/res/res/drawable/item_background_material_dark.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_dark">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+</ripple>
diff --git a/core/res/res/drawable/item_background_material_light.xml b/core/res/res/drawable/item_background_material_light.xml
new file mode 100644
index 0000000..2f3d157
--- /dev/null
+++ b/core/res/res/drawable/item_background_material_light.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/ripple_material_light">
+ <item android:id="@id/mask">
+ <color android:color="@color/white" />
+ </item>
+</ripple>
diff --git a/core/res/res/layout/floating_popup_close_overflow_button.xml b/core/res/res/layout/floating_popup_close_overflow_button.xml
index 0dbf7f7..4dae1ae 100644
--- a/core/res/res/layout/floating_popup_close_overflow_button.xml
+++ b/core/res/res/layout/floating_popup_close_overflow_button.xml
@@ -20,6 +20,6 @@
android:layout_height="match_parent"
android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
android:minHeight="@dimen/floating_toolbar_height"
- android:src="?android:attr/actionModeCloseDrawable"
+ android:src="?attr/floatingToolbarCloseDrawable"
android:contentDescription="@string/floating_toolbar_close_overflow_description"
- android:background="?attr/selectableItemBackgroundBorderless" />
+ android:background="?attr/floatingToolbarItemBackgroundBorderlessDrawable" />
diff --git a/core/res/res/layout/floating_popup_container.xml b/core/res/res/layout/floating_popup_container.xml
index f37aee15..63dae44 100644
--- a/core/res/res/layout/floating_popup_container.xml
+++ b/core/res/res/layout/floating_popup_container.xml
@@ -24,4 +24,4 @@
android:elevation="2dp"
android:focusable="true"
android:focusableInTouchMode="true"
- android:background="@drawable/floating_popup_background"/>
+ android:background="?attr/floatingToolbarPopupBackgroundDrawable"/>
diff --git a/core/res/res/layout/floating_popup_menu_button.xml b/core/res/res/layout/floating_popup_menu_button.xml
index b549198..1b58ce5 100644
--- a/core/res/res/layout/floating_popup_menu_button.xml
+++ b/core/res/res/layout/floating_popup_menu_button.xml
@@ -30,5 +30,5 @@
android:fontFamily="sans-serif-medium"
android:textSize="@dimen/floating_toolbar_text_size"
android:textAllCaps="true"
- android:textColor="?attr/colorForeground"
- android:background="?attr/selectableItemBackground" />
+ android:textColor="?attr/floatingToolbarForegroundColor"
+ android:background="?attr/floatingToolbarItemBackgroundDrawable" />
diff --git a/core/res/res/layout/floating_popup_menu_image_button.xml b/core/res/res/layout/floating_popup_menu_image_button.xml
index 07eb7a3..1ba7848 100644
--- a/core/res/res/layout/floating_popup_menu_image_button.xml
+++ b/core/res/res/layout/floating_popup_menu_image_button.xml
@@ -32,5 +32,5 @@
android:paddingEnd="@dimen/floating_toolbar_menu_button_side_padding"
android:paddingBottom="@dimen/floating_toolbar_menu_image_button_vertical_padding"
android:scaleType="centerInside"
- android:background="?attr/selectableItemBackground" />
+ android:background="?attr/floatingToolbarItemBackgroundDrawable" />
</LinearLayout>
diff --git a/core/res/res/layout/floating_popup_open_overflow_button.xml b/core/res/res/layout/floating_popup_open_overflow_button.xml
index 3027565..f6a3e8d 100644
--- a/core/res/res/layout/floating_popup_open_overflow_button.xml
+++ b/core/res/res/layout/floating_popup_open_overflow_button.xml
@@ -24,6 +24,6 @@
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:paddingEnd="4dp"
- android:src="@drawable/ic_menu_moreoverflow_material"
+ android:src="?attr/floatingToolbarOpenDrawable"
android:contentDescription="@string/floating_toolbar_open_overflow_description"
- android:background="?attr/selectableItemBackgroundBorderless" />
+ android:background="?attr/floatingToolbarItemBackgroundBorderlessDrawable" />
diff --git a/core/res/res/layout/floating_popup_overflow_list_item.xml b/core/res/res/layout/floating_popup_overflow_list_item.xml
index 2ff45bb..22f4e68 100644
--- a/core/res/res/layout/floating_popup_overflow_list_item.xml
+++ b/core/res/res/layout/floating_popup_overflow_list_item.xml
@@ -31,6 +31,6 @@
android:ellipsize="end"
android:fontFamily="sans-serif-medium"
android:textSize="@dimen/floating_toolbar_text_size"
- android:textColor="?attr/colorForeground"
+ android:textColor="?attr/floatingToolbarForegroundColor"
android:textAllCaps="true" />
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index d5c2d19..a3cc4ae 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -310,7 +310,11 @@
<item>@drawable/fastscroll_label_right_material</item>
<item>@drawable/fastscroll_thumb_material</item>
<item>@drawable/fastscroll_track_material</item>
+ <item>@drawable/floating_popup_background_dark</item>
+ <item>@drawable/floating_popup_background_light</item>
<item>@drawable/ic_ab_back_material</item>
+ <item>@drawable/ic_ab_back_material_dark</item>
+ <item>@drawable/ic_ab_back_material_light</item>
<item>@drawable/ic_clear_material</item>
<item>@drawable/ic_commit_search_api_material</item>
<item>@drawable/ic_dialog_alert_material</item>
@@ -330,7 +334,11 @@
<item>@drawable/ic_search_api_material</item>
<item>@drawable/ic_voice_search_api_material</item>
<item>@drawable/item_background_borderless_material</item>
+ <item>@drawable/item_background_borderless_material_dark</item>
+ <item>@drawable/item_background_borderless_material_light</item>
<item>@drawable/item_background_material</item>
+ <item>@drawable/item_background_material_dark</item>
+ <item>@drawable/item_background_material_light</item>
<item>@drawable/list_divider_material</item>
<item>@drawable/list_section_divider_material</item>
<item>@drawable/notification_material_action_background</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 52e2cf0..c08d511 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -550,6 +550,17 @@
<attr name="windowTransitionBackgroundFadeDuration" format="integer"/>
<!-- ============ -->
+ <!-- Floating toolbar styles -->
+ <!-- ============ -->
+ <eat-comment />
+ <attr name="floatingToolbarCloseDrawable" format="reference" />
+ <attr name="floatingToolbarForegroundColor" format="reference|color" />
+ <attr name="floatingToolbarItemBackgroundBorderlessDrawable" format="reference" />
+ <attr name="floatingToolbarItemBackgroundDrawable" format="reference" />
+ <attr name="floatingToolbarOpenDrawable" format="reference" />
+ <attr name="floatingToolbarPopupBackgroundDrawable" format="reference" />
+
+ <!-- ============ -->
<!-- Alert Dialog styles -->
<!-- ============ -->
<eat-comment />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index ecf00f0..b7acdd4 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -389,6 +389,14 @@
<item name="segmentedButtonStyle">@style/SegmentedButton</item>
<item name="fingerprintAuthDrawable">@drawable/ic_fingerprint</item>
+ <!-- Floating toolbar styles -->
+ <item name="floatingToolbarCloseDrawable">@drawable/ic_ab_back_material_dark</item>
+ <item name="floatingToolbarForegroundColor">@color/foreground_material_dark</item>
+ <item name="floatingToolbarItemBackgroundBorderlessDrawable">@drawable/item_background_borderless_material_dark</item>
+ <item name="floatingToolbarItemBackgroundDrawable">@drawable/item_background_material_dark</item>
+ <item name="floatingToolbarOpenDrawable">@drawable/ic_menu_moreoverflow_material_dark</item>
+ <item name="floatingToolbarPopupBackgroundDrawable">@drawable/floating_popup_background_dark</item>
+
<!-- SearchView attributes -->
<item name="searchViewStyle">@style/Widget.Holo.SearchView</item>
<item name="searchDialogTheme">@style/Theme.SearchBar</item>
@@ -538,6 +546,14 @@
<item name="mediaRouteButtonStyle">@style/Widget.DeviceDefault.Light.MediaRouteButton</item>
<item name="findOnPageNextDrawable">@drawable/ic_find_next_holo_light</item>
<item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_holo_light</item>
+
+ <!-- Floating toolbar styles -->
+ <item name="floatingToolbarCloseDrawable">@drawable/ic_ab_back_material_light</item>
+ <item name="floatingToolbarForegroundColor">@color/foreground_material_light</item>
+ <item name="floatingToolbarItemBackgroundBorderlessDrawable">@drawable/item_background_borderless_material_light</item>
+ <item name="floatingToolbarItemBackgroundDrawable">@drawable/item_background_material_light</item>
+ <item name="floatingToolbarOpenDrawable">@drawable/ic_menu_moreoverflow_material_light</item>
+ <item name="floatingToolbarPopupBackgroundDrawable">@drawable/floating_popup_background_light</item>
</style>
<!-- Variant of {@link #Theme_Light} with no title bar -->
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index e8e4664..532c888 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -809,6 +809,14 @@
* {@link android.graphics.PixelFormat#TRANSPARENT}, or
* {@link android.graphics.PixelFormat#OPAQUE}.
*
+ * <p>An OPAQUE drawable is one that draws all all content within its bounds, completely
+ * covering anything behind the drawable. A TRANSPARENT drawable is one that draws nothing
+ * within its bounds, allowing everything behind it to show through. A TRANSLUCENT drawable
+ * is a drawable in any other state, where the drawable will draw some, but not all,
+ * of the content within its bounds and at least some content behind the drawable will
+ * be visible. If the visibility of the drawable's contents cannot be determined, the
+ * safest/best return value is TRANSLUCENT.
+ *
* <p>Generally a Drawable should be as conservative as possible with the
* value it returns. For example, if it contains multiple child drawables
* and only shows one of them at a time, if only one of the children is
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 4ac4362..75e700a 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -392,11 +392,27 @@
if (isLayer) {
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
- LOG_ALWAYS_FATAL_IF(!isLayer && properties().getHasOverlappingRendering());
- renderer.scaleAlpha(properties().getAlpha());
+ if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) {
+ // simply scale rendering content's alpha
+ renderer.scaleAlpha(properties().getAlpha());
+ } else {
+ // savelayer needed to create an offscreen buffer
+ Rect layerBounds(0, 0, getWidth(), getHeight());
+ if (clipFlags) {
+ properties().getClippingRectForFlags(clipFlags, &layerBounds);
+ clipFlags = 0; // all clipping done by savelayer
+ }
+ SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
+ layerBounds.left, layerBounds.top,
+ layerBounds.right, layerBounds.bottom,
+ (int) (properties().getAlpha() * 255),
+ SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
+ handler(op, PROPERTY_SAVECOUNT, properties().getClipToBounds());
+ }
if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) {
- // pretend to cause savelayer to warn about performance problem affecting old versions
+ // pretend alpha always causes savelayer to warn about
+ // performance problem affecting old versions
ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(),
static_cast<int>(getWidth()),
static_cast<int>(getHeight()));
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 07b8ce6..4f6ef4e 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -152,7 +152,24 @@
clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
- ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
+ if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
+ // simply scale rendering content's alpha
+ ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
+ } else {
+ // savelayeralpha to create an offscreen buffer to apply alpha
+ Rect layerBounds(0, 0, getWidth(), getHeight());
+ if (clipFlags) {
+ getClippingRectForFlags(clipFlags, &layerBounds);
+ clipFlags = 0; // all clipping done by savelayer
+ }
+ ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
+ (int)layerBounds.left, (int)layerBounds.top,
+ (int)layerBounds.right, (int)layerBounds.bottom,
+ (int)(mPrimitiveFields.mAlpha * 255),
+ SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
+ }
+
+
}
if (clipFlags) {
Rect clipRect;
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 98029a8..65c1c4a 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -28,6 +28,7 @@
#include <SkRegion.h>
#include <SkXfermode.h>
+#include "Caches.h"
#include "Rect.h"
#include "RevealClip.h"
#include "Outline.h"
@@ -577,10 +578,13 @@
}
bool promotedToLayer() const {
+ const int maxTextureSize = Caches::getInstance().maxTextureSize;
return mLayerProperties.mType == LayerType::None
&& !MathUtils::isZero(mPrimitiveFields.mAlpha)
&& mPrimitiveFields.mAlpha < 1
- && mPrimitiveFields.mHasOverlappingRendering;
+ && mPrimitiveFields.mHasOverlappingRendering
+ && mPrimitiveFields.mWidth <= maxTextureSize
+ && mPrimitiveFields.mHeight <= maxTextureSize;
}
LayerType effectiveLayerType() const {
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 6a4ac2c..6ae5cf3 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -19,22 +19,25 @@
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_combo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
- <com.android.systemui.statusbar.AlphaOptimizedImageView
+ <com.android.systemui.statusbar.AnimatedImageView
android:theme="@style/DualToneLightTheme"
android:id="@+id/mobile_signal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
/>
- <com.android.systemui.statusbar.AlphaOptimizedImageView
+ <com.android.systemui.statusbar.AnimatedImageView
android:theme="@style/DualToneDarkTheme"
android:id="@+id/mobile_signal_dark"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
<ImageView
android:id="@+id/mobile_type"
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index a2121ee..f8bd6fd 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -20,6 +20,7 @@
<!-- extends LinearLayout -->
<com.android.systemui.statusbar.SignalClusterView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:gravity="center_vertical"
@@ -43,6 +44,7 @@
android:id="@+id/ethernet"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:theme="@style/DualToneDarkTheme"
@@ -50,6 +52,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
</FrameLayout>
<FrameLayout
@@ -62,6 +65,7 @@
android:id="@+id/wifi_signal"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ systemui:hasOverlappingRendering="false"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:theme="@style/DualToneDarkTheme"
@@ -69,6 +73,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
</FrameLayout>
<View
@@ -94,6 +99,7 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/stat_sys_no_sims"
+ systemui:hasOverlappingRendering="false"
/>
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:theme="@style/DualToneDarkTheme"
@@ -102,6 +108,7 @@
android:layout_width="wrap_content"
android:src="@drawable/stat_sys_no_sims"
android:alpha="0.0"
+ systemui:hasOverlappingRendering="false"
/>
</FrameLayout>
<View
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 0e1517f..7262ed2 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -162,6 +162,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
+ systemui:hasOverlappingRendering="false"
/>
<TextView
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 354b70b..527248c 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -86,5 +86,9 @@
<declare-styleable name="StatusBarWindowView_Layout">
<attr name="ignoreRightInset" format="boolean" />
</declare-styleable>
+
+ <declare-styleable name="AlphaOptimizedImageView">
+ <attr name="hasOverlappingRendering" format="boolean" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
index 858c118..700ea34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AlphaOptimizedImageView.java
@@ -17,34 +17,49 @@
package com.android.systemui.statusbar;
import android.content.Context;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ImageView;
+import com.android.systemui.R;
+
/**
- * An ImageView which does not have overlapping rendering commands and therefore does not need a
- * layer when alpha is changed.
+ * An ImageView which supports an attribute specifying whether it has overlapping rendering
+ * commands and therefore does not need a layer when alpha is changed.
*/
-public class AlphaOptimizedImageView extends ImageView
-{
+public class AlphaOptimizedImageView extends ImageView {
+ private final boolean mHasOverlappingRendering;
+
public AlphaOptimizedImageView(Context context) {
- super(context);
+ this(context, null /* attrs */);
}
public AlphaOptimizedImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0 /* defStyleAttr */);
}
public AlphaOptimizedImageView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
+ this(context, attrs, defStyleAttr, 0 /* defStyleRes */);
}
public AlphaOptimizedImageView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
+ R.styleable.AlphaOptimizedImageView, 0, 0);
+
+ try {
+ // Default to true, which is what View.java defaults to
+ mHasOverlappingRendering = a.getBoolean(
+ R.styleable.AlphaOptimizedImageView_hasOverlappingRendering, true);
+ } finally {
+ a.recycle();
+ }
}
@Override
public boolean hasOverlappingRendering() {
- return false;
+ return mHasOverlappingRendering;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
index 9839fe9..90f7c08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/AnimatedImageView.java
@@ -25,10 +25,15 @@
import android.widget.RemoteViews.RemoteView;
@RemoteView
-public class AnimatedImageView extends ImageView {
+public class AnimatedImageView extends AlphaOptimizedImageView {
AnimationDrawable mAnim;
boolean mAttached;
+ // Tracks the last image that was set, so that we don't refresh the image if it is exactly
+ // the same as the previous one. If this is a resid, we track that. If it's a drawable, we
+ // track the hashcode of the drawable.
+ int mDrawableId;
+
public AnimatedImageView(Context context) {
super(context);
}
@@ -43,7 +48,7 @@
mAnim.stop();
}
if (drawable instanceof AnimationDrawable) {
- mAnim = (AnimationDrawable)drawable;
+ mAnim = (AnimationDrawable) drawable;
if (isShown()) {
mAnim.start();
}
@@ -54,6 +59,13 @@
@Override
public void setImageDrawable(Drawable drawable) {
+ if (drawable != null) {
+ if (mDrawableId == drawable.hashCode()) return;
+
+ mDrawableId = drawable.hashCode();
+ } else {
+ mDrawableId = 0;
+ }
super.setImageDrawable(drawable);
updateAnim();
}
@@ -61,6 +73,9 @@
@Override
@android.view.RemotableViewMethod
public void setImageResource(int resid) {
+ if (mDrawableId == resid) return;
+
+ mDrawableId = resid;
super.setImageResource(resid);
updateAnim();
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 66fd36f..fbb6dc9 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -21,8 +21,8 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetooth;
-import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothCallback;
+import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothHeadset;
import android.bluetooth.IBluetoothManager;
import android.bluetooth.IBluetoothManagerCallback;
@@ -37,6 +37,7 @@
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.database.ContentObserver;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -56,11 +57,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
-
import java.util.HashMap;
import java.util.Map;
-
-import java.util.*;
class BluetoothManagerService extends IBluetoothManager.Stub {
private static final String TAG = "BluetoothManagerService";
private static final boolean DBG = true;
@@ -259,6 +257,8 @@
mName = null;
mErrorRecoveryRetryCounter = 0;
mContentResolver = context.getContentResolver();
+ // Observe BLE scan only mode settings change.
+ registerForBleScanModeChange();
mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
@@ -458,6 +458,40 @@
return false;
}
+ // Monitor change of BLE scan only mode settings.
+ private void registerForBleScanModeChange() {
+ ContentObserver contentObserver = new ContentObserver(null) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if (!isBleScanAlwaysAvailable()) {
+ disableBleScanMode();
+ clearBleApps();
+ try {
+ if (mBluetooth != null) mBluetooth.onBrEdrDown();
+ } catch (RemoteException e) {
+ Log.e(TAG, "error when disabling bluetooth", e);
+ }
+ }
+ }
+ };
+
+ mContentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE),
+ false, contentObserver);
+ }
+
+ // Disable ble scan only mode.
+ private void disableBleScanMode() {
+ try {
+ if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
+ if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
+ mEnable = false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "getState()", e);
+ }
+ }
+
public int updateBleAppCount(IBinder token, boolean enable) {
if (enable) {
ClientDeathRecipient r = mBleApps.get(token);
@@ -478,11 +512,8 @@
} else {
ClientDeathRecipient r = mBleApps.get(token);
if (r != null) {
- try {
- token.linkToDeath(r, 0);
- } catch (RemoteException ex) {
- throw new IllegalArgumentException("Wake lock is already dead.");
- }
+ // Unregister death recipient as the app goes away.
+ token.unlinkToDeath(r, 0);
mBleApps.remove(token);
synchronized (this) {
if (mBleAppCount > 0) --mBleAppCount;
@@ -492,18 +523,19 @@
}
if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
if (mBleAppCount == 0 && mEnable) {
- try {
- if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
- if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
- mEnable = false;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getState()", e);
- }
+ disableBleScanMode();
}
return mBleAppCount;
}
+ // Clear all apps using BLE scan only mode.
+ private void clearBleApps() {
+ synchronized (this) {
+ mBleApps.clear();
+ mBleAppCount = 0;
+ }
+ }
+
/** @hide*/
public boolean isBleAppPresent() {
if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6496ba2..029a3b2 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19382,15 +19382,16 @@
enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
"setDumpHeapDebugLimit()");
} else {
- if (!Build.IS_DEBUGGABLE) {
- throw new SecurityException("Not running a debuggable build");
- }
synchronized (mPidsSelfLocked) {
ProcessRecord proc = mPidsSelfLocked.get(Binder.getCallingPid());
if (proc == null) {
throw new SecurityException("No process found for calling pid "
+ Binder.getCallingPid());
}
+ if (!Build.IS_DEBUGGABLE
+ && (proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Not running a debuggable build");
+ }
processName = proc.processName;
uid = proc.uid;
if (reportPackage != null && !proc.pkgList.containsKey(reportPackage)) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2753700..ea66a04 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,9 @@
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -90,19 +93,19 @@
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
-import android.text.TextUtils;
import android.service.persistentdata.PersistentDataBlockManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
-import android.view.IWindowManager;
import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
@@ -117,11 +120,6 @@
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
import org.xmlpull.v1.XmlPullParser;
-
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.END_TAG;
-import static org.xmlpull.v1.XmlPullParser.TEXT;
-
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -178,6 +176,7 @@
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
+ private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001;
private static final boolean DBG = false;
@@ -354,6 +353,7 @@
if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
mHandler.post(new Runnable() {
+ @Override
public void run() {
handlePasswordExpirationNotification(userHandle);
}
@@ -1929,6 +1929,7 @@
* @param adminReceiver The admin to add
* @param refreshing true = update an active admin, no error
*/
+ @Override
public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
if (!mHasFeature) {
return;
@@ -1980,6 +1981,7 @@
}
}
+ @Override
public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
return false;
@@ -2002,6 +2004,7 @@
}
}
+ @Override
public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
if (!mHasFeature) {
return false;
@@ -2016,6 +2019,7 @@
}
}
+ @Override
@SuppressWarnings("unchecked")
public List<ComponentName> getActiveAdmins(int userHandle) {
if (!mHasFeature) {
@@ -2037,6 +2041,7 @@
}
}
+ @Override
public boolean packageHasActiveAdmins(String packageName, int userHandle) {
if (!mHasFeature) {
return false;
@@ -2054,6 +2059,7 @@
}
}
+ @Override
public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
return;
@@ -2081,6 +2087,7 @@
}
}
+ @Override
public void setPasswordQuality(ComponentName who, int quality) {
if (!mHasFeature) {
return;
@@ -2099,6 +2106,7 @@
}
}
+ @Override
public int getPasswordQuality(ComponentName who, int userHandle) {
if (!mHasFeature) {
return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -2128,6 +2136,7 @@
}
}
+ @Override
public void setPasswordMinimumLength(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2144,6 +2153,7 @@
}
}
+ @Override
public int getPasswordMinimumLength(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2173,6 +2183,7 @@
}
}
+ @Override
public void setPasswordHistoryLength(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2189,6 +2200,7 @@
}
}
+ @Override
public int getPasswordHistoryLength(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2218,6 +2230,7 @@
}
}
+ @Override
public void setPasswordExpirationTimeout(ComponentName who, long timeout) {
if (!mHasFeature) {
return;
@@ -2247,6 +2260,7 @@
* Return a single admin's expiration cycle time, or the min of all cycle times.
* Returns 0 if not configured.
*/
+ @Override
public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0L;
@@ -2373,6 +2387,7 @@
return timeout;
}
+ @Override
public long getPasswordExpiration(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0L;
@@ -2383,6 +2398,7 @@
}
}
+ @Override
public void setPasswordMinimumUpperCase(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2399,6 +2415,7 @@
}
}
+ @Override
public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2428,6 +2445,7 @@
}
}
+ @Override
public void setPasswordMinimumLowerCase(ComponentName who, int length) {
Preconditions.checkNotNull(who, "ComponentName is null");
final int userHandle = UserHandle.getCallingUserId();
@@ -2441,6 +2459,7 @@
}
}
+ @Override
public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2470,6 +2489,7 @@
}
}
+ @Override
public void setPasswordMinimumLetters(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2486,6 +2506,7 @@
}
}
+ @Override
public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2518,6 +2539,7 @@
}
}
+ @Override
public void setPasswordMinimumNumeric(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2534,6 +2556,7 @@
}
}
+ @Override
public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2566,6 +2589,7 @@
}
}
+ @Override
public void setPasswordMinimumSymbols(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2582,6 +2606,7 @@
}
}
+ @Override
public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2614,6 +2639,7 @@
}
}
+ @Override
public void setPasswordMinimumNonLetter(ComponentName who, int length) {
if (!mHasFeature) {
return;
@@ -2630,6 +2656,7 @@
}
}
+ @Override
public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -2662,6 +2689,7 @@
}
}
+ @Override
public boolean isActivePasswordSufficient(int userHandle) {
if (!mHasFeature) {
return true;
@@ -2696,6 +2724,7 @@
}
}
+ @Override
public int getCurrentFailedPasswordAttempts(int userHandle) {
synchronized (this) {
// This API can only be called by an active device admin,
@@ -2712,6 +2741,7 @@
}
}
+ @Override
public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
if (!mHasFeature) {
return;
@@ -2786,6 +2816,7 @@
return strictestAdmin;
}
+ @Override
public boolean resetPassword(String passwordOrNull, int flags) {
if (!mHasFeature) {
return false;
@@ -2938,6 +2969,7 @@
}
}
+ @Override
public boolean getDoNotAskCredentialsOnBoot() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT, null);
@@ -2947,6 +2979,7 @@
}
}
+ @Override
public void setMaximumTimeToLock(ComponentName who, long timeMs) {
if (!mHasFeature) {
return;
@@ -2988,6 +3021,7 @@
}
}
+ @Override
public long getMaximumTimeToLock(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -3020,6 +3054,7 @@
}
}
+ @Override
public void lockNow() {
if (!mHasFeature) {
return;
@@ -3336,14 +3371,19 @@
wipeDataLocked(wipeExtRequested, reason);
} else {
mHandler.post(new Runnable() {
+ @Override
public void run() {
try {
IActivityManager am = ActivityManagerNative.getDefault();
if (am.getCurrentUser().id == userHandle) {
am.switchUser(UserHandle.USER_OWNER);
}
+
+ boolean isManagedProfile = isManagedProfile(userHandle);
if (!mUserManager.removeUser(userHandle)) {
Slog.w(LOG_TAG, "Couldn't remove user " + userHandle);
+ } else if (isManagedProfile) {
+ sendWipeProfileNotification();
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -3353,6 +3393,19 @@
}
}
+ private void sendWipeProfileNotification() {
+ String contentText = mContext.getString(R.string.work_profile_deleted_description_dpm_wipe);
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setContentTitle(mContext.getString(R.string.work_profile_deleted))
+ .setContentText(contentText)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setStyle(new Notification.BigTextStyle().bigText(contentText))
+ .build();
+ getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
+ }
+
+ @Override
public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
if (!mHasFeature) {
return;
@@ -3386,6 +3439,7 @@
}
}
+ @Override
public void setActivePasswordState(int quality, int length, int letters, int uppercase,
int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
if (!mHasFeature) {
@@ -3455,6 +3509,7 @@
}
}
+ @Override
public void reportFailedPasswordAttempt(int userHandle) {
enforceCrossUserPermission(userHandle);
enforceNotManagedProfile(userHandle, "report failed password attempt");
@@ -3496,6 +3551,7 @@
}
}
+ @Override
public void reportSuccessfulPasswordAttempt(int userHandle) {
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
@@ -3521,6 +3577,7 @@
}
}
+ @Override
public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
String exclusionList) {
if (!mHasFeature) {
@@ -3575,6 +3632,7 @@
}
}
+ @Override
public ComponentName getGlobalProxyAdmin(int userHandle) {
if (!mHasFeature) {
return null;
@@ -3598,6 +3656,7 @@
return null;
}
+ @Override
public void setRecommendedGlobalProxy(ComponentName who, ProxyInfo proxyInfo) {
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -3659,6 +3718,7 @@
* Set the storage encryption request for a single admin. Returns the new total request
* status (for all admins).
*/
+ @Override
public int setStorageEncryption(ComponentName who, boolean encrypt) {
if (!mHasFeature) {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
@@ -3711,6 +3771,7 @@
* Get the current storage encryption request status for a given admin, or aggregate of all
* active admins.
*/
+ @Override
public boolean getStorageEncryption(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3740,6 +3801,7 @@
/**
* Get the current encryption status of the device.
*/
+ @Override
public int getStorageEncryptionStatus(int userHandle) {
if (!mHasFeature) {
// Ok to return current status.
@@ -3794,6 +3856,7 @@
/**
* Set whether the screen capture is disabled for the user managed by the specified admin.
*/
+ @Override
public void setScreenCaptureDisabled(ComponentName who, boolean disabled) {
if (!mHasFeature) {
return;
@@ -3815,6 +3878,7 @@
* Returns whether or not screen capture is disabled for a given admin, or disabled for any
* active admin (if given admin is null).
*/
+ @Override
public boolean getScreenCaptureDisabled(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3851,6 +3915,7 @@
/**
* Set whether auto time is required by the specified admin (must be device owner).
*/
+ @Override
public void setAutoTimeRequired(ComponentName who, boolean required) {
if (!mHasFeature) {
return;
@@ -3881,6 +3946,7 @@
/**
* Returns whether or not auto time is required by the device owner.
*/
+ @Override
public boolean getAutoTimeRequired() {
if (!mHasFeature) {
return false;
@@ -3901,6 +3967,7 @@
/**
* Disables all device cameras according to the specified admin.
*/
+ @Override
public void setCameraDisabled(ComponentName who, boolean disabled) {
if (!mHasFeature) {
return;
@@ -3922,6 +3989,7 @@
* Gets whether or not all device cameras are disabled for a given admin, or disabled for any
* active admins.
*/
+ @Override
public boolean getCameraDisabled(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
@@ -3948,6 +4016,7 @@
/**
* Selectively disable keyguard features.
*/
+ @Override
public void setKeyguardDisabledFeatures(ComponentName who, int which) {
if (!mHasFeature) {
return;
@@ -3972,6 +4041,7 @@
* Gets the disabled state for features in keyguard for the given admin,
* or the aggregate of all active admins if who is null.
*/
+ @Override
public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
@@ -4735,6 +4805,7 @@
}
}
+ @Override
public void setTrustAgentConfiguration(ComponentName admin, ComponentName agent,
PersistableBundle args) {
if (!mHasFeature) {
@@ -4753,6 +4824,7 @@
}
}
+ @Override
public List<PersistableBundle> getTrustAgentConfiguration(ComponentName admin,
ComponentName agent, int userHandle) {
if (!mHasFeature) {
@@ -4834,6 +4906,7 @@
}
}
+ @Override
public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
@@ -4859,6 +4932,7 @@
}
}
+ @Override
public void clearCrossProfileIntentFilters(ComponentName who) {
Preconditions.checkNotNull(who, "ComponentName is null");
int callingUserId = UserHandle.getCallingUserId();
@@ -5779,6 +5853,7 @@
* This function can only be called by the device owner.
* @param packages The list of packages allowed to enter lock task mode.
*/
+ @Override
public void setLockTaskPackages(ComponentName who, String[] packages)
throws SecurityException {
Preconditions.checkNotNull(who, "ComponentName is null");
@@ -5802,6 +5877,7 @@
/**
* This function returns the list of components allowed to start the task lock mode.
*/
+ @Override
public String[] getLockTaskPackages(ComponentName who) {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
@@ -5822,6 +5898,7 @@
* lock task mode.
* @param pkg The package to check
*/
+ @Override
public boolean isLockTaskPermitted(String pkg) {
// Get current user's devicepolicy
int uid = Binder.getCallingUid();
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 9d3db16..e3c0868 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -27,34 +27,27 @@
*/
public class AppIdleHistory {
- private SparseArray<ArrayMap<String,byte[]>> idleHistory = new SparseArray<>();
+ private SparseArray<ArrayMap<String,byte[]>> mIdleHistory = new SparseArray<>();
private long lastPeriod = 0;
private static final long ONE_MINUTE = 60 * 1000;
private static final int HISTORY_SIZE = 100;
private static final int FLAG_LAST_STATE = 2;
private static final int FLAG_PARTIAL_ACTIVE = 1;
- private static final long PERIOD_DURATION = UsageStatsService.DEBUG ? ONE_MINUTE
+ private static final long PERIOD_DURATION = UsageStatsService.COMPRESS_TIME ? ONE_MINUTE
: 60 * ONE_MINUTE;
public void addEntry(String packageName, int userId, boolean idle, long timeNow) {
- ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
- if (userHistory == null) {
- userHistory = new ArrayMap<>();
- idleHistory.put(userId, userHistory);
- }
- byte[] packageHistory = userHistory.get(packageName);
- if (packageHistory == null) {
- packageHistory = new byte[HISTORY_SIZE];
- userHistory.put(packageName, packageHistory);
- }
+ ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
+ byte[] packageHistory = getPackageHistory(userHistory, packageName);
+
long thisPeriod = timeNow / PERIOD_DURATION;
// Has the period switched over? Slide all users' package histories
if (lastPeriod != 0 && lastPeriod < thisPeriod
&& (thisPeriod - lastPeriod) < HISTORY_SIZE - 1) {
int diff = (int) (thisPeriod - lastPeriod);
- final int NUSERS = idleHistory.size();
+ final int NUSERS = mIdleHistory.size();
for (int u = 0; u < NUSERS; u++) {
- userHistory = idleHistory.valueAt(u);
+ userHistory = mIdleHistory.valueAt(u);
for (byte[] history : userHistory.values()) {
// Shift left
System.arraycopy(history, diff, history, 0, HISTORY_SIZE - diff);
@@ -74,12 +67,36 @@
}
}
+ private ArrayMap<String, byte[]> getUserHistory(int userId) {
+ ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
+ if (userHistory == null) {
+ userHistory = new ArrayMap<>();
+ mIdleHistory.put(userId, userHistory);
+ }
+ return userHistory;
+ }
+
+ private byte[] getPackageHistory(ArrayMap<String, byte[]> userHistory, String packageName) {
+ byte[] packageHistory = userHistory.get(packageName);
+ if (packageHistory == null) {
+ packageHistory = new byte[HISTORY_SIZE];
+ userHistory.put(packageName, packageHistory);
+ }
+ return packageHistory;
+ }
+
public void removeUser(int userId) {
- idleHistory.remove(userId);
+ mIdleHistory.remove(userId);
+ }
+
+ public boolean isIdle(int userId, String packageName) {
+ ArrayMap<String, byte[]> userHistory = getUserHistory(userId);
+ byte[] packageHistory = getPackageHistory(userHistory, packageName);
+ return (packageHistory[HISTORY_SIZE - 1] & FLAG_LAST_STATE) == 0;
}
public void dump(IndentingPrintWriter idpw, int userId) {
- ArrayMap<String, byte[]> userHistory = idleHistory.get(userId);
+ ArrayMap<String, byte[]> userHistory = mIdleHistory.get(userId);
if (userHistory == null) return;
final int P = userHistory.size();
for (int p = 0; p < P; p++) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 7a34757..8e1895e 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -43,6 +43,7 @@
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.BatteryManager;
+import android.os.BatteryStats;
import android.os.Binder;
import android.os.Environment;
import android.os.Handler;
@@ -65,6 +66,7 @@
import android.view.Display;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.DeviceIdleController;
@@ -91,7 +93,7 @@
static final String TAG = "UsageStatsService";
static final boolean DEBUG = false;
- private static final boolean COMPRESS_TIME = false;
+ static final boolean COMPRESS_TIME = false;
private static final long TEN_SECONDS = 10 * 1000;
private static final long ONE_MINUTE = 60 * 1000;
@@ -128,6 +130,7 @@
IDeviceIdleController mDeviceIdleController;
private DisplayManager mDisplayManager;
private PowerManager mPowerManager;
+ private IBatteryStats mBatteryStats;
private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
private File mUsageStatsDir;
@@ -200,6 +203,8 @@
mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class);
mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(DeviceIdleController.SERVICE_NAME));
+ mBatteryStats = IBatteryStats.Stub.asInterface(
+ ServiceManager.getService(BatteryStats.SERVICE_NAME));
mDisplayManager = (DisplayManager) getContext().getSystemService(
Context.DISPLAY_SERVICE);
mPowerManager = getContext().getSystemService(PowerManager.class);
@@ -228,7 +233,7 @@
}
} else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
if (userId >=0) {
- postCheckIdleStates();
+ postCheckIdleStates(userId);
}
}
}
@@ -307,7 +312,7 @@
mLastAppIdleParoledTime = checkAndGetTimeLocked();
postNextParoleTimeout();
}
- postCheckIdleStates();
+ postCheckIdleStates(UserHandle.USER_ALL);
}
}
}
@@ -332,22 +337,25 @@
mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, DEFAULT_PAROLE_DURATION);
}
- void postCheckIdleStates() {
- mHandler.removeMessages(MSG_CHECK_IDLE_STATES);
- mHandler.sendEmptyMessage(MSG_CHECK_IDLE_STATES);
+ void postCheckIdleStates(int userId) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
- /** Check all running users' apps to see if they enter an idle state. */
- void checkIdleStates() {
- final int[] runningUsers;
+ /** Check all running users' or specified user's apps to see if they enter an idle state. */
+ void checkIdleStates(int checkUserId) {
+ final int[] userIds;
try {
- runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
+ if (checkUserId == UserHandle.USER_ALL) {
+ userIds = ActivityManagerNative.getDefault().getRunningUserIds();
+ } else {
+ userIds = new int[] { checkUserId };
+ }
} catch (RemoteException re) {
return;
}
- for (int i = 0; i < runningUsers.length; i++) {
- final int userId = runningUsers[i];
+ for (int i = 0; i < userIds.length; i++) {
+ final int userId = userIds[i];
List<PackageInfo> packages =
getContext().getPackageManager().getInstalledPackages(
PackageManager.GET_DISABLED_COMPONENTS
@@ -355,17 +363,22 @@
userId);
synchronized (mLock) {
final long timeNow = checkAndGetTimeLocked();
+ final long screenOnTime = getScreenOnTimeLocked(timeNow);
+ UserUsageStatsService service = getUserDataAndInitializeIfNeededLocked(userId,
+ timeNow);
final int packageCount = packages.size();
for (int p = 0; p < packageCount; p++) {
final String packageName = packages.get(p).packageName;
- final boolean isIdle = isAppIdleFiltered(packageName, userId, timeNow);
+ final boolean isIdle = isAppIdleFiltered(packageName, userId, service, timeNow,
+ screenOnTime);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
userId, isIdle ? 1 : 0, packageName));
mAppIdleHistory.addEntry(packageName, userId, isIdle, timeNow);
}
}
}
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, checkUserId, 0),
+ mCheckIdleIntervalMillis);
}
/** Check if it's been a while since last parole and let idle apps do some work */
@@ -386,6 +399,20 @@
}
}
+ private void notifyBatteryStats(String packageName, int userId, boolean idle) {
+ try {
+ int uid = AppGlobals.getPackageManager().getPackageUid(packageName, userId);
+ if (idle) {
+ mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE,
+ packageName, uid);
+ } else {
+ mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE,
+ packageName, uid);
+ }
+ } catch (RemoteException re) {
+ }
+ }
+
void updateDisplayLocked() {
boolean screenOn = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).getState()
== Display.STATE_ON;
@@ -545,7 +572,7 @@
final long lastUsedTime = service.getSystemLastUsedTime(event.mPackage);
final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
lastUsedTime, screenOnTime, timeNow);
- service.reportEvent(event, getScreenOnTimeLocked(timeNow));
+ service.reportEvent(event, screenOnTime);
// Inform listeners if necessary
if ((event.mEventType == Event.MOVE_TO_FOREGROUND
|| event.mEventType == Event.MOVE_TO_BACKGROUND
@@ -555,6 +582,7 @@
// Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ 0, event.mPackage));
+ notifyBatteryStats(event.mPackage, userId, false);
mAppIdleHistory.addEntry(event.mPackage, userId, false, timeNow);
}
}
@@ -586,6 +614,9 @@
// Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
/* idle = */ idle ? 1 : 0, packageName));
+ if (!idle) {
+ notifyBatteryStats(packageName, userId, idle);
+ }
mAppIdleHistory.addEntry(packageName, userId, idle, timeNow);
}
}
@@ -660,19 +691,20 @@
}
}
- private boolean isAppIdleUnfiltered(String packageName, int userId, long timeNow) {
+ private boolean isAppIdleUnfiltered(String packageName, UserUsageStatsService userService,
+ long timeNow, long screenOnTime) {
synchronized (mLock) {
- final long screenOnTime = getScreenOnTimeLocked(timeNow);
- final UserUsageStatsService service =
- getUserDataAndInitializeIfNeededLocked(userId, timeNow);
- long beginIdleTime = service.getBeginIdleTime(packageName);
- long lastUsedTime = service.getSystemLastUsedTime(packageName);
- return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime, timeNow);
+ long beginIdleTime = userService.getBeginIdleTime(packageName);
+ long lastUsedTime = userService.getSystemLastUsedTime(packageName);
+ return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime,
+ timeNow);
}
}
/**
- * @param timestamp when the app was last used in device usage timebase
+ * @param beginIdleTime when the app was last used in device usage timebase
+ * @param lastUsedTime wallclock time of when the app was last used
+ * @param screenOnTime screen-on timebase time
* @param currentTime current time in device usage timebase
* @return whether it's been used far enough in the past to be considered inactive
*/
@@ -696,18 +728,29 @@
}
}
+ boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
+ final UserUsageStatsService userService;
+ final long screenOnTime;
+ synchronized (mLock) {
+ if (timeNow == -1) {
+ timeNow = checkAndGetTimeLocked();
+ }
+ userService = getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+ screenOnTime = getScreenOnTimeLocked(timeNow);
+ }
+ return isAppIdleFiltered(packageName, userId, userService, timeNow, screenOnTime);
+ }
+
/**
* Checks if an app has been idle for a while and filters out apps that are excluded.
* It returns false if the current system state allows all apps to be considered active.
* This happens if the device is plugged in or temporarily allowed to make exceptions.
* Called by interface impls.
*/
- boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
+ private boolean isAppIdleFiltered(String packageName, int userId,
+ UserUsageStatsService userService, long timeNow, long screenOnTime) {
if (packageName == null) return false;
synchronized (mLock) {
- if (timeNow == -1) {
- timeNow = checkAndGetTimeLocked();
- }
// Temporary exemption, probably due to device charging or occasional allowance to
// be allowed to sync, etc.
if (mAppIdleParoled) {
@@ -735,7 +778,7 @@
return false;
}
- return isAppIdleUnfiltered(packageName, userId, timeNow);
+ return isAppIdleUnfiltered(packageName, userService, timeNow, screenOnTime);
}
void setAppIdle(String packageName, boolean idle, int userId) {
@@ -844,7 +887,7 @@
break;
case MSG_CHECK_IDLE_STATES:
- checkIdleStates();
+ checkIdleStates(msg.arg1);
break;
case MSG_CHECK_PAROLE_TIMEOUT:
@@ -884,7 +927,7 @@
UserHandle.USER_OWNER);
mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
mAppIdleDurationMillis / 4);
- postCheckIdleStates();
+ postCheckIdleStates(UserHandle.USER_ALL);
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index a2e0706..e756a57 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -380,7 +380,7 @@
builder.append(" PROPERTY_HIGH_DEF_AUDIO");
}
if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
- builder.append(" EMERGENCY_CALLBACK_MODE");
+ builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
}
builder.append("]");
return builder.toString();