Merge "Fixing no first "device added" notification." 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/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 5e7bd0d..9ea1606 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -142,13 +142,22 @@
public static final int FLAG_ALLOW_WHILE_IDLE = 1<<2;
/**
+ * Flag for alarms: same as {@link #FLAG_ALLOW_WHILE_IDLE}, but doesn't have restrictions
+ * on how frequently it can be scheduled. Only available (and automatically applied) to
+ * system alarms.
+ *
+ * @hide
+ */
+ public static final int FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED = 1<<3;
+
+ /**
* Flag for alarms: this alarm marks the point where we would like to come out of idle
* mode. It may be moved by the alarm manager to match the first wake-from-idle alarm.
* Scheduling an alarm with this flag puts the alarm manager in to idle mode, where it
* avoids scheduling any further alarms until the marker alarm is executed.
* @hide
*/
- public static final int FLAG_IDLE_UNTIL = 1<<3;
+ public static final int FLAG_IDLE_UNTIL = 1<<4;
private final IAlarmManager mService;
private final boolean mAlwaysExact;
@@ -565,6 +574,12 @@
* of the device when idle (and thus cause significant battery blame to the app scheduling
* them), so they should be used with care.
*
+ * <p>To reduce abuse, there are restrictions on how frequently these alarms will go off
+ * for a particular application. Under normal system operation, it will not dispatch these
+ * alarms more than about every minute (at which point every such pending alarm is
+ * dispatched); when in low-power idle modes this duration may be significantly longer,
+ * such as 15 minutes.</p>
+ *
* <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
* out of order with any other alarms, even those from the same app. This will clearly happen
* when the device is idle (since this alarm can go off while idle, when any other alarms
@@ -608,6 +623,12 @@
* of the device when idle (and thus cause significant battery blame to the app scheduling
* them), so they should be used with care.
*
+ * <p>To reduce abuse, there are restrictions on how frequently these alarms will go off
+ * for a particular application. Under normal system operation, it will not dispatch these
+ * alarms more than about every minute (at which point every such pending alarm is
+ * dispatched); when in low-power idle modes this duration may be significantly longer,
+ * such as 15 minutes.</p>
+ *
* <p>Unlike other alarms, the system is free to reschedule this type of alarm to happen
* out of order with any other alarms, even those from the same app. This will clearly happen
* when the device is idle (since this alarm can go off while idle, when any other alarms
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/app/Notification.java b/core/java/android/app/Notification.java
index 96c6878..33a47b24 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1331,11 +1331,14 @@
public Notification(Context context, int icon, CharSequence tickerText, long when,
CharSequence contentTitle, CharSequence contentText, Intent contentIntent)
{
- this.when = when;
- this.icon = icon;
- this.tickerText = tickerText;
- setLatestEventInfo(context, contentTitle, contentText,
- PendingIntent.getActivity(context, 0, contentIntent, 0));
+ new Builder(context)
+ .setWhen(when)
+ .setSmallIcon(icon)
+ .setTicker(tickerText)
+ .setContentTitle(contentTitle)
+ .setContentText(contentText)
+ .setContentIntent(PendingIntent.getActivity(context, 0, contentIntent, 0))
+ .buildInto(this);
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 42d0dcb..9f49154 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -149,6 +149,7 @@
* <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}</li>
* <li>{@link #EXTRA_PROVISIONING_SKIP_ENCRYPTION}, optional</li>
* <li>{@link #EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED}, optional</li>
+ * <li>{@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}, optional</li>
* </ul>
*
* <p> When device owner provisioning has completed, an intent of the type
@@ -163,14 +164,19 @@
= "android.app.action.PROVISION_MANAGED_DEVICE";
/**
- * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows
- * a mobile device management application that starts managed profile provisioning to pass data
- * to itself on the managed profile when provisioning completes. The mobile device management
- * application sends this extra in an intent with the action
- * {@link #ACTION_PROVISION_MANAGED_PROFILE} and receives it in
+ * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
+ * allows a mobile device management application which starts managed provisioning to pass data
+ * to itself.
+ * <p>
+ * If used with {@link #ACTION_PROVISION_MANAGED_PROFILE} it can be used by the application that
+ * sends the intent to pass data to itself on the newly created profile.
+ * If used with {@link #ACTION_PROVISION_MANAGED_DEVICE} it allows passing data to the same
+ * instance of the app on the primary user.
+ * <p>
+ * In both cases the application receives the data in
* {@link DeviceAdminReceiver#onProfileProvisioningComplete} via an intent with the action
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}. The bundle is not changed
- * during the managed profile provisioning.
+ * during the managed provisioning.
*/
public static final String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE =
"android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
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/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index f7d28218..353388d 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -246,41 +246,65 @@
public static final long NANOS_PER_MS = 1000000;
private static final Object sFormatSync = new Object();
- private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5];
-
- private static final long LARGEST_DURATION = (1000 * DateUtils.DAY_IN_MILLIS) - 1;
+ private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10];
+ private static char[] sTmpFormatStr = new char[HUNDRED_DAY_FIELD_LEN+10];
static private int accumField(int amt, int suffix, boolean always, int zeropad) {
- if (amt > 99 || (always && zeropad >= 3)) {
- return 3+suffix;
- }
- if (amt > 9 || (always && zeropad >= 2)) {
- return 2+suffix;
- }
- if (always || amt > 0) {
- return 1+suffix;
+ if (amt > 999) {
+ int num = 0;
+ while (amt != 0) {
+ num++;
+ amt /= 10;
+ }
+ return num + suffix;
+ } else {
+ if (amt > 99 || (always && zeropad >= 3)) {
+ return 3+suffix;
+ }
+ if (amt > 9 || (always && zeropad >= 2)) {
+ return 2+suffix;
+ }
+ if (always || amt > 0) {
+ return 1+suffix;
+ }
}
return 0;
}
- static private int printField(char[] formatStr, int amt, char suffix, int pos,
+ static private int printFieldLocked(char[] formatStr, int amt, char suffix, int pos,
boolean always, int zeropad) {
if (always || amt > 0) {
final int startPos = pos;
- if ((always && zeropad >= 3) || amt > 99) {
- int dig = amt/100;
- formatStr[pos] = (char)(dig + '0');
+ if (amt > 999) {
+ int tmp = 0;
+ while (amt != 0 && tmp < sTmpFormatStr.length) {
+ int dig = amt % 10;
+ sTmpFormatStr[tmp] = (char)(dig + '0');
+ tmp++;
+ amt /= 10;
+ }
+ tmp--;
+ while (tmp >= 0) {
+ formatStr[pos] = sTmpFormatStr[tmp];
+ pos++;
+ tmp--;
+ }
+ } else {
+ if ((always && zeropad >= 3) || amt > 99) {
+ int dig = amt/100;
+ formatStr[pos] = (char)(dig + '0');
+ pos++;
+ amt -= (dig*100);
+ }
+ if ((always && zeropad >= 2) || amt > 9 || startPos != pos) {
+ int dig = amt/10;
+ formatStr[pos] = (char)(dig + '0');
+ pos++;
+ amt -= (dig*10);
+ }
+ formatStr[pos] = (char)(amt + '0');
pos++;
- amt -= (dig*100);
}
- if ((always && zeropad >= 2) || amt > 9 || startPos != pos) {
- int dig = amt/10;
- formatStr[pos] = (char)(dig + '0');
- pos++;
- amt -= (dig*10);
- }
- formatStr[pos] = (char)(amt + '0');
- pos++;
formatStr[pos] = suffix;
pos++;
}
@@ -312,10 +336,6 @@
duration = -duration;
}
- if (duration > LARGEST_DURATION) {
- duration = LARGEST_DURATION;
- }
-
int millis = (int)(duration%1000);
int seconds = (int) Math.floor(duration / 1000);
int days = 0, hours = 0, minutes = 0;
@@ -353,11 +373,11 @@
int start = pos;
boolean zeropad = fieldLen != 0;
- pos = printField(formatStr, days, 'd', pos, false, 0);
- pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0);
- pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0);
- pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0);
- pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0);
+ pos = printFieldLocked(formatStr, days, 'd', pos, false, 0);
+ pos = printFieldLocked(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0);
+ pos = printFieldLocked(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0);
+ pos = printFieldLocked(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0);
+ pos = printFieldLocked(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0);
formatStr[pos] = 's';
return pos + 1;
}
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/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/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 7ae7d0f..05cfd81 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -47,7 +47,6 @@
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.ActionMode;
-import android.view.ActionMode.Callback;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -106,6 +105,10 @@
private static final int INVALID_POSITION = -1;
+ // The fade duration for toolbar and action bar when entering/exiting action mode.
+ private static final long FADE_OUT_DURATION_MS = 100;
+ private static final long FADE_IN_DURATION_MS = 200;
+
private int mContextDisplayMode;
private boolean mHasEmbeddedTabs;
@@ -866,8 +869,21 @@
hideForActionMode();
}
- mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
- mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
+ Animator fadeIn, fadeOut;
+ if (toActionMode) {
+ fadeOut = mDecorToolbar.setupAnimatorToVisibility(View.GONE,
+ FADE_OUT_DURATION_MS);
+ fadeIn = mContextView.setupAnimatorToVisibility(View.VISIBLE,
+ FADE_IN_DURATION_MS);
+ } else {
+ fadeIn = mDecorToolbar.setupAnimatorToVisibility(View.VISIBLE,
+ FADE_IN_DURATION_MS);
+ fadeOut = mContextView.setupAnimatorToVisibility(View.GONE,
+ FADE_OUT_DURATION_MS);
+ }
+ AnimatorSet set = new AnimatorSet();
+ set.playSequentially(fadeOut, fadeIn);
+ set.start();
// mTabScrollView's visibility is not affected by action mode.
}
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 850ea23..35eeca7 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -136,10 +136,11 @@
return getVisibility();
}
- public void animateToVisibility(int visibility) {
+ public Animator setupAnimatorToVisibility(int visibility, long duration) {
if (mVisibilityAnim != null) {
mVisibilityAnim.cancel();
}
+
if (visibility == VISIBLE) {
if (getVisibility() != VISIBLE) {
setAlpha(0);
@@ -147,38 +148,43 @@
mMenuView.setAlpha(0);
}
}
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
- anim.setDuration(FADE_DURATION);
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, View.ALPHA, 1);
+ anim.setDuration(duration);
anim.setInterpolator(sAlphaInterpolator);
if (mSplitView != null && mMenuView != null) {
AnimatorSet set = new AnimatorSet();
- ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
- splitAnim.setDuration(FADE_DURATION);
+ ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, View.ALPHA, 1);
+ splitAnim.setDuration(duration);
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
set.play(anim).with(splitAnim);
- set.start();
+ return set;
} else {
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
- anim.start();
+ return anim;
}
} else {
- ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
- anim.setDuration(FADE_DURATION);
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, View.ALPHA, 0);
+ anim.setDuration(duration);
anim.setInterpolator(sAlphaInterpolator);
if (mSplitView != null && mMenuView != null) {
AnimatorSet set = new AnimatorSet();
- ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
- splitAnim.setDuration(FADE_DURATION);
+ ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, View.ALPHA, 0);
+ splitAnim.setDuration(duration);
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
set.play(anim).with(splitAnim);
- set.start();
+ return set;
} else {
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
- anim.start();
+ return anim;
}
}
}
+ public void animateToVisibility(int visibility) {
+ Animator anim = setupAnimatorToVisibility(visibility, FADE_DURATION);
+ anim.start();
+ }
+
@Override
public void setVisibility(int visibility) {
if (visibility != getVisibility()) {
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index c5d3290..693b194 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -21,10 +21,6 @@
import android.widget.ActionMenuView;
import com.android.internal.view.menu.MenuBuilder;
-import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@@ -35,14 +31,13 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* @hide
*/
-public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
+public class ActionBarContextView extends AbsActionBarView {
private static final String TAG = "ActionBarContextView";
private CharSequence mTitle;
@@ -59,14 +54,6 @@
private boolean mTitleOptional;
private int mCloseItemLayout;
- private Animator mCurrentAnimation;
- private boolean mAnimateInOnLayout;
- private int mAnimationMode;
-
- private static final int ANIMATE_IDLE = 0;
- private static final int ANIMATE_IN = 1;
- private static final int ANIMATE_OUT = 2;
-
public ActionBarContextView(Context context) {
this(context, null);
}
@@ -255,43 +242,23 @@
mMenuView.setBackgroundDrawable(mSplitBackground);
mSplitView.addView(mMenuView, layoutParams);
}
-
- mAnimateInOnLayout = true;
}
public void closeMode() {
- if (mAnimationMode == ANIMATE_OUT) {
- // Called again during close; just finish what we were doing.
- return;
- }
if (mClose == null) {
killMode();
return;
}
- finishAnimation();
- mAnimationMode = ANIMATE_OUT;
- mCurrentAnimation = makeOutAnimation();
- mCurrentAnimation.start();
- }
-
- private void finishAnimation() {
- final Animator a = mCurrentAnimation;
- if (a != null) {
- mCurrentAnimation = null;
- a.end();
- }
}
public void killMode() {
- finishAnimation();
removeAllViews();
if (mSplitView != null) {
mSplitView.removeView(mMenuView);
}
mCustomView = null;
mMenuView = null;
- mAnimateInOnLayout = false;
}
@Override
@@ -343,7 +310,7 @@
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
"with android:layout_height=\"wrap_content\"");
}
-
+
final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
int maxHeight = mContentHeight > 0 ?
@@ -353,7 +320,7 @@
int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
final int height = maxHeight - verticalPadding;
final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
-
+
if (mClose != null) {
availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
@@ -411,66 +378,13 @@
}
}
- private Animator makeInAnimation() {
- mClose.setTranslationX(-mClose.getWidth() -
- ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
- ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0);
- buttonAnimator.setDuration(200);
- buttonAnimator.addListener(this);
- buttonAnimator.setInterpolator(new DecelerateInterpolator());
-
- AnimatorSet set = new AnimatorSet();
- AnimatorSet.Builder b = set.play(buttonAnimator);
-
- if (mMenuView != null) {
- final int count = mMenuView.getChildCount();
- if (count > 0) {
- for (int i = count - 1, j = 0; i >= 0; i--, j++) {
- View child = mMenuView.getChildAt(i);
- child.setScaleY(0);
- ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1);
- a.setDuration(300);
- b.with(a);
- }
- }
- }
-
- return set;
- }
-
- private Animator makeOutAnimation() {
- ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
- -mClose.getWidth() - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
- buttonAnimator.setDuration(200);
- buttonAnimator.addListener(this);
- buttonAnimator.setInterpolator(new DecelerateInterpolator());
-
- AnimatorSet set = new AnimatorSet();
- AnimatorSet.Builder b = set.play(buttonAnimator);
-
- if (mMenuView != null) {
- final int count = mMenuView.getChildCount();
- if (count > 0) {
- for (int i = 0; i < 0; i++) {
- View child = mMenuView.getChildAt(i);
- child.setScaleY(0);
- ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
- a.setDuration(300);
- b.with(a);
- }
- }
- }
-
- return set;
- }
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final boolean isLayoutRtl = isLayoutRtl();
int x = isLayoutRtl ? r - l - getPaddingRight() : getPaddingLeft();
final int y = getPaddingTop();
final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
-
+
if (mClose != null && mClose.getVisibility() != GONE) {
MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
final int startMargin = (isLayoutRtl ? lp.rightMargin : lp.leftMargin);
@@ -479,12 +393,6 @@
x += positionChild(mClose, x, y, contentHeight, isLayoutRtl);
x = next(x, endMargin, isLayoutRtl);
- if (mAnimateInOnLayout) {
- mAnimationMode = ANIMATE_IN;
- mCurrentAnimation = makeInAnimation();
- mCurrentAnimation.start();
- mAnimateInOnLayout = false;
- }
}
if (mTitleLayout != null && mCustomView == null && mTitleLayout.getVisibility() != GONE) {
@@ -503,26 +411,6 @@
}
@Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mAnimationMode == ANIMATE_OUT) {
- killMode();
- }
- mAnimationMode = ANIMATE_IDLE;
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
-
- @Override
public boolean shouldDelayChildPressedState() {
return false;
}
diff --git a/core/java/com/android/internal/widget/DecorToolbar.java b/core/java/com/android/internal/widget/DecorToolbar.java
index fb413b5..fe70d7b 100644
--- a/core/java/com/android/internal/widget/DecorToolbar.java
+++ b/core/java/com/android/internal/widget/DecorToolbar.java
@@ -17,6 +17,7 @@
package com.android.internal.widget;
+import android.animation.Animator;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Parcelable;
@@ -87,6 +88,7 @@
void setCustomView(View view);
View getCustomView();
void animateToVisibility(int visibility);
+ Animator setupAnimatorToVisibility(int visibility, long duration);
void setNavigationIcon(Drawable icon);
void setNavigationIcon(int resId);
void setNavigationContentDescription(CharSequence description);
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
index 54df87b..32aae72 100644
--- a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.TypedArray;
@@ -59,6 +60,8 @@
private static final int AFFECTS_LOGO_MASK =
ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO;
+ // Default fade duration for fading in/out tool bar.
+ private static final long DEFAULT_FADE_DURATION_MS = 200;
private Toolbar mToolbar;
@@ -571,9 +574,19 @@
@Override
public void animateToVisibility(int visibility) {
+ Animator anim = setupAnimatorToVisibility(visibility, DEFAULT_FADE_DURATION_MS);
+ if (anim != null) {
+ anim.start();
+ }
+ }
+
+ @Override
+ public Animator setupAnimatorToVisibility(int visibility, long duration) {
+
if (visibility == View.GONE) {
- mToolbar.animate().alpha(0)
- .setListener(new AnimatorListenerAdapter() {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(mToolbar, View.ALPHA, 1, 0);
+ anim.setDuration(duration);
+ anim.addListener(new AnimatorListenerAdapter() {
private boolean mCanceled = false;
@Override
public void onAnimationEnd(Animator animation) {
@@ -587,15 +600,19 @@
mCanceled = true;
}
});
+ return anim;
} else if (visibility == View.VISIBLE) {
- mToolbar.animate().alpha(1)
- .setListener(new AnimatorListenerAdapter() {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(mToolbar, View.ALPHA, 0, 1);
+ anim.setDuration(duration);
+ anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mToolbar.setVisibility(View.VISIBLE);
}
});
+ return anim;
}
+ return null;
}
@Override
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index a13dc85..97df978e 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -58,6 +58,7 @@
android:layout_marginStart="4dp"
android:scaleType="fitCenter"
android:visibility="gone"
+ android:contentDescription="@string/notification_work_profile_content_description"
/>
</LinearLayout>
<include
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index b677a98..7ae29fb 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -60,6 +60,7 @@
android:layout_marginStart="4dp"
android:scaleType="fitCenter"
android:visibility="gone"
+ android:contentDescription="@string/notification_work_profile_content_description"
/>
</LinearLayout>
<ImageView
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index c109225..950ae40 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -62,6 +62,7 @@
android:layout_marginStart="4dp"
android:scaleType="fitCenter"
android:visibility="gone"
+ android:contentDescription="@string/notification_work_profile_content_description"
/>
</LinearLayout>
<TextView android:id="@+id/inbox_text1"
diff --git a/core/res/res/layout/notification_template_part_line2.xml b/core/res/res/layout/notification_template_part_line2.xml
index aeef3ab..db43271 100644
--- a/core/res/res/layout/notification_template_part_line2.xml
+++ b/core/res/res/layout/notification_template_part_line2.xml
@@ -43,6 +43,7 @@
android:layout_marginStart="4dp"
android:scaleType="fitCenter"
android:visibility="gone"
+ android:contentDescription="@string/notification_work_profile_content_description"
/>
</LinearLayout>
<ViewStub
diff --git a/core/res/res/layout/notification_template_part_line3.xml b/core/res/res/layout/notification_template_part_line3.xml
index 6c043a0..da3c5c5 100644
--- a/core/res/res/layout/notification_template_part_line3.xml
+++ b/core/res/res/layout/notification_template_part_line3.xml
@@ -51,5 +51,6 @@
android:layout_marginStart="4dp"
android:scaleType="fitCenter"
android:visibility="gone"
+ android:contentDescription="@string/notification_work_profile_content_description"
/>
</LinearLayout>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a6b7e35..915a445 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4168,6 +4168,9 @@
<string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
<string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
+ <!-- Content description of the work profile icon in the notification. -->
+ <string name="notification_work_profile_content_description">Work profile</string>
+
<!-- User visible name for USB MIDI Peripheral port -->
<string name="usb_midi_peripheral_name">Android USB Peripheral Port</string>
<!-- Manufacturer name for USB MIDI Peripheral port -->
diff --git a/core/tests/notificationtests/src/android/app/NotificationStressTest.java b/core/tests/notificationtests/src/android/app/NotificationStressTest.java
index 52ea1c4..4cb617e 100644
--- a/core/tests/notificationtests/src/android/app/NotificationStressTest.java
+++ b/core/tests/notificationtests/src/android/app/NotificationStressTest.java
@@ -77,15 +77,20 @@
}
private void sendNotification(int id, CharSequence text) {
- // Create "typical" notification with random icon
- Notification notification = new Notification(ICONS[mRandom.nextInt(ICONS.length)], text,
- System.currentTimeMillis());
// Fill in arbitrary content
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
CharSequence title = text + " " + id;
CharSequence subtitle = String.valueOf(System.currentTimeMillis());
- notification.setLatestEventInfo(mContext, title, subtitle, pendingIntent);
+ // Create "typical" notification with random icon
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(ICONS[mRandom.nextInt(ICONS.length)])
+ .setTicker(text)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle(title)
+ .setContentText(subtitle)
+ .setContentIntent(pendingIntent)
+ .build();
mNotificationManager.notify(id, notification);
SystemClock.sleep(10);
}
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/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
index 19375a2..d2d5850 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
@@ -368,7 +368,10 @@
byte[] output;
try {
- output = mMainDataStreamer.doFinal(input, inputOffset, inputLen);
+ byte[] additionalEntropy =
+ KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
+ mRng, getAdditionalEntropyAmountForFinish());
+ output = mMainDataStreamer.doFinal(input, inputOffset, inputLen, additionalEntropy);
} catch (KeyStoreException e) {
switch (e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
@@ -667,21 +670,37 @@
/**
* Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code begin} operation.
+ * {@code begin} operation. This amount of entropy is typically what's consumed to generate
+ * random parameters, such as IV.
*
- * <p>For decryption, this should be {@code 0} because decryption should not be consuming any
- * entropy. For encryption, this value should match (or exceed) the amount of Shannon entropy of
- * the ciphertext produced by this cipher assuming the key, the plaintext, and all explicitly
- * provided parameters to {@code Cipher.init} are known. For example, for AES CBC encryption
- * with an explicitly provided IV this should be {@code 0}, whereas for the case where IV is
- * generated by the KeyStore's {@code begin} operation this should be {@code 16}. For RSA with
- * OAEP this should be the size of the OAEP hash output. For RSA with PKCS#1 padding this should
- * be the size of the padding string or could be raised (for simplicity) to the size of the
- * modulus.
+ * <p>For decryption, the return value should be {@code 0} because decryption should not be
+ * consuming any entropy. For encryption, the value combined with
+ * {@link #getAdditionalEntropyAmountForFinish()} should match (or exceed) the amount of Shannon
+ * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
+ * explicitly provided parameters to {@code Cipher.init} are known. For example, for AES CBC
+ * encryption with an explicitly provided IV the return value should be {@code 0}, whereas for
+ * the case where IV is generated by the KeyStore's {@code begin} operation it should be
+ * {@code 16}.
*/
protected abstract int getAdditionalEntropyAmountForBegin();
/**
+ * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
+ * {@code finish} operation. This amount of entropy is typically what's consumed by encryption
+ * padding scheme.
+ *
+ * <p>For decryption, the return value should be {@code 0} because decryption should not be
+ * consuming any entropy. For encryption, the value combined with
+ * {@link #getAdditionalEntropyAmountForBegin()} should match (or exceed) the amount of Shannon
+ * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
+ * explicitly provided parameters to {@code Cipher.init} are known. For example, for RSA with
+ * OAEP the return value should be the size of the OAEP hash output. For RSA with PKCS#1 padding
+ * the return value should be the size of the padding string or could be raised (for simplicity)
+ * to the size of the modulus.
+ */
+ protected abstract int getAdditionalEntropyAmountForFinish();
+
+ /**
* Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
*
* @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
index 335da07..d19a766 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
@@ -117,7 +117,7 @@
}
@Override
- protected int getAdditionalEntropyAmountForBegin() {
- return (isSigning()) ? mGroupSizeBytes : 0;
+ protected int getAdditionalEntropyAmountForSign() {
+ return mGroupSizeBytes;
}
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
index f31c06d..f7c184c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
@@ -232,7 +232,10 @@
byte[] result;
try {
- result = mChunkedStreamer.doFinal(null, 0, 0);
+ result = mChunkedStreamer.doFinal(
+ null, 0, 0,
+ null // no additional entropy needed -- HMAC is deterministic
+ );
} catch (KeyStoreException e) {
throw new ProviderException("Keystore operation failed", e);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 35af34f..b93424d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -215,14 +215,8 @@
legacySpec.getKeystoreAlias(),
KeyProperties.PURPOSE_SIGN
| KeyProperties.PURPOSE_VERIFY);
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
+ // Authorized to be used with any digest (including no digest).
+ specBuilder.setDigests(KeyProperties.DIGEST_NONE);
break;
case KeymasterDefs.KM_ALGORITHM_RSA:
specBuilder = new KeyGenParameterSpec.Builder(
@@ -231,19 +225,13 @@
| KeyProperties.PURPOSE_DECRYPT
| KeyProperties.PURPOSE_SIGN
| KeyProperties.PURPOSE_VERIFY);
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
+ // Authorized to be used with any digest (including no digest).
+ specBuilder.setDigests(KeyProperties.DIGEST_NONE);
specBuilder.setSignaturePaddings(
KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+ // Authorized to be used with any padding (including no padding).
specBuilder.setEncryptionPaddings(
- KeyProperties.ENCRYPTION_PADDING_NONE,
- KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+ KeyProperties.ENCRYPTION_PADDING_NONE);
// Disable randomized encryption requirement to support encryption
// padding NONE above.
specBuilder.setRandomizedEncryptionRequired(false);
@@ -703,6 +691,36 @@
}
case KeymasterDefs.KM_ALGORITHM_RSA:
{
+ // Check whether this key is authorized for PKCS#1 signature padding.
+ // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
+ // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
+ // to be authorized for PKCS#1 padding or padding NONE which means any padding.
+ boolean pkcs1SignaturePaddingSupported = false;
+ for (int keymasterPadding : KeyProperties.SignaturePadding.allToKeymaster(
+ spec.getSignaturePaddings())) {
+ if ((keymasterPadding == KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN)
+ || (keymasterPadding == KeymasterDefs.KM_PAD_NONE)) {
+ pkcs1SignaturePaddingSupported = true;
+ break;
+ }
+ }
+ if (!pkcs1SignaturePaddingSupported) {
+ // Keymaster doesn't distinguish between encryption padding NONE and signature
+ // padding NONE. In the Android Keystore API only encryption padding NONE is
+ // exposed.
+ for (int keymasterPadding : KeyProperties.EncryptionPadding.allToKeymaster(
+ spec.getEncryptionPaddings())) {
+ if (keymasterPadding == KeymasterDefs.KM_PAD_NONE) {
+ pkcs1SignaturePaddingSupported = true;
+ break;
+ }
+ }
+ }
+ if (!pkcs1SignaturePaddingSupported) {
+ // Key not authorized for PKCS#1 signature padding -- can't sign
+ return null;
+ }
+
Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
spec.getDigests(),
AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
index d33692a..6abdf19 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
@@ -99,6 +99,11 @@
}
@Override
+ protected final int getAdditionalEntropyAmountForFinish() {
+ return 0;
+ }
+
+ @Override
@NonNull
protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
KeyStore keyStore, IBinder operationToken) {
@@ -142,7 +147,8 @@
}
@Override
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength)
+ public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
+ byte[] additionalEntropy)
throws KeyStoreException {
if (inputLength > 0) {
mInputBuffer.write(input, inputOffset, inputLength);
@@ -165,7 +171,7 @@
"Message size (" + bufferedInput.length + " bytes) must be smaller than"
+ " modulus (" + mModulusSizeBytes + " bytes)");
}
- return mDelegate.doFinal(paddedInput, 0, paddedInput.length);
+ return mDelegate.doFinal(paddedInput, 0, paddedInput.length, additionalEntropy);
}
}
}
@@ -207,6 +213,11 @@
@Override
protected final int getAdditionalEntropyAmountForBegin() {
+ return 0;
+ }
+
+ @Override
+ protected final int getAdditionalEntropyAmountForFinish() {
return (isEncrypting()) ? getModulusSizeBytes() : 0;
}
}
@@ -361,6 +372,11 @@
@Override
protected final int getAdditionalEntropyAmountForBegin() {
+ return 0;
+ }
+
+ @Override
+ protected final int getAdditionalEntropyAmountForFinish() {
return (isEncrypting()) ? mDigestOutputSizeBytes : 0;
}
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
index 898336d..954b71a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
@@ -36,7 +36,7 @@
}
@Override
- protected final int getAdditionalEntropyAmountForBegin() {
+ protected final int getAdditionalEntropyAmountForSign() {
// No entropy required for this deterministic signature scheme.
return 0;
}
@@ -92,8 +92,8 @@
}
@Override
- protected final int getAdditionalEntropyAmountForBegin() {
- return (isSigning()) ? SALT_LENGTH_BYTES : 0;
+ protected final int getAdditionalEntropyAmountForSign() {
+ return SALT_LENGTH_BYTES;
}
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
index f072ae7..5cdcc41 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -198,15 +198,14 @@
KeymasterArguments keymasterInputArgs = new KeymasterArguments();
addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
- byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- appRandom, getAdditionalEntropyAmountForBegin());
OperationResult opResult = mKeyStore.begin(
mKey.getAlias(),
mSigning ? KeymasterDefs.KM_PURPOSE_SIGN : KeymasterDefs.KM_PURPOSE_VERIFY,
true, // permit aborting this operation if keystore runs out of resources
keymasterInputArgs,
- additionalEntropy);
+ null // no additional entropy for begin -- only finish might need some
+ );
if (opResult == null) {
throw new KeyStoreConnectException();
}
@@ -311,7 +310,11 @@
byte[] signature;
try {
ensureKeystoreOperationInitialized();
- signature = mMessageStreamer.doFinal(EmptyArray.BYTE, 0, 0);
+
+ byte[] additionalEntropy =
+ KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
+ appRandom, getAdditionalEntropyAmountForSign());
+ signature = mMessageStreamer.doFinal(EmptyArray.BYTE, 0, 0, additionalEntropy);
} catch (InvalidKeyException | KeyStoreException e) {
throw new SignatureException(e);
}
@@ -388,15 +391,14 @@
/**
* Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code begin} operation.
+ * {@code finish} operation when generating a signature.
*
- * <p>For signature verification, this should be {@code 0} because verification should not be
- * consuming any entropy. For signature generation, this value should match (or exceed) the
- * amount of Shannon entropy of the produced signature assuming the key and the message are
- * known. For example, for ECDSA signature this should be the size of {@code R}, whereas for the
- * RSA signature with PKCS#1 padding this should be {@code 0}.
+ * <p>This value should match (or exceed) the amount of Shannon entropy of the produced
+ * signature assuming the key and the message are known. For example, for ECDSA signature this
+ * should be the size of {@code R}, whereas for the RSA signature with PKCS#1 padding this
+ * should be {@code 0}.
*/
- protected abstract int getAdditionalEntropyAmountForBegin();
+ protected abstract int getAdditionalEntropyAmountForSign();
/**
* Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 831a106..3bd9d1d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -247,14 +247,8 @@
specBuilder =
new KeyProtection.Builder(
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
+ // Authorized to be used with any digest (including no digest).
+ specBuilder.setDigests(KeyProperties.DIGEST_NONE);
} else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
specBuilder =
new KeyProtection.Builder(
@@ -262,19 +256,13 @@
| KeyProperties.PURPOSE_DECRYPT
| KeyProperties.PURPOSE_SIGN
| KeyProperties.PURPOSE_VERIFY);
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
+ // Authorized to be used with any digest (including no digest).
+ specBuilder.setDigests(KeyProperties.DIGEST_NONE);
specBuilder.setSignaturePaddings(
KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+ // Authorized to be used with any padding (including no padding).
specBuilder.setEncryptionPaddings(
- KeyProperties.ENCRYPTION_PADDING_NONE,
- KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+ KeyProperties.ENCRYPTION_PADDING_NONE);
// Disable randomized encryption requirement to support encryption padding NONE
// above.
specBuilder.setRandomizedEncryptionRequired(false);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
index 47cd1d1..76804a9 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
@@ -210,6 +210,11 @@
}
@Override
+ protected final int getAdditionalEntropyAmountForFinish() {
+ return 0;
+ }
+
+ @Override
protected final void addAlgorithmSpecificParametersToBegin(
@NonNull KeymasterArguments keymasterArgs) {
if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) {
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 68c9c79..47aab74 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -611,9 +611,14 @@
*
* <p>This must be specified for keys which are used for signing/verification. For HMAC
* keys, the set of digests defaults to the digest associated with the key algorithm (e.g.,
- * {@code SHA-256} for key algorithm {@code HmacSHA256}
+ * {@code SHA-256} for key algorithm {@code HmacSHA256}).
*
- * @see KeyProperties.Digest
+ * <p>For private keys used for TLS/SSL client or server authentication it is usually
+ * necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is
+ * because TLS/SSL stacks typically generate the necessary digest(s) themselves and then use
+ * a private key to sign it.
+ *
+ * <p>See {@link KeyProperties}.{@code DIGEST} constants.
*/
@NonNull
public Builder setDigests(@KeyProperties.DigestEnum String... digests) {
@@ -629,6 +634,12 @@
*
* <p>This must be specified for keys which are used for encryption/decryption.
*
+ * <p>For RSA private keys used by TLS/SSL servers to authenticate themselves to clients it
+ * is usually necessary to authorize the use of no/any padding
+ * ({@link KeyProperties#ENCRYPTION_PADDING_NONE}). This is because RSA decryption is
+ * required by some cipher suites, and some stacks request decryption using no padding
+ * whereas others request PKCS#1 padding.
+ *
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
*/
@NonNull
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 5af4181..403e814 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -368,6 +368,9 @@
/**
* No encryption padding.
+ *
+ * <p><b>NOTE</b>: If a key is authorized to be used with no padding, then it can be used with
+ * any padding scheme.
*/
public static final String ENCRYPTION_PADDING_NONE = "NoPadding";
@@ -514,6 +517,9 @@
/**
* No digest: sign/authenticate the raw message.
+ *
+ * <p><b>NOTE</b>: If a key is authorized to be used with no digest, then it can be used with
+ * any digest.
*/
public static final String DIGEST_NONE = "NONE";
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 48c0ed0f..432fc12 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -374,6 +374,12 @@
*
* <p>This must be specified for keys which are used for encryption/decryption.
*
+ * <p>For RSA private keys used by TLS/SSL servers to authenticate themselves to clients it
+ * is usually necessary to authorize the use of no/any padding
+ * ({@link KeyProperties#ENCRYPTION_PADDING_NONE}). This is because RSA decryption is
+ * required by some cipher suites, and some stacks request decryption using no padding
+ * whereas others request PKCS#1 padding.
+ *
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
*/
@NonNull
@@ -408,6 +414,11 @@
* {@link Key#getAlgorithm()}. For asymmetric signing keys the set of digest algorithms
* must be specified.
*
+ * <p>For private keys used for TLS/SSL client or server authentication it is usually
+ * necessary to authorize the use of no digest ({@link KeyProperties#DIGEST_NONE}). This is
+ * because TLS/SSL stacks typically generate the necessary digest(s) themselves and then use
+ * a private key to sign it.
+ *
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
*/
@NonNull
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
index 47b4996..9957e79 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
@@ -35,8 +35,8 @@
* amount of data in one go because the operations are marshalled via Binder. Secondly, the update
* operation may consume less data than provided, in which case the caller has to buffer the
* remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int) doFinal} operations which can be used to conveniently implement
- * various JCA crypto primitives.
+ * {@link #doFinal(byte[], int, int, byte[]) doFinal} operations which can be used to conveniently
+ * implement various JCA crypto primitives.
*
* <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
* a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
@@ -60,7 +60,7 @@
* Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
* be reached.
*/
- OperationResult finish();
+ OperationResult finish(byte[] additionalEntropy);
}
// Binder buffer is about 1MB, but it's shared between all active transactions of the process.
@@ -192,7 +192,7 @@
}
@Override
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength)
+ public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] additionalEntropy)
throws KeyStoreException {
if (inputLength == 0) {
// No input provided -- simplify the rest of the code
@@ -204,7 +204,7 @@
byte[] output = update(input, inputOffset, inputLength);
output = ArrayUtils.concat(output, flush());
- OperationResult opResult = mKeyStoreStream.finish();
+ OperationResult opResult = mKeyStoreStream.finish(additionalEntropy);
if (opResult == null) {
throw new KeyStoreConnectException();
} else if (opResult.resultCode != KeyStore.NO_ERROR) {
@@ -268,8 +268,8 @@
}
@Override
- public OperationResult finish() {
- return mKeyStore.finish(mOperationToken, null, null);
+ public OperationResult finish(byte[] additionalEntropy) {
+ return mKeyStore.finish(mOperationToken, null, null, additionalEntropy);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
index 2fb8f20..1c6de2d 100644
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
+++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
@@ -28,12 +28,13 @@
* amount of data in one go because the operations are marshalled via Binder. Secondly, the update
* operation may consume less data than provided, in which case the caller has to buffer the
* remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int) doFinal} operations which can be used to conveniently implement
- * various JCA crypto primitives.
+ * {@link #doFinal(byte[], int, int, byte[]) doFinal} operations which can be used to conveniently
+ * implement various JCA crypto primitives.
*
* @hide
*/
interface KeyStoreCryptoOperationStreamer {
byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
- byte[] doFinal(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
+ byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] additionalEntropy)
+ throws KeyStoreException;
}
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index b077a85..f05857c 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -494,7 +494,9 @@
// complex clip has a complex set of expectations on the renderer state - for now, avoid taking
// the merge path in those cases
deferInfo.mergeable &= !recordingComplexClip();
- deferInfo.opaqueOverBounds &= !recordingComplexClip() && mSaveStack.isEmpty();
+ deferInfo.opaqueOverBounds &= !recordingComplexClip()
+ && mSaveStack.isEmpty()
+ && !state->mRoundRectClipState;
if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() &&
state->mClipSideFlags != kClipSide_ConservativeFull &&
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index b7cdaa2..288fed3 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -29,8 +29,9 @@
#include <GLES2/gl2.h>
#include <SkPaint.h>
-namespace android {
-namespace uirenderer {
+#define DEBUG_GLOP_BUILDER 0
+
+#if DEBUG_GLOP_BUILDER
#define TRIGGER_STAGE(stageFlag) \
LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
@@ -40,6 +41,16 @@
LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
"not prepared for current stage")
+#else
+
+#define TRIGGER_STAGE(stageFlag) ((void)0)
+#define REQUIRE_STAGES(requiredFlags) ((void)0)
+
+#endif
+
+namespace android {
+namespace uirenderer {
+
static void setUnitQuadTextureCoords(Rect uvs, TextureVertex* quadVertex) {
quadVertex[0] = {0, 0, uvs.left, uvs.top};
quadVertex[1] = {1, 0, uvs.right, uvs.top};
@@ -301,7 +312,7 @@
GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
const int textureFillFlags, const SkPaint* paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter)
? GL_LINEAR : PaintUtils::getFilter(paint);
@@ -345,7 +356,7 @@
GlopBuilder& GlopBuilder::setFillPaint(const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
@@ -359,7 +370,7 @@
GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
//specify invalid filter/clamp, since these are always static for PathTextures
mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
@@ -376,7 +387,7 @@
GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
//specify invalid filter/clamp, since these are always static for ShadowTextures
mOutGlop->fill.texture = { &texture, GL_TEXTURE_2D, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
@@ -399,7 +410,7 @@
GlopBuilder& GlopBuilder::setFillBlack() {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, Blend::ModeOrderSwap::NoSwap,
@@ -409,7 +420,7 @@
GlopBuilder& GlopBuilder::setFillClear() {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, Blend::ModeOrderSwap::NoSwap,
@@ -420,7 +431,7 @@
GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
float alpha, SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { &texture,
GL_TEXTURE_2D, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
@@ -434,7 +445,7 @@
GlopBuilder& GlopBuilder::setFillTextureLayer(Layer& layer, float alpha) {
TRIGGER_STAGE(kFillStage);
- REQUIRE_STAGES(kMeshStage);
+ REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { &(layer.getTexture()),
layer.getRenderTarget(), GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 5769376..433e178 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -847,11 +847,11 @@
&& layer->getHeight() == (uint32_t) rect.getHeight();
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
.setFillTextureLayer(*layer, getLayerAlpha(layer))
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -859,12 +859,12 @@
void OpenGLRenderer::composeLayerRectSwapped(Layer* layer, const Rect& rect) {
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(nullptr, layer->texCoords)
.setFillLayer(layer->getTexture(), layer->getColorFilter(),
getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::Swap)
.setTransform(*currentSnapshot(), TransformFlags::MeshIgnoresCanvasTransform)
.setModelViewMapUnitToRect(rect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -880,11 +880,11 @@
&& layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(nullptr, layer->texCoords)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, rect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1021,11 +1021,11 @@
Rect modelRect = Rect(rect.getWidth(), rect.getHeight());
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRectSnap(rect.left, rect.top, modelRect)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
@@ -1140,11 +1140,11 @@
const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(nullptr) // clear ignores clip state
.setMeshIndexedQuads(&mesh[0], quadCount)
.setFillClear()
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop, false);
@@ -1330,11 +1330,11 @@
Glop glop;
Vertex* vertices = &rectangleVertices[0];
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshIndexedQuads(vertices, rectangleVertices.size() / 4)
.setFillBlack()
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, scissorBox)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1534,11 +1534,11 @@
const int transformFlags = TransformFlags::MeshIgnoresCanvasTransform;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedMesh(vertices, bitmapCount * 6)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1557,11 +1557,11 @@
? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUnitQuad(texture->uvMapper)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1647,11 +1647,11 @@
const int textureFillFlags = TextureFillFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshColoredTexturedMesh(mesh.get(), elementCount)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1676,11 +1676,11 @@
&& MathUtils::areEqual(src.getHeight(), dst.getHeight());
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUvQuad(texture->uvMapper, uv)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRectOptionalSnap(tryToSnap, dst)
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1702,11 +1702,11 @@
}
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshPatchQuads(*mesh)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1732,11 +1732,11 @@
}
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedIndexedQuads(vertices, elementCount)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -1753,11 +1753,11 @@
const int transformFlags = TransformFlags::OffsetByFudgeFactor;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshVertexBuffer(vertexBuffer, shadowInterp)
.setFillPaint(*paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2039,11 +2039,11 @@
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
.setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2364,11 +2364,11 @@
} else if (layer->mesh) {
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
#if DEBUG_LAYERS_AS_REGIONS
@@ -2422,11 +2422,11 @@
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
.setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
.setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2560,11 +2560,11 @@
? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshIndexedQuads(&mesh[0], count / 4)
.setFillPaint(*paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
@@ -2575,11 +2575,11 @@
? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
Glop glop;
GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.setMeshUnitQuad()
.setFillPaint(*paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
.setModelViewMapUnitToRect(Rect(left, top, right, bottom))
- .setRoundRectClipState(currentSnapshot()->roundRectClipState)
.build();
renderGlop(glop);
}
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/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index 95b3eb3..260f380 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -172,7 +172,7 @@
* <p>
* This is lazily created, so use {@link #setNINotification()}.
*/
- private Notification mNiNotification;
+ private Notification.Builder mNiNotificationBuilder;
public GpsNetInitiatedHandler(Context context,
INetInitiatedListener netInitiatedListener,
@@ -367,29 +367,31 @@
", message: " + message);
// Construct Notification
- if (mNiNotification == null) {
- mNiNotification = new Notification();
- mNiNotification.icon = com.android.internal.R.drawable.stat_sys_gps_on; /* Change notification icon here */
- mNiNotification.when = 0;
+ if (mNiNotificationBuilder == null) {
+ mNiNotificationBuilder = new Notification.Builder(mContext)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
+ .setWhen(0)
+ .setOngoing(true)
+ .setAutoCancel(true)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
}
if (mPlaySounds) {
- mNiNotification.defaults |= Notification.DEFAULT_SOUND;
+ mNiNotificationBuilder.setDefaults(Notification.DEFAULT_SOUND);
} else {
- mNiNotification.defaults &= ~Notification.DEFAULT_SOUND;
+ mNiNotificationBuilder.setDefaults(0);
}
- mNiNotification.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_AUTO_CANCEL;
- mNiNotification.tickerText = getNotifTicker(notif, mContext);
-
// if not to popup dialog immediately, pending intent will open the dialog
Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent();
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0);
- mNiNotification.color = mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- mNiNotification.setLatestEventInfo(mContext, title, message, pi);
+ mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext))
+ .setContentTitle(title)
+ .setContentText(message)
+ .setContentIntent(pi);
- notificationManager.notifyAsUser(null, notif.notificationId, mNiNotification,
+ notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(),
UserHandle.ALL);
}
diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
index e30796d..c2cc2b9 100644
--- a/media/java/android/media/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -31,4 +31,5 @@
void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
MidiDeviceInfo getDeviceInfo();
+ void setDeviceInfo(in MidiDeviceInfo deviceInfo);
}
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index 1b56e1c..1212b64 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -269,8 +269,20 @@
public MidiDeviceInfo getDeviceInfo() {
return mDeviceInfo;
}
+
+ @Override
+ public void setDeviceInfo(MidiDeviceInfo deviceInfo) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("setDeviceInfo should only be called by MidiService");
+ }
+ if (mDeviceInfo != null) {
+ throw new IllegalStateException("setDeviceInfo should only be called once");
+ }
+ mDeviceInfo = deviceInfo;
+ }
};
+ // Constructor for MidiManager.createDeviceServer()
/* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,
int numOutputPorts, Callback callback) {
mMidiManager = midiManager;
@@ -292,6 +304,13 @@
mGuard.open("close");
}
+ // Constructor for MidiDeviceService.onCreate()
+ /* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,
+ MidiDeviceInfo deviceInfo, Callback callback) {
+ this(midiManager, inputPortReceivers, deviceInfo.getOutputPortCount(), callback);
+ mDeviceInfo = deviceInfo;
+ }
+
/* package */ IMidiDeviceServer getBinderInterface() {
return mServer;
}
@@ -300,13 +319,6 @@
return mServer.asBinder();
}
- /* package */ void setDeviceInfo(MidiDeviceInfo deviceInfo) {
- if (mDeviceInfo != null) {
- throw new IllegalStateException("setDeviceInfo should only be called once");
- }
- mDeviceInfo = deviceInfo;
- }
-
private void updateDeviceStatus() {
// clear calling identity, since we may be in a Binder call from one of our clients
long identityToken = Binder.clearCallingIdentity();
diff --git a/media/java/android/media/midi/MidiDeviceService.java b/media/java/android/media/midi/MidiDeviceService.java
index d897ad2..388d95b 100644
--- a/media/java/android/media/midi/MidiDeviceService.java
+++ b/media/java/android/media/midi/MidiDeviceService.java
@@ -83,9 +83,7 @@
if (inputPortReceivers == null) {
inputPortReceivers = new MidiReceiver[0];
}
- server = new MidiDeviceServer(mMidiManager, inputPortReceivers,
- deviceInfo.getOutputPortCount(), mCallback);
- server.setDeviceInfo(deviceInfo);
+ server = new MidiDeviceServer(mMidiManager, inputPortReceivers, deviceInfo, mCallback);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in IMidiManager.getServiceDeviceInfo");
server = null;
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 0beb9a4..89230fe 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -318,7 +318,6 @@
Log.e(TAG, "registerVirtualDevice failed");
return null;
}
- server.setDeviceInfo(deviceInfo);
return server;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in createVirtualDevice");
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 50a215c..f52ccc9 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -434,9 +434,12 @@
}
/**
- * Informs the application that the video is now available for watching. This is primarily
- * used to signal the application to unblock the screen. The TV input service must call this
- * method as soon as the content rendered onto its surface gets ready for viewing.
+ * Informs the application that the video is now available for watching. Video is blocked
+ * until this method is called.
+ *
+ * <p>The TV input service must call this method as soon as the content rendered onto its
+ * surface is ready for viewing. This method must be called each time {@link #onTune(Uri)}
+ * is called.
*
* @see #notifyVideoUnavailable
*/
@@ -761,9 +764,11 @@
public abstract void onSetStreamVolume(float volume);
/**
- * Tunes to a given channel. When the video is available, {@link #notifyVideoAvailable()}
- * should be called. Also, {@link #notifyVideoUnavailable(int)} should be called when the TV
- * input cannot continue playing the given channel.
+ * Tunes to a given channel.
+ *
+ * <p>No video will be displayed until {@link #notifyVideoAvailable()} is called.
+ * Also, {@link #notifyVideoUnavailable(int)} should be called when the TV input cannot
+ * continue playing the given channel.
*
* @param channelUri The URI of the channel.
* @return {@code true} if the tuning was successful, {@code false} otherwise.
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 742f570..26ece72 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -47,6 +47,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
import android.util.TimeUtils;
import java.io.ByteArrayOutputStream;
@@ -84,6 +85,12 @@
// Minimum alarm recurrence interval
private static final long MIN_INTERVAL = 60 * 1000; // one minute, in millis
+ // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle.
+ private static final long ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
+
+ // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling.
+ private static final long ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
+
private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP;
private static final int RTC_MASK = 1 << RTC;
private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP;
@@ -123,8 +130,8 @@
int mBroadcastRefCount = 0;
PowerManager.WakeLock mWakeLock;
boolean mLastWakeLockUnimportantForLogging;
- ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<Alarm>();
- ArrayList<InFlight> mInFlight = new ArrayList<InFlight>();
+ ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
+ ArrayList<InFlight> mInFlight = new ArrayList<>();
final AlarmHandler mHandler = new AlarmHandler();
ClockReceiver mClockReceiver;
InteractiveStateReceiver mInteractiveStateReceiver;
@@ -141,8 +148,15 @@
long mNextNonWakeupDeliveryTime;
long mLastTimeChangeClockTime;
long mLastTimeChangeRealtime;
+ long mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_SHORT_TIME;
int mNumTimeChanged;
+ /**
+ * For each uid, this is the last time we dispatched an "allow while idle" alarm,
+ * used to determine the earliest we can dispatch the next such alarm.
+ */
+ final SparseLongArray mLastAllowWhileIdleDispatch = new SparseLongArray();
+
private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser =
new SparseArray<>();
private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray =
@@ -552,7 +566,7 @@
a.when = a.origWhen;
long whenElapsed = convertToElapsed(a.when, a.type);
final long maxElapsed;
- if (a.whenElapsed == a.maxWhenElapsed) {
+ if (a.windowLength == AlarmManager.WINDOW_EXACT) {
// Exact
maxElapsed = whenElapsed;
} else {
@@ -580,6 +594,9 @@
}
}
+ // Make sure we are using the correct ALLOW_WHILE_IDLE min time.
+ mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_SHORT_TIME;
+
// Reschedule everything.
rescheduleKernelAlarmsLocked();
updateNextAlarmClockLocked();
@@ -632,7 +649,7 @@
mTag = tag;
}
}
-
+
static final class BroadcastStats {
final int mUid;
final String mPackageName;
@@ -649,7 +666,7 @@
mPackageName = packageName;
}
}
-
+
final SparseArray<ArrayMap<String, BroadcastStats>> mBroadcastStats
= new SparseArray<ArrayMap<String, BroadcastStats>>();
@@ -751,7 +768,7 @@
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, int flags, WorkSource workSource,
- AlarmManager.AlarmClockInfo alarmClock) {
+ AlarmManager.AlarmClockInfo alarmClock, int callingUid) {
if (operation == null) {
Slog.w(TAG, "set/setRepeating ignored because there is no intent");
return;
@@ -779,9 +796,8 @@
}
if (triggerAtTime < 0) {
- final long who = Binder.getCallingUid();
final long what = Binder.getCallingPid();
- Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + who
+ Slog.w(TAG, "Invalid alarm trigger time! " + triggerAtTime + " from uid=" + callingUid
+ " pid=" + what);
triggerAtTime = 0;
}
@@ -797,12 +813,12 @@
maxElapsed = triggerElapsed;
} else if (windowLength < 0) {
maxElapsed = maxTriggerTime(nowElapsed, triggerElapsed, interval);
+ // Fix this window in place, so that as time approaches we don't collapse it.
+ windowLength = maxElapsed - triggerElapsed;
} else {
maxElapsed = triggerElapsed + windowLength;
}
- final int userId = UserHandle.getCallingUserId();
-
synchronized (mLock) {
if (DEBUG_BATCH) {
Slog.v(TAG, "set(" + operation + ") : type=" + type
@@ -811,26 +827,20 @@
+ " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
- interval, operation, flags, true, workSource, alarmClock, userId);
+ interval, operation, flags, true, workSource, alarmClock, callingUid);
}
}
private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
long maxWhen, long interval, PendingIntent operation, int flags,
boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
- int userId) {
+ int uid) {
Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
- operation, workSource, flags, alarmClock, userId);
+ operation, workSource, flags, alarmClock, uid);
removeLocked(operation);
setImplLocked(a, false, doValidate);
}
- private void updateNextWakeFromIdleFuzzLocked() {
- if (mNextWakeFromIdle != null) {
-
- }
- }
-
private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
// This is a special alarm that will put the system into idle until it goes off.
@@ -862,7 +872,9 @@
} else if (mPendingIdleUntil != null) {
// We currently have an idle until alarm scheduled; if the new alarm has
// not explicitly stated it wants to run while idle, then put it on hold.
- if ((a.flags&(AlarmManager.FLAG_ALLOW_WHILE_IDLE|AlarmManager.FLAG_WAKE_FROM_IDLE))
+ if ((a.flags&(AlarmManager.FLAG_ALLOW_WHILE_IDLE
+ | AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
+ | AlarmManager.FLAG_WAKE_FROM_IDLE))
== 0) {
mPendingWhileIdleAlarms.add(a);
return;
@@ -892,6 +904,7 @@
if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
mPendingIdleUntil = a;
+ mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_LONG_TIME;
needRebatch = true;
} else if ((a.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
if (mNextWakeFromIdle == null || mNextWakeFromIdle.whenElapsed > a.whenElapsed) {
@@ -933,23 +946,45 @@
public void set(int type, long triggerAtTime, long windowLength, long interval, int flags,
PendingIntent operation, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock) {
+ final int callingUid = Binder.getCallingUid();
if (workSource != null) {
- getContext().enforceCallingPermission(
+ getContext().enforcePermission(
android.Manifest.permission.UPDATE_DEVICE_STATS,
- "AlarmManager.set");
+ Binder.getCallingPid(), callingUid, "AlarmManager.set");
}
+ // No incoming callers can request either WAKE_FROM_IDLE or
+ // ALLOW_WHILE_IDLE_UNRESTRICTED -- we will apply those later as appropriate.
+ flags &= ~(AlarmManager.FLAG_WAKE_FROM_IDLE
+ | AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED);
+
+ // Only the system can use FLAG_IDLE_UNTIL -- this is used to tell the alarm
+ // manager when to come out of idle mode, which is only for DeviceIdleController.
+ if (callingUid != Process.SYSTEM_UID) {
+ flags &= ~AlarmManager.FLAG_IDLE_UNTIL;
+ }
+
+ // If the caller is a core system component, and not calling to do work on behalf
+ // of someone else, then always set ALLOW_WHILE_IDLE_UNRESTRICTED. This means we
+ // will allow these alarms to go off as normal even while idle, with no timing
+ // restrictions.
+ if (callingUid < Process.FIRST_APPLICATION_UID && workSource == null) {
+ flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+ }
+
+ // If this is an exact time alarm, then it can't be batched with other alarms.
if (windowLength == AlarmManager.WINDOW_EXACT) {
flags |= AlarmManager.FLAG_STANDALONE;
}
+
+ // If this alarm is for an alarm clock, then it must be standalone and we will
+ // use it to wake early from idle if needed.
if (alarmClock != null) {
flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
}
- if (Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
- flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE;
- }
+
setImpl(type, triggerAtTime, windowLength, interval, operation,
- flags, workSource, alarmClock);
+ flags, workSource, alarmClock, callingUid);
}
@Override
@@ -1126,6 +1161,22 @@
pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
pw.println();
+ pw.print("mAllowWhileIdleMinTime=");
+ TimeUtils.formatDuration(mAllowWhileIdleMinTime, pw);
+ pw.println();
+ if (mLastAllowWhileIdleDispatch.size() > 0) {
+ pw.println("Last allow while idle dispatch times:");
+ for (int i=0; i<mLastAllowWhileIdleDispatch.size(); i++) {
+ pw.print(" UID ");
+ UserHandle.formatUid(pw, mLastAllowWhileIdleDispatch.keyAt(i));
+ pw.print(": ");
+ TimeUtils.formatDuration(mLastAllowWhileIdleDispatch.valueAt(i),
+ nowELAPSED, pw);
+ pw.println();
+ }
+ }
+ pw.println();
+
if (mLog.dump(pw, " Recent problems", " ")) {
pw.println();
}
@@ -1322,7 +1373,7 @@
for (int j = 0; j < M; j++) {
Alarm a = alarms.get(j);
if (a.alarmClock != null) {
- final int userId = a.userId;
+ final int userId = UserHandle.getUserId(a.uid);
if (DEBUG_ALARM_CLOCK) {
Log.v(TAG, "Found AlarmClockInfo at " +
@@ -1531,6 +1582,11 @@
mPendingWhileIdleAlarms.remove(i);
}
}
+ for (int i = mLastAllowWhileIdleDispatch.size() - 1; i >= 0; i--) {
+ if (UserHandle.getUserId(mLastAllowWhileIdleDispatch.keyAt(i)) == userHandle) {
+ mLastAllowWhileIdleDispatch.removeAt(i);
+ }
+ }
if (didRemove) {
if (DEBUG_BATCH) {
@@ -1666,6 +1722,25 @@
final int N = batch.size();
for (int i = 0; i < N; i++) {
Alarm alarm = batch.get(i);
+
+ if ((alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
+ // If this is an ALLOW_WHILE_IDLE alarm, we constrain how frequently the app can
+ // schedule such alarms.
+ long lastTime = mLastAllowWhileIdleDispatch.get(alarm.uid, 0);
+ long minTime = lastTime + mAllowWhileIdleMinTime;
+ if (nowELAPSED < minTime) {
+ // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
+ // alarm went off for this app. Reschedule the alarm to be in the
+ // correct time period.
+ alarm.whenElapsed = minTime;
+ if (alarm.maxWhenElapsed < minTime) {
+ alarm.maxWhenElapsed = minTime;
+ }
+ setImplLocked(alarm, true, false);
+ continue;
+ }
+ }
+
alarm.count = 1;
triggerList.add(alarm);
if ((alarm.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
@@ -1695,7 +1770,7 @@
setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
alarm.repeatInterval, alarm.operation, alarm.flags, true,
- alarm.workSource, alarm.alarmClock, alarm.userId);
+ alarm.workSource, alarm.alarmClock, alarm.uid);
}
if (alarm.wakeup) {
@@ -1749,19 +1824,19 @@
public final String tag;
public final WorkSource workSource;
public final int flags;
+ public final AlarmManager.AlarmClockInfo alarmClock;
+ public final int uid;
public int count;
public long when;
public long windowLength;
public long whenElapsed; // 'when' in the elapsed time base
public long maxWhenElapsed; // also in the elapsed time base
public long repeatInterval;
- public final AlarmManager.AlarmClockInfo alarmClock;
- public final int userId;
public PriorityClass priorityClass;
public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
long _interval, PendingIntent _op, WorkSource _ws, int _flags,
- AlarmManager.AlarmClockInfo _info, int _userId) {
+ AlarmManager.AlarmClockInfo _info, int _uid) {
type = _type;
origWhen = _when;
wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
@@ -1776,7 +1851,7 @@
workSource = _ws;
flags = _flags;
alarmClock = _info;
- userId = _userId;
+ uid = _uid;
}
public static String makeTag(PendingIntent pi, int type) {
@@ -1812,7 +1887,7 @@
pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw);
}
pw.println();
- pw.print(prefix); pw.print("window="); pw.print(windowLength);
+ pw.print(prefix); pw.print("window="); TimeUtils.formatDuration(windowLength, pw);
pw.print(" repeatInterval="); pw.print(repeatInterval);
pw.print(" count="); pw.print(count);
pw.print(" flags=0x"); pw.println(Integer.toHexString(flags));
@@ -1925,6 +2000,11 @@
mInFlight.add(inflight);
mBroadcastRefCount++;
+ if ((alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
+ // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
+ mLastAllowWhileIdleDispatch.put(alarm.uid, nowELAPSED);
+ }
+
final BroadcastStats bs = inflight.mBroadcastStats;
bs.count++;
if (bs.nesting == 0) {
@@ -2196,7 +2276,8 @@
final WorkSource workSource = null; // Let system take blame for time tick events.
setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
- 0, mTimeTickSender, AlarmManager.FLAG_STANDALONE, workSource, null);
+ 0, mTimeTickSender, AlarmManager.FLAG_STANDALONE, workSource, null,
+ Process.myUid());
}
public void scheduleDateChangedEvent() {
@@ -2210,7 +2291,7 @@
final WorkSource workSource = null; // Let system take blame for date change events.
setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender,
- AlarmManager.FLAG_STANDALONE, workSource, null);
+ AlarmManager.FLAG_STANDALONE, workSource, null, Process.myUid());
}
}
@@ -2243,6 +2324,7 @@
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
sdFilter.addAction(Intent.ACTION_USER_STOPPED);
+ sdFilter.addAction(Intent.ACTION_UID_REMOVED);
getContext().registerReceiver(this, sdFilter);
}
@@ -2267,6 +2349,11 @@
if (userHandle >= 0) {
removeUserLocked(userHandle);
}
+ } else if (Intent.ACTION_UID_REMOVED.equals(action)) {
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid >= 0) {
+ mLastAllowWhileIdleDispatch.delete(uid);
+ }
} else {
if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
&& intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
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/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9c6e16f..f645764 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3289,7 +3289,6 @@
CharSequence title;
CharSequence details;
int icon;
- Notification notification = new Notification();
if (notifyType == NotificationType.NO_INTERNET &&
networkType == ConnectivityManager.TYPE_WIFI) {
title = r.getString(R.string.wifi_no_internet, 0);
@@ -3324,14 +3323,17 @@
return;
}
- notification.when = 0;
- notification.icon = icon;
- notification.flags = Notification.FLAG_AUTO_CANCEL;
- notification.tickerText = title;
- notification.color = mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- notification.setLatestEventInfo(mContext, title, details, notification.contentIntent);
- notification.contentIntent = intent;
+ Notification notification = new Notification.Builder(mContext)
+ .setWhen(0)
+ .setSmallIcon(icon)
+ .setAutoCancel(true)
+ .setTicker(title)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(details)
+ .setContentIntent(intent)
+ .build();
try {
notificationManager.notify(NOTIFICATION_ID, id, notification);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 6e6fb7f..a5d536e 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -71,6 +71,7 @@
import android.inputmethodservice.InputMethodService;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
@@ -212,7 +213,7 @@
private NotificationManager mNotificationManager;
private KeyguardManager mKeyguardManager;
private StatusBarManagerService mStatusBar;
- private Notification mImeSwitcherNotification;
+ private Notification.Builder mImeSwitcherNotification;
private PendingIntent mImeSwitchPendingIntent;
private boolean mShowOngoingImeSwitcherForPhones;
private boolean mNotificationShown;
@@ -798,18 +799,15 @@
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
- mImeSwitcherNotification = new Notification();
- mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default;
- mImeSwitcherNotification.when = 0;
- mImeSwitcherNotification.flags = Notification.FLAG_ONGOING_EVENT;
- mImeSwitcherNotification.tickerText = null;
- mImeSwitcherNotification.defaults = 0; // please be quiet
- mImeSwitcherNotification.sound = null;
- mImeSwitcherNotification.vibrate = null;
-
- // Tag this notification specially so SystemUI knows it's important
- mImeSwitcherNotification.extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
- mImeSwitcherNotification.category = Notification.CATEGORY_SYSTEM;
+ Bundle extras = new Bundle();
+ extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
+ mImeSwitcherNotification = new Notification.Builder(mContext)
+ .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
+ .setWhen(0)
+ .setOngoing(true)
+ .addExtras(extras)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setColor(com.android.internal.R.color.system_notification_accent_color);
Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
@@ -1766,11 +1764,9 @@
com.android.internal.R.string.select_input_method);
final CharSequence summary = InputMethodUtils.getImeAndSubtypeDisplayName(
mContext, imi, mCurrentSubtype);
-
- mImeSwitcherNotification.color = mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- mImeSwitcherNotification.setLatestEventInfo(
- mContext, title, summary, mImeSwitchPendingIntent);
+ mImeSwitcherNotification.setContentTitle(title)
+ .setContentText(summary)
+ .setContentIntent(mImeSwitchPendingIntent);
if ((mNotificationManager != null)
&& !mWindowManagerService.hasNavigationBar()) {
if (DEBUG) {
@@ -1778,7 +1774,7 @@
}
mNotificationManager.notifyAsUser(null,
com.android.internal.R.string.select_input_method,
- mImeSwitcherNotification, UserHandle.ALL);
+ mImeSwitcherNotification.build(), UserHandle.ALL);
mNotificationShown = true;
}
} else {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index aa7d1f8..f69626d 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -993,6 +993,7 @@
private void onDiskScannedLocked(DiskInfo disk) {
final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.WRITE_MEDIA_STORAGE);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 64f3070..0b67ad8 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -601,21 +601,22 @@
if (mCarModeEnabled) {
Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
- Notification n = new Notification();
- n.icon = R.drawable.stat_notify_car_mode;
- n.defaults = Notification.DEFAULT_LIGHTS;
- n.flags = Notification.FLAG_ONGOING_EVENT;
- n.when = 0;
- n.color = context.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- n.setLatestEventInfo(
- context,
- context.getString(R.string.car_mode_disable_notification_title),
- context.getString(R.string.car_mode_disable_notification_message),
- PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
- null, UserHandle.CURRENT));
+ Notification.Builder n = new Notification.Builder(context)
+ .setSmallIcon(R.drawable.stat_notify_car_mode)
+ .setDefaults(Notification.DEFAULT_LIGHTS)
+ .setOngoing(true)
+ .setWhen(0)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(
+ context.getString(R.string.car_mode_disable_notification_title))
+ .setContentText(
+ context.getString(R.string.car_mode_disable_notification_message))
+ .setContentIntent(
+ PendingIntent.getActivityAsUser(context, 0, carModeOffIntent, 0,
+ null, UserHandle.CURRENT));
mNotificationManager.notifyAsUser(null,
- R.string.car_mode_disable_notification_title, n, UserHandle.ALL);
+ R.string.car_mode_disable_notification_title, n.build(), UserHandle.ALL);
} else {
mNotificationManager.cancelAsUser(null,
R.string.car_mode_disable_notification_title, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 49d9988..3456dbc 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2005,8 +2005,6 @@
String authTokenLabel = intent.getStringExtra(
GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
- Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
- 0 /* when */);
final String titleAndSubtitle =
mContext.getString(R.string.permission_request_notification_with_subtitle,
account.name);
@@ -2019,11 +2017,16 @@
}
UserHandle user = new UserHandle(userId);
Context contextForUser = getContextForUser(user);
- n.color = contextForUser.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- n.setLatestEventInfo(contextForUser, title, subtitle,
- PendingIntent.getActivityAsUser(mContext, 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT, null, user));
+ Notification n = new Notification.Builder(contextForUser)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setWhen(0)
+ .setColor(contextForUser.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(subtitle)
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null, user))
+ .build();
installNotification(getCredentialPermissionNotificationId(
account, authTokenType, uid), n, user);
}
@@ -3542,19 +3545,21 @@
} else {
final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
intent.addCategory(String.valueOf(notificationId));
- Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
- 0 /* when */);
UserHandle user = new UserHandle(userId);
Context contextForUser = getContextForUser(user);
final String notificationTitleFormat =
contextForUser.getText(R.string.notification_title).toString();
- n.color = contextForUser.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- n.setLatestEventInfo(contextForUser,
- String.format(notificationTitleFormat, account.name),
- message, PendingIntent.getActivityAsUser(
- mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
- null, user));
+ Notification n = new Notification.Builder(contextForUser)
+ .setWhen(0)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setColor(contextForUser.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(String.format(notificationTitleFormat, account.name))
+ .setContentText(message)
+ .setContentIntent(PendingIntent.getActivityAsUser(
+ mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
+ null, user))
+ .build();
installNotification(notificationId, n, user);
}
} finally {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6496ba2..421ba86 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1714,22 +1714,20 @@
Context context = mContext.createPackageContext(process.info.packageName, 0);
String text = mContext.getString(R.string.heavy_weight_notification,
context.getApplicationInfo().loadLabel(context.getPackageManager()));
- Notification notification = new Notification();
- notification.icon = com.android.internal.R.drawable.stat_sys_adb; //context.getApplicationInfo().icon;
- notification.when = 0;
- notification.flags = Notification.FLAG_ONGOING_EVENT;
- notification.tickerText = text;
- notification.defaults = 0; // please be quiet
- notification.sound = null;
- notification.vibrate = null;
- notification.color = mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- notification.setLatestEventInfo(context, text,
- mContext.getText(R.string.heavy_weight_notification_detail),
- PendingIntent.getActivityAsUser(mContext, 0, root.intent,
- PendingIntent.FLAG_CANCEL_CURRENT, null,
- new UserHandle(root.userId)));
-
+ Notification notification = new Notification.Builder(context)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(text)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(text)
+ .setContentText(
+ mContext.getText(R.string.heavy_weight_notification_detail))
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+ root.intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(root.userId)))
+ .build();
try {
int[] outId = new int[1];
inm.enqueueNotificationWithTag("android", "android", null,
@@ -1948,20 +1946,10 @@
}
String text = mContext.getString(R.string.dump_heap_notification, procName);
- Notification notification = new Notification();
- notification.icon = com.android.internal.R.drawable.stat_sys_adb;
- notification.when = 0;
- notification.flags = Notification.FLAG_ONGOING_EVENT|Notification.FLAG_AUTO_CANCEL;
- notification.tickerText = text;
- notification.defaults = 0; // please be quiet
- notification.sound = null;
- notification.vibrate = null;
- notification.color = mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color);
+
+
Intent deleteIntent = new Intent();
deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
- notification.deleteIntent = PendingIntent.getBroadcastAsUser(mContext, 0,
- deleteIntent, 0, UserHandle.OWNER);
Intent intent = new Intent();
intent.setClassName("android", DumpHeapActivity.class.getName());
intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
@@ -1970,11 +1958,23 @@
intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
}
int userId = UserHandle.getUserId(uid);
- notification.setLatestEventInfo(mContext, text,
- mContext.getText(R.string.dump_heap_notification_detail),
- PendingIntent.getActivityAsUser(mContext, 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT, null,
- new UserHandle(userId)));
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setWhen(0)
+ .setOngoing(true)
+ .setAutoCancel(true)
+ .setTicker(text)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(text)
+ .setContentText(
+ mContext.getText(R.string.dump_heap_notification_detail))
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0,
+ intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
+ new UserHandle(userId)))
+ .setDeleteIntent(PendingIntent.getBroadcastAsUser(mContext, 0,
+ deleteIntent, 0, UserHandle.OWNER))
+ .build();
try {
int[] outId = new int[1];
@@ -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/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index cd467bd..d39b25f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2852,6 +2852,49 @@
}
}
+ void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
+ if (btDevice == null) {
+ return;
+ }
+
+ String address = btDevice.getAddress();
+ BluetoothClass btClass = btDevice.getBluetoothClass();
+ int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+ int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ if (btClass != null) {
+ switch (btClass.getDeviceClass()) {
+ case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+ case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
+ outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ break;
+ case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+ outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ break;
+ }
+ }
+
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ address = "";
+ }
+
+ boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
+
+ String btDeviceName = btDevice.getName();
+ boolean success =
+ handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
+ handleDeviceConnection(connected, inDevice, address, btDeviceName);
+ if (success) {
+ synchronized (mScoClients) {
+ if (connected) {
+ mBluetoothHeadsetDevice = btDevice;
+ } else {
+ mBluetoothHeadsetDevice = null;
+ resetBluetoothSco();
+ }
+ }
+ }
+ }
+
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -3002,6 +3045,10 @@
case BluetoothProfile.HEADSET:
synchronized (mScoClients) {
+ if (mBluetoothHeadsetDevice != null) {
+ setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
+ BluetoothProfile.STATE_DISCONNECTED);
+ }
mBluetoothHeadset = null;
}
break;
@@ -4894,49 +4941,9 @@
} else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
- outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
- inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
- String address = null;
-
BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- if (btDevice == null) {
- return;
- }
- address = btDevice.getAddress();
- BluetoothClass btClass = btDevice.getBluetoothClass();
- if (btClass != null) {
- switch (btClass.getDeviceClass()) {
- case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
- case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
- outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
- break;
- case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
- outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
- break;
- }
- }
-
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- address = "";
- }
-
- boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
-
- String btDeviceName = btDevice.getName();
- boolean success =
- handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
- handleDeviceConnection(connected, inDevice, address, btDeviceName);
- if (success) {
- synchronized (mScoClients) {
- if (connected) {
- mBluetoothHeadsetDevice = btDevice;
- } else {
- mBluetoothHeadsetDevice = null;
- resetBluetoothSco();
- }
- }
- }
+ setBtScoDeviceConnectionState(btDevice, state);
} else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
boolean broadcast = false;
int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 897300f..c1aaf07 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -130,7 +130,8 @@
private StateMachine mTetherMasterSM;
- private Notification mTetheredNotification;
+ private Notification.Builder mTetheredNotificationBuilder;
+ private int mLastNotificationId;
private boolean mRndisEnabled; // track the RNDIS function enabled state
private boolean mUsbTetherRequested; // true if USB tethering should be started
@@ -450,12 +451,13 @@
return;
}
- if (mTetheredNotification != null) {
- if (mTetheredNotification.icon == icon) {
+ if (mLastNotificationId != 0) {
+ if (mLastNotificationId == icon) {
return;
}
- notificationManager.cancelAsUser(null, mTetheredNotification.icon,
+ notificationManager.cancelAsUser(null, mLastNotificationId,
UserHandle.ALL);
+ mLastNotificationId = 0;
}
Intent intent = new Intent();
@@ -470,31 +472,32 @@
CharSequence message = r.getText(com.android.internal.R.string.
tethered_notification_message);
- if (mTetheredNotification == null) {
- mTetheredNotification = new Notification();
- mTetheredNotification.when = 0;
+ if (mTetheredNotificationBuilder == null) {
+ mTetheredNotificationBuilder = new Notification.Builder(mContext);
+ mTetheredNotificationBuilder.setWhen(0)
+ .setOngoing(true)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setCategory(Notification.CATEGORY_STATUS);
}
- mTetheredNotification.icon = icon;
- mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
- mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
- mTetheredNotification.tickerText = title;
- mTetheredNotification.visibility = Notification.VISIBILITY_PUBLIC;
- mTetheredNotification.color = mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
- mTetheredNotification.category = Notification.CATEGORY_STATUS;
+ mTetheredNotificationBuilder.setSmallIcon(icon)
+ .setContentTitle(title)
+ .setContentText(message)
+ .setContentIntent(pi);
+ mLastNotificationId = icon;
- notificationManager.notifyAsUser(null, mTetheredNotification.icon,
- mTetheredNotification, UserHandle.ALL);
+ notificationManager.notifyAsUser(null, mLastNotificationId,
+ mTetheredNotificationBuilder.build(), UserHandle.ALL);
}
private void clearTetheredNotification() {
NotificationManager notificationManager =
(NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- if (notificationManager != null && mTetheredNotification != null) {
- notificationManager.cancelAsUser(null, mTetheredNotification.icon,
+ if (notificationManager != null && mLastNotificationId != 0) {
+ notificationManager.cancelAsUser(null, mLastNotificationId,
UserHandle.ALL);
- mTetheredNotification = null;
+ mLastNotificationId = 0;
}
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 3dc282b..f222dba 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3260,16 +3260,18 @@
R.string.contentServiceTooManyDeletesNotificationDesc);
Context contextForUser = getContextForUser(user);
- Notification notification =
- new Notification(R.drawable.stat_notify_sync_error,
- mContext.getString(R.string.contentServiceSync),
- System.currentTimeMillis());
- notification.color = contextForUser.getColor(
- com.android.internal.R.color.system_notification_accent_color);
- notification.setLatestEventInfo(contextForUser,
- contextForUser.getString(R.string.contentServiceSyncNotificationTitle),
- String.format(tooManyDeletesDescFormat.toString(), authorityName),
- pendingIntent);
+ Notification notification = new Notification.Builder(contextForUser)
+ .setSmallIcon(R.drawable.stat_notify_sync_error)
+ .setTicker(mContext.getString(R.string.contentServiceSync))
+ .setWhen(System.currentTimeMillis())
+ .setColor(contextForUser.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(contextForUser.getString(
+ R.string.contentServiceSyncNotificationTitle))
+ .setContentText(
+ String.format(tooManyDeletesDescFormat.toString(), authorityName))
+ .setContentIntent(pendingIntent)
+ .build();
notification.flags |= Notification.FLAG_ONGOING_EVENT;
mNotificationMgr.notifyAsUser(null, account.hashCode() ^ authority.hashCode(),
notification, user);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 7673af4..81ef4d5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -376,8 +376,13 @@
void updatePowerSaveTempWhitelistLocked() {
try {
+ // Clear the states of the current whitelist
+ final int N = mPowerSaveTempWhitelistAppIds.size();
+ for (int i = 0; i < N; i++) {
+ mPowerSaveTempWhitelistAppIds.setValueAt(i, false);
+ }
+ // Update the states with the new whitelist
final int[] whitelist = mDeviceIdleController.getAppIdTempWhitelist();
- mPowerSaveTempWhitelistAppIds.clear();
if (whitelist != null) {
for (int uid : whitelist) {
mPowerSaveTempWhitelistAppIds.put(uid, true);
@@ -387,6 +392,18 @@
}
}
+ /**
+ * Remove unnecessary entries in the temp whitelist
+ */
+ void purgePowerSaveTempWhitelistLocked() {
+ final int N = mPowerSaveTempWhitelistAppIds.size();
+ for (int i = N - 1; i >= 0; i--) {
+ if (mPowerSaveTempWhitelistAppIds.valueAt(i) == false) {
+ mPowerSaveTempWhitelistAppIds.removeAt(i);
+ }
+ }
+ }
+
public void systemReady() {
if (!isBandwidthControlEnabled()) {
Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
@@ -521,6 +538,7 @@
} else {
updatePowerSaveTempWhitelistLocked();
updateRulesForTempWhitelistChangeLocked();
+ purgePowerSaveTempWhitelistLocked();
}
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 7e66cd1..7b1ac5ca 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -16,6 +16,7 @@
package com.android.server.pm;
+import android.app.AlarmManager;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.app.job.JobScheduler;
@@ -34,6 +35,8 @@
public class BackgroundDexOptService extends JobService {
static final String TAG = "BackgroundDexOptService";
+ static final long RETRY_LATENCY = 4 * AlarmManager.INTERVAL_HOUR;
+
static final int BACKGROUND_DEXOPT_JOB = 800;
private static ComponentName sDexoptServiceName = new ComponentName(
"android",
@@ -46,11 +49,12 @@
final AtomicBoolean mIdleTime = new AtomicBoolean(false);
- public static void schedule(Context context) {
+ public static void schedule(Context context, long minLatency) {
JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName)
.setRequiresDeviceIdle(true)
.setRequiresCharging(true)
+ .setMinimumLatency(minLatency)
.build();
js.schedule(job);
}
@@ -62,6 +66,7 @@
(PackageManagerService)ServiceManager.getService("package");
if (pm.isStorageLow()) {
+ schedule(BackgroundDexOptService.this, RETRY_LATENCY);
return false;
}
final ArraySet<String> pkgs = pm.getPackagesThatNeedDexOpt();
@@ -77,7 +82,7 @@
for (String pkg : pkgs) {
if (!mIdleTime.get()) {
// stopped while still working, so we need to reschedule
- schedule(BackgroundDexOptService.this);
+ schedule(BackgroundDexOptService.this, 0);
return;
}
if (sFailedPackageNames.contains(pkg)) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 25ca167..dbcfa19 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -243,7 +243,7 @@
}
/** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
- static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
+ static final int WAITING_FOR_DRAWN_TIMEOUT = 500;
/**
* Lock protecting internal state. Must not call out into window
@@ -836,13 +836,18 @@
// If sensor is turned off or nonexistent for some reason
return;
}
- //Could have been invoked due to screen turning on or off or
- //change of the currently visible window's orientation
+ // Could have been invoked due to screen turning on or off or
+ // change of the currently visible window's orientation.
if (localLOGV) Slog.v(TAG, "mScreenOnEarly=" + mScreenOnEarly
+ ", mAwake=" + mAwake + ", mCurrentAppOrientation=" + mCurrentAppOrientation
- + ", mOrientationSensorEnabled=" + mOrientationSensorEnabled);
+ + ", mOrientationSensorEnabled=" + mOrientationSensorEnabled
+ + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
+ + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
boolean disable = true;
- if (mScreenOnEarly && mAwake) {
+ // Note: We postpone the rotating of the screen until the keyguard as well as the
+ // window manager have reported a draw complete.
+ if (mScreenOnEarly && mAwake &&
+ mKeyguardDrawComplete && mWindowManagerDrawComplete) {
if (needSensorRunningLp()) {
disable = false;
//enable listener if not already enabled
@@ -5369,7 +5374,7 @@
private void finishKeyguardDrawn() {
synchronized (mLock) {
if (!mAwake || mKeyguardDrawComplete) {
- return; // spurious
+ return; // We are not awake yet or we have already informed of this event.
}
mKeyguardDrawComplete = true;
@@ -5407,18 +5412,18 @@
mScreenOnFully = false;
mWindowManagerDrawComplete = false;
mScreenOnListener = screenOnListener;
- updateOrientationListenerLp();
}
mWindowManagerInternal.waitForAllWindowsDrawn(mWindowManagerDrawCallback,
WAITING_FOR_DRAWN_TIMEOUT);
- // ... eventually calls finishWindowsDrawn
+ // ... eventually calls finishWindowsDrawn which will finalize our screen turn on
+ // as well as enabling the orientation change logic/sensor.
}
private void finishWindowsDrawn() {
synchronized (mLock) {
if (!mScreenOnEarly || mWindowManagerDrawComplete) {
- return; // spurious
+ return; // Screen is not turned on or we did already handle this case earlier.
}
mWindowManagerDrawComplete = true;
@@ -5428,6 +5433,11 @@
}
private void finishScreenTurningOn() {
+ synchronized (mLock) {
+ // We have just finished drawing screen content. Since the orientation listener
+ // gets only installed when all windows are drawn, we try to install it again.
+ updateOrientationListenerLp();
+ }
final ScreenOnListener listener;
final boolean enableScreen;
synchronized (mLock) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 925a609..29c65db 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -958,7 +958,7 @@
try {
Slog.i(TAG, "BackgroundDexOptService");
- BackgroundDexOptService.schedule(context);
+ BackgroundDexOptService.schedule(context, 0);
} catch (Throwable e) {
reportWtf("starting BackgroundDexOptService", e);
}
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index d1bbbfc..3ecfd55 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -741,6 +741,15 @@
MidiDeviceInfo deviceInfo = new MidiDeviceInfo(type, id, numInputPorts, numOutputPorts,
inputPortNames, outputPortNames, properties, isPrivate);
+ if (server != null) {
+ try {
+ server.setDeviceInfo(deviceInfo);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in setDeviceInfo()");
+ return null;
+ }
+ }
+
Device device = null;
BluetoothDevice bluetoothDevice = null;
if (type == MidiDeviceInfo.TYPE_BLUETOOTH) {
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();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 9a63aa3..91566f8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -448,8 +448,13 @@
/**
* Stores a list of the video callbacks, keyed by IBinder.
+ *
+ * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is
+ * load factor before resizing, 1 means we only expect a single thread to
+ * access the map so make only a single shard
*/
- private HashMap<IBinder, IVideoCallback> mVideoCallbacks = new HashMap<>();
+ private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks =
+ new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1);
/**
* Default handler used to consolidate binder method calls onto a single thread.
@@ -470,12 +475,16 @@
IBinder binder = (IBinder) msg.obj;
IVideoCallback callback = IVideoCallback.Stub
.asInterface((IBinder) msg.obj);
+ if (callback == null) {
+ Log.w(this, "addVideoProvider - skipped; callback is null.");
+ break;
+ }
+
if (mVideoCallbacks.containsKey(binder)) {
Log.i(this, "addVideoProvider - skipped; already present.");
break;
}
mVideoCallbacks.put(binder, callback);
- Log.i(this, "addVideoProvider "+ mVideoCallbacks.size());
break;
}
case MSG_REMOVE_VIDEO_CALLBACK: {
@@ -594,7 +603,7 @@
public VideoProvider() {
mBinder = new VideoProvider.VideoProviderBinder();
- mMessageHandler = new VideoProvider.VideoProviderHandler();
+ mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper());
}
/**
@@ -763,11 +772,12 @@
*/
public void receiveSessionModifyRequest(VideoProfile videoProfile) {
if (mVideoCallbacks != null) {
- try {
- for (IVideoCallback callback : mVideoCallbacks.values()) {
+ for (IVideoCallback callback : mVideoCallbacks.values()) {
+ try {
callback.receiveSessionModifyRequest(videoProfile);
+ } catch (RemoteException ignored) {
+ Log.w(this, "receiveSessionModifyRequest callback failed", ignored);
}
- } catch (RemoteException ignored) {
}
}
}
@@ -793,12 +803,13 @@
public void receiveSessionModifyResponse(int status,
VideoProfile requestedProfile, VideoProfile responseProfile) {
if (mVideoCallbacks != null) {
- try {
- for (IVideoCallback callback : mVideoCallbacks.values()) {
+ for (IVideoCallback callback : mVideoCallbacks.values()) {
+ try {
callback.receiveSessionModifyResponse(status, requestedProfile,
responseProfile);
+ } catch (RemoteException ignored) {
+ Log.w(this, "receiveSessionModifyResponse callback failed", ignored);
}
- } catch (RemoteException ignored) {
}
}
}
@@ -819,11 +830,12 @@
*/
public void handleCallSessionEvent(int event) {
if (mVideoCallbacks != null) {
- try {
- for (IVideoCallback callback : mVideoCallbacks.values()) {
+ for (IVideoCallback callback : mVideoCallbacks.values()) {
+ try {
callback.handleCallSessionEvent(event);
+ } catch (RemoteException ignored) {
+ Log.w(this, "handleCallSessionEvent callback failed", ignored);
}
- } catch (RemoteException ignored) {
}
}
}
@@ -843,11 +855,12 @@
*/
public void changePeerDimensions(int width, int height) {
if (mVideoCallbacks != null) {
- try {
- for (IVideoCallback callback : mVideoCallbacks.values()) {
+ for (IVideoCallback callback : mVideoCallbacks.values()) {
+ try {
callback.changePeerDimensions(width, height);
+ } catch (RemoteException ignored) {
+ Log.w(this, "changePeerDimensions callback failed", ignored);
}
- } catch (RemoteException ignored) {
}
}
}
@@ -869,11 +882,12 @@
*/
public void setCallDataUsage(long dataUsage) {
if (mVideoCallbacks != null) {
- try {
- for (IVideoCallback callback : mVideoCallbacks.values()) {
+ for (IVideoCallback callback : mVideoCallbacks.values()) {
+ try {
callback.changeCallDataUsage(dataUsage);
+ } catch (RemoteException ignored) {
+ Log.w(this, "setCallDataUsage callback failed", ignored);
}
- } catch (RemoteException ignored) {
}
}
}
@@ -905,11 +919,12 @@
*/
public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) {
if (mVideoCallbacks != null) {
- try {
- for (IVideoCallback callback : mVideoCallbacks.values()) {
+ for (IVideoCallback callback : mVideoCallbacks.values()) {
+ try {
callback.changeCameraCapabilities(cameraCapabilities);
+ } catch (RemoteException ignored) {
+ Log.w(this, "changeCameraCapabilities callback failed", ignored);
}
- } catch (RemoteException ignored) {
}
}
}
@@ -929,11 +944,12 @@
*/
public void changeVideoQuality(int videoQuality) {
if (mVideoCallbacks != null) {
- try {
- for (IVideoCallback callback : mVideoCallbacks.values()) {
+ for (IVideoCallback callback : mVideoCallbacks.values()) {
+ try {
callback.changeVideoQuality(videoQuality);
+ } catch (RemoteException ignored) {
+ Log.w(this, "changeVideoQuality callback failed", ignored);
}
- } catch (RemoteException ignored) {
}
}
}
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index c105491..dae7cc5 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -76,5 +76,6 @@
android:authorities="com.google.android.test.activity.single_user"
android:singleUser="true" android:exported="true" />
<receiver android:name="TrackTimeReceiver" />
+ <receiver android:name="AlarmSpamReceiver" />
</application>
</manifest>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index ddcfd9e..94cbabf 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -22,6 +22,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
+import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
@@ -36,6 +37,7 @@
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.graphics.Bitmap;
@@ -58,6 +60,7 @@
static final String KEY_CONFIGURATION = "configuration";
ActivityManager mAm;
+ AlarmManager mAlarm;
Configuration mOverrideConfig;
int mSecondUser;
@@ -66,6 +69,7 @@
ServiceConnection mIsolatedConnection;
static final int MSG_SPAM = 1;
+ static final int MSG_SPAM_ALARM = 2;
final Handler mHandler = new Handler() {
@Override
@@ -82,6 +86,15 @@
startActivity(intent, options);
scheduleSpam(!fg);
} break;
+ case MSG_SPAM_ALARM: {
+ long when = SystemClock.elapsedRealtime();
+ Intent intent = new Intent(ActivityTestMain.this, AlarmSpamReceiver.class);
+ intent.setAction("com.example.SPAM_ALARM=" + when);
+ PendingIntent pi = PendingIntent.getBroadcast(ActivityTestMain.this,
+ 0, intent, 0);
+ mAlarm.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, when+(30*1000), pi);
+ scheduleSpamAlarm(30*1000);
+ } break;
}
super.handleMessage(msg);
}
@@ -146,6 +159,7 @@
Log.i(TAG, "Referrer: " + getReferrer());
mAm = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+ mAlarm = (AlarmManager)getSystemService(ALARM_SERVICE);
if (savedInstanceState != null) {
mOverrideConfig = savedInstanceState.getParcelable(KEY_CONFIGURATION);
if (mOverrideConfig != null) {
@@ -436,6 +450,13 @@
return true;
}
});
+ menu.add("Spam idle alarm").setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ scheduleSpamAlarm(0);
+ return true;
+ }
+ });
return true;
}
@@ -467,6 +488,7 @@
@Override
protected void onStop() {
super.onStop();
+ mHandler.removeMessages(MSG_SPAM_ALARM);
for (ServiceConnection conn : mConnections) {
unbindService(conn);
}
@@ -536,6 +558,12 @@
mHandler.sendMessageDelayed(msg, 500);
}
+ void scheduleSpamAlarm(long delay) {
+ mHandler.removeMessages(MSG_SPAM_ALARM);
+ Message msg = mHandler.obtainMessage(MSG_SPAM_ALARM);
+ mHandler.sendMessageDelayed(msg, delay);
+ }
+
private View scrollWrap(View view) {
ScrollView scroller = new ScrollView(this);
scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/AlarmSpamReceiver.java b/tests/ActivityTests/src/com/google/android/test/activity/AlarmSpamReceiver.java
new file mode 100644
index 0000000..0cb1ffb
--- /dev/null
+++ b/tests/ActivityTests/src/com/google/android/test/activity/AlarmSpamReceiver.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package com.google.android.test.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+
+public class AlarmSpamReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.i("AlarmSpamReceiver", "Received spam = " + intent);
+ }
+}
diff --git a/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java b/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java
index 947ea78..2e51570 100644
--- a/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java
+++ b/tests/FixVibrateSetting/src/com/android/fixvibratesetting/FixVibrateSetting.java
@@ -109,14 +109,20 @@
}
private void test() {
- Notification n = new Notification(R.drawable.stat_sys_warning, "Test notification",
- System.currentTimeMillis());
Intent intent = new Intent(this, FixVibrateSetting.class);
PendingIntent pending = PendingIntent.getActivity(this, 0, intent, 0);
- n.setLatestEventInfo(this, "Test notification", "Test notification", pending);
- n.vibrate = new long[] { 0, 700, 500, 1000 };
- n.flags |= Notification.FLAG_AUTO_CANCEL;
+ Notification n = new Notification.Builder(this)
+ .setSmallIcon(R.drawable.stat_sys_warning)
+ .setTicker("Test notification")
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("Test notification")
+ .setContentText("Test notification")
+ .setContentIntent(pending)
+ .setVibrate(new long[] { 0, 700, 500, 1000 })
+ .setAutoCancel(true)
+ .build();
+
mNotificationManager.notify(1, n);
}
}
diff --git a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
index 7691e64..fc3f390 100644
--- a/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
+++ b/tests/FrameworkPerf/src/com/android/frameworkperf/SchedulerService.java
@@ -26,15 +26,18 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- Notification status = new Notification(R.drawable.stat_happy, null,
- System.currentTimeMillis());
- status.flags |= Notification.FLAG_ONGOING_EVENT;
- status.setLatestEventInfo(this, "Scheduler Test running",
- "Scheduler Test running", PendingIntent.getActivity(this, 0,
- new Intent(this, FrameworkPerfActivity.class)
- .setAction(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_LAUNCHER)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0));
+ Notification status = new Notification.Builder(this)
+ .setSmallIcon(R.drawable.stat_happy)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("Scheduler Test running")
+ .setContentText("Scheduler Test running")
+ .setContentIntent(PendingIntent.getActivity(this, 0,
+ new Intent(this, FrameworkPerfActivity.class)
+ .setAction(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0))
+ .setOngoing(true)
+ .build();
startForeground(1, status);
return START_STICKY;
}
diff --git a/tests/StatusBar/res/drawable-hdpi/stat_sys_warning.png b/tests/StatusBar/res/drawable-hdpi/stat_sys_warning.png
new file mode 100644
index 0000000..dbaf944
--- /dev/null
+++ b/tests/StatusBar/res/drawable-hdpi/stat_sys_warning.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable-mdpi/stat_sys_warning.png b/tests/StatusBar/res/drawable-mdpi/stat_sys_warning.png
new file mode 100644
index 0000000..168f8f6
--- /dev/null
+++ b/tests/StatusBar/res/drawable-mdpi/stat_sys_warning.png
Binary files differ
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index ba160b18..67b9d77 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -25,7 +25,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Vibrator;
import android.os.Handler;
import android.os.UserHandle;
@@ -85,7 +84,7 @@
}
private Test[] mTests = new Test[] {
- new Test("Off and sound") {
+ new Test("Off") {
public void run() {
PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl =
@@ -94,9 +93,12 @@
pm.goToSleep(SystemClock.uptimeMillis());
- Notification n = new Notification();
- n.sound = Uri.parse("file://" + Environment.getExternalStorageDirectory() +
- "/virtual-void.mp3");
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.stat_sys_phone)
+ .setContentTitle(name)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .build();
Log.d(TAG, "n.sound=" + n.sound);
mNM.notify(1, n);
@@ -114,122 +116,120 @@
}
},
- new Test("Button") {
+ new Test("Custom Button") {
public void run() {
- Notification n = new Notification(R.drawable.icon1, null,
- mActivityCreateTime);
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle(name)
+ .setOngoing(true)
+ .build();
n.contentView = new RemoteViews(getPackageName(), R.layout.button_notification);
- n.flags |= Notification.FLAG_ONGOING_EVENT;
- n.contentIntent = makeIntent();
n.contentView.setOnClickPendingIntent(R.id.button, makeIntent2());
mNM.notify(1, n);
}
},
- new Test("custom intent on text view") {
+ new Test("Action Button") {
public void run() {
- Notification n = new Notification(R.drawable.icon1, null,
- mActivityCreateTime);
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is a notification!!!", null);
- n.contentView.setOnClickPendingIntent(com.android.internal.R.id.text,
- makeIntent2());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle(name)
+ .setOngoing(true)
+ .addAction(R.drawable.ic_statusbar_chat, "Button", makeIntent2())
+ .build();
+
mNM.notify(1, n);
}
},
- new Test("Ticker 1 line") {
+ new Test("with intent") {
public void run() {
- Notification n = new Notification(R.drawable.icon1, "tick tick tick",
- mActivityCreateTime);
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is a notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle("Persistent #1")
+ .setContentText("This is a notification!!!")
+ .setContentIntent(makeIntent2())
+ .setOngoing(true)
+ .build();
+
mNM.notify(1, n);
}
},
- new Test("No view") {
- public void run() {
- Notification n = new Notification(R.drawable.icon1, "No view",
- System.currentTimeMillis());
- mNM.notify(1, n);
- }
- },
-
- new Test("No intent") {
- public void run() {
- Notification n = new Notification(R.drawable.icon1, "No intent",
- System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this, "No intent",
- "No intent", null);
- mNM.notify(1, n);
- }
- },
-
- new Test("Layout") {
+ new Test("Whens") {
public void run()
{
- Notification n;
+ Notification.Builder n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setContentTitle(name)
+ .setOngoing(true);
- n = new Notification(NotificationTestList.this,
- R.drawable.ic_statusbar_missedcall,
- null, System.currentTimeMillis()-(1000*60*60*24),
- "(453) 123-2328",
- "", null);
- n.flags |= Notification.FLAG_ONGOING_EVENT;
+ mNM.notify(1, n.setContentTitle("(453) 123-2328")
+ .setWhen(System.currentTimeMillis()-(1000*60*60*24))
+ .build());
- mNM.notify(1, n);
+ mNM.notify(1, n.setContentTitle("Mark Willem, Me (2)")
+ .setWhen(System.currentTimeMillis())
+ .build());
- mNM.notify(2, new Notification(NotificationTestList.this,
- R.drawable.ic_statusbar_email,
- null, System.currentTimeMillis(),
- "Mark Willem, Me (2)",
- "Re: Didn't you get the memo?", null));
-
- mNM.notify(3, new Notification(NotificationTestList.this,
- R.drawable.ic_statusbar_chat,
- null, System.currentTimeMillis()+(1000*60*60*24),
- "Sophia Winterlanden",
- "Lorem ipsum dolor sit amet.", null));
+ mNM.notify(1, n.setContentTitle("Sophia Winterlanden")
+ .setWhen(System.currentTimeMillis() + (1000 * 60 * 60 * 24))
+ .build());
}
},
new Test("Bad Icon #1 (when=create)") {
public void run() {
- Notification n = new Notification(R.layout.chrono_notification /* not an icon */,
- null, mActivityCreateTime);
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is the same notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.layout.chrono_notification /* not an icon */)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle("Persistent #1")
+ .setContentText("This is the same notification!!")
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(1, n);
}
},
new Test("Bad Icon #1 (when=now)") {
public void run() {
- Notification n = new Notification(R.layout.chrono_notification /* not an icon */,
- null, System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is the same notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.layout.chrono_notification /* not an icon */)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("Persistent #1")
+ .setContentText("This is the same notification!!")
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(1, n);
}
},
new Test("Null Icon #1 (when=now)") {
public void run() {
- Notification n = new Notification(0, null, System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is the same notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(0)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("Persistent #1")
+ .setContentText("This is the same notification!!")
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(1, n);
}
},
new Test("Bad resource #1 (when=create)") {
public void run() {
- Notification n = new Notification(R.drawable.icon2,
- null, mActivityCreateTime);
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is the same notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle("Persistent #1")
+ .setContentText("This is the same notification!!")
+ .setContentIntent(makeIntent())
+ .build();
n.contentView.setInt(1 /*bogus*/, "bogus method", 666);
mNM.notify(1, n);
}
@@ -237,29 +237,18 @@
new Test("Bad resource #1 (when=now)") {
public void run() {
- Notification n = new Notification(R.drawable.icon2,
- null, System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is the same notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("Persistent #1")
+ .setContentText("This is the same notification!!")
+ .setContentIntent(makeIntent())
+ .build();
n.contentView.setInt(1 /*bogus*/, "bogus method", 666);
mNM.notify(1, n);
}
},
-
- new Test("Bad resource #3") {
- public void run()
- {
- Notification n = new Notification(NotificationTestList.this,
- R.drawable.ic_statusbar_missedcall,
- null, System.currentTimeMillis()-(1000*60*60*24),
- "(453) 123-2328",
- "", null);
- n.contentView.setInt(1 /*bogus*/, "bogus method", 666);
- mNM.notify(3, n);
- }
- },
-
new Test("Times") {
public void run()
{
@@ -278,22 +267,25 @@
new Runnable() {
public void run() {
Log.d(TAG, "Stress - Ongoing/Latest 0");
- Notification n = new Notification(NotificationTestList.this,
- R.drawable.icon3,
- null, System.currentTimeMillis(), "Stress - Ongoing",
- "Notify me!!!", null);
- n.flags |= Notification.FLAG_ONGOING_EVENT;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon3)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("Stress - Ongoing")
+ .setContentText("Notify me!!!")
+ .setOngoing(true)
+ .build();
mNM.notify(1, n);
}
},
new Runnable() {
public void run() {
Log.d(TAG, "Stress - Ongoing/Latest 1");
- Notification n = new Notification(NotificationTestList.this,
- R.drawable.icon4,
- null, System.currentTimeMillis(), "Stress - Latest",
- "Notify me!!!", null);
- //n.flags |= Notification.FLAG_ONGOING_EVENT;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon4)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle("Stress - Latest")
+ .setContentText("Notify me!!!")
+ .build();
mNM.notify(1, n);
}
}
@@ -302,12 +294,15 @@
new Test("Long") {
public void run()
{
- Notification n = new Notification();
- n.defaults |= Notification.DEFAULT_SOUND ;
- n.vibrate = new long[] {
- 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
- 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
- 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setContentTitle(name)
+ .setDefaults(Notification.DEFAULT_SOUND)
+ .setVibrate(new long[] {
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 })
+ .build();
mNM.notify(1, n);
}
},
@@ -320,21 +315,19 @@
Thread t = new Thread() {
public void run() {
int x = 0;
+ final Notification.Builder n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setContentTitle(name)
+ .setOngoing(true);
+
while (!mProgressDone) {
- Notification n = new Notification(R.drawable.icon1, null,
- PROGRESS_UPDATES_WHEN
+ n.setWhen(PROGRESS_UPDATES_WHEN
? System.currentTimeMillis()
: mActivityCreateTime);
- RemoteViews v = new RemoteViews(getPackageName(),
- R.layout.progress_notification);
-
- v.setProgressBar(R.id.progress_bar, 100, x, false);
- v.setTextViewText(R.id.status_text, "Progress: " + x + "%");
-
- n.contentView = v;
- n.flags |= Notification.FLAG_ONGOING_EVENT;
+ n.setProgress(100, x, false);
+ n.setContentText("Progress: " + x + "%");
- mNM.notify(500, n);
+ mNM.notify(500, n.build());
x = (x + 7) % 100;
try {
@@ -359,11 +352,12 @@
new Test("Blue Lights") {
public void run()
{
- Notification n = new Notification();
- n.flags |= Notification.FLAG_SHOW_LIGHTS;
- n.ledARGB = 0xff0000ff;
- n.ledOnMS = 1;
- n.ledOffMS = 0;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setLights(0xff0000ff, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS)
+ .build();
mNM.notify(1, n);
}
},
@@ -371,11 +365,12 @@
new Test("Red Lights") {
public void run()
{
- Notification n = new Notification();
- n.flags |= Notification.FLAG_SHOW_LIGHTS;
- n.ledARGB = 0xffff0000;
- n.ledOnMS = 1;
- n.ledOffMS = 0;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setLights(0xffff0000, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS)
+ .build();
mNM.notify(1, n);
}
},
@@ -383,11 +378,12 @@
new Test("Yellow Lights") {
public void run()
{
- Notification n = new Notification();
- n.flags |= Notification.FLAG_SHOW_LIGHTS;
- n.ledARGB = 0xffffff00;
- n.ledOnMS = 1;
- n.ledOffMS = 0;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setLights(0xffffff00, 1, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS)
+ .build();
mNM.notify(1, n);
}
},
@@ -395,11 +391,12 @@
new Test("Lights off") {
public void run()
{
- Notification n = new Notification();
- n.flags |= Notification.FLAG_SHOW_LIGHTS;
- n.ledARGB = 0x00000000;
- n.ledOnMS = 0;
- n.ledOffMS = 0;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setLights(0x00000000, 0, 0)
+ .setDefaults(Notification.DEFAULT_LIGHTS)
+ .build();
mNM.notify(1, n);
}
},
@@ -407,11 +404,12 @@
new Test("Blue Blinking Slow") {
public void run()
{
- Notification n = new Notification();
- n.flags |= Notification.FLAG_SHOW_LIGHTS;
- n.ledARGB = 0xff0000ff;
- n.ledOnMS = 1300;
- n.ledOffMS = 1300;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setLights(0xff0000ff, 1300, 1300)
+ .setDefaults(Notification.DEFAULT_LIGHTS)
+ .build();
mNM.notify(1, n);
}
},
@@ -419,11 +417,12 @@
new Test("Blue Blinking Fast") {
public void run()
{
- Notification n = new Notification();
- n.flags |= Notification.FLAG_SHOW_LIGHTS;
- n.ledARGB = 0xff0000ff;
- n.ledOnMS = 300;
- n.ledOffMS = 300;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setLights(0xff0000ff, 300, 300)
+ .setDefaults(Notification.DEFAULT_LIGHTS)
+ .build();
mNM.notify(1, n);
}
},
@@ -431,8 +430,11 @@
new Test("Default All") {
public void run()
{
- Notification n = new Notification();
- n.defaults |= Notification.DEFAULT_ALL;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setDefaults(Notification.DEFAULT_ALL)
+ .build();
mNM.notify(1, n);
}
},
@@ -440,20 +442,12 @@
new Test("Default All, once") {
public void run()
{
- Notification n = new Notification();
- n.defaults |= Notification.DEFAULT_ALL;
- n.flags |= Notification.FLAG_ONLY_ALERT_ONCE ;
- mNM.notify(1, n);
- }
- },
-
- new Test("Content Sound") {
- public void run()
- {
- Notification n = new Notification();
- n.sound = Uri.parse(
- "content://media/internal/audio/media/7");
-
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setContentTitle(name)
+ .setOnlyAlertOnce(true)
+ .setDefaults(Notification.DEFAULT_ALL)
+ .build();
mNM.notify(1, n);
}
},
@@ -461,10 +455,12 @@
new Test("Resource Sound") {
public void run()
{
- Notification n = new Notification();
- n.sound = Uri.parse(
- ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
- getPackageName() + "/raw/ringer");
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.stat_sys_phone)
+ .setContentTitle(name)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .build();
Log.d(TAG, "n.sound=" + n.sound);
mNM.notify(1, n);
@@ -474,9 +470,13 @@
new Test("Sound and Cancel") {
public void run()
{
- Notification n = new Notification();
- n.sound = Uri.parse(
- "content://media/internal/audio/media/7");
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.stat_sys_phone)
+ .setContentTitle(name)
+ .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+ getPackageName() + "/raw/ringer"))
+ .build();
+ Log.d(TAG, "n.sound=" + n.sound);
mNM.notify(1, n);
SystemClock.sleep(200);
@@ -487,8 +487,11 @@
new Test("Vibrate") {
public void run()
{
- Notification n = new Notification();
- n.vibrate = new long[] { 0, 700, 500, 1000 };
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.stat_sys_phone)
+ .setContentTitle(name)
+ .setVibrate(new long[]{0, 700, 500, 1000})
+ .build();
mNM.notify(1, n);
}
@@ -497,8 +500,11 @@
new Test("Vibrate and cancel") {
public void run()
{
- Notification n = new Notification();
- n.vibrate = new long[] { 0, 700, 500, 1000 };
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.stat_sys_phone)
+ .setContentTitle(name)
+ .setVibrate(new long[]{0, 700, 500, 1000})
+ .build();
mNM.notify(1, n);
SystemClock.sleep(500);
@@ -566,10 +572,13 @@
new Test("Persistent #1") {
public void run() {
- Notification n = new Notification(R.drawable.icon1, "tick tick tick",
- mActivityCreateTime);
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is a notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle(name)
+ .setContentText("This is a notification!!!")
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(1, n);
}
},
@@ -578,18 +587,19 @@
public void run() {
mHandler.postDelayed(new Runnable() {
public void run() {
- Notification n = new Notification(R.drawable.icon1,
- " "
+ String message = " "
+ "tick tock tick tock\n\nSometimes notifications can "
+ "be really long and wrap to more than one line.\n"
+ "Sometimes."
+ "Ohandwhathappensifwehaveonereallylongstringarewesure"
- + "thatwesegmentitcorrectly?\n",
- System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this,
- "Still Persistent #1",
- "This is still a notification!!!",
- makeIntent());
+ + "thatwesegmentitcorrectly?\n";
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setContentTitle(name)
+ .setContentText("This is still a notification!!!")
+ .setContentIntent(makeIntent())
+ .setStyle(new Notification.BigTextStyle().bigText(message))
+ .build();
mNM.notify(1, n);
}
}, 3000);
@@ -598,54 +608,67 @@
new Test("Persistent #2") {
public void run() {
- Notification n = new Notification(R.drawable.icon2, "tock tock tock",
- System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #2",
- "Notify me!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle(name)
+ .setContentText("This is a notification!!!")
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(2, n);
}
},
new Test("Persistent #3") {
public void run() {
- Notification n = new Notification(R.drawable.icon2, "tock tock tock\nmooooo",
- System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #3",
- "Notify me!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle(name)
+ .setContentText("This is a notification!!!")
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(3, n);
}
},
new Test("Persistent #2 Vibrate") {
public void run() {
- Notification n = new Notification(R.drawable.icon2, "tock tock tock",
- System.currentTimeMillis());
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #2",
- "Notify me!!!", makeIntent());
- n.defaults = Notification.DEFAULT_VIBRATE;
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle(name)
+ .setContentText("This is a notification!!!")
+ .setContentIntent(makeIntent())
+ .setDefaults(Notification.DEFAULT_VIBRATE)
+ .build();
mNM.notify(2, n);
}
},
new Test("Persistent #1 - different icon") {
public void run() {
- Notification n = new Notification(R.drawable.icon2, null,
- mActivityCreateTime);
- n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
- "This is the same notification!!!", makeIntent());
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon2)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle(name)
+ .setContentText("This is a notification!!!")
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(1, n);
}
},
new Test("Chronometer Start") {
public void run() {
- Notification n = new Notification(R.drawable.icon2, "me me me me",
- System.currentTimeMillis());
- n.contentView = new RemoteViews(getPackageName(), R.layout.chrono_notification);
- mChronometerBase = SystemClock.elapsedRealtime();
- n.contentView.setChronometer(R.id.time, mChronometerBase, "Yay! (%s)", true);
- n.flags |= Notification.FLAG_ONGOING_EVENT;
- n.contentIntent = makeIntent();
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle(name)
+ .setContentIntent(makeIntent())
+ .setOngoing(true)
+ .setUsesChronometer(true)
+ .build();
mNM.notify(2, n);
}
},
@@ -655,12 +678,12 @@
mHandler.postDelayed(new Runnable() {
public void run() {
Log.d(TAG, "Chronometer Stop");
- Notification n = new Notification();
- n.icon = R.drawable.icon1;
- n.contentView = new RemoteViews(getPackageName(),
- R.layout.chrono_notification);
- n.contentView.setChronometer(R.id.time, mChronometerBase, null, false);
- n.contentIntent = makeIntent();
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle(name)
+ .setContentIntent(makeIntent())
+ .build();
mNM.notify(2, n);
}
}, 3000);
@@ -669,29 +692,29 @@
new Test("Sequential Persistent") {
public void run() {
- mNM.notify(1, notificationWithNumbers(1));
- mNM.notify(2, notificationWithNumbers(2));
+ mNM.notify(1, notificationWithNumbers(name, 1));
+ mNM.notify(2, notificationWithNumbers(name, 2));
}
},
new Test("Replace Persistent") {
public void run() {
- mNM.notify(1, notificationWithNumbers(1));
- mNM.notify(1, notificationWithNumbers(1));
+ mNM.notify(1, notificationWithNumbers(name, 1));
+ mNM.notify(1, notificationWithNumbers(name, 1));
}
},
new Test("Run and Cancel (n=1)") {
public void run() {
- mNM.notify(1, notificationWithNumbers(1));
+ mNM.notify(1, notificationWithNumbers(name, 1));
mNM.cancel(1);
}
},
new Test("Run an Cancel (n=2)") {
public void run() {
- mNM.notify(1, notificationWithNumbers(1));
- mNM.notify(2, notificationWithNumbers(2));
+ mNM.notify(1, notificationWithNumbers(name, 1));
+ mNM.notify(2, notificationWithNumbers(name, 2));
mNM.cancel(2);
}
},
@@ -701,8 +724,8 @@
public void run() {
for (int i = 0; i < 10; i++) {
Log.d(TAG, "Add two notifications");
- mNM.notify(1, notificationWithNumbers(1));
- mNM.notify(2, notificationWithNumbers(2));
+ mNM.notify(1, notificationWithNumbers(name, 1));
+ mNM.notify(2, notificationWithNumbers(name, 2));
Log.d(TAG, "Cancel two notifications");
mNM.cancel(1);
mNM.cancel(2);
@@ -712,29 +735,14 @@
new Test("Ten Notifications") {
public void run() {
- for (int i = 0; i < 2; i++) {
- Notification n = new Notification(
- kNumberedIconResIDs[i],
- null, System.currentTimeMillis());
- n.number = i;
- n.setLatestEventInfo(
- NotificationTestList.this,
- "Persistent #" + i,
- "Notify me!!!" + i,
- null);
- n.flags |= Notification.FLAG_ONGOING_EVENT;
- mNM.notify((i+1)*10, n);
- }
- for (int i = 2; i < 10; i++) {
- Notification n = new Notification(
- kNumberedIconResIDs[i],
- null, System.currentTimeMillis());
- n.number = i;
- n.setLatestEventInfo(
- NotificationTestList.this,
- "Persistent #" + i,
- "Notify me!!!" + i,
- null);
+ for (int i = 0; i < 10; i++) {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(kNumberedIconResIDs[i])
+ .setContentTitle("Persistent #" + i)
+ .setContentText("Notify me!!!" + i)
+ .setOngoing(i < 2)
+ .setNumber(i)
+ .build();
mNM.notify((i+1)*10, n);
}
}
@@ -757,25 +765,25 @@
new Test("Persistent with numbers 1") {
public void run() {
- mNM.notify(1, notificationWithNumbers(1));
+ mNM.notify(1, notificationWithNumbers(name, 1));
}
},
new Test("Persistent with numbers 22") {
public void run() {
- mNM.notify(1, notificationWithNumbers(22));
+ mNM.notify(1, notificationWithNumbers(name, 22));
}
},
new Test("Persistent with numbers 333") {
public void run() {
- mNM.notify(1, notificationWithNumbers(333));
+ mNM.notify(1, notificationWithNumbers(name, 333));
}
},
new Test("Persistent with numbers 4444") {
public void run() {
- mNM.notify(1, notificationWithNumbers(4444));
+ mNM.notify(1, notificationWithNumbers(name, 4444));
}
},
@@ -786,7 +794,7 @@
.setContentTitle("High priority")
.setContentText("This should appear before all others")
.setPriority(Notification.PRIORITY_HIGH)
- .getNotification();
+ .build();
int[] idOut = new int[1];
try {
@@ -812,7 +820,7 @@
.setContentTitle("MAX priority")
.setContentText("This might appear as an intruder alert")
.setPriority(Notification.PRIORITY_MAX)
- .getNotification();
+ .build();
int[] idOut = new int[1];
try {
@@ -838,7 +846,7 @@
.setContentTitle("MIN priority")
.setContentText("You should not see this")
.setPriority(Notification.PRIORITY_MIN)
- .getNotification();
+ .build();
int[] idOut = new int[1];
try {
@@ -875,16 +883,15 @@
};
- private Notification notificationWithNumbers(int num) {
- Notification n = new Notification(this,
- (num >= 0 && num < kNumberedIconResIDs.length)
- ? kNumberedIconResIDs[num]
- : kUnnumberedIconResID,
- null,
- System.currentTimeMillis(),
- "Notification", "Number=" + num,
- null);
- n.number = num;
+ private Notification notificationWithNumbers(String name, int num) {
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon((num >= 0 && num < kNumberedIconResIDs.length)
+ ? kNumberedIconResIDs[num]
+ : kUnnumberedIconResID)
+ .setContentTitle(name)
+ .setContentText("Number=" + num)
+ .setNumber(num)
+ .build();
return n;
}
@@ -932,9 +939,12 @@
}
void timeNotification(int n, String label, long time) {
- mNM.notify(n, new Notification(NotificationTestList.this,
- R.drawable.ic_statusbar_missedcall, null,
- time, label, "" + new java.util.Date(time), null));
+ mNM.notify(n, new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.ic_statusbar_missedcall)
+ .setWhen(time)
+ .setContentTitle(label)
+ .setContentText(new java.util.Date(time).toString())
+ .build());
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index 50f98b8..cd04c2e 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -153,25 +153,24 @@
},
new Test("Priority notification") {
public void run() {
- Notification not = new Notification();
- not.icon = R.drawable.stat_sys_phone;
- not.when = System.currentTimeMillis()-(1000*60*60*24);
- not.setLatestEventInfo(StatusBarTest.this,
- "Incoming call",
- "from: Imperious Leader",
- null
- );
- not.flags |= Notification.FLAG_HIGH_PRIORITY;
Intent fullScreenIntent = new Intent(StatusBarTest.this, TestAlertActivity.class);
int id = (int)System.currentTimeMillis(); // XXX HAX
fullScreenIntent.putExtra("id", id);
- not.fullScreenIntent = PendingIntent.getActivity(
+ PendingIntent pi = PendingIntent.getActivity(
StatusBarTest.this,
0,
fullScreenIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
- // if you tap on it you should get the original alert box
- not.contentIntent = not.fullScreenIntent;
+ Notification not = new Notification.Builder(StatusBarTest.this)
+ .setSmallIcon(R.drawable.stat_sys_phone)
+ .setWhen(System.currentTimeMillis() - (1000 * 60 * 60 * 24))
+ .setContentTitle("Incoming call")
+ .setContentText("from: Imperious Leader")
+ .setContentIntent(pi)
+ .setFullScreenIntent(pi, true)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .build();
+
mNotificationManager.notify(id, not);
}
},