java.lang.Object
↳androidx.wear.ongoing.OngoingActivity
Gradle dependencies
compile group: 'androidx.wear', name: 'wear-ongoing', version: '1.0.0'
- groupId: androidx.wear
- artifactId: wear-ongoing
- version: 1.0.0
Artifact androidx.wear:wear-ongoing:1.0.0 it located at Google repository (https://maven.google.com/)
Overview
Main class to access the Ongoing Activities API.
It's created with the OngoingActivity.Builder. After it's created (and before building and
posting the Notification
) OngoingActivity.apply(Context) apply needs to be
called:
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
....
OngoingActivity ongoingActivity = new OngoingActivity.Builder(context, notificationId, builder);
....
ongoingActivity.apply(context);
notificationManager.notify(notificationId, builder.build());
Note that the notification passed to the
OngoingActivity.Builder is also usen to take defaults if they
are not explicitly set on it (see the
OngoingActivity.Builder for details).
Note that if a Notification with that id was previously posted it will be replaced. If you
need more than one Notification with the same ID you can use a String tag to differentiate
them in both the OngoingActivity.Builder and
Afterward, update can be used to
update the status.
If saving the OngoingActivity instance is not convenient, it can be recovered (after the
notification is posted) with OngoingActivity.recoverOngoingActivity(Context)
It's worth mentioning that the information provided may be used/redered differently on different
SysUIs, so we can only provide a general expectation.
Summary
Methods |
---|
public void | apply(Context context)
Notify the system that this activity should be shown as an Ongoing Activity. |
public Icon | getAnimatedIcon()
Get the animated icon that can be used on some surfaces to represent this
OngoingActivity. |
public java.lang.String | getCategory()
Get the Category of this OngoingActivity if set, otherwise the category of the
corresponding notification. |
public LocusIdCompat | getLocusId()
Get the LocusId of this OngoingActivity, this can be used by the launcher to
identify the corresponding launcher item and display it accordingly. |
public int | getNotificationId()
Get the notificationId of the notification associated with this OngoingActivity. |
public int | getOngoingActivityId()
Get the id to this OngoingActivity. |
public Icon | getStaticIcon()
Get the static icon that can be used on some surfaces to represent this
OngoingActivity. |
public Status | getStatus()
Get the status of this ongoing activity, the status may be displayed on the UI to
show progress of the Ongoing Activity. |
public java.lang.String | getTag()
Get the tag of the notification associated with this OngoingActivity, or null if
there is none. |
public long | getTimestamp()
Get the time (in time) the OngoingActivity was built. |
public java.lang.String | getTitle()
Get the title of this OngoingActivity if set. |
public PendingIntent | getTouchIntent()
Get the intent to be used to go back to the activity when the user interacts with the
Ongoing Activity in other surfaces (for example, taps the Icon on the WatchFace). |
public static OngoingActivity | recoverOngoingActivity(Context context)
Convenience method for clients that don’t want to / can’t store the OngoingActivity
instance. |
public static OngoingActivity | recoverOngoingActivity(Context context, int ongoingActivityId)
Convenience method for clients that don’t want to / can’t store the OngoingActivity
instance. |
public static OngoingActivity | recoverOngoingActivity(Context context, java.util.function.Predicate<OngoingActivity> filter)
Convenience method for clients that don’t want to / can’t store the OngoingActivity
instance. |
public void | update(Context context, Status status)
Update the status of this Ongoing Activity. |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Methods
public int
getNotificationId()
Get the notificationId of the notification associated with this OngoingActivity.
public java.lang.String
getTag()
Get the tag of the notification associated with this OngoingActivity, or null if
there is none.
public Icon
getAnimatedIcon()
Get the animated icon that can be used on some surfaces to represent this
OngoingActivity. For example, in the WatchFace.
public Icon
getStaticIcon()
Get the static icon that can be used on some surfaces to represent this
OngoingActivity. For example in the WatchFace in ambient mode. If not set, returns
the small icon of the corresponding Notification.
Get the status of this ongoing activity, the status may be displayed on the UI to
show progress of the Ongoing Activity. If not set, returns the content text of the
corresponding Notification.
public PendingIntent
getTouchIntent()
Get the intent to be used to go back to the activity when the user interacts with the
Ongoing Activity in other surfaces (for example, taps the Icon on the WatchFace). If not
set, returns the touch intent of the corresponding Notification.
Get the LocusId of this OngoingActivity, this can be used by the launcher to
identify the corresponding launcher item and display it accordingly. If not set, returns
the one in the corresponding Notification.
public int
getOngoingActivityId()
Get the id to this OngoingActivity. This id is used to reference it in
OngoingActivity.recoverOngoingActivity(Context, int)
public java.lang.String
getCategory()
Get the Category of this OngoingActivity if set, otherwise the category of the
corresponding notification.
public long
getTimestamp()
Get the time (in time) the OngoingActivity was built.
public java.lang.String
getTitle()
Get the title of this OngoingActivity if set.
public void
apply(Context context)
Notify the system that this activity should be shown as an Ongoing Activity.
This will modify the notification builder associated with this Ongoing Activity, so needs
to be called before building and posting that notification.
Parameters:
context: May be used to access system services. A reference will not be kept after
this call returns.
public void
update(Context context,
Status status)
Update the status of this Ongoing Activity.
Note that this may post the notification updated with the new information.
Parameters:
context: May be used to access system services. A reference will not be kept after
this call returns.
status: The new status of this Ongoing Activity.
public static
OngoingActivity recoverOngoingActivity(Context context, java.util.function.Predicate<OngoingActivity> filter)
Convenience method for clients that don’t want to / can’t store the OngoingActivity
instance.
Parameters:
context: May be used to access system services. A reference will not be kept after
this call returns.
filter: used to find the required OngoingActivity.
Returns:
the Ongoing Activity or null if not found
Convenience method for clients that don’t want to / can’t store the OngoingActivity
instance.
Note that if there is more than one Ongoing Activity active you have not guarantee
over which one you get, you need to use one of the other variations of this method.
Parameters:
context: May be used to access system services. A reference will not be kept after
this call returns.
Returns:
the Ongoing Activity or null if not found
public static
OngoingActivity recoverOngoingActivity(Context context, int ongoingActivityId)
Convenience method for clients that don’t want to / can’t store the OngoingActivity
instance.
Parameters:
context: May be used to access system services. A reference will not be kept
after this call returns.
ongoingActivityId: the id of the Ongoing Activity to retrieve, set in
OngoingActivity.Builder.setOngoingActivityId(int)
Returns:
the Ongoing Activity or null if not found
Source
/*
* Copyright 2020 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 androidx.wear.ongoing;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.core.content.LocusIdCompat;
import androidx.core.util.Preconditions;
import java.util.function.Predicate;
/**
* Main class to access the Ongoing Activities API.
*
* It's created with the {@link Builder}. After it's created (and before building and
* posting the {@link Notification}) {@link OngoingActivity#apply(Context)} apply needs to be
* called:
*
* <pre>{@code
* NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
* ....
* OngoingActivity ongoingActivity = new OngoingActivity.Builder(context, notificationId, builder);
* ....
* ongoingActivity.apply(context);
* notificationManager.notify(notificationId, builder.build());
* }</pre>
*
* Note that the notification passed to the {@link Builder} is also usen to take defaults if they
* are not explicitly set on it (see the {@link Builder} for details).
* <p>
* Note that if a Notification with that id was previously posted it will be replaced. If you
* need more than one Notification with the same ID you can use a String tag to differentiate
* them in both the {@link Builder#Builder(Context, String, int, NotificationCompat.Builder)} and
* {@link NotificationManager#notify(String, int, Notification)}
* <p>
* Afterward, {@link OngoingActivity#update(Context, Status) update} can be used to
* update the status.
* <p>
* If saving the {@link OngoingActivity} instance is not convenient, it can be recovered (after the
* notification is posted) with {@link OngoingActivity#recoverOngoingActivity(Context)}
* <p>
* It's worth mentioning that the information provided may be used/redered differently on different
* SysUIs, so we can only provide a general expectation.
*/
@RequiresApi(24)
public final class OngoingActivity {
@Nullable
private final String mTag;
private final int mNotificationId;
@Nullable
private final NotificationCompat.Builder mNotificationBuilder;
private final OngoingActivityData mData;
private OngoingActivity(@Nullable String tag,
int notificationId,
@NonNull NotificationCompat.Builder notificationBuilder,
@NonNull OngoingActivityData data) {
this.mTag = tag;
this.mNotificationId = notificationId;
this.mNotificationBuilder = notificationBuilder;
this.mData = data;
}
// Used when reconstructing an OngoingActivity form a bundle.
OngoingActivity(@NonNull OngoingActivityData data) {
this.mTag = null;
this.mNotificationId = 0;
this.mNotificationBuilder = null;
this.mData = data;
}
/**
* Builder used to build an {@link OngoingActivity}
* <p>
* Note that many fields take a default value from the provided notification if not
* explicitly set. If set explicitly and in the notification, the value set through the
* {@link Builder} will be used.
* <p>
* The only required fields (set through the builder or the notification) are static icon and
* pending intent.
*
*/
public static final class Builder {
private final Context mContext;
private final int mNotificationId;
private final String mTag;
private final NotificationCompat.Builder mNotificationBuilder;
// Ongoing Activity Data
private Icon mAnimatedIcon;
private Icon mStaticIcon;
private Status mStatus;
private PendingIntent mTouchIntent;
private LocusIdCompat mLocusId;
private int mOngoingActivityId = DEFAULT_ID;
private String mCategory;
private String mTitle;
static final int DEFAULT_ID = -1;
/**
* Construct a new empty {@link Builder}, associated with the given notification.
*
* @param context to be used during the life of this {@link Builder}, will
* NOT pass a reference into the built {@link OngoingActivity}
* @param notificationId id that will be used to post the notification associated
* with this Ongoing Activity
* @param notificationBuilder builder for the notification associated with this Ongoing
* Activity
*/
public Builder(@NonNull Context context, int notificationId,
@NonNull NotificationCompat.Builder notificationBuilder) {
this(context, null, notificationId, notificationBuilder);
}
/**
* Construct a new empty {@link Builder}, associated with the given notification.
*
* @param context to be used during the life of this {@link Builder}, will
* NOT pass a reference into the built {@link OngoingActivity}
* @param tag tag that will be used to post the notification associated
* with this Ongoing Activity
* @param notificationId id that will be used to post the notification associated
* with this Ongoing Activity
* @param notificationBuilder builder for the notification associated with this Ongoing
* Activity
*/
public Builder(@NonNull Context context, @NonNull String tag, int notificationId,
@NonNull NotificationCompat.Builder notificationBuilder) {
this.mContext = context;
this.mTag = tag;
this.mNotificationId = notificationId;
this.mNotificationBuilder = notificationBuilder;
}
/**
* Set the animated icon that can be used on some surfaces to represent this
* {@link OngoingActivity}. For example, in the WatchFace.
* Should be white with a transparent background, preferably an AnimatedVectorDrawable.
* <p>
* If not provided, or set to null, the static icon will be used.
*/
@NonNull
public Builder setAnimatedIcon(@Nullable Icon animatedIcon) {
mAnimatedIcon = animatedIcon;
return this;
}
/**
* Set the animated icon that can be used on some surfaces to represent this
* {@link OngoingActivity}. For example, in the WatchFace.
* Should be white with a transparent background, preferably an AnimatedVectorDrawable.
* <p>
* If not provided, the static icon will be used.
*/
@NonNull
public Builder setAnimatedIcon(@DrawableRes int animatedIcon) {
mAnimatedIcon = Icon.createWithResource(mContext, animatedIcon);
return this;
}
/**
* Set the static icon that can be used on some surfaces to represent this
* {@link OngoingActivity}, for example in the WatchFace in ambient mode.
* Should be white with a transparent background, preferably a VectorDrawable.
* <p>
* If not set, the smallIcon of the notification will be used. If neither is set,
* {@link Builder#build()} will throw an exception.
*/
@NonNull
public Builder setStaticIcon(@NonNull Icon staticIcon) {
mStaticIcon = staticIcon;
return this;
}
/**
* Set the static icon that can be used on some surfaces to represent this
* {@link OngoingActivity}, for example in the WatchFace in ambient mode.
* Should be white with a transparent background, preferably a VectorDrawable.
* <p>
* If not set, the smallIcon of the notification will be used. If neither is set,
* {@link Builder#build()} will throw an exception.
*/
@NonNull
public Builder setStaticIcon(@DrawableRes int staticIcon) {
mStaticIcon = Icon.createWithResource(mContext, staticIcon);
return this;
}
/**
* Set the initial status of this ongoing activity, the status may be displayed on the UI to
* show progress of the Ongoing Activity.
* <p>
* If not provided, the contentText of the notification will be used.
*/
@NonNull
public Builder setStatus(@NonNull Status status) {
mStatus = status;
return this;
}
/**
* Set the intent to be used to go back to the activity when the user interacts with the
* Ongoing Activity in other surfaces (for example, taps the Icon on the WatchFace).
* <p>
* If not set, the contentIntent of the notification will be used. If neither is set,
* {@link Builder#build()} will throw an exception.
*/
@NonNull
public Builder setTouchIntent(@NonNull PendingIntent touchIntent) {
mTouchIntent = touchIntent;
return this;
}
/**
* Set the corresponding LocusId of this {@link OngoingActivity}, this will be used by the
* launcher to identify the corresponding launcher item and display it accordingly.
* <p>
* If set to null or not set, the launcher will use heuristics to do the matching.
*/
@NonNull
public Builder setLocusId(@Nullable LocusIdCompat locusId) {
mLocusId = locusId;
return this;
}
/**
* Give an id to this {@link OngoingActivity}, as a way to reference it in
* {@link OngoingActivity#recoverOngoingActivity(Context, int)}
*/
@NonNull
public Builder setOngoingActivityId(int ongoingActivityId) {
mOngoingActivityId = ongoingActivityId;
return this;
}
/**
* Set the category of this {@link OngoingActivity}. It may be used by the system to
* prioritize displaying the {@link OngoingActivity}.
* <p>
* If set, it Must be one of the predefined notification categories (see the
* {@code CATEGORY_*} constants in {@link NotificationCompat}) that best describes this
* {@link OngoingActivity}.
* <p>
* If this is not set (or null), the notification's category is used if present.
*/
@NonNull
public Builder setCategory(@Nullable String category) {
mCategory = category;
return this;
}
/**
* Sets the Title of this {@link OngoingActivity}. If this is set to a non-null value, it
* could be used by the launcher to override the app's title.
* <p>
* No defaults from the notification are used for this field.
*/
@NonNull
public Builder setTitle(@Nullable String title) {
mTitle = title;
return this;
}
/**
* Combine all options provided and the information in the notification if needed,
* return a new {@link OngoingActivity} object. See particular setters for information on
* what defaults from the notification are used.
*
* @throws IllegalArgumentException if the static icon or the touch intent are not provided.
*/
@SuppressWarnings("SyntheticAccessor")
@NonNull
public OngoingActivity build() {
Notification notification = mNotificationBuilder.build();
Icon staticIcon = mStaticIcon == null ? notification.getSmallIcon() : mStaticIcon;
if (staticIcon == null) {
throw new IllegalArgumentException("Static icon should be specified.");
}
PendingIntent touchIntent = mTouchIntent == null
? notification.contentIntent
: mTouchIntent;
if (touchIntent == null) {
throw new IllegalArgumentException("Touch intent should be specified.");
}
OngoingActivityStatus status = mStatus == null ? null : mStatus.toVersionedParcelable();
if (status == null) {
String text = notification.extras.getString(Notification.EXTRA_TEXT);
if (text != null) {
status = Status.forPart(new Status.TextPart(text))
.toVersionedParcelable();
}
}
LocusIdCompat locusId = mLocusId;
if (locusId == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
locusId = Api29Impl.getLocusId(notification);
}
String category = mCategory == null ? notification.category : mCategory;
return new OngoingActivity(mTag, mNotificationId, mNotificationBuilder,
new OngoingActivityData(
mAnimatedIcon,
staticIcon,
status,
touchIntent,
locusId == null ? null : locusId.getId(),
mOngoingActivityId,
category,
SystemClock.elapsedRealtime(),
mTitle
));
}
}
/**
* Get the notificationId of the notification associated with this {@link OngoingActivity}.
*/
public int getNotificationId() {
return mNotificationId;
}
/**
* Get the tag of the notification associated with this {@link OngoingActivity}, or null if
* there is none.
*/
@Nullable
public String getTag() {
return mTag;
}
/**
* Get the animated icon that can be used on some surfaces to represent this
* {@link OngoingActivity}. For example, in the WatchFace.
*/
@Nullable
public Icon getAnimatedIcon() {
return mData.getAnimatedIcon();
}
/**
* Get the static icon that can be used on some surfaces to represent this
* {@link OngoingActivity}. For example in the WatchFace in ambient mode. If not set, returns
* the small icon of the corresponding Notification.
*/
@NonNull
public Icon getStaticIcon() {
return mData.getStaticIcon();
}
/**
* Get the status of this ongoing activity, the status may be displayed on the UI to
* show progress of the Ongoing Activity. If not set, returns the content text of the
* corresponding Notification.
*/
@Nullable
public Status getStatus() {
return mData.getStatus() == null ? null :
Status.fromVersionedParcelable(mData.getStatus());
}
/**
* Get the intent to be used to go back to the activity when the user interacts with the
* Ongoing Activity in other surfaces (for example, taps the Icon on the WatchFace). If not
* set, returns the touch intent of the corresponding Notification.
*/
@NonNull
public PendingIntent getTouchIntent() {
return mData.getTouchIntent();
}
/**
* Get the LocusId of this {@link OngoingActivity}, this can be used by the launcher to
* identify the corresponding launcher item and display it accordingly. If not set, returns
* the one in the corresponding Notification.
*/
@Nullable
public LocusIdCompat getLocusId() {
return mData.getLocusId();
}
/**
* Get the id to this {@link OngoingActivity}. This id is used to reference it in
* {@link #recoverOngoingActivity(Context, int)}
*/
public int getOngoingActivityId() {
return mData.getOngoingActivityId();
}
/**
* Get the Category of this {@link OngoingActivity} if set, otherwise the category of the
* corresponding notification.
*/
@Nullable
public String getCategory() {
return mData.getCategory();
}
/**
* Get the time (in {@link SystemClock#elapsedRealtime()} time) the OngoingActivity was built.
*/
public long getTimestamp() {
return mData.getTimestamp();
}
/**
* Get the title of this {@link OngoingActivity} if set.
*/
@Nullable
public String getTitle() {
return mData.getTitle();
}
/**
* Notify the system that this activity should be shown as an Ongoing Activity.
*
* This will modify the notification builder associated with this Ongoing Activity, so needs
* to be called before building and posting that notification.
*
* @param context May be used to access system services. A reference will not be kept after
* this call returns.
*/
public void apply(@NonNull @SuppressWarnings("unused") Context context) {
Preconditions.checkNotNull(mNotificationBuilder);
SerializationHelper.extend(mNotificationBuilder, mData);
}
/**
* Update the status of this Ongoing Activity.
*
* Note that this may post the notification updated with the new information.
*
* @param context May be used to access system services. A reference will not be kept after
* this call returns.
* @param status The new status of this Ongoing Activity.
*/
public void update(@NonNull Context context, @NonNull Status status) {
Preconditions.checkNotNull(mNotificationBuilder);
mData.setStatus(status.toVersionedParcelable());
Notification notification = SerializationHelper.extendAndBuild(mNotificationBuilder, mData);
NotificationManager manager = context.getSystemService(NotificationManager.class);
if (mTag == null) {
manager.notify(mNotificationId, notification);
} else {
manager.notify(mTag, mNotificationId, notification);
}
}
/**
* Convenience method for clients that don’t want to / can’t store the OngoingActivity
* instance.
*
* @param context May be used to access system services. A reference will not be kept after
* this call returns.
* @param filter used to find the required {@link OngoingActivity}.
* @return the Ongoing Activity or null if not found
*/
@Nullable
public static OngoingActivity recoverOngoingActivity(
@NonNull Context context,
@NonNull Predicate<OngoingActivity> filter
) {
StatusBarNotification[] notifications =
context.getSystemService(NotificationManager.class).getActiveNotifications();
for (StatusBarNotification statusBarNotification : notifications) {
OngoingActivityData data =
SerializationHelper.createInternal(statusBarNotification.getNotification());
if (data != null) {
OngoingActivity oa = new OngoingActivity(
statusBarNotification.getTag(),
statusBarNotification.getId(),
new NotificationCompat.Builder(context,
statusBarNotification.getNotification()),
data);
if (filter.test(oa)) {
return oa;
}
}
}
return null;
}
/**
* Convenience method for clients that don’t want to / can’t store the OngoingActivity
* instance.
*
* Note that if there is more than one Ongoing Activity active you have not guarantee
* over which one you get, you need to use one of the other variations of this method.
*
* @param context May be used to access system services. A reference will not be kept after
* this call returns.
* @return the Ongoing Activity or null if not found
*/
@Nullable
public static OngoingActivity recoverOngoingActivity(@NonNull Context context) {
return recoverOngoingActivity(context, (data) -> true);
}
/**
* Convenience method for clients that don’t want to / can’t store the OngoingActivity
* instance.
*
* @param context May be used to access system services. A reference will not be kept
* after this call returns.
* @param ongoingActivityId the id of the Ongoing Activity to retrieve, set in
* {@link OngoingActivity.Builder#setOngoingActivityId(int)}
* @return the Ongoing Activity or null if not found
*/
@Nullable
public static OngoingActivity recoverOngoingActivity(@NonNull Context context,
int ongoingActivityId) {
return recoverOngoingActivity(context,
(data) -> data.getOngoingActivityId() == ongoingActivityId);
}
// Inner class required to avoid VFY errors during class init.
@RequiresApi(29)
static class Api29Impl {
// Avoid instantiation.
private Api29Impl() {
}
@Nullable
private static LocusIdCompat getLocusId(@NonNull Notification notification) {
return notification.getLocusId() != null
? LocusIdCompat.toLocusIdCompat(notification.getLocusId()) : null;
}
}
}