OSDN Git Service

NoMan/SysUI: Clear LEDs only when entering the shade
authorChristoph Studer <chstuder@google.com>
Wed, 26 Nov 2014 14:32:20 +0000 (15:32 +0100)
committerChristoph Studer <chstuder@google.com>
Tue, 2 Dec 2014 15:52:13 +0000 (16:52 +0100)
Don't clear notification LEDs when seeing notifications on the
lockscreen.

Also fix a bug where the LED didn't continue flashing after
the screen turned off.

For devices with doze capability, ensure that the LED continuing
to flash after screen off doesn't cause an immediate pulses, but
delay the first pulse by 10s.

Bug: 15449039
Change-Id: Id34d51a2c91ceaf069e49add1ab690bb855f9638

core/java/com/android/internal/statusbar/IStatusBarService.aidl
packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
packages/SystemUI/src/com/android/systemui/doze/DozeService.java
packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
services/core/java/com/android/server/notification/NotificationDelegate.java
services/core/java/com/android/server/notification/NotificationManagerService.java
services/core/java/com/android/server/statusbar/StatusBarManagerService.java

index 5e610ed..40c009f 100644 (file)
@@ -40,8 +40,10 @@ interface IStatusBarService
     // You need the STATUS_BAR_SERVICE permission
     void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
             out int[] switches, out List<IBinder> binders);
-    void onPanelRevealed();
+    void onPanelRevealed(boolean clearNotificationEffects);
     void onPanelHidden();
