...kill previous notification.
Add new platform API to detach a notification from a service
without dismissing it.
Also, while I am here, add some more @IntDefs.
Change-Id: I3bb46d9cd3db7f73716c8ced19c20fea800eb30d
method public boolean onUnbind(android.content.Intent);
method public final void startForeground(int, android.app.Notification);
method public final void stopForeground(boolean);
+ method public final void stopForeground(int);
method public final void stopSelf();
method public final void stopSelf(int);
method public final boolean stopSelfResult(int);
field public static final int START_REDELIVER_INTENT = 3; // 0x3
field public static final int START_STICKY = 1; // 0x1
field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
}
public abstract class SharedElementCallback {
method public boolean onUnbind(android.content.Intent);
method public final void startForeground(int, android.app.Notification);
method public final void stopForeground(boolean);
+ method public final void stopForeground(int);
method public final void stopSelf();
method public final void stopSelf(int);
method public final boolean stopSelfResult(int);
field public static final int START_REDELIVER_INTENT = 3; // 0x3
field public static final int START_STICKY = 1; // 0x1
field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
}
public abstract class SharedElementCallback {
method public boolean onUnbind(android.content.Intent);
method public final void startForeground(int, android.app.Notification);
method public final void stopForeground(boolean);
+ method public final void stopForeground(int);
method public final void stopSelf();
method public final void stopSelf(int);
method public final boolean stopSelfResult(int);
field public static final int START_REDELIVER_INTENT = 3; // 0x3
field public static final int START_STICKY = 1; // 0x1
field public static final int START_STICKY_COMPATIBILITY = 0; // 0x0
+ field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+ field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
}
public abstract class SharedElementCallback {
if (data.readInt() != 0) {
notification = Notification.CREATOR.createFromParcel(data);
}
- boolean removeNotification = data.readInt() != 0;
- setServiceForeground(className, token, id, notification, removeNotification);
+ int sflags = data.readInt();
+ setServiceForeground(className, token, id, notification, sflags);
reply.writeNoException();
return true;
}
return res;
}
public void setServiceForeground(ComponentName className, IBinder token,
- int id, Notification notification, boolean removeNotification) throws RemoteException {
+ int id, Notification notification, int flags) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
} else {
data.writeInt(0);
}
- data.writeInt(removeNotification ? 1 : 0);
+ data.writeInt(flags);
mRemote.transact(SET_SERVICE_FOREGROUND_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) throws RemoteException;
public void setServiceForeground(ComponentName className, IBinder token,
- int id, Notification notification, boolean keepNotification) throws RemoteException;
+ int id, Notification notification, int flags) throws RemoteException;
public int bindService(IApplicationThread caller, IBinder token, Intent service,
String resolvedType, IServiceConnection connection, int flags,
String callingPackage, int userId) throws RemoteException;
package android.app;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* A Service is an application component representing either an application's desire
public abstract class Service extends ContextWrapper implements ComponentCallbacks2 {
private static final String TAG = "Service";
+ /**
+ * Flag for {@link #stopForeground(int)}: if set, the notification previously provided
+ * to {@link #startForeground} will be removed. Otherwise it will remain
+ * until a later call (to {@link #startForeground(int, Notification)} or
+ * {@link #stopForeground(int)} removes it, or the service is destroyed.
+ */
+ public static final int STOP_FOREGROUND_REMOVE = 1<<0;
+
+ /**
+ * Flag for {@link #stopForeground(int)}: if set, the notification previously provided
+ * to {@link #startForeground} will be detached from the service. Only makes sense
+ * when {@link #STOP_FOREGROUND_REMOVE} is <b>not</b> set -- in this case, the notification
+ * will remain shown, but be completely detached from the service and so no longer changed
+ * except through direct calls to the notification manager.
+ */
+ public static final int STOP_FOREGROUND_DETACH = 1<<1;
+
+ /** @hide */
+ @IntDef(flag = true,
+ value = {
+ STOP_FOREGROUND_REMOVE,
+ STOP_FOREGROUND_DETACH
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StopForegroundFlags {}
+
public Service() {
super(null);
}
* alarm goes off.
*/
public static final int START_NOT_STICKY = 2;
-
+
/**
* Constant to return from {@link #onStartCommand}: if this service's
* process is killed while it is started (after returning from
* pending events will be delivered at the point of restart).
*/
public static final int START_REDELIVER_INTENT = 3;
-
+
+ /** @hide */
+ @IntDef(flag = false,
+ value = {
+ START_STICKY_COMPATIBILITY,
+ START_STICKY,
+ START_NOT_STICKY,
+ START_REDELIVER_INTENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartResult {}
+
/**
* Special constant for reporting that we are done processing
* {@link #onTaskRemoved(Intent)}.
* {@link #onStartCommand(Intent, int, int)}.
*/
public static final int START_FLAG_RETRY = 0x0002;
-
+
+ /** @hide */
+ @IntDef(flag = true,
+ value = {
+ START_FLAG_REDELIVERY,
+ START_FLAG_RETRY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StartArgFlags {}
+
+
/**
* Called by the system every time a client explicitly starts the service by calling
* {@link android.content.Context#startService}, providing the arguments it supplied and a
*
* @see #stopSelfResult(int)
*/
- public int onStartCommand(Intent intent, int flags, int startId) {
+ public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
try {
mActivityManager.setServiceForeground(
new ComponentName(this, mClassName), mToken, id,
- notification, true);
+ notification, 0);
} catch (RemoteException ex) {
}
}
/**
+ * Synonym for {@link #stopForeground(int)}.
+ * @param removeNotification If true, the {@link #STOP_FOREGROUND_REMOVE} flag
+ * will be supplied.
+ * @see #stopForeground(int)
+ * @see #startForeground(int, Notification)
+ */
+ public final void stopForeground(boolean removeNotification) {
+ stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : 0);
+ }
+
+ /**
* Remove this service from foreground state, allowing it to be killed if
* more memory is needed.
- * @param removeNotification If true, the notification previously provided
- * to {@link #startForeground} will be removed. Otherwise it will remain
- * until a later call removes it (or the service is destroyed).
+ * @param flags Additional behavior options: {@link #STOP_FOREGROUND_REMOVE},
+ * {@link #STOP_FOREGROUND_DETACH}.
* @see #startForeground(int, Notification)
*/
- public final void stopForeground(boolean removeNotification) {
+ public final void stopForeground(@StopForegroundFlags int flags) {
try {
mActivityManager.setServiceForeground(
- new ComponentName(this, mClassName), mToken, 0, null,
- removeNotification);
+ new ComponentName(this, mClassName), mToken, 0, null, flags);
} catch (RemoteException ex) {
}
}
-
+
/**
* Print the Service's state into the given stream. This gets invoked if
* you run "adb shell dumpsys activity service <yourservicename>"
}
public void setServiceForegroundLocked(ComponentName className, IBinder token,
- int id, Notification notification, boolean removeNotification) {
+ int id, Notification notification, int flags) {
final int userId = UserHandle.getCallingUserId();
final long origId = Binder.clearCallingIdentity();
try {
updateServiceForegroundLocked(r.app, true);
}
}
- if (removeNotification) {
+ if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
r.cancelNotification();
r.foregroundId = 0;
r.foregroundNoti = null;
} else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
r.stripForegroundServiceFlagFromNotification();
+ if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
+ r.foregroundId = 0;
+ r.foregroundNoti = null;
+ }
}
}
}
@Override
public void setServiceForeground(ComponentName className, IBinder token,
- int id, Notification notification, boolean removeNotification) {
+ int id, Notification notification, int flags) {
synchronized(this) {
- mServices.setServiceForegroundLocked(className, token, id, notification,
- removeNotification);
+ mServices.setServiceForegroundLocked(className, token, id, notification, flags);
}
}
// If it gave us a garbage notification, it doesn't
// get to be foreground.
ams.setServiceForeground(name, ServiceRecord.this,
- 0, null, true);
+ 0, null, 0);
ams.crashApplication(appUid, appPid, localPackageName,
"Bad notification for startForeground: " + e);
}