Api updates for wearable extensions to notifications

1. Move Extender outside of Builder
2. Rename apply/applyTo to extend
3. Move Wearable extenders into Notification.java
4. Collapse Builder model into single classes
5. Use Bundle for storage: no new parcelable types.

Minor fix to RemoteInput to use flags int for boolean options.

Change-Id: I40012fd0458ec103eabf75ed4c91f636e02f4c8f
This commit is contained in:
Griff Hazen
2014-05-22 14:38:36 -07:00
parent adb0a906dc
commit c3104157d8
5 changed files with 836 additions and 998 deletions

View File

@@ -4001,13 +4001,22 @@ package android.app {
ctor public Notification.Action.Builder(android.app.Notification.Action);
method public android.app.Notification.Action.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
method public android.app.Notification.Action.Builder apply(android.app.Notification.Action.Builder.Extender);
method public android.app.Notification.Action build();
method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
method public android.os.Bundle getExtras();
}
public static abstract interface Notification.Action.Builder.Extender {
method public abstract android.app.Notification.Action.Builder applyTo(android.app.Notification.Action.Builder);
public static abstract interface Notification.Action.Extender {
method public abstract android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
}
public static final class Notification.Action.WearableExtender implements android.app.Notification.Action.Extender {
ctor public Notification.Action.WearableExtender();
ctor public Notification.Action.WearableExtender(android.app.Notification.Action);
method public android.app.Notification.Action.WearableExtender clone();
method public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Builder);
method public boolean isAvailableOffline();
method public android.app.Notification.Action.WearableExtender setAvailableOffline(boolean);
}
public static class Notification.BigPictureStyle extends android.app.Notification.Style {
@@ -4032,8 +4041,8 @@ package android.app {
method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Builder addAction(android.app.Notification.Action);
method public android.app.Notification.Builder addExtras(android.os.Bundle);
method public android.app.Notification.Builder apply(android.app.Notification.Builder.Extender);
method public android.app.Notification build();
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
method public android.os.Bundle getExtras();
method public deprecated android.app.Notification getNotification();
method public android.app.Notification.Builder setAutoCancel(boolean);
@@ -4071,8 +4080,8 @@ package android.app {
method public android.app.Notification.Builder setWhen(long);
}
public static abstract interface Notification.Builder.Extender {
method public abstract android.app.Notification.Builder applyTo(android.app.Notification.Builder);
public static abstract interface Notification.Extender {
method public abstract android.app.Notification.Builder extend(android.app.Notification.Builder);
}
public static class Notification.InboxStyle extends android.app.Notification.Style {
@@ -4094,6 +4103,51 @@ package android.app {
field protected android.app.Notification.Builder mBuilder;
}
public static final class Notification.WearableExtender implements android.app.Notification.Extender {
ctor public Notification.WearableExtender();
ctor public Notification.WearableExtender(android.app.Notification);
method public android.app.Notification.WearableExtender addAction(android.app.Notification.Action);
method public android.app.Notification.WearableExtender addActions(java.util.List<android.app.Notification.Action>);
method public android.app.Notification.WearableExtender addPage(android.app.Notification);
method public android.app.Notification.WearableExtender addPages(java.util.List<android.app.Notification>);
method public android.app.Notification.WearableExtender clearActions();
method public android.app.Notification.WearableExtender clearPages();
method public android.app.Notification.WearableExtender clone();
method public android.app.Notification.Builder extend(android.app.Notification.Builder);
method public java.util.List<android.app.Notification.Action> getActions();
method public android.graphics.Bitmap getBackground();
method public int getContentAction();
method public int getContentIcon();
method public int getContentIconGravity();
method public boolean getContentIntentAvailableOffline();
method public int getCustomContentHeight();
method public int getCustomSizePreset();
method public android.app.PendingIntent getDisplayIntent();
method public int getGravity();
method public boolean getHintHideIcon();
method public boolean getHintShowBackgroundOnly();
method public java.util.List<android.app.Notification> getPages();
method public boolean getStartScrollBottom();
method public android.app.Notification.WearableExtender setBackground(android.graphics.Bitmap);
method public android.app.Notification.WearableExtender setContentAction(int);
method public android.app.Notification.WearableExtender setContentIcon(int);
method public android.app.Notification.WearableExtender setContentIconGravity(int);
method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean);
method public android.app.Notification.WearableExtender setCustomContentHeight(int);
method public android.app.Notification.WearableExtender setCustomSizePreset(int);
method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
method public android.app.Notification.WearableExtender setGravity(int);
method public android.app.Notification.WearableExtender setHintHideIcon(boolean);
method public android.app.Notification.WearableExtender setHintShowBackgroundOnly(boolean);
method public android.app.Notification.WearableExtender setStartScrollBottom(boolean);
field public static final int SIZE_DEFAULT = 0; // 0x0
field public static final int SIZE_LARGE = 4; // 0x4
field public static final int SIZE_MEDIUM = 3; // 0x3
field public static final int SIZE_SMALL = 2; // 0x2
field public static final int SIZE_XSMALL = 1; // 0x1
field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
}
public class NotificationManager {
method public void cancel(int);
method public void cancel(java.lang.String, int);
@@ -4661,80 +4715,6 @@ package android.app.backup {
}
package android.app.wearable {
public final class WearableActionExtensions implements android.app.Notification.Action.Builder.Extender android.os.Parcelable {
method public android.app.Notification.Action.Builder applyTo(android.app.Notification.Action.Builder);
method public int describeContents();
method public static android.app.wearable.WearableActionExtensions from(android.app.Notification.Action);
method public boolean isAvailableOffline();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
}
public static final class WearableActionExtensions.Builder {
ctor public WearableActionExtensions.Builder();
ctor public WearableActionExtensions.Builder(android.app.wearable.WearableActionExtensions);
method public android.app.wearable.WearableActionExtensions build();
method public android.app.wearable.WearableActionExtensions.Builder setAvailableOffline(boolean);
}
public final class WearableNotificationExtensions implements android.app.Notification.Builder.Extender android.os.Parcelable {
method public android.app.Notification.Builder applyTo(android.app.Notification.Builder);
method public int describeContents();
method public static android.app.wearable.WearableNotificationExtensions from(android.app.Notification);
method public android.app.Notification.Action getAction(int);
method public int getActionCount();
method public android.app.Notification.Action[] getActions();
method public android.graphics.Bitmap getBackground();
method public int getContentAction();
method public int getContentIcon();
method public int getContentIconGravity();
method public boolean getContentIntentAvailableOffline();
method public int getCustomContentHeight();
method public int getCustomSizePreset();
method public android.app.PendingIntent getDisplayIntent();
method public int getGravity();
method public boolean getHintHideIcon();
method public boolean getHintShowBackgroundOnly();
method public android.app.Notification[] getPages();
method public boolean getStartScrollBottom();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int SIZE_DEFAULT = 0; // 0x0
field public static final int SIZE_LARGE = 4; // 0x4
field public static final int SIZE_MEDIUM = 3; // 0x3
field public static final int SIZE_SMALL = 2; // 0x2
field public static final int SIZE_XSMALL = 1; // 0x1
field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
}
public static final class WearableNotificationExtensions.Builder {
ctor public WearableNotificationExtensions.Builder();
ctor public WearableNotificationExtensions.Builder(android.app.wearable.WearableNotificationExtensions);
method public android.app.wearable.WearableNotificationExtensions.Builder addAction(android.app.Notification.Action);
method public android.app.wearable.WearableNotificationExtensions.Builder addActions(java.util.List<android.app.Notification.Action>);
method public android.app.wearable.WearableNotificationExtensions.Builder addPage(android.app.Notification);
method public android.app.wearable.WearableNotificationExtensions.Builder addPages(java.util.List<android.app.Notification>);
method public android.app.wearable.WearableNotificationExtensions build();
method public android.app.wearable.WearableNotificationExtensions.Builder clearActions();
method public android.app.wearable.WearableNotificationExtensions.Builder clearPages();
method public android.app.wearable.WearableNotificationExtensions.Builder setBackground(android.graphics.Bitmap);
method public android.app.wearable.WearableNotificationExtensions.Builder setContentAction(int);
method public android.app.wearable.WearableNotificationExtensions.Builder setContentIcon(int);
method public android.app.wearable.WearableNotificationExtensions.Builder setContentIconGravity(int);
method public android.app.wearable.WearableNotificationExtensions.Builder setContentIntentAvailableOffline(boolean);
method public android.app.wearable.WearableNotificationExtensions.Builder setCustomContentHeight(int);
method public android.app.wearable.WearableNotificationExtensions.Builder setCustomSizePreset(int);
method public android.app.wearable.WearableNotificationExtensions.Builder setDisplayIntent(android.app.PendingIntent);
method public android.app.wearable.WearableNotificationExtensions.Builder setGravity(int);
method public android.app.wearable.WearableNotificationExtensions.Builder setHintHideIcon(boolean);
method public android.app.wearable.WearableNotificationExtensions.Builder setHintShowBackgroundOnly(boolean);
method public android.app.wearable.WearableNotificationExtensions.Builder setStartScrollBottom(boolean);
}
}
package android.appwidget {
public class AppWidgetHost {

View File

@@ -31,6 +31,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;
@@ -39,7 +40,9 @@ import com.android.internal.R;
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
@@ -696,7 +699,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.
@@ -839,24 +842,11 @@ 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.
@@ -904,6 +894,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;
}
}
}
}
/**
@@ -2000,24 +2105,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;
@@ -2693,4 +2785,634 @@ public class Notification implements Parcelable
return wip;
}
}
/**
* 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;
}
}

View File

@@ -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);
}

View File

@@ -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];
}
};
}

View File

@@ -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];
}
};
}