Home | History | Annotate | Download | only in statusbar
      1 /*
      2  * Copyright (C) 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.systemui.statusbar;
     18 
     19 import static com.android.systemui.statusbar.notification.row.NotificationContentInflater.FLAG_CONTENT_VIEW_AMBIENT;
     20 
     21 import android.annotation.NonNull;
     22 import android.content.Context;
     23 import android.content.res.Resources;
     24 import android.util.ArraySet;
     25 
     26 import com.android.internal.annotations.VisibleForTesting;
     27 import com.android.systemui.R;
     28 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
     29 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
     30 
     31 import javax.inject.Inject;
     32 import javax.inject.Singleton;
     33 
     34 /**
     35  * Manager which handles high priority notifications that should "pulse" in when the device is
     36  * dozing and/or in AOD.  The pulse uses the notification's ambient view and pops in briefly
     37  * before automatically dismissing the alert.
     38  */
     39 @Singleton
     40 public class AmbientPulseManager extends AlertingNotificationManager {
     41 
     42     protected final ArraySet<OnAmbientChangedListener> mListeners = new ArraySet<>();
     43     @VisibleForTesting
     44     protected long mExtensionTime;
     45 
     46     @Inject
     47     public AmbientPulseManager(@NonNull final Context context) {
     48         Resources resources = context.getResources();
     49         mAutoDismissNotificationDecay = resources.getInteger(R.integer.ambient_notification_decay);
     50         mMinimumDisplayTime = resources.getInteger(R.integer.ambient_notification_minimum_time);
     51         mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
     52     }
     53 
     54     /**
     55      * Adds an OnAmbientChangedListener to observe events.
     56      */
     57     public void addListener(@NonNull OnAmbientChangedListener listener) {
     58         mListeners.add(listener);
     59     }
     60 
     61     /**
     62      * Removes the OnAmbientChangedListener from the observer list.
     63      */
     64     public void removeListener(@NonNull OnAmbientChangedListener listener) {
     65         mListeners.remove(listener);
     66     }
     67 
     68     /**
     69      * Extends the lifetime of the currently showing pulsing notification so that the pulse lasts
     70      * longer.
     71      */
     72     public void extendPulse() {
     73         AmbientEntry topEntry = getTopEntry();
     74         if (topEntry == null) {
     75             return;
     76         }
     77         topEntry.extendPulse();
     78     }
     79 
     80     public @InflationFlag int getContentFlag() {
     81         return FLAG_CONTENT_VIEW_AMBIENT;
     82     }
     83 
     84     @Override
     85     protected void onAlertEntryAdded(AlertEntry alertEntry) {
     86         NotificationEntry entry = alertEntry.mEntry;
     87         entry.setAmbientPulsing(true);
     88         for (OnAmbientChangedListener listener : mListeners) {
     89             listener.onAmbientStateChanged(entry, true);
     90         }
     91     }
     92 
     93     @Override
     94     protected void onAlertEntryRemoved(AlertEntry alertEntry) {
     95         NotificationEntry entry = alertEntry.mEntry;
     96         entry.setAmbientPulsing(false);
     97         for (OnAmbientChangedListener listener : mListeners) {
     98             listener.onAmbientStateChanged(entry, false);
     99         }
    100         entry.freeContentViewWhenSafe(FLAG_CONTENT_VIEW_AMBIENT);
    101     }
    102 
    103     @Override
    104     protected AlertEntry createAlertEntry() {
    105         return new AmbientEntry();
    106     }
    107 
    108     /**
    109      * Get the top pulsing entry.  This should be the currently showing one if there are multiple.
    110      * @return the currently showing entry
    111      */
    112     private AmbientEntry getTopEntry() {
    113         if (mAlertEntries.isEmpty()) {
    114             return null;
    115         }
    116         AlertEntry topEntry = null;
    117         for (AlertEntry entry : mAlertEntries.values()) {
    118             if (topEntry == null || entry.compareTo(topEntry) < 0) {
    119                 topEntry = entry;
    120             }
    121         }
    122         return (AmbientEntry) topEntry;
    123     }
    124 
    125     /**
    126      * Observer interface for any changes in the ambient entries.
    127      */
    128     public interface OnAmbientChangedListener {
    129         /**
    130          * Called when an entry starts or stops pulsing.
    131          * @param entry the entry that changed
    132          * @param isPulsing true if the entry is now pulsing, false otherwise
    133          */
    134         void onAmbientStateChanged(@NonNull NotificationEntry entry, boolean isPulsing);
    135     }
    136 
    137     private final class AmbientEntry extends AlertEntry {
    138         private boolean extended;
    139 
    140         /**
    141          * Extend the lifetime of the alertEntry so that it auto-removes later.  Can only be
    142          * extended once.
    143          */
    144         private void extendPulse() {
    145             if (!extended) {
    146                 extended = true;
    147                 updateEntry(false);
    148             }
    149         }
    150 
    151         @Override
    152         public void reset() {
    153             super.reset();
    154             extended = false;
    155         }
    156 
    157         @Override
    158         protected long calculateFinishTime() {
    159             return super.calculateFinishTime() + (extended ? mExtensionTime : 0);
    160         }
    161     }
    162 }
    163