需求:控制Notification显示,让所有的通知都没有声音、震动、headsup(就是弹出来显示,类似短信)。但是在statusbar下拉时还有这个通知,这样玩游戏的时候就不会受到影响,通知也不会丢。
其实这个功能Android7.0默认就有了,在Settings中。
这里如果选择Block all就会阻止这个app相关的所有通知。不会有任何通知。如果选择Show silently,就和我们的需求是一致的。这里的实现代码已经找到了,但是我们不能用,因为用了的话就会产生冲突。比如我没有选Show silently,当我们这个需求的模式开启后,在进Settings这个选项看的话,肯定就会被勾选了,所以我们不能用它的方法实现。
这个Show silently的实现代码就是在frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
REASON_PACKAGE_BANNED, null);
}
}
我们这里不用这个方法,我们要看这个方法设置了之后,哪里会用到,哪里会判断,来控制通知的显示,到时候就在那里加我们的判断来实现控制通知。就是多加一个我们的flag而已。
这边的通知是分2部分的,一部分是控制通知的声音、震动、led灯这些,还有一部分就是statusbar上的显示,比如是不是弹出显示通知Headsup。
1.NotificationManagerService控制通知声音、震动等,然后丢给StatusBar显示。
当应用程序发出通知,就一定会走这里
private class EnqueueNotificationRunnable implements Runnable {
private final NotificationRecord r;
private final int userId;
EnqueueNotificationRunnable(int userId, NotificationRecord r) {
this.userId = userId;
this.r = r;
};
@Override
public void run() {
synchronized (mNotificationList) {
final StatusBarNotification n = r.sbn;
if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
NotificationRecord old = mNotificationsByKey.get(n.getKey());
if (old != null) {
// Retain ranking information from previous record
r.copyRankingInformation(old);
Log.i("a", "NotificationManagerService: 2652");
}
final int callingUid = n.getUid();
final int callingPid = n.getInitialPid();
final Notification notification = n.getNotification();
final String pkg = n.getPackageName();
final int id = n.getId();
final String tag = n.getTag();
final boolean isSystemNotification = isUidSystem(callingUid) ||
("android".equals(pkg));
// Handle grouped notifications and bail out early if we
// can to avoid extracting signals.
handleGroupedNotificationLocked(r, old, callingUid, callingPid);
// 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")
|| Log.isLoggable("DownloadManager", Log.VERBOSE)) {
int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
if (old != null) {
enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Log.i("a", "NotificationManagerService: 2676");
}
EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
pkg, id, tag, userId, notification.toString(),
enqueueStatus);
}
mRankingHelper.extractSignals(r);
final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
// blocked apps
// 这里是blocked的apps,就是你在settings中选择Block all的app,这里就会帮通知都屏蔽了
if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
|| !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
if (!isSystemNotification) {
if (isPackageSuspended) {
Slog.e(TAG, "Suppressing notification from package due to package "
+ "suspended by administrator.");
mUsageStats.registerSuspendedByAdmin(r);
Log.i("a", "NotificationManagerService: 2695");
} else {
Slog.e(TAG, "Suppressing notification from package by user request.");
mUsageStats.registerBlocked(r);
Log.i("a", "NotificationManagerService: 2699");
}
return;
}
}
// tell the ranker service about the notification
if (mRankerServices.isEnabled()) {
mRankerServices.onNotificationEnqueued(r);
Log.i("a", "NotificationManagerService: 2708");
// TODO delay the code below here for 100ms or until there is an answer
}
int index = indexOfNotificationLocked(n.getKey());
if (index < 0) {
mNotificationList.add(r);
mUsageStats.registerPostedByApp(r);
Log.i("a", "NotificationManagerService: 2717");
} else {
old = mNotificationList.get(index);
mNotificationList.set(index, r);
mUsageStats.registerUpdatedByApp(r, old);
// Make sure we don't lose the foreground service state.
notification.flags |=
old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
r.isUpdate = true;
Log.i("a", "NotificationManagerService: 2726");
}
mNotificationsByKey.put(n.getKey(), r);
// 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;
Log.i("a", "NotificationManagerService: 2736");
}
applyZenModeLocked(r);
mRankingHelper.sort(mNotificationList);
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
mListeners.notifyPostedLocked(n, oldSbn);
Log.i("a", "NotificationManagerService: 2745");
} else {
Slog.e(TAG, "Not posting notification without small icon: " + notification);
if (old != null && !old.isCanceled) {
mListeners.notifyRemovedLocked(n);
Log.i("a", "NotificationManagerService: 2750");
}
// ATTENTION: in a future release we will bail out here
// so that we do not play sounds, show lights, etc. for invalid
// notifications
Slog.e(TAG, "WARNING: In a future release this will crash the app: "
+ n.getPackageName());
}
buzzBeepBlinkLocked(r);
}
}
}
下面来看看buzzBeepBlinkLocked这个函数
@VisibleForTesting
void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false;
boolean beep = false;
boolean blink = false;
final Notification notification = record.sbn.getNotification();
final String key = record.getKey();
// Should this notification make noise, vibe, or use the LED?
final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
if (DBG || record.isIntercepted())
Slog.v(TAG,
"pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
" intercept=" + record.isIntercepted()
);
final int currentUser;
final long token = Binder.clearCallingIdentity();
try {
currentUser = ActivityManager.getCurrentUser();
} finally {
Binder.restoreCallingIdentity(token);
}
Log.i("a", "NotificationManagerService: 2837");
// If we're not supposed to beep, vibrate, etc. then don't.
final String disableEffects = disableNotificationEffects(record);
if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects);
Log.i("a", "NotificationManagerService: 2843");
}
// Remember if this notification already owns the notification channels.
boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
// These are set inside the conditional if the notification is allowed to make noise.
boolean hasValidVibrate = false;
boolean hasValidSound = false;
boolean smsRingtone = false;
if (mCarrierConfig != null) {
smsRingtone = mCarrierConfig.getBoolean(
CarrierConfigManager.KEY_CONFIG_SMS_RINGTONE_INCALL);
Log.i("a", "NotificationManagerService: 2858");
}
Log.i("a", "NotificationManagerService: 2860");
// 这里就是我们要加flag判断的地方。如果要silent通知就不要进这个if判断,我们可以在这个if外面在多加一个我们的flag。
if ((disableEffects == null || (smsRingtone && mInCall))
&& (record.getUserId() == UserHandle.USER_ALL ||
record.getUserId() == currentUser ||
mUserProfiles.isCurrentProfile(record.getUserId()))
&& canInterrupt
&& mSystemReady
&& mAudioManager != null) {
if (DBG) Slog.v(TAG, "Interrupting!");
Log.i("a", "NotificationManagerService: 2869");
// should we use the default notification sound? (indicated either by
// DEFAULT_SOUND or because notification.sound is pointing at
// Settings.System.NOTIFICATION_SOUND)
final boolean useDefaultSound =
(notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
Settings.System.DEFAULT_NOTIFICATION_URI
.equals(notification.sound);
Uri soundUri = null;
if (useDefaultSound) {
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
// check to see if the default notification sound is silent
hasValidSound = mSystemNotificationSound != null;
Log.i("a", "NotificationManagerService: 2884");
} else if (notification.sound != null) {
soundUri = notification.sound;
hasValidSound = (soundUri != null);
Log.i("a", "NotificationManagerService: 2888");
}
// Does the notification want to specify its own vibration?
final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate
// mode, and no other vibration is specified, we fall back to vibration
final boolean convertSoundToVibration =
!hasCustomVibrate
&& hasValidSound
&& (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
hasCustomVibrate;
Log.i("a", "useDefaultVibrate || convertSoundToVibration hasCustomVibrate "+useDefaultVibrate+convertSoundToVibration+hasCustomVibrate);
// We can alert, and we're allowed to alert, but if the developer asked us to only do
// it once, and we already have, then don't.
if (!(record.isUpdate
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
sendAccessibilityEvent(notification, record.sbn.getPackageName());
if (hasValidSound) {
boolean looping =
(notification.flags & Notification.FLAG_INSISTENT) != 0;
AudioAttributes audioAttributes = audioAttributesForNotification(notification);
mSoundNotificationKey = key;
// do not play notifications if stream volume is 0 (typically because
// ringer mode is silent) or if there is a user of exclusive audio focus
if ((mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
&& !mAudioManager.isAudioFocusExclusive()) {
final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player =
mAudioManager.getRingtonePlayer();
if (player != null) {
if (DBG) Slog.v(TAG, "Playing sound " + soundUri
+ " with attributes " + audioAttributes);
player.playAsync(soundUri, record.sbn.getUser(), looping,
audioAttributes);
beep = true;
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotificationKey = key;
if (useDefaultVibrate || convertSoundToVibration) {
// Escalate privileges so we can use the vibrator even if the
// notifying app does not have the VIBRATE permission.
long identity = Binder.clearCallingIdentity();
try {
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
useDefaultVibrate ? mDefaultVibrationPattern
: mFallbackVibrationPattern,
((notification.flags & Notification.FLAG_INSISTENT) != 0)
? 0: -1, audioAttributesForNotification(notification));
buzz = true;
} finally {
Binder.restoreCallingIdentity(identity);
}
} else if (notification.vibrate.length > 1) {
// If you want your own vibration pattern, you need the VIBRATE
// permission
mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
notification.vibrate,
((notification.flags & Notification.FLAG_INSISTENT) != 0)
? 0: -1, audioAttributesForNotification(notification));
buzz = true;
}
}
}
}
Log.i("a", "NotificationManagerService: 2977");
// If a notification is updated to remove the actively playing sound or vibrate,
// cancel that feedback now
if (wasBeep && !hasValidSound) {
clearSoundLocked();
Log.i("a", "NotificationManagerService: 2982");
}
if (wasBuzz && !hasValidVibrate) {
clearVibrateLocked();
Log.i("a", "NotificationManagerService: 2986");
}
// light
// release the light
boolean wasShowLights = mLights.remove(key);
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
&& ((record.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Log.i("a", "NotificationManagerService: 2995");
mLights.add(key);
updateLightsLocked();
if (mUseAttentionLight) {
mAttentionLight.pulse();
}
blink = true;
} else if (wasShowLights) {
updateLightsLocked();
Log.i("a", "NotificationManagerService: 3004");
}
if (buzz || beep || blink) {
if (((record.getSuppressedVisualEffects()
& NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
} else {
EventLogTags.writeNotificationAlert(key,
buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
mHandler.post(mBuzzBeepBlinked);
}
}
}
关于声音、震动、灯光就在上面这处理的。
2.StatusBar部分,控制通知的显示,Headsup就在这控制。
BaseStatusBar.java
当有通知从NotificationManagerService过来后,就会走onNotificationPosted。onNotificationPosted会根据通知是新增还是更新做不同的处理,所以我们要在2个地方去阻止通知显示。
@Override
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
Log.i("a", "StatusBarNotification "+sbn);
Log.i("a", "Notification "+sbn.getNotification());
if (sbn != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
processForRemoteInput(sbn.getNotification());
String key = sbn.getKey();
mKeysKeptForRemoteInput.remove(key);
boolean isUpdate = mNotificationData.get(key) != null;
// In case we don't allow child notifications, we ignore children of
// notifications that have a summary, since we're not going to show them
// anyway. This is true also when the summary is canceled,
// because children are automatically canceled by NoMan in that case.
if (!ENABLE_CHILD_NOTIFICATIONS
&& mGroupManager.isChildInGroupWithSummary(sbn)) {
if (DEBUG) {
Log.d(TAG, "Ignoring group child due to existing summary: " + sbn);
}
// Remove existing notification to avoid stale data.
if (isUpdate) {
removeNotification(key, rankingMap);
} else {
mNotificationData.updateRanking(rankingMap);
}
return;
}
if (isUpdate) {
updateNotification(sbn, rankingMap);
Log.i("a", "StatusBar: "+653);
} else {
addNotification(sbn, rankingMap, null /* oldEntry */);
Log.i("a", "StatusBar: "+656);
}
}
});
}
}
首先看updateNotification,这个函数在BaseStatusBar.java中
public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
Entry entry = mNotificationData.get(key);
if (entry == null) {
return;
} else {
mHeadsUpEntriesToRemoveOnSwitch.remove(entry);
mRemoteInputEntriesToRemoveOnCollapse.remove(entry);
}
Notification n = notification.getNotification();
mNotificationData.updateRanking(ranking);
boolean applyInPlace;
try {
applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
} catch (RuntimeException e) {
Log.e(TAG, "Unable to get notification remote views", e);
applyInPlace = false;
}
boolean shouldPeek = shouldPeek(entry, notification);
//这里会根据shouldPeek的值,来处理是否显示headsup通知,所以把shouldPeek该成false就可以阻止了。
Log.i("a", "StatusBar: set shouldPeek updateNotification "+shouldPeek);
Log.i("a", "StatusBar: "+2407);
boolean alertAgain = alertAgain(entry, n);
if (DEBUG) {
Log.d(TAG, "applyInPlace=" + applyInPlace
+ " shouldPeek=" + shouldPeek
+ " alertAgain=" + alertAgain);
}
final StatusBarNotification oldNotification = entry.notification;
entry.notification = notification;
mGroupManager.onEntryUpdated(entry, oldNotification);
boolean updateSuccessful = false;
if (applyInPlace) {
Log.i("a", "StatusBar: "+2421);
if (DEBUG) Log.d(TAG, "reusing notification for key: " + key);
try {
if (entry.icon != null) {
Log.i("a", "StatusBar: "+2425);
// Update the icon
final StatusBarIcon ic = new StatusBarIcon(
notification.getUser(),
notification.getPackageName(),
n.getSmallIcon(),
n.iconLevel,
n.number,
StatusBarIconView.contentDescForNotification(mContext, n));
entry.icon.setNotification(n);
if (!entry.icon.set(ic)) {
Log.i("a", "StatusBar: "+2436);
handleNotificationError(notification, "Couldn't update icon: " + ic);
return;
}
}
Log.i("a", "StatusBar: "+2441);
updateNotificationViews(entry, notification);
updateSuccessful = true;
}
catch (RuntimeException e) {
// It failed to apply cleanly.
Log.w(TAG, "Couldn't reapply views for package " +
notification.getPackageName(), e);
}
}
if (!updateSuccessful) {
Log.i("a", "StatusBar: "+2452);
if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key);
final StatusBarIcon ic = new StatusBarIcon(
notification.getUser(),
notification.getPackageName(),
n.getSmallIcon(),
n.iconLevel,
n.number,
StatusBarIconView.contentDescForNotification(mContext, n));
entry.icon.setNotification(n);
entry.icon.set(ic);
if (!inflateViews(entry, mStackScroller)) {
Log.i("a", "StatusBar: "+2464);
handleNotificationError(notification, "Couldn't update remote views for: "
+ notification);
}
}
updateHeadsUp(key, entry, shouldPeek, alertAgain);
updateNotifications();
if (!notification.isClearable()) {
Log.i("a", "StatusBar: "+2473);
// The user may have performed a dismiss action on the notification, since it's
// not clearable we should snap it back.
mStackScroller.snapViewIfNeeded(entry.row);
}
if (DEBUG) {
// Is this for you?
boolean isForCurrentUser = isNotificationForCurrentProfiles(notification);
Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you");
}
setAreThereNotifications();
}
addNotification是在PhoneStatusBar.java中实现的。
@Override
public void addNotification(StatusBarNotification notification, RankingMap ranking,
Entry oldEntry) {
if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
mNotificationData.updateRanking(ranking);
Entry shadeEntry = createNotificationViews(notification);
if (shadeEntry == null) {
return;
}
boolean isHeadsUped = shouldPeek(shadeEntry);
// 和updateNotification那一样,把isHeadsUped设置成false就可以阻止了。
Log.i("a", "PhoneStatusBar: set is headsuped false");
Log.i("a", "PhoneStatusBar: "+isHeadsUped+1575);
if (isHeadsUped) {
mHeadsUpManager.showNotification(shadeEntry);
// Mark as seen immediately
setNotificationShown(notification);
Log.i("a", "PhoneStatusBar: "+1582);
}
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
if (shouldSuppressFullScreenIntent(notification.getKey())) {
if (DEBUG) {
Log.i("a", "PhoneStatusBar: "+1586);
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
}
} else if (mNotificationData.getImportance(notification.getKey())
< NotificationListenerService.Ranking.IMPORTANCE_MAX) {
if (DEBUG) {
Log.i("a", "PhoneStatusBar: "+1592);
Log.d(TAG, "No Fullscreen intent: not important enough: "
+ notification.getKey());
}
}else if(!isHeadsUped) {
Log.i("a", "PhoneStatusBar: "+1599);
}
else {
Log.i("a", "PhoneStatusBar: "+1597);
// Stop screensaver if the notification has a full-screen intent.
// (like an incoming phone call)
awakenDreams();
// not immersive & a full-screen alert should be shown
if (DEBUG)
Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
try {
EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
notification.getKey());
notification.getNotification().fullScreenIntent.send();
shadeEntry.notifyFullScreenIntentLaunched();
MetricsLogger.count(mContext, "note_fullscreen", 1);
} catch (PendingIntent.CanceledException e) {
}
}
}
addNotificationViews(shadeEntry, ranking);
// Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();
}
最后看看shouldPeek,在BaseStatusBar.java中实现
protected boolean shouldPeek(Entry entry, StatusBarNotification sbn) {
Log.i("a", "StatusBar: "+2548);
if (!mUseHeadsUp || isDeviceInVrMode()) {
Log.i("a", "StatusBar: "+2550);
return false;
}
if (mNotificationData.shouldFilterOut(sbn)) {
if (DEBUG) Log.d(TAG, "No peeking: filtered notification: " + sbn.getKey());
Log.i("a", "StatusBar: "+2556);
return false;
}
boolean inUse = mPowerManager.isScreenOn();
try {
inUse = inUse && !mDreamManager.isDreaming();
Log.i("a", "StatusBar: "+2563);
} catch (RemoteException e) {
Log.d(TAG, "failed to query dream manager", e);
}
if (!inUse) {
if (DEBUG) {
Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
}
Log.i("a", "StatusBar: "+2572);
return false;
}
if (mNotificationData.shouldSuppressScreenOn(sbn.getKey())) {
if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
Log.i("a", "StatusBar: "+2578);
return false;
}
if (entry.hasJustLaunchedFullScreenIntent()) {
if (DEBUG) Log.d(TAG, "No peeking: recent fullscreen: " + sbn.getKey());
Log.i("a", "StatusBar: "+2584);
return false;
}
if (isSnoozedPackage(sbn)) {
if (DEBUG) Log.d(TAG, "No peeking: snoozed package: " + sbn.getKey());
Log.i("a", "StatusBar: "+2590);
return false;
}
// 在settings中设置了show silently后,就会走这里。只要这个shouldPeek函数返回false,就不会显示headsup这样的通知。
if (mNotificationData.getImportance(sbn.getKey()) < IMPORTANCE_HIGH) {
if (DEBUG) Log.d(TAG, "No peeking: unimportant notification: " + sbn.getKey());
Log.i("a", "StatusBar: "+2596);
return false;
}
if (sbn.getNotification().fullScreenIntent != null) {
if (mAccessibilityManager.isTouchExplorationEnabled()) {
if (DEBUG) Log.d(TAG, "No peeking: accessible fullscreen: " + sbn.getKey());
Log.i("a", "StatusBar: "+2603);
return false;
} else {
Log.i("a", "StatusBar: "+2606);
// we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
return !mStatusBarKeyguardViewManager.isShowing()
|| mStatusBarKeyguardViewManager.isOccluded();
}
}
return true;
}
最后在settings数据库中加入自己的字段做flag,在上面的地方来判断,是否开启这个模式。开启后就可以实现和系统自带的Settings->Notifications中Show silently一样的效果了,也不会和系统这个功能有冲突。