Fix issue #2047139: Remove Service.setForeground()
This API is becoming seriously abused, so now it is deprecated and has become a no-op. As an alternative, there is now a new API that allows you to make a service be in the foreground but requires providing a persistent notification to go along with this state, allowing the user to know about and control it.
This commit is contained in:
@@ -22200,6 +22200,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="FLAG_FOREGROUND_SERVICE"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="64"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="FLAG_INSISTENT"
|
||||
type="int"
|
||||
transient="false"
|
||||
@@ -23760,12 +23771,40 @@
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
deprecated="deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="isForeground" type="boolean">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="startForeground"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="id" type="int">
|
||||
</parameter>
|
||||
<parameter name="notification" type="android.app.Notification">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="stopForeground"
|
||||
return="void"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="removeNotification" type="boolean">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="stopSelf"
|
||||
return="void"
|
||||
abstract="false"
|
||||
|
||||
@@ -39,9 +39,6 @@ import android.text.TextUtils;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -551,8 +548,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
|
||||
data.enforceInterface(IActivityManager.descriptor);
|
||||
ComponentName className = ComponentName.readFromParcel(data);
|
||||
IBinder token = data.readStrongBinder();
|
||||
boolean isForeground = data.readInt() != 0;
|
||||
setServiceForeground(className, token, isForeground);
|
||||
int id = data.readInt();
|
||||
Notification notification = null;
|
||||
if (data.readInt() != 0) {
|
||||
notification = Notification.CREATOR.createFromParcel(data);
|
||||
}
|
||||
boolean removeNotification = data.readInt() != 0;
|
||||
setServiceForeground(className, token, id, notification, removeNotification);
|
||||
reply.writeNoException();
|
||||
return true;
|
||||
}
|
||||
@@ -1664,13 +1666,20 @@ class ActivityManagerProxy implements IActivityManager
|
||||
return res;
|
||||
}
|
||||
public void setServiceForeground(ComponentName className, IBinder token,
|
||||
boolean isForeground) throws RemoteException {
|
||||
int id, Notification notification, boolean removeNotification) throws RemoteException {
|
||||
Parcel data = Parcel.obtain();
|
||||
Parcel reply = Parcel.obtain();
|
||||
data.writeInterfaceToken(IActivityManager.descriptor);
|
||||
ComponentName.writeToParcel(className, data);
|
||||
data.writeStrongBinder(token);
|
||||
data.writeInt(isForeground ? 1 : 0);
|
||||
data.writeInt(id);
|
||||
if (notification != null) {
|
||||
data.writeInt(1);
|
||||
notification.writeToParcel(data, 0);
|
||||
} else {
|
||||
data.writeInt(0);
|
||||
}
|
||||
data.writeInt(removeNotification ? 1 : 0);
|
||||
mRemote.transact(SET_SERVICE_FOREGROUND_TRANSACTION, data, reply, 0);
|
||||
reply.readException();
|
||||
data.recycle();
|
||||
|
||||
@@ -139,7 +139,7 @@ public interface IActivityManager extends IInterface {
|
||||
public boolean stopServiceToken(ComponentName className, IBinder token,
|
||||
int startId) throws RemoteException;
|
||||
public void setServiceForeground(ComponentName className, IBinder token,
|
||||
boolean isForeground) throws RemoteException;
|
||||
int id, Notification notification, boolean keepNotification) throws RemoteException;
|
||||
public int bindService(IApplicationThread caller, IBinder token,
|
||||
Intent service, String resolvedType,
|
||||
IServiceConnection connection, int flags) throws RemoteException;
|
||||
|
||||
@@ -257,6 +257,13 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
public static final int FLAG_NO_CLEAR = 0x00000020;
|
||||
|
||||
/**
|
||||
* Bit to be bitwise-ored into the {@link #flags} field that should be
|
||||
* set if this notification represents a currently running service. This
|
||||
* will normally be set for you by {@link Service#startForeground}.
|
||||
*/
|
||||
public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
|
||||
|
||||
public int flags;
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,7 +61,8 @@ public class NotificationManager
|
||||
|
||||
private static INotificationManager sService;
|
||||
|
||||
static private INotificationManager getService()
|
||||
/** @hide */
|
||||
static public INotificationManager getService()
|
||||
{
|
||||
if (sService != null) {
|
||||
return sService;
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.RemoteException;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -304,24 +305,52 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
|
||||
}
|
||||
|
||||
/**
|
||||
* Control whether this service is considered to be a foreground service.
|
||||
* @deprecated This is a now a no-op, use
|
||||
* {@link #startForeground(int, Notification)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final void setForeground(boolean isForeground) {
|
||||
Log.w(TAG, "setForeground: ignoring old API call on " + getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this service run in the foreground, supplying the ongoing
|
||||
* notification to be shown to the user while in this state.
|
||||
* By default services are background, meaning that if the system needs to
|
||||
* kill them to reclaim more memory (such as to display a large page in a
|
||||
* web browser), they can be killed without too much harm. You can set this
|
||||
* flag if killing your service would be disruptive to the user: such as
|
||||
* flag if killing your service would be disruptive to the user, such as
|
||||
* if your service is performing background music playback, so the user
|
||||
* would notice if their music stopped playing.
|
||||
*
|
||||
* @param isForeground Determines whether this service is considered to
|
||||
* be foreground (true) or background (false).
|
||||
* @param id The identifier for this notification as per
|
||||
* {@link NotificationManager#notify(int, Notification)
|
||||
* NotificationManager.notify(int, Notification)}.
|
||||
* @param notification The Notification to be displayed.
|
||||
*
|
||||
* @see #stopForeground(boolean)
|
||||
*/
|
||||
public final void setForeground(boolean isForeground) {
|
||||
if (mActivityManager == null) {
|
||||
return;
|
||||
}
|
||||
public final void startForeground(int id, Notification notification) {
|
||||
try {
|
||||
mActivityManager.setServiceForeground(
|
||||
new ComponentName(this, mClassName), mToken, isForeground);
|
||||
new ComponentName(this, mClassName), mToken, id,
|
||||
notification, true);
|
||||
} catch (RemoteException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this service from foreground state, allowing it to be killed if
|
||||
* more memory is needed.
|
||||
* @param keepNotification If true, the notification previously provided
|
||||
* to {@link #startForeground} will remain displayed.
|
||||
* @see #startForeground(int, Notification)
|
||||
*/
|
||||
public final void stopForeground(boolean removeNotification) {
|
||||
try {
|
||||
mActivityManager.setServiceForeground(
|
||||
new ComponentName(this, mClassName), mToken, 0, null,
|
||||
removeNotification);
|
||||
} catch (RemoteException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
@@ -48,6 +49,7 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Power;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.Vibrator;
|
||||
@@ -257,7 +259,8 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
|
||||
public void onNotificationClick(String pkg, int id) {
|
||||
cancelNotification(pkg, id, Notification.FLAG_AUTO_CANCEL);
|
||||
cancelNotification(pkg, id, Notification.FLAG_AUTO_CANCEL,
|
||||
Notification.FLAG_FOREGROUND_SERVICE);
|
||||
}
|
||||
|
||||
public void onPanelRevealed() {
|
||||
@@ -326,7 +329,7 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
if (pkgName == null) {
|
||||
return;
|
||||
}
|
||||
cancelAllNotifications(pkgName);
|
||||
cancelAllNotificationsInt(pkgName, 0, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -580,6 +583,8 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
// ============================================================================
|
||||
public void enqueueNotification(String pkg, int id, Notification notification, int[] idOut)
|
||||
{
|
||||
checkIncomingCall(pkg);
|
||||
|
||||
// This conditional is a dirty hack to limit the logging done on
|
||||
// behalf of the download manager without affecting other apps.
|
||||
if (!pkg.equals("com.android.providers.downloads")
|
||||
@@ -612,7 +617,20 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
} else {
|
||||
old = mNotificationList.remove(index);
|
||||
mNotificationList.add(index, r);
|
||||
// Make sure we don't lose the foreground service state.
|
||||
if (old != null) {
|
||||
notification.flags |=
|
||||
old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure if this is a foreground service that the proper additional
|
||||
// flags are set.
|
||||
if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
|
||||
notification.flags |= Notification.FLAG_ONGOING_EVENT
|
||||
| Notification.FLAG_NO_CLEAR;
|
||||
}
|
||||
|
||||
if (notification.icon != 0) {
|
||||
IconData icon = IconData.makeIcon(null, pkg, notification.icon,
|
||||
notification.iconLevel,
|
||||
@@ -807,9 +825,11 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a notification ONLY if it has all of the {@code mustHaveFlags}.
|
||||
* Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
|
||||
* and none of the {@code mustNotHaveFlags}.
|
||||
*/
|
||||
private void cancelNotification(String pkg, int id, int mustHaveFlags) {
|
||||
private void cancelNotification(String pkg, int id, int mustHaveFlags,
|
||||
int mustNotHaveFlags) {
|
||||
EventLog.writeEvent(EVENT_LOG_CANCEL, pkg, id, mustHaveFlags);
|
||||
|
||||
synchronized (mNotificationList) {
|
||||
@@ -822,6 +842,9 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
|
||||
return;
|
||||
}
|
||||
if ((r.notification.flags & mustNotHaveFlags) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
mNotificationList.remove(index);
|
||||
|
||||
@@ -835,7 +858,8 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
* Cancels all notifications from a given package that have all of the
|
||||
* {@code mustHaveFlags}.
|
||||
*/
|
||||
private void cancelAllNotificationsInt(String pkg, int mustHaveFlags) {
|
||||
void cancelAllNotificationsInt(String pkg, int mustHaveFlags,
|
||||
int mustNotHaveFlags) {
|
||||
EventLog.writeEvent(EVENT_LOG_CANCEL_ALL, pkg, mustHaveFlags);
|
||||
|
||||
synchronized (mNotificationList) {
|
||||
@@ -846,6 +870,9 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
if ((r.notification.flags & mustHaveFlags) != mustHaveFlags) {
|
||||
continue;
|
||||
}
|
||||
if ((r.notification.flags & mustNotHaveFlags) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (!r.pkg.equals(pkg)) {
|
||||
continue;
|
||||
}
|
||||
@@ -860,17 +887,40 @@ class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
|
||||
|
||||
public void cancelNotification(String pkg, int id)
|
||||
{
|
||||
cancelNotification(pkg, id, 0);
|
||||
public void cancelNotification(String pkg, int id) {
|
||||
checkIncomingCall(pkg);
|
||||
// Don't allow client applications to cancel foreground service notis.
|
||||
cancelNotification(pkg, id, 0,
|
||||
Binder.getCallingUid() == Process.SYSTEM_UID
|
||||
? 0 : Notification.FLAG_FOREGROUND_SERVICE);
|
||||
}
|
||||
|
||||
public void cancelAllNotifications(String pkg)
|
||||
{
|
||||
cancelAllNotificationsInt(pkg, 0);
|
||||
public void cancelAllNotifications(String pkg) {
|
||||
checkIncomingCall(pkg);
|
||||
|
||||
// Calling from user space, don't allow the canceling of actively
|
||||
// running foreground services.
|
||||
cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE);
|
||||
}
|
||||
|
||||
public void cancelAll() {
|
||||
void checkIncomingCall(String pkg) {
|
||||
int uid = Binder.getCallingUid();
|
||||
if (uid == Process.SYSTEM_UID || uid == 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ApplicationInfo ai = mContext.getPackageManager().getApplicationInfo(
|
||||
pkg, 0);
|
||||
if (ai.uid != uid) {
|
||||
throw new SecurityException("Calling uid " + uid + " gave package"
|
||||
+ pkg + " which is owned by uid " + ai.uid);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new SecurityException("Unknown package " + pkg);
|
||||
}
|
||||
}
|
||||
|
||||
void cancelAll() {
|
||||
synchronized (mNotificationList) {
|
||||
final int N = mNotificationList.size();
|
||||
for (int i=N-1; i>=0; i--) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import android.app.IInstrumentationWatcher;
|
||||
import android.app.IServiceConnection;
|
||||
import android.app.IThumbnailReceiver;
|
||||
import android.app.Instrumentation;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.ResultInfo;
|
||||
import android.backup.IBackupManager;
|
||||
@@ -9936,6 +9937,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
}
|
||||
ensurePackageDexOpt(r.serviceInfo.packageName);
|
||||
app.thread.scheduleCreateService(r, r.serviceInfo);
|
||||
r.postNotification();
|
||||
created = true;
|
||||
} finally {
|
||||
if (!created) {
|
||||
@@ -9970,6 +9972,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
if (!mRestartingServices.contains(r)) {
|
||||
mRestartingServices.add(r);
|
||||
}
|
||||
r.cancelNotification();
|
||||
mHandler.removeCallbacks(r.restarter);
|
||||
mHandler.postDelayed(r.restarter, r.restartDelay);
|
||||
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
|
||||
@@ -10138,13 +10141,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
}
|
||||
}
|
||||
|
||||
r.cancelNotification();
|
||||
r.isForeground = false;
|
||||
r.foregroundId = 0;
|
||||
r.foregroundNoti = null;
|
||||
|
||||
if (r.app != null) {
|
||||
synchronized (r.stats.getBatteryStats()) {
|
||||
r.stats.stopLaunchedLocked();
|
||||
}
|
||||
r.app.services.remove(r);
|
||||
if (r.app.thread != null) {
|
||||
updateServiceForegroundLocked(r.app, false);
|
||||
try {
|
||||
Log.i(TAG, "Stopping service: " + r.shortName);
|
||||
bumpServiceExecutingLocked(r);
|
||||
@@ -10156,6 +10163,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
+ r.shortName, e);
|
||||
serviceDoneExecutingLocked(r, true);
|
||||
}
|
||||
updateServiceForegroundLocked(r.app, false);
|
||||
} else {
|
||||
if (DEBUG_SERVICE) Log.v(
|
||||
TAG, "Removed service that has no process: " + r.shortName);
|
||||
@@ -10334,20 +10342,45 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
|
||||
}
|
||||
|
||||
public void setServiceForeground(ComponentName className, IBinder token,
|
||||
boolean isForeground) {
|
||||
int id, Notification notification, boolean removeNotification) {
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized(this) {
|
||||
ServiceRecord r = findServiceLocked(className, token);
|
||||
if (r != null) {
|
||||
if (r.isForeground != isForeground) {
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
r.isForeground = isForeground;
|
||||
if (id != 0) {
|
||||
if (notification == null) {
|
||||
throw new IllegalArgumentException("null notification");
|
||||
}
|
||||
if (r.foregroundId != id) {
|
||||
r.cancelNotification();
|
||||
r.foregroundId = id;
|
||||
}
|
||||
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
|
||||
r.foregroundNoti = notification;
|
||||
r.isForeground = true;
|
||||
r.postNotification();
|
||||
if (r.app != null) {
|
||||
updateServiceForegroundLocked(r.app, true);
|
||||
}
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
} else {
|
||||
if (r.isForeground) {
|
||||
r.isForeground = false;
|
||||
if (r.app != null) {
|
||||
updateServiceForegroundLocked(r.app, true);
|
||||
}
|
||||
}
|
||||
if (removeNotification) {
|
||||
r.cancelNotification();
|
||||
r.foregroundId = 0;
|
||||
r.foregroundNoti = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
|
||||
|
||||
@@ -18,12 +18,16 @@ package com.android.server.am;
|
||||
|
||||
import com.android.internal.os.BatteryStatsImpl;
|
||||
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -63,8 +67,10 @@ class ServiceRecord extends Binder {
|
||||
final List<Intent> startArgs = new ArrayList<Intent>();
|
||||
// start() arguments that haven't yet been delivered.
|
||||
|
||||
ProcessRecord app; // where this service is running or null.
|
||||
boolean isForeground; // asked to run as a foreground service?
|
||||
ProcessRecord app; // where this service is running or null.
|
||||
boolean isForeground; // is service currently in foreground mode?
|
||||
int foregroundId; // Notification ID of last foreground req.
|
||||
Notification foregroundNoti; // Notification record of foreground state.
|
||||
long lastActivity; // last time there was some activity on the service.
|
||||
boolean startRequested; // someone explicitly called start?
|
||||
int lastStartId; // identifier of most recent start request.
|
||||
@@ -92,18 +98,26 @@ class ServiceRecord extends Binder {
|
||||
if (!resDir.equals(baseDir)) pw.print(" resDir="); pw.print(resDir);
|
||||
pw.print(" dataDir="); pw.println(dataDir);
|
||||
pw.print(prefix); pw.print("app="); pw.println(app);
|
||||
pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
|
||||
pw.print(" lastActivity="); pw.println(lastActivity);
|
||||
pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
|
||||
pw.print(" startId="); pw.print(lastStartId);
|
||||
pw.print(" executeNesting="); pw.print(executeNesting);
|
||||
if (isForeground || foregroundId != 0) {
|
||||
pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
|
||||
pw.print(" foregroundId="); pw.print(foregroundId);
|
||||
pw.print(" foregroundNoti="); pw.println(foregroundNoti);
|
||||
}
|
||||
pw.print(prefix); pw.print("lastActivity="); pw.print(lastActivity);
|
||||
pw.print(" executingStart="); pw.print(executingStart);
|
||||
pw.print(" crashCount="); pw.println(crashCount);
|
||||
pw.print(prefix); pw.print("totalRestartCount="); pw.print(totalRestartCount);
|
||||
pw.print(" restartCount="); pw.print(restartCount);
|
||||
pw.print(" restartDelay="); pw.print(restartDelay);
|
||||
pw.print(" restartTime="); pw.print(restartTime);
|
||||
pw.print(" nextRestartTime="); pw.println(nextRestartTime);
|
||||
pw.print(" restartTime="); pw.println(restartTime);
|
||||
if (startRequested || lastStartId != 0) {
|
||||
pw.print(prefix); pw.print("startRequested="); pw.print(startRequested);
|
||||
pw.print(" lastStartId="); pw.println(lastStartId);
|
||||
}
|
||||
if (executeNesting != 0 || crashCount != 0 || restartCount != 0
|
||||
|| restartDelay != 0 || nextRestartTime != 0) {
|
||||
pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
|
||||
pw.print(" restartCount="); pw.print(restartCount);
|
||||
pw.print(" restartDelay="); pw.print(restartDelay);
|
||||
pw.print(" nextRestartTime="); pw.print(nextRestartTime);
|
||||
pw.print(" crashCount="); pw.println(crashCount);
|
||||
}
|
||||
if (bindings.size() > 0) {
|
||||
Iterator<IntentBindRecord> it = bindings.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
@@ -166,6 +180,32 @@ class ServiceRecord extends Binder {
|
||||
restartTime = 0;
|
||||
}
|
||||
|
||||
public void postNotification() {
|
||||
if (foregroundId != 0 && foregroundNoti != null) {
|
||||
INotificationManager inm = NotificationManager.getService();
|
||||
if (inm != null) {
|
||||
try {
|
||||
int[] outId = new int[1];
|
||||
inm.enqueueNotification(packageName, foregroundId,
|
||||
foregroundNoti, outId);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelNotification() {
|
||||
if (foregroundId != 0) {
|
||||
INotificationManager inm = NotificationManager.getService();
|
||||
if (inm != null) {
|
||||
try {
|
||||
inm.cancelNotification(packageName, foregroundId);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (stringName != null) {
|
||||
return stringName;
|
||||
|
||||
Reference in New Issue
Block a user