+    // Mark current notifications as "seen" and stop ringing, vibrating, blinking.
+    void clearNotificationEffects();
     void onNotificationClick(String key);
     void onNotificationActionClick(String key, int actionIndex);
     void onNotificationError(String pkg, String tag, int id,
index e92f988..7070220 100644 (file)
@@ -28,6 +28,7 @@ public interface DozeHost {
     void pulseWhileDozing(@NonNull PulseCallback callback);
     void stopDozing();
     boolean isPowerSaveActive();
+    boolean isNotificationLightOn();
 
     public interface Callback {
         void onNewNotifications();
index 89b3e5b..f309e69 100644 (file)
@@ -56,6 +56,17 @@ public class DozeService extends DreamService {
     private static final String NOTIFICATION_PULSE_ACTION = ACTION_BASE + ".notification_pulse";
     private static final String EXTRA_INSTANCE = "instance";
 
+    /**
+     * Earliest time we pulse due to a notification light after the service started.
+     *
+     * <p>Incoming notification light events during the blackout period are
+     * delayed to the earliest time defined by this constant.</p>
+     *
+     * <p>This delay avoids a pulse immediately after screen off, at which
+     * point the notification light is re-enabled again by NoMan.</p>
+     */
+    private static final int EARLIEST_LIGHT_PULSE_AFTER_START_MS = 10 * 1000;
+
     private final String mTag = String.format(TAG + ".%08x", hashCode());
     private final Context mContext = this;
     private final DozeParameters mDozeParameters = new DozeParameters(mContext);
@@ -77,6 +88,7 @@ public class DozeService extends DreamService {
     private boolean mPowerSaveActive;
     private boolean mCarMode;
     private long mNotificationPulseTime;
+    private long mEarliestPulseDueToLight;
     private int mScheduleResetsRemaining;
 
     public DozeService() {
@@ -159,8 +171,9 @@ public class DozeService extends DreamService {
         }
 
         mDreaming = true;
-        listenForPulseSignals(true);
         rescheduleNotificationPulse(false /*predicate*/);  // cancel any pending pulse alarms
+        mEarliestPulseDueToLight = System.currentTimeMillis() + EARLIEST_LIGHT_PULSE_AFTER_START_MS;
+        listenForPulseSignals(true);
 
         // Ask the host to get things ready to start dozing.
         // Once ready, we call startDozing() at which point the CPU may suspend
@@ -295,6 +308,12 @@ public class DozeService extends DreamService {
         if (listen) {
             resetNotificationResets();
             mHost.addCallback(mHostCallback);
+
+            // Continue to pulse for existing LEDs.
+            mNotificationLightOn = mHost.isNotificationLightOn();
+            if (mNotificationLightOn) {
+                updateNotificationPulseDueToLight();
+            }
         } else {
             mHost.removeCallback(mHostCallback);
         }
@@ -305,21 +324,26 @@ public class DozeService extends DreamService {
         mScheduleResetsRemaining = mDozeParameters.getPulseScheduleResets();
     }
 
-    private void updateNotificationPulse() {
-        if (DEBUG) Log.d(mTag, "updateNotificationPulse");
+    private void updateNotificationPulseDueToLight() {
+        long timeMs = System.currentTimeMillis();
+        timeMs = Math.max(timeMs, mEarliestPulseDueToLight);
+        updateNotificationPulse(timeMs);
+    }
+
+    private void updateNotificationPulse(long notificationTimeMs) {
+        if (DEBUG) Log.d(mTag, "updateNotificationPulse notificationTimeMs=" + notificationTimeMs);
         if (!mDozeParameters.getPulseOnNotifications()) return;
         if (mScheduleResetsRemaining <= 0) {
             if (DEBUG) Log.d(mTag, "No more schedule resets remaining");
             return;
         }
-        final long now = System.currentTimeMillis();
-        if ((now - mNotificationPulseTime) < mDozeParameters.getPulseDuration()) {
+        if ((notificationTimeMs - mNotificationPulseTime) < mDozeParameters.getPulseDuration()) {
             if (DEBUG) Log.d(mTag, "Recently updated, not resetting schedule");
             return;
         }
         mScheduleResetsRemaining--;
         if (DEBUG) Log.d(mTag, "mScheduleResetsRemaining = " + mScheduleResetsRemaining);
-        mNotificationPulseTime = now;
+        mNotificationPulseTime = notificationTimeMs;
         rescheduleNotificationPulse(true /*predicate*/);
     }
 
@@ -401,14 +425,14 @@ public class DozeService extends DreamService {
     private final DozeHost.Callback mHostCallback = new DozeHost.Callback() {
         @Override
         public void onNewNotifications() {
-            if (DEBUG) Log.d(mTag, "onNewNotifications");
+            if (DEBUG) Log.d(mTag, "onNewNotifications (noop)");
             // noop for now
         }
 
         @Override
         public void onBuzzBeepBlinked() {
             if (DEBUG) Log.d(mTag, "onBuzzBeepBlinked");
-            updateNotificationPulse();
+            updateNotificationPulse(System.currentTimeMillis());
         }
 
         @Override
@@ -417,7 +441,7 @@ public class DozeService extends DreamService {
             if (mNotificationLightOn == on) return;
             mNotificationLightOn = on;
             if (mNotificationLightOn) {
-                updateNotificationPulse();
+                updateNotificationPulseDueToLight();
             }
         }
 
index 4a16f8d..416fdec 100644 (file)
@@ -1642,7 +1642,11 @@ public abstract class BaseStatusBar extends SystemUI implements
     protected void handleVisibleToUserChanged(boolean visibleToUser) {
         try {
             if (visibleToUser) {
-                mBarService.onPanelRevealed();
+                // Only stop blinking, vibrating, ringing when the user went into the shade
+                // manually (SHADE or SHADE_LOCKED).
+                boolean clearNotificationEffects =
+                        (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
+                mBarService.onPanelRevealed(clearNotificationEffects);
             } else {
                 mBarService.onPanelHidden();
             }
index 54eb18c..5664548 100644 (file)
@@ -3807,6 +3807,16 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
      * @param state The {@link StatusBarState} to set.
      */
     public void setBarState(int state) {
+        // If we're visible and switched to SHADE_LOCKED (the user dragged down
+        // on the lockscreen), clear notification LED, vibration, ringing.
+        // Other transitions are covered in handleVisibleToUserChanged().
+        if (mVisible && mState != state && state == StatusBarState.SHADE_LOCKED) {
+            try {
+                mBarService.clearNotificationEffects();
+            } catch (RemoteException e) {
+                // Ignore.
+            }
+        }
         mState = state;
         mStatusBarWindowManager.setStatusBarState(state);
     }
@@ -4138,6 +4148,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
         private final H mHandler = new H();
 
+        // Keeps the last reported state by fireNotificationLight.
+        private boolean mNotificationLightOn;
+
         @Override
         public String toString() {
             return "PSB.DozeServiceHost[mCallbacks=" + mCallbacks.size() + "]";
@@ -4156,6 +4169,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         }
 
         public void fireNotificationLight(boolean on) {
+            mNotificationLightOn = on;
             for (Callback callback : mCallbacks) {
                 callback.onNotificationLight(on);
             }
@@ -4197,6 +4211,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
             return mBatteryController != null && mBatteryController.isPowerSave();
         }
 
+        @Override
+        public boolean isNotificationLightOn() {
+            return mNotificationLightOn;
+        }
+
         private void handleStartDozing(@NonNull Runnable ready) {
             if (!mDozing) {
                 mDozing = true;
index 24fc455..fdb443e 100644 (file)
@@ -26,8 +26,9 @@ public interface NotificationDelegate {
     void onNotificationError(int callingUid, int callingPid,
             String pkg, String tag, int id,
             int uid, int initialPid, String message, int userId);
-    void onPanelRevealed();
+    void onPanelRevealed(boolean clearEffects);
     void onPanelHidden();
+    void clearEffects();
     void onNotificationVisibilityChanged(
             String[] newlyVisibleKeys, String[] noLongerVisibleKeys);
     void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
index 70d0e6a..4e1640f 100644 (file)
@@ -122,7 +122,7 @@ import java.util.Objects;
 /** {@hide} */
 public class NotificationManagerService extends SystemService {
     static final String TAG = "NotificationService";
-    static final boolean DBG = false;
+    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
 
     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
 
@@ -564,9 +564,23 @@ public class NotificationManagerService extends SystemService {
         }
 
         @Override
-        public void onPanelRevealed() {
+        public void onPanelRevealed(boolean clearEffects) {
             EventLogTags.writeNotificationPanelRevealed();
+            if (clearEffects) {
+                clearEffects();
+            }
+        }
+
+        @Override
+        public void onPanelHidden() {
+            EventLogTags.writeNotificationPanelHidden();
+        }
+
+        @Override
+        public void clearEffects() {
             synchronized (mNotificationList) {
+                if (DBG) Slog.d(TAG, "clearEffects");
+
                 // sound
                 mSoundNotification = null;
 
@@ -598,11 +612,6 @@ public class NotificationManagerService extends SystemService {
         }
 
         @Override
-        public void onPanelHidden() {
-            EventLogTags.writeNotificationPanelHidden();
-        }
-
-        @Override
         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
                 int uid, int initialPid, String message, int userId) {
             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
@@ -740,8 +749,10 @@ public class NotificationManagerService extends SystemService {
                 // Keep track of screen on/off state, but do not turn off the notification light
                 // until user passes through the lock screen or views the notification.
                 mScreenOn = true;
+                updateNotificationPulse();
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 mScreenOn = false;
+                updateNotificationPulse();
             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
index 9828cd4..cf2ed07 100644 (file)
@@ -26,7 +26,6 @@ import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.util.Slog;
-import android.view.WindowManager;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.IStatusBarService;
@@ -495,16 +494,26 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
     }
 
     /**
-     * The status bar service should call this each time the user brings the panel from
-     * invisible to visible in order to clear the notification light.
+     * @param clearNotificationEffects whether to consider notifications as "shown" and stop
+     *     LED, vibration, and ringing
      */
     @Override
-    public void onPanelRevealed() {
+    public void onPanelRevealed(boolean clearNotificationEffects) {
         enforceStatusBarService();
         long identity = Binder.clearCallingIdentity();
         try {
-            // tell the notification manager to turn off the lights.
-            mNotificationDelegate.onPanelRevealed();
+            mNotificationDelegate.onPanelRevealed(clearNotificationEffects);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void clearNotificationEffects() throws RemoteException {
+        enforceStatusBarService();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            mNotificationDelegate.clearEffects();
         } finally {
             Binder.restoreCallingIdentity(identity);
         }