summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/app/ActivityThread.java4
-rw-r--r--core/java/android/app/ActivityTransitionCoordinator.java4
-rw-r--r--core/java/android/app/EnterTransitionCoordinator.java4
-rw-r--r--core/java/android/app/ExitTransitionCoordinator.java6
-rw-r--r--core/java/android/app/Notification.java784
-rw-r--r--core/java/android/app/RemoteInput.java32
-rw-r--r--core/java/android/app/wearable/WearableActionExtensions.java176
-rw-r--r--core/java/android/app/wearable/WearableNotificationExtensions.java702
-rw-r--r--core/java/android/content/Context.java4
-rw-r--r--core/java/android/content/pm/PackageInstaller.java16
-rw-r--r--core/java/android/ddm/DdmHandleHello.java22
-rw-r--r--core/java/android/hardware/Sensor.java1
-rw-r--r--core/java/android/hardware/camera2/legacy/CameraDeviceState.java8
-rw-r--r--core/java/android/net/ConnectivityManager.java38
-rw-r--r--core/java/android/net/EthernetManager.java5
-rw-r--r--core/java/android/net/IConnectivityManager.aidl3
-rw-r--r--core/java/android/net/Network.java89
-rw-r--r--core/java/android/net/NetworkUtils.java44
-rw-r--r--core/java/android/os/FileBridge.java165
-rw-r--r--core/java/android/provider/TvContract.java70
-rw-r--r--core/java/android/view/GLES20Canvas.java355
-rw-r--r--core/java/android/view/View.java30
-rw-r--r--core/java/android/view/ViewRootImpl.java63
-rw-r--r--core/java/android/widget/GridLayout.java209
24 files changed, 1556 insertions, 1278 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5fd288f..d9adba3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3010,8 +3010,8 @@ public final class ActivityThread {
int h;
if (w < 0) {
Resources res = r.activity.getResources();
- int wId = com.android.internal.R.dimen.recents_thumbnail_width;
- int hId = com.android.internal.R.dimen.recents_thumbnail_height;
+ int wId = com.android.internal.R.dimen.thumbnail_width;
+ int hId = com.android.internal.R.dimen.thumbnail_height;
mThumbnailWidth = w = res.getDimensionPixelSize(wId);
mThumbnailHeight = h = res.getDimensionPixelSize(hId);
} else {
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 7617886..d08978b 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -189,15 +189,17 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver {
final protected SharedElementListener mListener;
protected ResultReceiver mResultReceiver;
final private FixedEpicenterCallback mEpicenterCallback = new FixedEpicenterCallback();
+ final protected boolean mIsReturning;
public ActivityTransitionCoordinator(Window window,
ArrayList<String> allSharedElementNames,
ArrayList<String> accepted, ArrayList<String> localNames,
- SharedElementListener listener) {
+ SharedElementListener listener, boolean isReturning) {
super(new Handler());
mWindow = window;
mListener = listener;
mAllSharedElementNames = allSharedElementNames;
+ mIsReturning = isReturning;
setSharedElements(accepted, localNames);
if (getViewsTransition() != null) {
getDecor().captureTransitioningViews(mTransitioningViews);
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 4cca355..bc97852 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -55,16 +55,14 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator {
private boolean mHasStopped;
private Handler mHandler;
private boolean mIsCanceled;
- private boolean mIsReturning;
private ObjectAnimator mBackgroundAnimator;
public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver,
ArrayList<String> sharedElementNames,
ArrayList<String> acceptedNames, ArrayList<String> mappedNames) {
super(activity.getWindow(), sharedElementNames, acceptedNames, mappedNames,
- getListener(activity, acceptedNames));
+ getListener(activity, acceptedNames), acceptedNames != null);
mActivity = activity;
- mIsReturning = acceptedNames != null;
setResultReceiver(resultReceiver);
prepareEnter();
Bundle resultReceiverBundle = new Bundle();
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index f36c36a..93eb53e 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -58,16 +58,14 @@ class ExitTransitionCoordinator extends ActivityTransitionCoordinator {
private Handler mHandler;
- private boolean mIsReturning;
-
private ObjectAnimator mBackgroundAnimator;
private boolean mIsHidden;
public ExitTransitionCoordinator(Activity activity, ArrayList<String> names,
ArrayList<String> accepted, ArrayList<String> mapped, boolean isReturning) {
- super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning));
- mIsReturning = isReturning;
+ super(activity.getWindow(), names, accepted, mapped, getListener(activity, isReturning),
+ isReturning);
mIsBackgroundReady = !isReturning;
mActivity = activity;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index dfd927f..6e23b11 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -35,6 +35,7 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
+import android.view.Gravity;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.RemoteViews;
@@ -46,7 +47,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.NumberFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
/**
* A class that represents how a persistent notification is to be presented to
@@ -767,7 +770,7 @@ public class Notification implements Parcelable
*/
public static class Action implements Parcelable {
private final Bundle mExtras;
- private RemoteInput[] mRemoteInputs;
+ private final RemoteInput[] mRemoteInputs;
/**
* Small icon representing the action.
@@ -910,25 +913,12 @@ public class Notification implements Parcelable
* Apply an extender to this action builder. Extenders may be used to add
* metadata or change options on this builder.
*/
- public Builder apply(Extender extender) {
- extender.applyTo(this);
+ public Builder extend(Extender extender) {
+ extender.extend(this);
return this;
}
/**
- * Extender interface for use with {@link #apply}. Extenders may be used to add
- * metadata or change options on this builder.
- */
- public interface Extender {
- /**
- * Apply this extender to a notification action builder.
- * @param builder the builder to be modified.
- * @return the build object for chaining.
- */
- public Builder applyTo(Builder builder);
- }
-
- /**
* Combine all of the options that have been set and return a new {@link Action}
* object.
* @return the built action
@@ -975,6 +965,121 @@ public class Notification implements Parcelable
return new Action[size];
}
};
+
+ /**
+ * Extender interface for use with {@link Builder#extend}. Extenders may be used to add
+ * metadata or change options on an action builder.
+ */
+ public interface Extender {
+ /**
+ * Apply this extender to a notification action builder.
+ * @param builder the builder to be modified.
+ * @return the build object for chaining.
+ */
+ public Builder extend(Builder builder);
+ }
+
+ /**
+ * Wearable extender for notification actions. To add extensions to an action,
+ * create a new {@link android.app.Notification.Action.WearableExtender} object using
+ * the {@code WearableExtender()} constructor and apply it to a
+ * {@link android.app.Notification.Action.Builder} using
+ * {@link android.app.Notification.Action.Builder#extend}.
+ *
+ * <pre class="prettyprint">
+ * Notification.Action action = new Notification.Action.Builder(
+ * R.drawable.archive_all, "Archive all", actionIntent)
+ * .apply(new Notification.Action.WearableExtender()
+ * .setAvailableOffline(false))
+ * .build();
+ * </pre>
+ */
+ public static final class WearableExtender implements Extender {
+ /** Notification action extra which contains wearable extensions */
+ private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
+
+ private static final String KEY_FLAGS = "flags";
+
+ // Flags bitwise-ored to mFlags
+ private static final int FLAG_AVAILABLE_OFFLINE = 0x1;
+
+ // Default value for flags integer
+ private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE;
+
+ private int mFlags = DEFAULT_FLAGS;
+
+ /**
+ * Create a {@link android.app.Notification.Action.WearableExtender} with default
+ * options.
+ */
+ public WearableExtender() {
+ }
+
+ /**
+ * Create a {@link android.app.Notification.Action.WearableExtender} by reading
+ * wearable options present in an existing notification action.
+ * @param action the notification action to inspect.
+ */
+ public WearableExtender(Action action) {
+ Bundle wearableBundle = action.getExtras().getBundle(EXTRA_WEARABLE_EXTENSIONS);
+ if (wearableBundle != null) {
+ mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
+ }
+ }
+
+ /**
+ * Apply wearable extensions to a notification action that is being built. This is
+ * typically called by the {@link android.app.Notification.Action.Builder#extend}
+ * method of {@link android.app.Notification.Action.Builder}.
+ */
+ @Override
+ public Action.Builder extend(Action.Builder builder) {
+ Bundle wearableBundle = new Bundle();
+
+ if (mFlags != DEFAULT_FLAGS) {
+ wearableBundle.putInt(KEY_FLAGS, mFlags);
+ }
+
+ builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
+ return builder;
+ }
+
+ @Override
+ public WearableExtender clone() {
+ WearableExtender that = new WearableExtender();
+ that.mFlags = this.mFlags;
+ return that;
+ }
+
+ /**
+ * Set whether this action is available when the wearable device is not connected to
+ * a companion device. The user can still trigger this action when the wearable device is
+ * offline, but a visual hint will indicate that the action may not be available.
+ * Defaults to true.
+ */
+ public WearableExtender setAvailableOffline(boolean availableOffline) {
+ setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline);
+ return this;
+ }
+
+ /**
+ * Get whether this action is available when the wearable device is not connected to
+ * a companion device. The user can still trigger this action when the wearable device is
+ * offline, but a visual hint will indicate that the action may not be available.
+ * Defaults to true.
+ */
+ public boolean isAvailableOffline() {
+ return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0;
+ }
+
+ private void setFlag(int mask, boolean value) {
+ if (value) {
+ mFlags |= mask;
+ } else {
+ mFlags &= ~mask;
+ }
+ }
+ }
}
/**
@@ -2169,24 +2274,11 @@ public class Notification implements Parcelable
* Apply an extender to this notification builder. Extenders may be used to add
* metadata or change options on this builder.
*/
- public Builder apply(Extender extender) {
- extender.applyTo(this);
+ public Builder extend(Extender extender) {
+ extender.extend(this);
return this;
}
- /**
- * Extender interface for use with {@link #apply}. Extenders may be used to add
- * metadata or change options on this builder.
- */
- public interface Extender {
- /**
- * Apply this extender to a notification builder.
- * @param builder the builder to be modified.
- * @return the build object for chaining.
- */
- public Builder applyTo(Builder builder);
- }
-
private void setFlag(int mask, boolean value) {
if (value) {
mFlags |= mask;
@@ -3163,4 +3255,634 @@ public class Notification implements Parcelable
return big;
}
}
+
+ /**
+ * Extender interface for use with {@link Builder#extend}. Extenders may be used to add
+ * metadata or change options on a notification builder.
+ */
+ public interface Extender {
+ /**
+ * Apply this extender to a notification builder.
+ * @param builder the builder to be modified.
+ * @return the build object for chaining.
+ */
+ public Builder extend(Builder builder);
+ }
+
+ /**
+ * Helper class to add wearable extensions to notifications.
+ * <p class="note"> See
+ * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications
+ * for Android Wear</a> for more information on how to use this class.
+ * <p>
+ * To create a notification with wearable extensions:
+ * <ol>
+ * <li>Create a {@link android.app.Notification.Builder}, setting any desired
+ * properties.
+ * <li>Create a {@link android.app.Notification.WearableExtender}.
+ * <li>Set wearable-specific properties using the
+ * {@code add} and {@code set} methods of {@link android.app.Notification.WearableExtender}.
+ * <li>Call {@link android.app.Notification.Builder#extend} to apply the extensions to a
+ * notification.
+ * <li>Post the notification to the notification system with the
+ * {@code NotificationManager.notify(...)} methods.
+ * </ol>
+ *
+ * <pre class="prettyprint">
+ * Notification notif = new Notification.Builder(mContext)
+ * .setContentTitle(&quot;New mail from &quot; + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_mail)
+ * .extend(new Notification.WearableExtender()
+ * .setContentIcon(R.drawable.new_mail))
+ * .build();
+ * NotificationManager notificationManger =
+ * (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ * notificationManger.notify(0, notif);</pre>
+ *
+ * <p>Wearable extensions can be accessed on an existing notification by using the
+ * {@code WearableExtender(Notification)} constructor,
+ * and then using the {@code get} methods to access values.
+ *
+ * <pre class="prettyprint">
+ * Notification.WearableExtender wearableExtender = new Notification.WearableExtender(
+ * notification);
+ * List&lt;Notification&gt; pages = wearableExtender.getPages();
+ * </pre>
+ */
+ public static final class WearableExtender implements Extender {
+ /**
+ * Sentinel value for an action index that is unset.
+ */
+ public static final int UNSET_ACTION_INDEX = -1;
+
+ /**
+ * Size value for use with {@link #setCustomSizePreset} to show this notification with
+ * default sizing.
+ * <p>For custom display notifications created using {@link #setDisplayIntent},
+ * the default is {@link #SIZE_LARGE}. All other notifications size automatically based
+ * on their content.
+ */
+ public static final int SIZE_DEFAULT = 0;
+
+ /**
+ * Size value for use with {@link #setCustomSizePreset} to show this notification
+ * with an extra small size.
+ * <p>This value is only applicable for custom display notifications created using
+ * {@link #setDisplayIntent}.
+ */
+ public static final int SIZE_XSMALL = 1;
+
+ /**
+ * Size value for use with {@link #setCustomSizePreset} to show this notification
+ * with a small size.
+ * <p>This value is only applicable for custom display notifications created using
+ * {@link #setDisplayIntent}.
+ */
+ public static final int SIZE_SMALL = 2;
+
+ /**
+ * Size value for use with {@link #setCustomSizePreset} to show this notification
+ * with a medium size.
+ * <p>This value is only applicable for custom display notifications created using
+ * {@link #setDisplayIntent}.
+ */
+ public static final int SIZE_MEDIUM = 3;
+
+ /**
+ * Size value for use with {@link #setCustomSizePreset} to show this notification
+ * with a large size.
+ * <p>This value is only applicable for custom display notifications created using
+ * {@link #setDisplayIntent}.
+ */
+ public static final int SIZE_LARGE = 4;
+
+ /** Notification extra which contains wearable extensions */
+ private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
+
+ // Keys within EXTRA_WEARABLE_OPTIONS for wearable options.
+ private static final String KEY_ACTIONS = "actions";
+ private static final String KEY_FLAGS = "flags";
+ private static final String KEY_DISPLAY_INTENT = "displayIntent";
+ private static final String KEY_PAGES = "pages";
+ private static final String KEY_BACKGROUND = "background";
+ private static final String KEY_CONTENT_ICON = "contentIcon";
+ private static final String KEY_CONTENT_ICON_GRAVITY = "contentIconGravity";
+ private static final String KEY_CONTENT_ACTION_INDEX = "contentActionIndex";
+ private static final String KEY_CUSTOM_SIZE_PRESET = "customSizePreset";
+ private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight";
+ private static final String KEY_GRAVITY = "gravity";
+
+ // Flags bitwise-ored to mFlags
+ private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1;
+ private static final int FLAG_HINT_HIDE_ICON = 1 << 1;
+ private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2;
+ private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3;
+
+ // Default value for flags integer
+ private static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE;
+
+ private static final int DEFAULT_CONTENT_ICON_GRAVITY = Gravity.END;
+ private static final int DEFAULT_GRAVITY = Gravity.BOTTOM;
+
+ private ArrayList<Action> mActions = new ArrayList<Action>();
+ private int mFlags = DEFAULT_FLAGS;
+ private PendingIntent mDisplayIntent;
+ private ArrayList<Notification> mPages = new ArrayList<Notification>();
+ private Bitmap mBackground;
+ private int mContentIcon;
+ private int mContentIconGravity = DEFAULT_CONTENT_ICON_GRAVITY;
+ private int mContentActionIndex = UNSET_ACTION_INDEX;
+ private int mCustomSizePreset = SIZE_DEFAULT;
+ private int mCustomContentHeight;
+ private int mGravity = DEFAULT_GRAVITY;
+
+ /**
+ * Create a {@link android.app.Notification.WearableExtender} with default
+ * options.
+ */
+ public WearableExtender() {
+ }
+
+ public WearableExtender(Notification notif) {
+ Bundle wearableBundle = notif.extras.getBundle(EXTRA_WEARABLE_EXTENSIONS);
+ if (wearableBundle != null) {
+ List<Action> actions = wearableBundle.getParcelableArrayList(KEY_ACTIONS);
+ if (actions != null) {
+ mActions.addAll(actions);
+ }
+
+ mFlags = wearableBundle.getInt(KEY_FLAGS, DEFAULT_FLAGS);
+ mDisplayIntent = wearableBundle.getParcelable(KEY_DISPLAY_INTENT);
+
+ Notification[] pages = getNotificationArrayFromBundle(
+ wearableBundle, KEY_PAGES);
+ if (pages != null) {
+ Collections.addAll(mPages, pages);
+ }
+
+ mBackground = wearableBundle.getParcelable(KEY_BACKGROUND);
+ mContentIcon = wearableBundle.getInt(KEY_CONTENT_ICON);
+ mContentIconGravity = wearableBundle.getInt(KEY_CONTENT_ICON_GRAVITY,
+ DEFAULT_CONTENT_ICON_GRAVITY);
+ mContentActionIndex = wearableBundle.getInt(KEY_CONTENT_ACTION_INDEX,
+ UNSET_ACTION_INDEX);
+ mCustomSizePreset = wearableBundle.getInt(KEY_CUSTOM_SIZE_PRESET,
+ SIZE_DEFAULT);
+ mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT);
+ mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY);
+ }
+ }
+
+ /**
+ * Apply wearable extensions to a notification that is being built. This is typically
+ * called by the {@link android.app.Notification.Builder#extend} method of
+ * {@link android.app.Notification.Builder}.
+ */
+ @Override
+ public Notification.Builder extend(Notification.Builder builder) {
+ Bundle wearableBundle = new Bundle();
+
+ if (!mActions.isEmpty()) {
+ wearableBundle.putParcelableArrayList(KEY_ACTIONS, mActions);
+ }
+ if (mFlags != DEFAULT_FLAGS) {
+ wearableBundle.putInt(KEY_FLAGS, mFlags);
+ }
+ if (mDisplayIntent != null) {
+ wearableBundle.putParcelable(KEY_DISPLAY_INTENT, mDisplayIntent);
+ }
+ if (!mPages.isEmpty()) {
+ wearableBundle.putParcelableArray(KEY_PAGES, mPages.toArray(
+ new Notification[mPages.size()]));
+ }
+ if (mBackground != null) {
+ wearableBundle.putParcelable(KEY_BACKGROUND, mBackground);
+ }
+ if (mContentIcon != 0) {
+ wearableBundle.putInt(KEY_CONTENT_ICON, mContentIcon);
+ }
+ if (mContentIconGravity != DEFAULT_CONTENT_ICON_GRAVITY) {
+ wearableBundle.putInt(KEY_CONTENT_ICON_GRAVITY, mContentIconGravity);
+ }
+ if (mContentActionIndex != UNSET_ACTION_INDEX) {
+ wearableBundle.putInt(KEY_CONTENT_ACTION_INDEX,
+ mContentActionIndex);
+ }
+ if (mCustomSizePreset != SIZE_DEFAULT) {
+ wearableBundle.putInt(KEY_CUSTOM_SIZE_PRESET, mCustomSizePreset);
+ }
+ if (mCustomContentHeight != 0) {
+ wearableBundle.putInt(KEY_CUSTOM_CONTENT_HEIGHT, mCustomContentHeight);
+ }
+ if (mGravity != DEFAULT_GRAVITY) {
+ wearableBundle.putInt(KEY_GRAVITY, mGravity);
+ }
+
+ builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
+ return builder;
+ }
+
+ @Override
+ public WearableExtender clone() {
+ WearableExtender that = new WearableExtender();
+ that.mActions = new ArrayList<Action>(this.mActions);
+ that.mFlags = this.mFlags;
+ that.mDisplayIntent = this.mDisplayIntent;
+ that.mPages = new ArrayList<Notification>(this.mPages);
+ that.mBackground = this.mBackground;
+ that.mContentIcon = this.mContentIcon;
+ that.mContentIconGravity = this.mContentIconGravity;
+ that.mContentActionIndex = this.mContentActionIndex;
+ that.mCustomSizePreset = this.mCustomSizePreset;
+ that.mCustomContentHeight = this.mCustomContentHeight;
+ that.mGravity = this.mGravity;
+ return that;
+ }
+
+ /**
+ * Add a wearable action to this notification.
+ *
+ * <p>When wearable actions are added using this method, the set of actions that
+ * show on a wearable device splits from devices that only show actions added
+ * using {@link android.app.Notification.Builder#addAction}. This allows for customization
+ * of which actions display on different devices.
+ *
+ * @param action the action to add to this notification
+ * @return this object for method chaining
+ * @see android.app.Notification.Action
+ */
+ public WearableExtender addAction(Action action) {
+ mActions.add(action);
+ return this;
+ }
+
+ /**
+ * Adds wearable actions to this notification.
+ *
+ * <p>When wearable actions are added using this method, the set of actions that
+ * show on a wearable device splits from devices that only show actions added
+ * using {@link android.app.Notification.Builder#addAction}. This allows for customization
+ * of which actions display on different devices.
+ *
+ * @param actions the actions to add to this notification
+ * @return this object for method chaining
+ * @see android.app.Notification.Action
+ */
+ public WearableExtender addActions(List<Action> actions) {
+ mActions.addAll(actions);
+ return this;
+ }
+
+ /**
+ * Clear all wearable actions present on this builder.
+ * @return this object for method chaining.
+ * @see #addAction
+ */
+ public WearableExtender clearActions() {
+ mActions.clear();
+ return this;
+ }
+
+ /**
+ * Get the wearable actions present on this notification.
+ */
+ public List<Action> getActions() {
+ return mActions;
+ }
+
+ /**
+ * Set an intent to launch inside of an activity view when displaying
+ * this notification. This {@link PendingIntent} should be for an activity.
+ *
+ * @param intent the {@link PendingIntent} for an activity
+ * @return this object for method chaining
+ * @see android.app.Notification.WearableExtender#getDisplayIntent
+ */
+ public WearableExtender setDisplayIntent(PendingIntent intent) {
+ mDisplayIntent = intent;
+ return this;
+ }
+
+ /**
+ * Get the intent to launch inside of an activity view when displaying this
+ * notification. This {@code PendingIntent} should be for an activity.
+ */
+ public PendingIntent getDisplayIntent() {
+ return mDisplayIntent;
+ }
+
+ /**
+ * Add an additional page of content to display with this notification. The current
+ * notification forms the first page, and pages added using this function form
+ * subsequent pages. This field can be used to separate a notification into multiple
+ * sections.
+ *
+ * @param page the notification to add as another page
+ * @return this object for method chaining
+ * @see android.app.Notification.WearableExtender#getPages
+ */
+ public WearableExtender addPage(Notification page) {
+ mPages.add(page);
+ return this;
+ }
+
+ /**
+ * Add additional pages of content to display with this notification. The current
+ * notification forms the first page, and pages added using this function form
+ * subsequent pages. This field can be used to separate a notification into multiple
+ * sections.
+ *
+ * @param pages a list of notifications
+ * @return this object for method chaining
+ * @see android.app.Notification.WearableExtender#getPages
+ */
+ public WearableExtender addPages(List<Notification> pages) {
+ mPages.addAll(pages);
+ return this;
+ }
+
+ /**
+ * Clear all additional pages present on this builder.
+ * @return this object for method chaining.
+ * @see #addPage
+ */
+ public WearableExtender clearPages() {
+ mPages.clear();
+ return this;
+ }
+
+ /**
+ * Get the array of additional pages of content for displaying this notification. The
+ * current notification forms the first page, and elements within this array form
+ * subsequent pages. This field can be used to separate a notification into multiple
+ * sections.
+ * @return the pages for this notification
+ */
+ public List<Notification> getPages() {
+ return mPages;
+ }
+
+ /**
+ * Set a background image to be displayed behind the notification content.
+ * Contrary to the {@link android.app.Notification.BigPictureStyle}, this background
+ * will work with any notification style.
+ *
+ * @param background the background bitmap
+ * @return this object for method chaining
+ * @see android.app.Notification.WearableExtender#getBackground
+ */
+ public WearableExtender setBackground(Bitmap background) {
+ mBackground = background;
+ return this;
+ }
+
+ /**
+ * Get a background image to be displayed behind the notification content.
+ * Contrary to the {@link android.app.Notification.BigPictureStyle}, this background
+ * will work with any notification style.
+ *
+ * @return the background image
+ * @see android.app.Notification.WearableExtender#setBackground
+ */
+ public Bitmap getBackground() {
+ return mBackground;
+ }
+
+ /**
+ * Set an icon that goes with the content of this notification.
+ */
+ public WearableExtender setContentIcon(int icon) {
+ mContentIcon = icon;
+ return this;
+ }
+
+ /**
+ * Get an icon that goes with the content of this notification.
+ */
+ public int getContentIcon() {
+ return mContentIcon;
+ }
+
+ /**
+ * Set the gravity that the content icon should have within the notification display.
+ * Supported values include {@link android.view.Gravity#START} and
+ * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
+ * @see #setContentIcon
+ */
+ public WearableExtender setContentIconGravity(int contentIconGravity) {
+ mContentIconGravity = contentIconGravity;
+ return this;
+ }
+
+ /**
+ * Get the gravity that the content icon should have within the notification display.
+ * Supported values include {@link android.view.Gravity#START} and
+ * {@link android.view.Gravity#END}. The default value is {@link android.view.Gravity#END}.
+ * @see #getContentIcon
+ */
+ public int getContentIconGravity() {
+ return mContentIconGravity;
+ }
+
+ /**
+ * Set an action from this notification's actions to be clickable with the content of
+ * this notification page. This action will no longer display separately from the
+ * notification content. This action's icon will display with optional subtext provided
+ * by the action's title.
+ * @param actionIndex The index of the action to hoist on the current notification page.
+ * If wearable actions are present, this index will apply to that list,
+ * otherwise it will apply to the main notification's actions list.
+ */
+ public WearableExtender setContentAction(int actionIndex) {
+ mContentActionIndex = actionIndex;
+ return this;
+ }
+
+ /**
+ * Get the action index of an action from this notification to show as clickable with
+ * the content of this notification page. When the user clicks this notification page,
+ * this action will trigger. This action will no longer display separately from the
+ * notification content. The action's icon will display with optional subtext provided
+ * by the action's title.
+ *
+ * <p>If wearable specific actions are present, this index will apply to that list,
+ * otherwise it will apply to the main notification's actions list.
+ */
+ public int getContentAction() {
+ return mContentActionIndex;
+ }
+
+ /**
+ * Set the gravity that this notification should have within the available viewport space.
+ * Supported values include {@link android.view.Gravity#TOP},
+ * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
+ * The default value is {@link android.view.Gravity#BOTTOM}.
+ */
+ public WearableExtender setGravity(int gravity) {
+ mGravity = gravity;
+ return this;
+ }
+
+ /**
+ * Get the gravity that this notification should have within the available viewport space.
+ * Supported values include {@link android.view.Gravity#TOP},
+ * {@link android.view.Gravity#CENTER_VERTICAL} and {@link android.view.Gravity#BOTTOM}.
+ * The default value is {@link android.view.Gravity#BOTTOM}.
+ */
+ public int getGravity() {
+ return mGravity;
+ }
+
+ /**
+ * Set the custom size preset for the display of this notification out of the available
+ * presets found in {@link android.app.Notification.WearableExtender}, e.g.
+ * {@link #SIZE_LARGE}.
+ * <p>Some custom size presets are only applicable for custom display notifications created
+ * using {@link android.app.Notification.WearableExtender#setDisplayIntent}. Check the
+ * documentation for the preset in question. See also
+ * {@link #setCustomContentHeight} and {@link #getCustomSizePreset}.
+ */
+ public WearableExtender setCustomSizePreset(int sizePreset) {
+ mCustomSizePreset = sizePreset;
+ return this;
+ }
+
+ /**
+ * Get the custom size preset for the display of this notification out of the available
+ * presets found in {@link android.app.Notification.WearableExtender}, e.g.
+ * {@link #SIZE_LARGE}.
+ * <p>Some custom size presets are only applicable for custom display notifications created
+ * using {@link #setDisplayIntent}. Check the documentation for the preset in question.
+ * See also {@link #setCustomContentHeight} and {@link #setCustomSizePreset}.
+ */
+ public int getCustomSizePreset() {
+ return mCustomSizePreset;
+ }
+
+ /**
+ * Set the custom height in pixels for the display of this notification's content.
+ * <p>This option is only available for custom display notifications created
+ * using {@link android.app.Notification.WearableExtender#setDisplayIntent}. See also
+ * {@link android.app.Notification.WearableExtender#setCustomSizePreset} and
+ * {@link #getCustomContentHeight}.
+ */
+ public WearableExtender setCustomContentHeight(int height) {
+ mCustomContentHeight = height;
+ return this;
+ }
+
+ /**
+ * Get the custom height in pixels for the display of this notification's content.
+ * <p>This option is only available for custom display notifications created
+ * using {@link #setDisplayIntent}. See also {@link #setCustomSizePreset} and
+ * {@link #setCustomContentHeight}.
+ */
+ public int getCustomContentHeight() {
+ return mCustomContentHeight;
+ }
+
+ /**
+ * Set whether the scrolling position for the contents of this notification should start
+ * at the bottom of the contents instead of the top when the contents are too long to
+ * display within the screen. Default is false (start scroll at the top).
+ */
+ public WearableExtender setStartScrollBottom(boolean startScrollBottom) {
+ setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom);
+ return this;
+ }
+
+ /**
+ * Get whether the scrolling position for the contents of this notification should start
+ * at the bottom of the contents instead of the top when the contents are too long to
+ * display within the screen. Default is false (start scroll at the top).
+ */
+ public boolean getStartScrollBottom() {
+ return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0;
+ }
+
+ /**
+ * Set whether the content intent is available when the wearable device is not connected
+ * to a companion device. The user can still trigger this intent when the wearable device
+ * is offline, but a visual hint will indicate that the content intent may not be available.
+ * Defaults to true.
+ */
+ public WearableExtender setContentIntentAvailableOffline(
+ boolean contentIntentAvailableOffline) {
+ setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline);
+ return this;
+ }
+
+ /**
+ * Get whether the content intent is available when the wearable device is not connected
+ * to a companion device. The user can still trigger this intent when the wearable device
+ * is offline, but a visual hint will indicate that the content intent may not be available.
+ * Defaults to true.
+ */
+ public boolean getContentIntentAvailableOffline() {
+ return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0;
+ }
+
+ /**
+ * Set a hint that this notification's icon should not be displayed.
+ * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise.
+ * @return this object for method chaining
+ */
+ public WearableExtender setHintHideIcon(boolean hintHideIcon) {
+ setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon);
+ return this;
+ }
+
+ /**
+ * Get a hint that this notification's icon should not be displayed.
+ * @return {@code true} if this icon should not be displayed, false otherwise.
+ * The default value is {@code false} if this was never set.
+ */
+ public boolean getHintHideIcon() {
+ return (mFlags & FLAG_HINT_HIDE_ICON) != 0;
+ }
+
+ /**
+ * Set a visual hint that only the background image of this notification should be
+ * displayed, and other semantic content should be hidden. This hint is only applicable
+ * to sub-pages added using {@link #addPage}.
+ */
+ public WearableExtender setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) {
+ setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly);
+ return this;
+ }
+
+ /**
+ * Get a visual hint that only the background image of this notification should be
+ * displayed, and other semantic content should be hidden. This hint is only applicable
+ * to sub-pages added using {@link android.app.Notification.WearableExtender#addPage}.
+ */
+ public boolean getHintShowBackgroundOnly() {
+ return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0;
+ }
+
+ private void setFlag(int mask, boolean value) {
+ if (value) {
+ mFlags |= mask;
+ } else {
+ mFlags &= ~mask;
+ }
+ }
+ }
+
+ /**
+ * Get an array of Notification objects from a parcelable array bundle field.
+ * Update the bundle to have a typed array so fetches in the future don't need
+ * to do an array copy.
+ */
+ private static Notification[] getNotificationArrayFromBundle(Bundle bundle, String key) {
+ Parcelable[] array = bundle.getParcelableArray(key);
+ if (array instanceof Notification[] || array == null) {
+ return (Notification[]) array;
+ }
+ Notification[] typedArray = Arrays.copyOf(array, array.length,
+ Notification[].class);
+ bundle.putParcelableArray(key, typedArray);
+ return typedArray;
+ }
}
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index 9cfc541..11420c5 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -64,18 +64,24 @@ public final class RemoteInput implements Parcelable {
/** Extra added to a clip data intent object to hold the results bundle. */
public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+ // Flags bitwise-ored to mFlags
+ private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1;
+
+ // Default value for flags integer
+ private static final int DEFAULT_FLAGS = FLAG_ALLOW_FREE_FORM_INPUT;
+
private final String mResultKey;
private final CharSequence mLabel;
private final CharSequence[] mChoices;
- private final boolean mAllowFreeFormInput;
+ private final int mFlags;
private final Bundle mExtras;
private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
- boolean allowFreeFormInput, Bundle extras) {
+ int flags, Bundle extras) {
this.mResultKey = resultKey;
this.mLabel = label;
this.mChoices = choices;
- this.mAllowFreeFormInput = allowFreeFormInput;
+ this.mFlags = flags;
this.mExtras = extras;
}
@@ -108,7 +114,7 @@ public final class RemoteInput implements Parcelable {
* if you set this to false and {@link #getChoices} returns {@code null} or empty.
*/
public boolean getAllowFreeFormInput() {
- return mAllowFreeFormInput;
+ return (mFlags & FLAG_ALLOW_FREE_FORM_INPUT) != 0;
}
/**
@@ -125,7 +131,7 @@ public final class RemoteInput implements Parcelable {
private final String mResultKey;
private CharSequence mLabel;
private CharSequence[] mChoices;
- private boolean mAllowFreeFormInput = true;
+ private int mFlags = DEFAULT_FLAGS;
private Bundle mExtras = new Bundle();
/**
@@ -178,7 +184,7 @@ public final class RemoteInput implements Parcelable {
* @return this object for method chaining
*/
public Builder setAllowFreeFormInput(boolean allowFreeFormInput) {
- mAllowFreeFormInput = allowFreeFormInput;
+ setFlag(mFlags, allowFreeFormInput);
return this;
}
@@ -205,12 +211,20 @@ public final class RemoteInput implements Parcelable {
return mExtras;
}
+ private void setFlag(int mask, boolean value) {
+ if (value) {
+ mFlags |= mask;
+ } else {
+ mFlags &= ~mask;
+ }
+ }
+
/**
* Combine all of the options that have been set and return a new {@link RemoteInput}
* object.
*/
public RemoteInput build() {
- return new RemoteInput(mResultKey, mLabel, mChoices, mAllowFreeFormInput, mExtras);
+ return new RemoteInput(mResultKey, mLabel, mChoices, mFlags, mExtras);
}
}
@@ -218,7 +232,7 @@ public final class RemoteInput implements Parcelable {
mResultKey = in.readString();
mLabel = in.readCharSequence();
mChoices = in.readCharSequenceArray();
- mAllowFreeFormInput = in.readInt() != 0;
+ mFlags = in.readInt();
mExtras = in.readBundle();
}
@@ -279,7 +293,7 @@ public final class RemoteInput implements Parcelable {
out.writeString(mResultKey);
out.writeCharSequence(mLabel);
out.writeCharSequenceArray(mChoices);
- out.writeInt(mAllowFreeFormInput ? 1 : 0);
+ out.writeInt(mFlags);
out.writeBundle(mExtras);
}
diff --git a/core/java/android/app/wearable/WearableActionExtensions.java b/core/java/android/app/wearable/WearableActionExtensions.java
deleted file mode 100644
index c296ef2..0000000
--- a/core/java/android/app/wearable/WearableActionExtensions.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.wearable;
-
-import android.app.Notification;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Wearable extensions to notification actions. To add extensions to an action,
- * create a new {@link WearableActionExtensions} object using
- * {@link WearableActionExtensions.Builder} and apply it to a
- * {@link android.app.Notification.Action.Builder}.
- *
- * <pre class="prettyprint">
- * Notification.Action action = new Notification.Action.Builder(
- * R.drawable.archive_all, "Archive all", actionIntent)
- * .apply(new WearableActionExtensions.Builder()
- * .setAvailableOffline(false)
- * .build())
- * .build();
- * </pre>
- */
-public final class WearableActionExtensions implements Notification.Action.Builder.Extender,
- Parcelable {
- /** Notification action extra which contains wearable extensions */
- private static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
-
- // Flags bitwise-ored to mFlags
- private static final int FLAG_AVAILABLE_OFFLINE = 1 << 0;
-
- // Default value for flags integer
- private static final int DEFAULT_FLAGS = FLAG_AVAILABLE_OFFLINE;
-
- private final int mFlags;
-
- private WearableActionExtensions(int flags) {
- mFlags = flags;
- }
-
- private WearableActionExtensions(Parcel in) {
- mFlags = in.readInt();
- }
-
- /**
- * Create a {@link WearableActionExtensions} by reading wearable extensions present on an
- * existing notification action.
- * @param action the notification action to inspect.
- * @return a new {@link WearableActionExtensions} object.
- */
- public static WearableActionExtensions from(Notification.Action action) {
- WearableActionExtensions extensions = action.getExtras().getParcelable(
- EXTRA_WEARABLE_EXTENSIONS);
- if (extensions != null) {
- return extensions;
- } else {
- // Return a WearableActionExtensions with default values.
- return new Builder().build();
- }
- }
-
- /**
- * Get whether this action is available when the wearable device is not connected to
- * a companion device. The user can still trigger this action when the wearable device is
- * offline, but a visual hint will indicate that the action may not be available.
- * Defaults to true.
- */
- public boolean isAvailableOffline() {
- return (mFlags & FLAG_AVAILABLE_OFFLINE) != 0;
- }
-
- @Override
- public Notification.Action.Builder applyTo(Notification.Action.Builder builder) {
- builder.getExtras().putParcelable(EXTRA_WEARABLE_EXTENSIONS, this);
- return builder;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mFlags);
- }
-
- /**
- * Builder for {@link WearableActionExtensions} objects, which adds wearable extensions to
- * notification actions. To extend an action, create an instance of this class, call the set
- * methods present, call {@link #build}, and finally apply the options to a
- * {@link Notification.Action.Builder} using its
- * {@link android.app.Notification.Action.Builder#apply} method.
- */
- public static final class Builder {
- private int mFlags = DEFAULT_FLAGS;
-
- /**
- * Construct a builder to be used for adding wearable extensions to notification actions.
- *
- * <pre class="prettyprint">
- * Notification.Action action = new Notification.Action.Builder(
- * R.drawable.archive_all, "Archive all", actionIntent)
- * .apply(new WearableActionExtensions.Builder()
- * .setAvailableOffline(false)
- * .build())
- * .build();</pre>
- */
- public Builder() {
- }
-
- /**
- * Create a {@link Builder} by reading wearable extensions present on an
- * existing {@code WearableActionExtensions} object.
- * @param other the existing extensions to inspect.
- */
- public Builder(WearableActionExtensions other) {
- mFlags = other.mFlags;
- }
-
- /**
- * Set whether this action is available when the wearable device is not connected to
- * a companion device. The user can still trigger this action when the wearable device is
- * offline, but a visual hint will indicate that the action may not be available.
- * Defaults to true.
- */
- public Builder setAvailableOffline(boolean availableOffline) {
- setFlag(FLAG_AVAILABLE_OFFLINE, availableOffline);
- return this;
- }
-
- /**
- * Build a new {@link WearableActionExtensions} object with the extensions
- * currently present on this builder.
- * @return the extensions object.
- */
- public WearableActionExtensions build() {
- return new WearableActionExtensions(mFlags);
- }
-
- private void setFlag(int mask, boolean value) {
- if (value) {
- mFlags |= mask;
- } else {
- mFlags &= ~mask;
- }
- }
- }
-
- public static final Creator<WearableActionExtensions> CREATOR =
- new Creator<WearableActionExtensions>() {
- @Override
- public WearableActionExtensions createFromParcel(Parcel in) {
- return new WearableActionExtensions(in);
- }
-
- @Override
- public WearableActionExtensions[] newArray(int size) {
- return new WearableActionExtensions[size];
- }
- };
-}
diff --git a/core/java/android/app/wearable/WearableNotificationExtensions.java b/core/java/android/app/wearable/WearableNotificationExtensions.java
deleted file mode 100644
index d433613..0000000
--- a/core/java/android/app/wearable/WearableNotificationExtensions.java
+++ /dev/null
@@ -1,702 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.wearable;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.graphics.Bitmap;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.Gravity;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Helper class that contains wearable extensions for notifications.
- * <p class="note"> See
- * <a href="{@docRoot}wear/notifications/creating.html">Creating Notifications
- * for Android Wear</a> for more information on how to use this class.
- * <p>
- * To create a notification with wearable extensions:
- * <ol>
- * <li>Create a {@link Notification.Builder}, setting any desired
- * properties.
- * <li>Create a {@link WearableNotificationExtensions.Builder}.
- * <li>Set wearable-specific properties using the
- * {@code add} and {@code set} methods of {@link WearableNotificationExtensions.Builder}.
- * <li>Call {@link WearableNotificationExtensions.Builder#build} to build the extensions
- * object.
- * <li>Call {@link Notification.Builder#apply} to apply the extensions to a notification.
- * <li>Post the notification to the notification system with the
- * {@code NotificationManager.notify(...)} methods.
- * </ol>
- *
- * <pre class="prettyprint">
- * Notification notif = new Notification.Builder(mContext)
- * .setContentTitle(&quot;New mail from &quot; + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_mail)
- * .apply(new new WearableNotificationExtensions.Builder()
- * .setContentIcon(R.drawable.new_mail)
- * .build())
- * .build();
- * NotificationManager notificationManger =
- * (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- * notificationManger.notify(0, notif);</pre>
- *
- * <p>Wearable extensions can be accessed on an existing notification by using the
- * {@link WearableNotificationExtensions#from} function.
- *
- * <pre class="prettyprint">
- * WearableNotificationExtensions wearableExtensions = WearableNotificationExtensions.from(
- * notification);
- * Notification[] pages = wearableExtensions.getPages();
- * </pre>
- */
-public final class WearableNotificationExtensions implements Notification.Builder.Extender,
- Parcelable {
- /**
- * Sentinel value for an action index that is unset.
- */
- public static final int UNSET_ACTION_INDEX = -1;
-
- /**
- * Size value for use with {@link Builder#setCustomSizePreset} to show this notification with
- * default sizing.
- * <p>For custom display notifications created using {@link Builder#setDisplayIntent},
- * the default is {@link #SIZE_LARGE}. All other notifications size automatically based
- * on their content.
- */
- public static final int SIZE_DEFAULT = 0;
-
- /**
- * Size value for use with {@link Builder#setCustomSizePreset} to show this notification
- * with an extra small size.
- * <p>This value is only applicable for custom display notifications created using
- * {@link Builder#setDisplayIntent}.
- */
- public static final int SIZE_XSMALL = 1;
-
- /**
- * Size value for use with {@link Builder#setCustomSizePreset} to show this notification
- * with a small size.
- * <p>This value is only applicable for custom display notifications created using
- * {@link Builder#setDisplayIntent}.
- */
- public static final int SIZE_SMALL = 2;
-
- /**
- * Size value for use with {@link Builder#setCustomSizePreset} to show this notification
- * with a medium size.
- * <p>This value is only applicable for custom display notifications created using
- * {@link Builder#setDisplayIntent}.
- */
- public static final int SIZE_MEDIUM = 3;
-
- /**
- * Size value for use with {@link Builder#setCustomSizePreset} to show this notification
- * with a large size.
- * <p>This value is only applicable for custom display notifications created using
- * {@link Builder#setDisplayIntent}.
- */
- public static final int SIZE_LARGE = 4;
-
- /** Notification extra which contains wearable extensions */
- static final String EXTRA_WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS";
-
- // Flags bitwise-ored to mFlags
- static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 1 << 0;
- static final int FLAG_HINT_HIDE_ICON = 1 << 1;
- static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2;
- static final int FLAG_START_SCROLL_BOTTOM = 1 << 3;
-
- // Default value for flags integer
- static final int DEFAULT_FLAGS = FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE;
-
- private final Notification.Action[] mActions;
- private final int mFlags;
- private final PendingIntent mDisplayIntent;
- private final Notification[] mPages;
- private final Bitmap mBackground;
- private final int mContentIcon;
- private final int mContentIconGravity;
- private final int mContentActionIndex;
- private final int mCustomSizePreset;
- private final int mCustomContentHeight;
- private final int mGravity;
-
- private WearableNotificationExtensions(Notification.Action[] actions, int flags,
- PendingIntent displayIntent, Notification[] pages, Bitmap background,
- int contentIcon, int contentIconGravity, int contentActionIndex,
- int customSizePreset, int customContentHeight, int gravity) {
- mActions = actions;
- mFlags = flags;
- mDisplayIntent = displayIntent;
- mPages = pages;
- mBackground = background;
- mContentIcon = contentIcon;
- mContentIconGravity = contentIconGravity;
- mContentActionIndex = contentActionIndex;
- mCustomSizePreset = customSizePreset;
- mCustomContentHeight = customContentHeight;
- mGravity = gravity;
- }
-
- private WearableNotificationExtensions(Parcel in) {
- mActions = in.createTypedArray(Notification.Action.CREATOR);
- mFlags = in.readInt();
- mDisplayIntent = in.readParcelable(PendingIntent.class.getClassLoader());
- mPages = in.createTypedArray(Notification.CREATOR);
- mBackground = in.readParcelable(Bitmap.class.getClassLoader());
- mContentIcon = in.readInt();
- mContentIconGravity = in.readInt();
- mContentActionIndex = in.readInt();
- mCustomSizePreset = in.readInt();
- mCustomContentHeight = in.readInt();
- mGravity = in.readInt();
- }
-
- /**
- * Create a {@link WearableNotificationExtensions} by reading wearable extensions present on an
- * existing notification.
- * @param notif the notification to inspect.
- * @return a new {@link WearableNotificationExtensions} object.
- */
- public static WearableNotificationExtensions from(Notification notif) {
- WearableNotificationExtensions extensions = notif.extras.getParcelable(
- EXTRA_WEARABLE_EXTENSIONS);
- if (extensions != null) {
- return extensions;
- } else {
- // Return a WearableNotificationExtensions with default values.
- return new Builder().build();
- }
- }
-
- /**
- * Apply wearable extensions to a notification that is being built. This is typically
- * called by {@link Notification.Builder#apply} method of {@link Notification.Builder}.
- */
- @Override
- public Notification.Builder applyTo(Notification.Builder builder) {
- builder.getExtras().putParcelable(EXTRA_WEARABLE_EXTENSIONS, this);
- return builder;
- }
-
- /**
- * Get the number of wearable actions present on this notification.
- *
- * @return the number of wearable actions for this notification
- */
- public int getActionCount() {
- return mActions.length;
- }
-
- /**
- * Get a {@link Notification.Action} for the wearable action at {@code actionIndex}.
- * @param actionIndex the index of the desired wearable action
- */
- public Notification.Action getAction(int actionIndex) {
- return mActions[actionIndex];
- }
-
- /**
- * Get the wearable actions present on this notification.
- */
- public Notification.Action[] getActions() {
- return mActions;
- }
-
- /**
- * Get the intent to launch inside of an activity view when displaying this
- * notification. This {@code PendingIntent} should be for an activity.
- */
- public PendingIntent getDisplayIntent() {
- return mDisplayIntent;
- }
-
- /**
- * Get the array of additional pages of content for displaying this notification. The
- * current notification forms the first page, and elements within this array form
- * subsequent pages. This field can be used to separate a notification into multiple
- * sections.
- * @return the pages for this notification
- */
- public Notification[] getPages() {
- return mPages;
- }
-
- /**
- * Get a background image to be displayed behind the notification content.
- * Contrary to the {@link Notification.BigPictureStyle}, this background
- * will work with any notification style.
- *
- * @return the background image
- * @see Builder#setBackground
- */
- public Bitmap getBackground() {
- return mBackground;
- }
-
- /**
- * Get an icon that goes with the content of this notification.
- */
- public int getContentIcon() {
- return mContentIcon;
- }
-
- /**
- * Get the gravity that the content icon should have within the notification display.
- * Supported values include {@link Gravity#START} and {@link Gravity#END}. The default
- * value is {@link android.view.Gravity#END}.
- * @see #getContentIcon
- */
- public int getContentIconGravity() {
- return mContentIconGravity;
- }
-
- /**
- * Get the action index of an action from this notification to show as clickable with
- * the content of this notification page. When the user clicks this notification page,
- * this action will trigger. This action will no longer display separately from the
- * notification content. The action's icon will display with optional subtext provided
- * by the action's title.
- *
- * <p>If wearable specific actions are present, this index will apply to that list,
- * otherwise it will apply to the main notification's actions list.
- */
- public int getContentAction() {
- return mContentActionIndex;
- }
-
- /**
- * Get the gravity that this notification should have within the available viewport space.
- * Supported values include {@link Gravity#TOP}, {@link Gravity#CENTER_VERTICAL} and
- * {@link android.view.Gravity#BOTTOM}. The default value is
- * {@link android.view.Gravity#BOTTOM}.
- */
- public int getGravity() {
- return mGravity;
- }
-
- /**
- * Get the custom size preset for the display of this notification out of the available
- * presets found in {@link WearableNotificationExtensions}, e.g. {@link #SIZE_LARGE}.
- * <p>Some custom size presets are only applicable for custom display notifications created
- * using {@link Builder#setDisplayIntent}. Check the documentation for the preset in question.
- * See also {@link Builder#setCustomContentHeight} and {@link Builder#setCustomSizePreset}.
- */
- public int getCustomSizePreset() {
- return mCustomSizePreset;
- }
-
- /**
- * Get the custom height in pixels for the display of this notification's content.
- * <p>This option is only available for custom display notifications created
- * using {@link Builder#setDisplayIntent}. See also {@link Builder#setCustomSizePreset} and
- * {@link Builder#setCustomContentHeight}.
- */
- public int getCustomContentHeight() {
- return mCustomContentHeight;
- }
-
- /**
- * Get whether the scrolling position for the contents of this notification should start
- * at the bottom of the contents instead of the top when the contents are too long to
- * display within the screen. Default is false (start scroll at the top).
- */
- public boolean getStartScrollBottom() {
- return (mFlags & FLAG_START_SCROLL_BOTTOM) != 0;
- }
-
- /**
- * Get whether the content intent is available when the wearable device is not connected
- * to a companion device. The user can still trigger this intent when the wearable device is
- * offline, but a visual hint will indicate that the content intent may not be available.
- * Defaults to true.
- */
- public boolean getContentIntentAvailableOffline() {
- return (mFlags & FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE) != 0;
- }
-
- /**
- * Get a hint that this notification's icon should not be displayed.
- * @return {@code true} if this icon should not be displayed, false otherwise.
- * The default value is {@code false} if this was never set.
- */
- public boolean getHintHideIcon() {
- return (mFlags & FLAG_HINT_HIDE_ICON) != 0;
- }
-
- /**
- * Get a visual hint that only the background image of this notification should be
- * displayed, and other semantic content should be hidden. This hint is only applicable
- * to sub-pages added using {@link Builder#addPage}.
- */
- public boolean getHintShowBackgroundOnly() {
- return (mFlags & FLAG_HINT_SHOW_BACKGROUND_ONLY) != 0;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeTypedArray(mActions, flags);
- out.writeInt(mFlags);
- out.writeParcelable(mDisplayIntent, flags);
- out.writeTypedArray(mPages, flags);
- out.writeParcelable(mBackground, flags);
- out.writeInt(mContentIcon);
- out.writeInt(mContentIconGravity);
- out.writeInt(mContentActionIndex);
- out.writeInt(mCustomSizePreset);
- out.writeInt(mCustomContentHeight);
- out.writeInt(mGravity);
- }
-
- /**
- * Builder to apply wearable notification extensions to a {@link Notification.Builder}
- * object.
- *
- * <p>You can chain the "set" methods for this builder in any order,
- * but you must call the {@link #build} method and then the {@link Notification.Builder#apply}
- * method to apply your extensions to a notification.
- *
- * <pre class="prettyprint">
- * Notification notif = new Notification.Builder(mContext)
- * .setContentTitle(&quot;New mail from &quot; + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_mail);
- * .apply(new WearableNotificationExtensions.Builder()
- * .setContentIcon(R.drawable.new_mail)
- * .build())
- * .build();
- * NotificationManager notificationManger =
- * (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- * notificationManager.notify(0, notif);</pre>
- */
- public static final class Builder {
- private final List<Notification.Action> mActions =
- new ArrayList<Notification.Action>();
- private int mFlags = DEFAULT_FLAGS;
- private PendingIntent mDisplayIntent;
- private final List<Notification> mPages = new ArrayList<Notification>();
- private Bitmap mBackground;
- private int mContentIcon;
- private int mContentIconGravity = Gravity.END;
- private int mContentActionIndex = UNSET_ACTION_INDEX;
- private int mCustomContentHeight;
- private int mCustomSizePreset = SIZE_DEFAULT;
- private int mGravity = Gravity.BOTTOM;
-
- /**
- * Construct a builder to be used for adding wearable extensions to notifications.
- *
- * <pre class="prettyprint">
- * Notification notif = new Notification.Builder(mContext)
- * .setContentTitle(&quot;New mail from &quot; + sender.toString())
- * .setContentText(subject)
- * .setSmallIcon(R.drawable.new_mail);
- * .apply(new WearableNotificationExtensions.Builder()
- * .setContentIcon(R.drawable.new_mail)
- * .build())
- * .build();
- * NotificationManager notificationManger =
- * (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- * notificationManager.notify(0, notif);</pre>
- */
- public Builder() {
- }
-
- /**
- * Create a {@link Builder} by reading wearable extensions present on an
- * existing {@code WearableNotificationExtensions} object.
- * @param other the existing extensions to inspect.
- */
- public Builder(WearableNotificationExtensions other) {
- Collections.addAll(mActions, other.mActions);
- mFlags = other.mFlags;
- mDisplayIntent = other.mDisplayIntent;
- Collections.addAll(mPages, other.mPages);
- mBackground = other.mBackground;
- mContentIcon = other.mContentIcon;
- mContentIconGravity = other.mContentIconGravity;
- mContentActionIndex = other.mContentActionIndex;
- mCustomContentHeight = other.mCustomContentHeight;
- mCustomSizePreset = other.mCustomSizePreset;
- mGravity = other.mGravity;
- }
-
- /**
- * Add a wearable action to this notification.
- *
- * <p>When wearable actions are added using this method, the set of actions that
- * show on a wearable device splits from devices that only show actions added
- * using {@link android.app.Notification.Builder#addAction}. This allows for customization
- * of which actions display on different devices.
- *
- * @param action the action to add to this notification
- * @return this object for method chaining
- * @see Notification.Action
- */
- public Builder addAction(Notification.Action action) {
- mActions.add(action);
- return this;
- }
-
- /**
- * Adds wearable actions to this notification.
- *
- * <p>When wearable actions are added using this method, the set of actions that
- * show on a wearable device splits from devices that only show actions added
- * using {@link android.app.Notification.Builder#addAction}. This allows for customization
- * of which actions display on different devices.
- *
- * @param actions the actions to add to this notification
- * @return this object for method chaining
- * @see Notification.Action
- */
- public Builder addActions(List<Notification.Action> actions) {
- mActions.addAll(actions);
- return this;
- }
-
- /**
- * Clear all wearable actions present on this builder.
- * @return this object for method chaining.
- * @see #addAction
- */
- public Builder clearActions() {
- mActions.clear();
- return this;
- }
-
- /**
- * Set an intent to launch inside of an activity view when displaying
- * this notification. This {@link android.app.PendingIntent} should be for an activity.
- *
- * @param intent the {@link android.app.PendingIntent} for an activity
- * @return this object for method chaining
- * @see WearableNotificationExtensions#getDisplayIntent
- */
- public Builder setDisplayIntent(PendingIntent intent) {
- mDisplayIntent = intent;
- return this;
- }
-
- /**
- * Add an additional page of content to display with this notification. The current
- * notification forms the first page, and pages added using this function form
- * subsequent pages. This field can be used to separate a notification into multiple
- * sections.
- *
- * @param page the notification to add as another page
- * @return this object for method chaining
- * @see WearableNotificationExtensions#getPages
- */
- public Builder addPage(Notification page) {
- mPages.add(page);
- return this;
- }
-
- /**
- * Add additional pages of content to display with this notification. The current
- * notification forms the first page, and pages added using this function form
- * subsequent pages. This field can be used to separate a notification into multiple
- * sections.
- *
- * @param pages a list of notifications
- * @return this object for method chaining
- * @see WearableNotificationExtensions#getPages
- */
- public Builder addPages(List<Notification> pages) {
- mPages.addAll(pages);
- return this;
- }
-
- /**
- * Clear all additional pages present on this builder.
- * @return this object for method chaining.
- * @see #addPage
- */
- public Builder clearPages() {
- mPages.clear();
- return this;
- }
-
- /**
- * Set a background image to be displayed behind the notification content.
- * Contrary to the {@link Notification.BigPictureStyle}, this background
- * will work with any notification style.
- *
- * @param background the background bitmap
- * @return this object for method chaining
- * @see WearableNotificationExtensions#getBackground
- */
- public Builder setBackground(Bitmap background) {
- mBackground = background;
- return this;
- }
-
- /**
- * Set an icon that goes with the content of this notification.
- */
- public Builder setContentIcon(int icon) {
- mContentIcon = icon;
- return this;
- }
-
- /**
- * Set the gravity that the content icon should have within the notification display.
- * Supported values include {@link Gravity#START} and {@link Gravity#END}. The default
- * value is {@link android.view.Gravity#END}.
- * @see #setContentIcon
- */
- public Builder setContentIconGravity(int contentIconGravity) {
- mContentIconGravity = contentIconGravity;
- return this;
- }
-
- /**
- * Set an action from this notification's actions to be clickable with the content of
- * this notification page. This action will no longer display separately from the
- * notification content. This action's icon will display with optional subtext provided
- * by the action's title.
- * @param actionIndex The index of the action to hoist on the current notification page.
- * If wearable actions are present, this index will apply to that list,
- * otherwise it will apply to the main notification's actions list.
- */
- public Builder setContentAction(int actionIndex) {
- mContentActionIndex = actionIndex;
- return this;
- }
-
- /**
- * Set the gravity that this notification should have within the available viewport space.
- * Supported values include {@link Gravity#TOP}, {@link Gravity#CENTER_VERTICAL} and
- * {@link Gravity#BOTTOM}. The default value is {@link Gravity#BOTTOM}.
- */
- public Builder setGravity(int gravity) {
- mGravity = gravity;
- return this;
- }
-
- /**
- * Set the custom size preset for the display of this notification out of the available
- * presets found in {@link WearableNotificationExtensions}, e.g. {@link #SIZE_LARGE}.
- * <p>Some custom size presets are only applicable for custom display notifications created
- * using {@link Builder#setDisplayIntent}. Check the documentation for the preset in
- * question. See also {@link Builder#setCustomContentHeight} and
- * {@link #getCustomSizePreset}.
- */
- public Builder setCustomSizePreset(int sizePreset) {
- mCustomSizePreset = sizePreset;
- return this;
- }
-
- /**
- * Set the custom height in pixels for the display of this notification's content.
- * <p>This option is only available for custom display notifications created
- * using {@link Builder#setDisplayIntent}. See also {@link Builder#setCustomSizePreset} and
- * {@link #getCustomContentHeight}.
- */
- public Builder setCustomContentHeight(int height) {
- mCustomContentHeight = height;
- return this;
- }
-
- /**
- * Set whether the scrolling position for the contents of this notification should start
- * at the bottom of the contents instead of the top when the contents are too long to
- * display within the screen. Default is false (start scroll at the top).
- */
- public Builder setStartScrollBottom(boolean startScrollBottom) {
- setFlag(FLAG_START_SCROLL_BOTTOM, startScrollBottom);
- return this;
- }
-
- /**
- * Set whether the content intent is available when the wearable device is not connected
- * to a companion device. The user can still trigger this intent when the wearable device
- * is offline, but a visual hint will indicate that the content intent may not be available.
- * Defaults to true.
- */
- public Builder setContentIntentAvailableOffline(boolean contentIntentAvailableOffline) {
- setFlag(FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE, contentIntentAvailableOffline);
- return this;
- }
-
- /**
- * Set a hint that this notification's icon should not be displayed.
- * @param hintHideIcon {@code true} to hide the icon, {@code false} otherwise.
- * @return this object for method chaining
- */
- public Builder setHintHideIcon(boolean hintHideIcon) {
- setFlag(FLAG_HINT_HIDE_ICON, hintHideIcon);
- return this;
- }
-
- /**
- * Set a visual hint that only the background image of this notification should be
- * displayed, and other semantic content should be hidden. This hint is only applicable
- * to sub-pages added using {@link #addPage}.
- */
- public Builder setHintShowBackgroundOnly(boolean hintShowBackgroundOnly) {
- setFlag(FLAG_HINT_SHOW_BACKGROUND_ONLY, hintShowBackgroundOnly);
- return this;
- }
-
- /**
- * Build a new {@link WearableNotificationExtensions} object with the extensions
- * currently present on this builder.
- * @return the extensions object.
- */
- public WearableNotificationExtensions build() {
- return new WearableNotificationExtensions(
- mActions.toArray(new Notification.Action[mActions.size()]), mFlags,
- mDisplayIntent, mPages.toArray(new Notification[mPages.size()]),
- mBackground, mContentIcon, mContentIconGravity, mContentActionIndex,
- mCustomSizePreset, mCustomContentHeight, mGravity);
- }
-
- private void setFlag(int mask, boolean value) {
- if (value) {
- mFlags |= mask;
- } else {
- mFlags &= ~mask;
- }
- }
- }
-
- public static final Creator<WearableNotificationExtensions> CREATOR =
- new Creator<WearableNotificationExtensions>() {
- @Override
- public WearableNotificationExtensions createFromParcel(Parcel in) {
- return new WearableNotificationExtensions(in);
- }
-
- @Override
- public WearableNotificationExtensions[] newArray(int size) {
- return new WearableNotificationExtensions[size];
- }
- };
-}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d0ac9c9..6ae006c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1994,6 +1994,7 @@ public abstract class Context {
WIFI_PASSPOINT_SERVICE,
WIFI_P2P_SERVICE,
WIFI_SCANNING_SERVICE,
+ //@hide: ETHERNET_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
MEDIA_ROUTER_SERVICE,
@@ -2069,9 +2070,6 @@ public abstract class Context {
* <dt> {@link #WIFI_P2P_SERVICE} ("wifip2p")
* <dd> A {@link android.net.wifi.p2p.WifiP2pManager WifiP2pManager} for management of
* Wi-Fi Direct connectivity.
- * <dt> {@link #ETHERNET_SERVICE} ("ethernet")
- * <dd> A {@link android.net.ethernet.EthernetManager EthernetManager} for
- * management of Ethernet connectivity.
* <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
* <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
* for management of input methods.
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d7bd473..4672015 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -19,9 +19,12 @@ package android.content.pm;
import android.app.PackageInstallObserver;
import android.app.PackageUninstallObserver;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.FileBridge;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import java.io.OutputStream;
+
/** {@hide} */
public class PackageInstaller {
private final PackageManager mPm;
@@ -127,10 +130,17 @@ public class PackageInstaller {
}
}
- public ParcelFileDescriptor openWrite(String overlayName, long offsetBytes,
- long lengthBytes) {
+ /**
+ * Open an APK file for writing, starting at the given offset. You can
+ * then stream data into the file, periodically calling
+ * {@link OutputStream#flush()} to ensure bytes have been written to
+ * disk.
+ */
+ public OutputStream openWrite(String splitName, long offsetBytes, long lengthBytes) {
try {
- return mSession.openWrite(overlayName, offsetBytes, lengthBytes);
+ final ParcelFileDescriptor clientSocket = mSession.openWrite(splitName,
+ offsetBytes, lengthBytes);
+ return new FileBridge.FileBridgeOutputStream(clientSocket.getFileDescriptor());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 220b40d..2dce425 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -22,6 +22,7 @@ import org.apache.harmony.dalvik.ddmc.DdmServer;
import android.util.Log;
import android.os.Debug;
import android.os.UserHandle;
+import dalvik.system.VMRuntime;
import java.nio.ByteBuffer;
@@ -126,8 +127,21 @@ public class DdmHandleHello extends ChunkHandler {
// appName = "unknown";
String appName = DdmHandleAppName.getAppName();
- ByteBuffer out = ByteBuffer.allocate(20
- + vmIdent.length()*2 + appName.length()*2);
+ VMRuntime vmRuntime = VMRuntime.getRuntime();
+ String instructionSetDescription =
+ vmRuntime.is64Bit() ? "64-bit" : "32-bit";
+ String vmInstructionSet = vmRuntime.vmInstructionSet();
+ if (vmInstructionSet != null && vmInstructionSet.length() > 0) {
+ instructionSetDescription += " (" + vmInstructionSet + ")";
+ }
+ String vmFlags = "CheckJNI="
+ + (vmRuntime.isCheckJniEnabled() ? "true" : "false");
+
+ ByteBuffer out = ByteBuffer.allocate(28
+ + vmIdent.length() * 2
+ + appName.length() * 2
+ + instructionSetDescription.length() * 2
+ + vmFlags.length() * 2);
out.order(ChunkHandler.CHUNK_ORDER);
out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
out.putInt(android.os.Process.myPid());
@@ -136,6 +150,10 @@ public class DdmHandleHello extends ChunkHandler {
putString(out, vmIdent);
putString(out, appName);
out.putInt(UserHandle.myUserId());
+ out.putInt(instructionSetDescription.length());
+ putString(out, instructionSetDescription);
+ out.putInt(vmFlags.length());
+ putString(out, vmFlags);
Chunk reply = new Chunk(CHUNK_HELO, out);
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 86208fc..c593e9e 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -613,6 +613,7 @@ public final class Sensor {
}
/**
+ * @hide
* @return The permission required to access this sensor. If empty, no permission is required.
*/
public String getRequiredPermission() {
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index 71adf8b..22ff9c6 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -93,7 +93,7 @@ public class CameraDeviceState {
* {@link CameraDeviceStateListener#onConfiguring()} will be called.
* </p>
*
- * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
+ * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
*/
public synchronized int setConfiguring() {
doStateTransition(STATE_CONFIGURING);
@@ -108,7 +108,7 @@ public class CameraDeviceState {
* {@link CameraDeviceStateListener#onIdle()} will be called.
* </p>
*
- * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
+ * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
*/
public synchronized int setIdle() {
doStateTransition(STATE_IDLE);
@@ -124,7 +124,7 @@ public class CameraDeviceState {
* </p>
*
* @param request A {@link RequestHolder} containing the request for the current capture.
- * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
+ * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
*/
public synchronized int setCaptureStart(final RequestHolder request) {
mCurrentRequest = request;
@@ -144,7 +144,7 @@ public class CameraDeviceState {
*
* @param request the {@link RequestHolder} request that created this result.
* @param result the {@link CameraMetadataNative} result to set.
- * @returns {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
+ * @return {@link CameraBinderDecorator#NO_ERROR}, or an error if one has occurred.
*/
public synchronized int setCaptureResult(final RequestHolder request,
final CameraMetadataNative result) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 80a9598..2f2aba3 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -35,15 +35,17 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.telephony.ITelephony;
+import com.android.internal.util.Protocol;
+
import java.net.InetAddress;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.HashMap;
-import com.android.internal.util.Protocol;
-
/**
* Class that answers queries about the state of network connectivity. It also
* notifies applications when network connectivity changes. Get an instance
@@ -940,34 +942,18 @@ public class ConnectivityManager {
}
/**
- * Gets the value of the setting for enabling Mobile data.
- *
- * @return Whether mobile data is enabled.
- *
- * <p>This method requires the call to hold the permission
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
* @hide
+ * @deprecated Talk to TelephonyManager directly
*/
public boolean getMobileDataEnabled() {
- try {
- return mService.getMobileDataEnabled();
- } catch (RemoteException e) {
- return true;
- }
- }
-
- /**
- * Sets the persisted value for enabling/disabling Mobile data.
- *
- * @param enabled Whether the user wants the mobile data connection used
- * or not.
- * @hide
- */
- public void setMobileDataEnabled(boolean enabled) {
- try {
- mService.setMobileDataEnabled(enabled);
- } catch (RemoteException e) {
+ IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE);
+ if (b != null) {
+ try {
+ ITelephony it = ITelephony.Stub.asInterface(b);
+ return it.getDataEnabled();
+ } catch (RemoteException e) { }
}
+ return false;
}
/**
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index 70cc708..5df4baf 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -47,7 +47,7 @@ public class EthernetManager {
}
/**
- * Get Ethernet configuration
+ * Get Ethernet configuration.
* @return the Ethernet Configuration, contained in {@link IpConfiguration}.
*/
public IpConfiguration getConfiguration() {
@@ -61,8 +61,7 @@ public class EthernetManager {
}
/**
- * Set Ethernet configuration
- * @return true if setting success
+ * Set Ethernet configuration.
*/
public void setConfiguration(IpConfiguration config) {
try {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d97b1e9..baec36a 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -74,9 +74,6 @@ interface IConnectivityManager
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName);
- boolean getMobileDataEnabled();
- void setMobileDataEnabled(boolean enabled);
-
/** Policy control over specific {@link NetworkStateTracker}. */
void setPolicyDataEnable(int networkType, boolean enabled);
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index e0d69e3..e489e05 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -16,10 +16,13 @@
package android.net;
+import android.net.NetworkUtils;
import android.os.Parcelable;
import android.os.Parcel;
+import java.io.IOException;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
@@ -38,6 +41,8 @@ public class Network implements Parcelable {
*/
public final int netId;
+ private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
+
/**
* @hide
*/
@@ -79,6 +84,59 @@ public class Network implements Parcelable {
}
/**
+ * A {@code SocketFactory} that produces {@code Socket}'s bound to this network.
+ */
+ private class NetworkBoundSocketFactory extends SocketFactory {
+ private final int mNetId;
+
+ public NetworkBoundSocketFactory(int netId) {
+ super();
+ mNetId = netId;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
+ Socket socket = createSocket();
+ socket.bind(new InetSocketAddress(localHost, localPort));
+ socket.connect(new InetSocketAddress(host, port));
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) throws IOException {
+ Socket socket = createSocket();
+ socket.bind(new InetSocketAddress(localAddress, localPort));
+ socket.connect(new InetSocketAddress(address, port));
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ Socket socket = createSocket();
+ socket.connect(new InetSocketAddress(host, port));
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) throws IOException {
+ Socket socket = createSocket();
+ socket.connect(new InetSocketAddress(host, port));
+ return socket;
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ Socket socket = new Socket();
+ // Query a property of the underlying socket to ensure the underlying
+ // socket exists so a file descriptor is available to bind to a network.
+ socket.getReuseAddress();
+ NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), mNetId);
+ return socket;
+ }
+ }
+
+ /**
* Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by
* this factory will have its traffic sent over this {@code Network}. Note that if this
* {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the
@@ -88,7 +146,10 @@ public class Network implements Parcelable {
* {@code Network}.
*/
public SocketFactory socketFactory() {
- return null;
+ if (mNetworkBoundSocketFactory == null) {
+ mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
+ }
+ return mNetworkBoundSocketFactory;
}
/**
@@ -99,6 +160,29 @@ public class Network implements Parcelable {
* doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}.
*/
public void bindProcess() {
+ NetworkUtils.bindProcessToNetwork(netId);
+ }
+
+ /**
+ * Binds host resolutions performed by this process to this network. {@link #bindProcess}
+ * takes precedence over this setting.
+ *
+ * @hide
+ * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+ */
+ public void bindProcessForHostResolution() {
+ NetworkUtils.bindProcessToNetworkForHostResolution(netId);
+ }
+
+ /**
+ * Clears any process specific {@link Network} binding for host resolution. This does
+ * not clear bindings enacted via {@link #bindProcess}.
+ *
+ * @hide
+ * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+ */
+ public void unbindProcessForHostResolution() {
+ NetworkUtils.unbindProcessToNetworkForHostResolution();
}
/**
@@ -107,7 +191,7 @@ public class Network implements Parcelable {
* @return {@code Network} to which this process is bound.
*/
public static Network getProcessBoundNetwork() {
- return null;
+ return new Network(NetworkUtils.getNetworkBoundToProcess());
}
/**
@@ -115,6 +199,7 @@ public class Network implements Parcelable {
* {@link Network#bindProcess}.
*/
public static void unbindProcess() {
+ NetworkUtils.unbindProcessToNetwork();
}
// implement the Parcelable interface
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index b24d396..edb3286 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -109,6 +109,50 @@ public class NetworkUtils {
public native static void markSocket(int socketfd, int mark);
/**
+ * Binds the current process to the network designated by {@code netId}. All sockets created
+ * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
+ * {@link Network#socketFactory}) will be bound to this network. Note that if this
+ * {@code Network} ever disconnects all sockets created in this way will cease to work. This
+ * is by design so an application doesn't accidentally use sockets it thinks are still bound to
+ * a particular {@code Network}.
+ */
+ public native static void bindProcessToNetwork(int netId);
+
+ /**
+ * Clear any process specific {@code Network} binding. This reverts a call to
+ * {@link #bindProcessToNetwork}.
+ */
+ public native static void unbindProcessToNetwork();
+
+ /**
+ * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
+ * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
+ */
+ public native static int getNetworkBoundToProcess();
+
+ /**
+ * Binds host resolutions performed by this process to the network designated by {@code netId}.
+ * {@link #bindProcessToNetwork} takes precedence over this setting.
+ *
+ * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+ */
+ public native static void bindProcessToNetworkForHostResolution(int netId);
+
+ /**
+ * Clears any process specific {@link Network} binding for host resolution. This does
+ * not clear bindings enacted via {@link #bindProcessToNetwork}.
+ *
+ * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
+ */
+ public native static void unbindProcessToNetworkForHostResolution();
+
+ /**
+ * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This
+ * overrides any binding via {@link #bindProcessToNetwork}.
+ */
+ public native static void bindSocketToNetwork(int socketfd, int netId);
+
+ /**
* Convert a IPv4 address from an integer to an InetAddress.
* @param hostAddress an int corresponding to the IPv4 address in network byte order
*/
diff --git a/core/java/android/os/FileBridge.java b/core/java/android/os/FileBridge.java
new file mode 100644
index 0000000..7f8bc9f
--- /dev/null
+++ b/core/java/android/os/FileBridge.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.SOCK_STREAM;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import libcore.io.IoBridge;
+import libcore.io.IoUtils;
+import libcore.io.Memory;
+import libcore.io.Streams;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.SyncFailedException;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+
+/**
+ * Simple bridge that allows file access across process boundaries without
+ * returning the underlying {@link FileDescriptor}. This is useful when the
+ * server side needs to strongly assert that a client side is completely
+ * hands-off.
+ *
+ * @hide
+ */
+public class FileBridge extends Thread {
+ private static final String TAG = "FileBridge";
+
+ // TODO: consider extending to support bidirectional IO
+
+ private static final int MSG_LENGTH = 8;
+
+ /** CMD_WRITE [len] [data] */
+ private static final int CMD_WRITE = 1;
+ /** CMD_FSYNC */
+ private static final int CMD_FSYNC = 2;
+
+ private FileDescriptor mTarget;
+
+ private final FileDescriptor mServer = new FileDescriptor();
+ private final FileDescriptor mClient = new FileDescriptor();
+
+ private volatile boolean mClosed;
+
+ public FileBridge() {
+ try {
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, mServer, mClient);
+ } catch (ErrnoException e) {
+ throw new RuntimeException("Failed to create bridge");
+ }
+ }
+
+ public boolean isClosed() {
+ return mClosed;
+ }
+
+ public void setTargetFile(FileDescriptor target) {
+ mTarget = target;
+ }
+
+ public FileDescriptor getClientSocket() {
+ return mClient;
+ }
+
+ @Override
+ public void run() {
+ final byte[] temp = new byte[8192];
+ try {
+ while (IoBridge.read(mServer, temp, 0, MSG_LENGTH) == MSG_LENGTH) {
+ final int cmd = Memory.peekInt(temp, 0, ByteOrder.BIG_ENDIAN);
+
+ if (cmd == CMD_WRITE) {
+ // Shuttle data into local file
+ int len = Memory.peekInt(temp, 4, ByteOrder.BIG_ENDIAN);
+ while (len > 0) {
+ int n = IoBridge.read(mServer, temp, 0, Math.min(temp.length, len));
+ IoBridge.write(mTarget, temp, 0, n);
+ len -= n;
+ }
+
+ } else if (cmd == CMD_FSYNC) {
+ // Sync and echo back to confirm
+ Os.fsync(mTarget);
+ IoBridge.write(mServer, temp, 0, MSG_LENGTH);
+ }
+ }
+
+ // Client was closed; one last fsync
+ Os.fsync(mTarget);
+
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Failed during bridge: ", e);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed during bridge: ", e);
+ } finally {
+ IoUtils.closeQuietly(mTarget);
+ IoUtils.closeQuietly(mServer);
+ IoUtils.closeQuietly(mClient);
+ mClosed = true;
+ }
+ }
+
+ public static class FileBridgeOutputStream extends OutputStream {
+ private final FileDescriptor mClient;
+ private final byte[] mTemp = new byte[MSG_LENGTH];
+
+ public FileBridgeOutputStream(FileDescriptor client) {
+ mClient = client;
+ }
+
+ @Override
+ public void close() throws IOException {
+ IoBridge.closeAndSignalBlockedThreads(mClient);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ Memory.pokeInt(mTemp, 0, CMD_FSYNC, ByteOrder.BIG_ENDIAN);
+ IoBridge.write(mClient, mTemp, 0, MSG_LENGTH);
+
+ // Wait for server to ack
+ if (IoBridge.read(mClient, mTemp, 0, MSG_LENGTH) == MSG_LENGTH) {
+ if (Memory.peekInt(mTemp, 0, ByteOrder.BIG_ENDIAN) == CMD_FSYNC) {
+ return;
+ }
+ }
+
+ throw new SyncFailedException("Failed to fsync() across bridge");
+ }
+
+ @Override
+ public void write(byte[] buffer, int byteOffset, int byteCount) throws IOException {
+ Arrays.checkOffsetAndCount(buffer.length, byteOffset, byteCount);
+ Memory.pokeInt(mTemp, 0, CMD_WRITE, ByteOrder.BIG_ENDIAN);
+ Memory.pokeInt(mTemp, 4, byteCount, ByteOrder.BIG_ENDIAN);
+ IoBridge.write(mClient, mTemp, 0, MSG_LENGTH);
+ IoBridge.write(mClient, buffer, byteOffset, byteCount);
+ }
+
+ @Override
+ public void write(int oneByte) throws IOException {
+ Streams.writeSingleByte(this, oneByte);
+ }
+ }
+}
diff --git a/core/java/android/provider/TvContract.java b/core/java/android/provider/TvContract.java
index 5ffffb5..e4f93a8 100644
--- a/core/java/android/provider/TvContract.java
+++ b/core/java/android/provider/TvContract.java
@@ -462,7 +462,7 @@ public final class TvContract {
* <p>
* A value of 1 indicates the channel is included in the channel list that applications use
* to browse channels, a value of 0 indicates the channel is not included in the list. If
- * not specified, this value is set to 1 by default.
+ * not specified, this value is set to 1 (browsable) by default.
* </p><p>
* Type: INTEGER (boolean)
* </p>
@@ -470,6 +470,36 @@ public final class TvContract {
public static final String COLUMN_BROWSABLE = "browsable";
/**
+ * The flag indicating whether this TV channel is searchable or not.
+ * <p>
+ * In some regions, it is not allowed to surface search results for a given channel without
+ * broadcaster's consent. This is used to impose such restriction. A value of 1 indicates
+ * the channel is searchable and can be included in search results, a value of 0 indicates
+ * the channel and its TV programs are hidden from search. If not specified, this value is
+ * set to 1 (searchable) by default.
+ * </p>
+ * <p>
+ * Type: INTEGER (boolean)
+ * </p>
+ */
+ public static final String COLUMN_SEARCHABLE = "searchable";
+
+ /**
+ * The flag indicating whether this TV channel is locked or not.
+ * <p>
+ * This is primarily used for alternative parental control to prevent unauthorized users
+ * from watching the current channel regardless of the content rating. A value of 1
+ * indicates the channel is locked and the user is required to enter passcode to unlock it
+ * in order to watch the current program from the channel, a value of 0 indicates the
+ * channel is not locked thus the user is not prompted to enter passcode If not specified,
+ * this value is set to 0 (not locked) by default.
+ * </p><p>
+ * Type: INTEGER (boolean)
+ * </p>
+ */
+ public static final String COLUMN_LOCKED = "locked";
+
+ /**
* Generic data used by individual TV input services.
* <p>
* Type: BLOB
@@ -544,6 +574,33 @@ public final class TvContract {
public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
/**
+ * The comma-separated genre string of this TV program.
+ * <p>
+ * Use the same language appeared in the underlying broadcast standard, if applicable. (For
+ * example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
+ * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, use one of the
+ * following genres:
+ * <ul>
+ * <li>Family/Kids</li>
+ * <li>Sports</li>
+ * <li>Shopping</li>
+ * <li>Movies</li>
+ * <li>Comedy</li>
+ * <li>Travel</li>
+ * <li>Drama</li>
+ * <li>Education</li>
+ * <li>Animal/Wildlife</li>
+ * <li>News</li>
+ * <li>Gaming</li>
+ * <li>Others</li>
+ * </ul>
+ * </p><p>
+ * Type: TEXT
+ * </p>
+ */
+ public static final String COLUMN_GENRE = "genre";
+
+ /**
* The description of this TV program that is displayed to the user by default.
* <p>
* The maximum length of this field is 256 characters.
@@ -566,6 +623,17 @@ public final class TvContract {
public static final String COLUMN_LONG_DESCRIPTION = "long_description";
/**
+ * The comma-separated audio languages of this TV program.
+ * <p>
+ * This is used to describe available audio languages included in the program. Use
+ * 3-character language code as specified by ISO 639-2.
+ * </p><p>
+ * Type: TEXT
+ * </p>
+ */
+ public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
+
+ /**
* Generic data used by TV input services.
* <p>
* Type: BLOB
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index a272296..424d860 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -41,10 +41,6 @@ import android.text.TextUtils;
* An implementation of Canvas on top of OpenGL ES 2.0.
*/
class GLES20Canvas extends HardwareCanvas {
- // Must match modifiers used in the JNI layer
- private static final int MODIFIER_NONE = 0;
- private static final int MODIFIER_SHADER = 2;
-
private final boolean mOpaque;
protected long mRenderer;
@@ -650,13 +646,8 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
- startAngle, sweepAngle, useCenter, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
+ startAngle, sweepAngle, useCenter, paint.mNativePaint);
}
private static native void nDrawArc(long renderer, float left, float top,
@@ -672,7 +663,6 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
- // Shaders are ignored when drawing patches
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@@ -682,7 +672,6 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
- // Shaders are ignored when drawing patches
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@@ -694,14 +683,8 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
throwIfCannotDraw(bitmap);
- // Shaders are ignored when drawing bitmaps
- int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
}
private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -710,15 +693,9 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
throwIfCannotDraw(bitmap);
- // Shaders are ignored when drawing bitmaps
- int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
- matrix.native_instance, nativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
+ matrix.native_instance, nativePaint);
}
private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -727,55 +704,43 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
throwIfCannotDraw(bitmap);
- // Shaders are ignored when drawing bitmaps
- int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-
- int left, top, right, bottom;
- if (src == null) {
- left = top = 0;
- right = bitmap.getWidth();
- bottom = bitmap.getHeight();
- } else {
- left = src.left;
- right = src.right;
- top = src.top;
- bottom = src.bottom;
- }
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ int left, top, right, bottom;
+ if (src == null) {
+ left = top = 0;
+ right = bitmap.getWidth();
+ bottom = bitmap.getHeight();
+ } else {
+ left = src.left;
+ right = src.right;
+ top = src.top;
+ bottom = src.bottom;
}
+
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@Override
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
throwIfCannotDraw(bitmap);
- // Shaders are ignored when drawing bitmaps
- int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
-
- float left, top, right, bottom;
- if (src == null) {
- left = top = 0;
- right = bitmap.getWidth();
- bottom = bitmap.getHeight();
- } else {
- left = src.left;
- right = src.right;
- top = src.top;
- bottom = src.bottom;
- }
-
- nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
- dst.left, dst.top, dst.right, dst.bottom, nativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+
+ float left, top, right, bottom;
+ if (src == null) {
+ left = top = 0;
+ right = bitmap.getWidth();
+ bottom = bitmap.getHeight();
+ } else {
+ left = src.left;
+ right = src.right;
+ top = src.top;
+ bottom = src.bottom;
}
+
+ nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+ dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -805,7 +770,6 @@ class GLES20Canvas extends HardwareCanvas {
throw new ArrayIndexOutOfBoundsException();
}
- // Shaders are ignored when drawing bitmaps
final long nativePaint = paint == null ? 0 : paint.mNativePaint;
nDrawBitmap(mRenderer, colors, offset, stride, x, y,
width, height, hasAlpha, nativePaint);
@@ -817,7 +781,6 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
int width, int height, boolean hasAlpha, Paint paint) {
- // Shaders are ignored when drawing bitmaps
drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
}
@@ -840,14 +803,9 @@ class GLES20Canvas extends HardwareCanvas {
checkRange(colors.length, colorOffset, count);
}
- int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
- try {
- final long nativePaint = paint == null ? 0 : paint.mNativePaint;
- nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
- verts, vertOffset, colors, colorOffset, nativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ final long nativePaint = paint == null ? 0 : paint.mNativePaint;
+ nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
+ verts, vertOffset, colors, colorOffset, nativePaint);
}
private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer,
@@ -856,12 +814,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawCircle(float cx, float cy, float radius, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
}
private static native void nDrawCircle(long renderer, float cx, float cy,
@@ -906,12 +859,7 @@ class GLES20Canvas extends HardwareCanvas {
if ((offset | count) < 0 || offset + count > pts.length) {
throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
}
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
}
private static native void nDrawLines(long renderer, float[] points,
@@ -924,12 +872,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawOval(RectF oval, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
}
private static native void nDrawOval(long renderer, float left, float top,
@@ -944,17 +887,12 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawPath(Path path, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- if (path.isSimplePath) {
- if (path.rects != null) {
- nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
- }
- } else {
- nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
+ if (path.isSimplePath) {
+ if (path.rects != null) {
+ nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
}
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ } else {
+ nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
}
}
@@ -962,12 +900,7 @@ class GLES20Canvas extends HardwareCanvas {
private static native void nDrawRects(long renderer, long region, long paint);
void drawRects(float[] rects, int count, Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawRects(mRenderer, rects, count, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawRects(mRenderer, rects, count, paint.mNativePaint);
}
private static native void nDrawRects(long renderer, float[] rects, int count, long paint);
@@ -1029,12 +962,7 @@ class GLES20Canvas extends HardwareCanvas {
public void drawPoints(float[] pts, int offset, int count, Paint paint) {
if (count < 2) return;
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
}
private static native void nDrawPoints(long renderer, float[] points,
@@ -1047,12 +975,7 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
- int modifiers = setupModifiers(paint);
- try {
- nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
}
private static native void nDrawPosText(long renderer, char[] text, int index, int count,
@@ -1065,12 +988,7 @@ class GLES20Canvas extends HardwareCanvas {
throw new ArrayIndexOutOfBoundsException();
}
- int modifiers = setupModifiers(paint);
- try {
- nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
}
private static native void nDrawPosText(long renderer, String text, int start, int end,
@@ -1079,12 +997,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawRect(float left, float top, float right, float bottom, Paint paint) {
if (left == right || top == bottom) return;
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
}
private static native void nDrawRect(long renderer, float left, float top,
@@ -1108,12 +1021,7 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
Paint paint) {
- int modifiers = setupModifiers(paint, MODIFIER_SHADER);
- try {
- nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
}
private static native void nDrawRoundRect(long renderer, float left, float top,
@@ -1125,13 +1033,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
- int modifiers = setupModifiers(paint);
- try {
- nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint,
- paint.mNativeTypeface);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawText(mRenderer, text, index, count, x, y,
+ paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
private static native void nDrawText(long renderer, char[] text, int index, int count,
@@ -1139,24 +1042,18 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
- int modifiers = setupModifiers(paint);
- try {
- if (text instanceof String || text instanceof SpannedString ||
- text instanceof SpannableString) {
- nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
- paint.mNativePaint, paint.mNativeTypeface);
- } else if (text instanceof GraphicsOperations) {
- ((GraphicsOperations) text).drawText(this, start, end, x, y,
- paint);
- } else {
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- nDrawText(mRenderer, buf, 0, end - start, x, y,
- paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
- TemporaryBuffer.recycle(buf);
- }
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ if (text instanceof String || text instanceof SpannedString ||
+ text instanceof SpannableString) {
+ nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
+ paint.mNativePaint, paint.mNativeTypeface);
+ } else if (text instanceof GraphicsOperations) {
+ ((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
+ } else {
+ char[] buf = TemporaryBuffer.obtain(end - start);
+ TextUtils.getChars(text, start, end, buf, 0);
+ nDrawText(mRenderer, buf, 0, end - start, x, y,
+ paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
+ TemporaryBuffer.recycle(buf);
}
}
@@ -1166,13 +1063,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
- int modifiers = setupModifiers(paint);
- try {
- nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint,
- paint.mNativeTypeface);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawText(mRenderer, text, start, end, x, y,
+ paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
private static native void nDrawText(long renderer, String text, int start, int end,
@@ -1180,13 +1072,8 @@ class GLES20Canvas extends HardwareCanvas {
@Override
public void drawText(String text, float x, float y, Paint paint) {
- int modifiers = setupModifiers(paint);
- try {
- nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
- paint.mNativePaint, paint.mNativeTypeface);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawText(mRenderer, text, 0, text.length(), x, y,
+ paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
@Override
@@ -1196,13 +1083,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new ArrayIndexOutOfBoundsException();
}
- int modifiers = setupModifiers(paint);
- try {
- nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
- paint.mBidiFlags, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
+ paint.mBidiFlags, paint.mNativePaint);
}
private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
@@ -1212,13 +1094,8 @@ class GLES20Canvas extends HardwareCanvas {
public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
if (text.length() == 0) return;
- int modifiers = setupModifiers(paint);
- try {
- nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
- paint.mBidiFlags, paint.mNativePaint);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
+ paint.mBidiFlags, paint.mNativePaint);
}
private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
@@ -1234,13 +1111,8 @@ class GLES20Canvas extends HardwareCanvas {
throw new IllegalArgumentException("Unknown direction: " + dir);
}
- int modifiers = setupModifiers(paint);
- try {
- nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
- paint.mNativePaint, paint.mNativeTypeface);
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
- }
+ nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
+ paint.mNativePaint, paint.mNativeTypeface);
}
private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
@@ -1253,27 +1125,22 @@ class GLES20Canvas extends HardwareCanvas {
throw new IndexOutOfBoundsException();
}
- int modifiers = setupModifiers(paint);
- try {
- int flags = dir == 0 ? 0 : 1;
- if (text instanceof String || text instanceof SpannedString ||
- text instanceof SpannableString) {
- nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
- contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
- } else if (text instanceof GraphicsOperations) {
- ((GraphicsOperations) text).drawTextRun(this, start, end,
- contextStart, contextEnd, x, y, flags, paint);
- } else {
- int contextLen = contextEnd - contextStart;
- int len = end - start;
- char[] buf = TemporaryBuffer.obtain(contextLen);
- TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
- nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
- x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
- TemporaryBuffer.recycle(buf);
- }
- } finally {
- if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+ int flags = dir == 0 ? 0 : 1;
+ if (text instanceof String || text instanceof SpannedString ||
+ text instanceof SpannableString) {
+ nDrawTextRun(mRenderer, text.toString(), start, end, contextStart,
+ contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ } else if (text instanceof GraphicsOperations) {
+ ((GraphicsOperations) text).drawTextRun(this, start, end,
+ contextStart, contextEnd, x, y, flags, paint);
+ } else {
+ int contextLen = contextEnd - contextStart;
+ int len = end - start;
+ char[] buf = TemporaryBuffer.obtain(contextLen);
+ TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
+ nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen,
+ x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ TemporaryBuffer.recycle(buf);
}
}
@@ -1286,40 +1153,4 @@ class GLES20Canvas extends HardwareCanvas {
int indexOffset, int indexCount, Paint paint) {
// TODO: Implement
}
-
- private int setupModifiers(Bitmap b, Paint paint) {
- if (b.getConfig() != Bitmap.Config.ALPHA_8) {
- return MODIFIER_NONE;
- } else {
- return setupModifiers(paint);
- }
- }
-
- private int setupModifiers(Paint paint) {
- int modifiers = MODIFIER_NONE;
-
- final Shader shader = paint.getShader();
- if (shader != null) {
- nSetupShader(mRenderer, shader.native_shader);
- modifiers |= MODIFIER_SHADER;
- }
-
- return modifiers;
- }
-
- private int setupModifiers(Paint paint, int flags) {
- int modifiers = MODIFIER_NONE;
-
- final Shader shader = paint.getShader();
- if (shader != null && (flags & MODIFIER_SHADER) != 0) {
- nSetupShader(mRenderer, shader.native_shader);
- modifiers |= MODIFIER_SHADER;
- }
-
- return modifiers;
- }
-
- private static native void nSetupShader(long renderer, long shader);
-
- private static native void nResetModifiers(long renderer, int modifiers);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0f21c1d..6396781 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9236,6 +9236,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
+ * Request unbuffered dispatch of the given stream of MotionEvents to this View.
+ *
+ * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input
+ * system not batch {@link MotionEvent}s but instead deliver them as soon as they're
+ * available. This method should only be called for touch events.
+ *
+ * <p class="note">This api is not intended for most applications. Buffered dispatch
+ * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent
+ * streams will not improve your input latency. Side effects include: increased latency,
+ * jittery scrolls and inability to take advantage of system resampling. Talk to your input
+ * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for
+ * you.</p>
+ */
+ public final void requestUnbufferedDispatch(MotionEvent event) {
+ final int action = event.getAction();
+ if (mAttachInfo == null
+ || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE
+ || !event.isTouchEvent()) {
+ return;
+ }
+ mAttachInfo.mUnbufferedDispatchRequested = true;
+ }
+
+ /**
* Set flags controlling behavior of this view.
*
* @param flags Constant indicating the value which should be set
@@ -19760,6 +19784,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mInTouchMode;
/**
+ * Indicates whether the view has requested unbuffered input dispatching for the current
+ * event stream.
+ */
+ boolean mUnbufferedDispatchRequested;
+
+ /**
* Indicates that ViewAncestor should trigger a global layout change
* the next time it performs a traversal
*/
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 799a406..148d9ec 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -230,6 +230,7 @@ public final class ViewRootImpl implements ViewParent,
QueuedInputEvent mPendingInputEventTail;
int mPendingInputEventCount;
boolean mProcessInputEventsScheduled;
+ boolean mUnbufferedInputDispatch;
String mPendingInputEventQueueLengthCounterName = "pq";
InputStage mFirstInputStage;
@@ -1005,7 +1006,9 @@ public final class ViewRootImpl implements ViewParent,
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
- scheduleConsumeBatchedInput();
+ if (!mUnbufferedInputDispatch) {
+ scheduleConsumeBatchedInput();
+ }
}
}
@@ -2604,7 +2607,7 @@ public final class ViewRootImpl implements ViewParent,
}
final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
- final Rect bounds = mView.mAttachInfo.mTmpInvalRect;
+ final Rect bounds = mAttachInfo.mTmpInvalRect;
if (provider == null) {
host.getBoundsOnScreen(bounds);
} else if (mAccessibilityFocusedVirtualView != null) {
@@ -3886,6 +3889,18 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ @Override
+ protected void onDeliverToNext(QueuedInputEvent q) {
+ if (mUnbufferedInputDispatch
+ && q.mEvent instanceof MotionEvent
+ && ((MotionEvent)q.mEvent).isTouchEvent()
+ && isTerminalInputEvent(q.mEvent)) {
+ mUnbufferedInputDispatch = false;
+ scheduleConsumeBatchedInput();
+ }
+ super.onDeliverToNext(q);
+ }
+
private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;
@@ -3998,10 +4013,15 @@ public final class ViewRootImpl implements ViewParent,
private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;
- if (mView.dispatchPointerEvent(event)) {
- return FINISH_HANDLED;
+ mAttachInfo.mUnbufferedDispatchRequested = false;
+ boolean handled = mView.dispatchPointerEvent(event);
+ if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
+ mUnbufferedInputDispatch = true;
+ if (mConsumeBatchedInputScheduled) {
+ scheduleConsumeBatchedInputImmediately();
+ }
}
- return FORWARD;
+ return handled ? FINISH_HANDLED : FORWARD;
}
private int processTrackballEvent(QueuedInputEvent q) {
@@ -5266,6 +5286,8 @@ public final class ViewRootImpl implements ViewParent,
writer.print(" mRemoved="); writer.println(mRemoved);
writer.print(innerPrefix); writer.print("mConsumeBatchedInputScheduled=");
writer.println(mConsumeBatchedInputScheduled);
+ writer.print(innerPrefix); writer.print("mConsumeBatchedInputImmediatelyScheduled=");
+ writer.println(mConsumeBatchedInputImmediatelyScheduled);
writer.print(innerPrefix); writer.print("mPendingInputEventCount=");
writer.println(mPendingInputEventCount);
writer.print(innerPrefix); writer.print("mProcessInputEventsScheduled=");
@@ -5676,6 +5698,7 @@ public final class ViewRootImpl implements ViewParent,
private void finishInputEvent(QueuedInputEvent q) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
q.mEvent.getSequenceNumber());
+
if (q.mReceiver != null) {
boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
q.mReceiver.finishInputEvent(q.mEvent, handled);
@@ -5715,15 +5738,25 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ void scheduleConsumeBatchedInputImmediately() {
+ if (!mConsumeBatchedInputImmediatelyScheduled) {
+ unscheduleConsumeBatchedInput();
+ mConsumeBatchedInputImmediatelyScheduled = true;
+ mHandler.post(mConsumeBatchedInputImmediatelyRunnable);
+ }
+ }
+
void doConsumeBatchedInput(long frameTimeNanos) {
if (mConsumeBatchedInputScheduled) {
mConsumeBatchedInputScheduled = false;
if (mInputEventReceiver != null) {
- if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)) {
+ if (mInputEventReceiver.consumeBatchedInputEvents(frameTimeNanos)
+ && frameTimeNanos != -1) {
// If we consumed a batch here, we want to go ahead and schedule the
// consumption of batched input events on the next frame. Otherwise, we would
// wait until we have more input events pending and might get starved by other
- // things occurring in the process.
+ // things occurring in the process. If the frame time is -1, however, then
+ // we're in a non-batching mode, so there's no need to schedule this.
scheduleConsumeBatchedInput();
}
}
@@ -5751,7 +5784,11 @@ public final class ViewRootImpl implements ViewParent,
@Override
public void onBatchedInputEventPending() {
- scheduleConsumeBatchedInput();
+ if (mUnbufferedInputDispatch) {
+ super.onBatchedInputEventPending();
+ } else {
+ scheduleConsumeBatchedInput();
+ }
}
@Override
@@ -5772,6 +5809,16 @@ public final class ViewRootImpl implements ViewParent,
new ConsumeBatchedInputRunnable();
boolean mConsumeBatchedInputScheduled;
+ final class ConsumeBatchedInputImmediatelyRunnable implements Runnable {
+ @Override
+ public void run() {
+ doConsumeBatchedInput(-1);
+ }
+ }
+ final ConsumeBatchedInputImmediatelyRunnable mConsumeBatchedInputImmediatelyRunnable =
+ new ConsumeBatchedInputImmediatelyRunnable();
+ boolean mConsumeBatchedInputImmediatelyScheduled;
+
final class InvalidateOnAnimationRunnable implements Runnable {
private boolean mPosted;
private final ArrayList<View> mViews = new ArrayList<View>();
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 8511601..97f89aa 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -104,14 +104,16 @@ import static java.lang.Math.min;
*
* <h4>Excess Space Distribution</h4>
*
- * GridLayout's distribution of excess space is based on <em>priority</em>
- * rather than <em>weight</em>.
+ * As of API 21, GridLayout's distribution of excess space accomodates the principle of weight.
+ * In the event that no weights are specified, the previous conventions are respected and
+ * columns and rows are taken as flexible if their views specify some form of alignment
+ * within their groups.
* <p>
- * A child's ability to stretch is inferred from the alignment properties of
- * its row and column groups (which are typically set by setting the
- * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters).
- * If alignment was defined along a given axis then the component
- * is taken as <em>flexible</em> in that direction. If no alignment was set,
+ * The flexibility of a view is therefore influenced by its alignment which is,
+ * in turn, typically defined by setting the
+ * {@link LayoutParams#setGravity(int) gravity} property of the child's layout parameters.
+ * If either a weight or alignment were defined along a given axis then the component
+ * is taken as <em>flexible</em> in that direction. If no weight or alignment was set,
* the component is instead assumed to be <em>inflexible</em>.
* <p>
* Multiple components in the same row or column group are
@@ -122,12 +124,16 @@ import static java.lang.Math.min;
* elements is flexible if <em>one</em> of its elements is flexible.
* <p>
* To make a column stretch, make sure all of the components inside it define a
- * gravity. To prevent a column from stretching, ensure that one of the components
- * in the column does not define a gravity.
+ * weight or a gravity. To prevent a column from stretching, ensure that one of the components
+ * in the column does not define a weight or a gravity.
* <p>
* When the principle of flexibility does not provide complete disambiguation,
* GridLayout's algorithms favour rows and columns that are closer to its <em>right</em>
- * and <em>bottom</em> edges.
+ * and <em>bottom</em> edges. To be more precise, GridLayout treats each of its layout
+ * parameters as a constraint in the a set of variables that define the grid-lines along a
+ * given axis. During layout, GridLayout solves the constraints so as to return the unique
+ * solution to those constraints for which all variables are less-than-or-equal-to
+ * the corresponding value in any other valid solution.
*
* <h4>Interpretation of GONE</h4>
*
@@ -140,18 +146,6 @@ import static java.lang.Math.min;
* had never been added to it.
* These statements apply equally to rows as well as columns, and to groups of rows or columns.
*
- * <h5>Limitations</h5>
- *
- * GridLayout does not provide support for the principle of <em>weight</em>, as defined in
- * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible
- * to configure a GridLayout to distribute excess space between multiple components.
- * <p>
- * Some common use-cases may nevertheless be accommodated as follows.
- * To place equal amounts of space around a component in a cell group;
- * use {@link #CENTER} alignment (or {@link LayoutParams#setGravity(int) gravity}).
- * For complete control over excess space distribution in a row or column;
- * use a {@link LinearLayout} subview to hold the components in the associated cell group.
- * When using either of these techniques, bear in mind that cell groups may be defined to overlap.
* <p>
* See {@link GridLayout.LayoutParams} for a full description of the
* layout parameters used by GridLayout.
@@ -1693,8 +1687,74 @@ public class GridLayout extends ViewGroup {
return trailingMargins;
}
- private void computeLocations(int[] a) {
+ private void solve(int[] a) {
solve(getArcs(), a);
+ }
+
+ private void resetDeltas() {
+ Bounds[] values = getGroupBounds().values;
+ for (int i = 0, N = values.length; i < N; i++) {
+ values[i].shareOfDelta = 0;
+ }
+ }
+
+ private boolean requiresWeightDistribution() {
+ Bounds[] values = getGroupBounds().values;
+ for (int i = 0, N = values.length; i < N; i++) {
+ if (values[i].weight != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void shareOutDelta(int[] locations) {
+ PackedMap<Spec, Bounds> groupBounds = getGroupBounds();
+ Spec[] specs = groupBounds.keys;
+ Bounds[] bounds = groupBounds.values;
+ int totalDelta = 0;
+ float totalWeight = 0;
+ final int N = bounds.length;
+
+ for (int i = 0; i < N; i++) {
+ Spec spec = specs[i];
+ Bounds bound = bounds[i];
+ if (bound.weight != 0) {
+ int minSize = bound.size(true);
+ Interval span = spec.span;
+ int actualSize = locations[span.max] - locations[span.min];
+ int delta = actualSize - minSize;
+ totalDelta += delta;
+ totalWeight += bound.weight;
+ }
+ }
+ for (int i = 0; i < N; i++) {
+ Bounds bound = bounds[i];
+ float weight = bound.weight;
+ if (weight != 0) {
+ int delta = Math.round((weight * totalDelta / totalWeight));
+ bound.shareOfDelta = delta;
+ // the two adjustments below compensate for the rounding above
+ totalDelta -= delta;
+ totalWeight -= weight;
+ }
+ }
+ }
+
+ private void solveAndDistributeSpace(int[] a) {
+ resetDeltas();
+ solve(a);
+ if (requiresWeightDistribution()) {
+ shareOutDelta(a);
+ arcsValid = false;
+ forwardLinksValid = false;
+ backwardLinksValid = false;
+ solve(a);
+ }
+ }
+
+ private void computeLocations(int[] a) {
+ solveAndDistributeSpace(a);
if (!orderPreserved) {
// Solve returns the smallest solution to the constraint system for which all
// values are positive. One value is therefore zero - though if the row/col
@@ -1810,6 +1870,23 @@ public class GridLayout extends ViewGroup {
* both aspects of alignment within the cell group. It is also possible to specify a child's
* alignment within its cell group by using the {@link GridLayout.LayoutParams#setGravity(int)}
* method.
+ * <p>
+ * The weight property is also included in Spec and specifies the proportion of any
+ * excess space that is due to the enclosing row or column.
+ * GridLayout's model of flexibility and weight is broadly based on the physical properties of
+ * systems of mechanical springs. For example, a column in a GridLayout is modeled as
+ * if a set of springs were attached in parallel at their ends. Columns are therefore
+ * flexible only if and only if all views inside them are flexible. Similarly, the combined
+ * weight of a column is defined as the <em>minimum</em> of the weights of the components it
+ * contains. So, if any one component in a column of components has a weight of zero,
+ * the entire group has a weight of zero and will not receive any of the
+ * excess space that GridLayout distributes in its second
+ * (internal) layout pass. The default weight of a component is zero,
+ * reflecting inflexibility, but the default weight of a column (with nothing in it)
+ * is effectively infinite, reflecting the fact that a parallel group of
+ * springs is infinitely flexible when it contains no springs.
+ * <p>
+ * The above comments apply equally to rows and groups of rows and columns.
*
* <h4>WRAP_CONTENT and MATCH_PARENT</h4>
*
@@ -1851,9 +1928,11 @@ public class GridLayout extends ViewGroup {
* <li>{@link #rowSpec}<code>.row</code> = {@link #UNDEFINED} </li>
* <li>{@link #rowSpec}<code>.rowSpan</code> = 1 </li>
* <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
+ * <li>{@link #rowSpec}<code>.weight</code> = 0 </li>
* <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
* <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
* <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li>
+ * <li>{@link #columnSpec}<code>.weight</code> = 0 </li>
* </ul>
*
* See {@link GridLayout} for a more complete description of the conventions
@@ -1861,8 +1940,10 @@ public class GridLayout extends ViewGroup {
*
* @attr ref android.R.styleable#GridLayout_Layout_layout_row
* @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight
* @attr ref android.R.styleable#GridLayout_Layout_layout_column
* @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight
* @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
*/
public static class LayoutParams extends MarginLayoutParams {
@@ -1889,9 +1970,11 @@ public class GridLayout extends ViewGroup {
private static final int COLUMN = R.styleable.GridLayout_Layout_layout_column;
private static final int COLUMN_SPAN = R.styleable.GridLayout_Layout_layout_columnSpan;
+ private static final int COLUMN_WEIGHT = R.styleable.GridLayout_Layout_layout_columnWeight;
private static final int ROW = R.styleable.GridLayout_Layout_layout_row;
private static final int ROW_SPAN = R.styleable.GridLayout_Layout_layout_rowSpan;
+ private static final int ROW_WEIGHT = R.styleable.GridLayout_Layout_layout_rowWeight;
private static final int GRAVITY = R.styleable.GridLayout_Layout_layout_gravity;
@@ -2034,11 +2117,13 @@ public class GridLayout extends ViewGroup {
int column = a.getInt(COLUMN, DEFAULT_COLUMN);
int colSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
- this.columnSpec = spec(column, colSpan, getAlignment(gravity, true));
+ float colWeight = a.getFloat(COLUMN_WEIGHT, Spec.DEFAULT_WEIGHT);
+ this.columnSpec = spec(column, colSpan, getAlignment(gravity, true), colWeight);
int row = a.getInt(ROW, DEFAULT_ROW);
int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
- this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false));
+ float rowWeight = a.getFloat(ROW_WEIGHT, Spec.DEFAULT_WEIGHT);
+ this.rowSpec = spec(row, rowSpan, getAlignment(gravity, false), rowWeight);
} finally {
a.recycle();
}
@@ -2244,6 +2329,8 @@ public class GridLayout extends ViewGroup {
public int before;
public int after;
public int flexibility; // we're flexible iff all included specs are flexible
+ public float weight; // the min of the weights of the individual specs
+ public int shareOfDelta;
private Bounds() {
reset();
@@ -2253,6 +2340,7 @@ public class GridLayout extends ViewGroup {
before = Integer.MIN_VALUE;
after = Integer.MIN_VALUE;
flexibility = CAN_STRETCH; // from the above, we're flexible when empty
+ weight = Float.MAX_VALUE; // default is large => row/cols take all slack when empty
}
protected void include(int before, int after) {
@@ -2266,7 +2354,7 @@ public class GridLayout extends ViewGroup {
return MAX_SIZE;
}
}
- return before + after;
+ return before + after + shareOfDelta;
}
protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
@@ -2275,6 +2363,7 @@ public class GridLayout extends ViewGroup {
protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
this.flexibility &= spec.getFlexibility();
+ weight = Math.min(weight, spec.weight);
boolean horizontal = axis.horizontal;
int size = gl.getMeasurementIncludingMargin(c, horizontal);
Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
@@ -2401,36 +2490,43 @@ public class GridLayout extends ViewGroup {
* <li>{@link #spec(int, int)}</li>
* <li>{@link #spec(int, Alignment)}</li>
* <li>{@link #spec(int, int, Alignment)}</li>
+ * <li>{@link #spec(int, float)}</li>
+ * <li>{@link #spec(int, int, float)}</li>
+ * <li>{@link #spec(int, Alignment, float)}</li>
+ * <li>{@link #spec(int, int, Alignment, float)}</li>
* </ul>
*
*/
public static class Spec {
static final Spec UNDEFINED = spec(GridLayout.UNDEFINED);
+ static final float DEFAULT_WEIGHT = 0;
final boolean startDefined;
final Interval span;
final Alignment alignment;
+ final float weight;
- private Spec(boolean startDefined, Interval span, Alignment alignment) {
+ private Spec(boolean startDefined, Interval span, Alignment alignment, float weight) {
this.startDefined = startDefined;
this.span = span;
this.alignment = alignment;
+ this.weight = weight;
}
- private Spec(boolean startDefined, int start, int size, Alignment alignment) {
- this(startDefined, new Interval(start, start + size), alignment);
+ private Spec(boolean startDefined, int start, int size, Alignment alignment, float weight) {
+ this(startDefined, new Interval(start, start + size), alignment, weight);
}
final Spec copyWriteSpan(Interval span) {
- return new Spec(startDefined, span, alignment);
+ return new Spec(startDefined, span, alignment, weight);
}
final Spec copyWriteAlignment(Alignment alignment) {
- return new Spec(startDefined, span, alignment);
+ return new Spec(startDefined, span, alignment, weight);
}
final int getFlexibility() {
- return (alignment == UNDEFINED_ALIGNMENT) ? INFLEXIBLE : CAN_STRETCH;
+ return (alignment == UNDEFINED_ALIGNMENT && weight == 0) ? INFLEXIBLE : CAN_STRETCH;
}
/**
@@ -2478,6 +2574,7 @@ public class GridLayout extends ViewGroup {
* <ul>
* <li> {@code spec.span = [start, start + size]} </li>
* <li> {@code spec.alignment = alignment} </li>
+ * <li> {@code spec.weight = weight} </li>
* </ul>
* <p>
* To leave the start index undefined, use the value {@link #UNDEFINED}.
@@ -2485,9 +2582,55 @@ public class GridLayout extends ViewGroup {
* @param start the start
* @param size the size
* @param alignment the alignment
+ * @param weight the weight
+ */
+ public static Spec spec(int start, int size, Alignment alignment, float weight) {
+ return new Spec(start != UNDEFINED, start, size, alignment, weight);
+ }
+
+ /**
+ * Equivalent to: {@code spec(start, 1, alignment, weight)}.
+ *
+ * @param start the start
+ * @param alignment the alignment
+ * @param weight the weight
+ */
+ public static Spec spec(int start, Alignment alignment, float weight) {
+ return spec(start, 1, alignment, weight);
+ }
+
+ /**
+ * Equivalent to: {@code spec(start, 1, default_alignment, weight)} -
+ * where {@code default_alignment} is specified in
+ * {@link android.widget.GridLayout.LayoutParams}.
+ *
+ * @param start the start
+ * @param size the size
+ * @param weight the weight
+ */
+ public static Spec spec(int start, int size, float weight) {
+ return spec(start, size, UNDEFINED_ALIGNMENT, weight);
+ }
+
+ /**
+ * Equivalent to: {@code spec(start, 1, weight)}.
+ *
+ * @param start the start
+ * @param weight the weight
+ */
+ public static Spec spec(int start, float weight) {
+ return spec(start, 1, weight);
+ }
+
+ /**
+ * Equivalent to: {@code spec(start, size, alignment, 0f)}.
+ *
+ * @param start the start
+ * @param size the size
+ * @param alignment the alignment
*/
public static Spec spec(int start, int size, Alignment alignment) {
- return new Spec(start != UNDEFINED, start, size, alignment);
+ return spec(start, size, alignment, Spec.DEFAULT_WEIGHT);
}
/**