Home | History | Annotate | Download | only in notification
      1 /*
      2  * Copyright (C) 2016 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.notification;
     18 
     19 import android.support.v4.util.ArraySet;
     20 import android.view.View;
     21 
     22 import com.android.systemui.statusbar.ExpandableNotificationRow;
     23 import com.android.systemui.statusbar.NotificationData;
     24 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
     25 
     26 import java.util.ArrayList;
     27 
     28 /**
     29  * A manager that ensures that notifications are visually stable. It will suppress reorderings
     30  * and reorder at the right time when they are out of view.
     31  */
     32 public class VisualStabilityManager implements OnHeadsUpChangedListener {
     33 
     34     private final ArrayList<Callback> mCallbacks =  new ArrayList<>();
     35 
     36     private boolean mPanelExpanded;
     37     private boolean mScreenOn;
     38     private boolean mReorderingAllowed;
     39     private VisibilityLocationProvider mVisibilityLocationProvider;
     40     private ArraySet<View> mAllowedReorderViews = new ArraySet<>();
     41     private ArraySet<View> mLowPriorityReorderingViews = new ArraySet<>();
     42     private ArraySet<View> mAddedChildren = new ArraySet<>();
     43     private boolean mPulsing;
     44 
     45     /**
     46      * Add a callback to invoke when reordering is allowed again.
     47      * @param callback
     48      */
     49     public void addReorderingAllowedCallback(Callback callback) {
     50         if (mCallbacks.contains(callback)) {
     51             return;
     52         }
     53         mCallbacks.add(callback);
     54     }
     55 
     56     /**
     57      * Set the panel to be expanded.
     58      */
     59     public void setPanelExpanded(boolean expanded) {
     60         mPanelExpanded = expanded;
     61         updateReorderingAllowed();
     62     }
     63 
     64     /**
     65      * @param screenOn whether the screen is on
     66      */
     67     public void setScreenOn(boolean screenOn) {
     68         mScreenOn = screenOn;
     69         updateReorderingAllowed();
     70     }
     71 
     72     /**
     73      * @param pulsing whether we are currently pulsing for ambient display.
     74      */
     75     public void setPulsing(boolean pulsing) {
     76         if (mPulsing == pulsing) {
     77             return;
     78         }
     79         mPulsing = pulsing;
     80         updateReorderingAllowed();
     81     }
     82 
     83     private void updateReorderingAllowed() {
     84         boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
     85         boolean changed = reorderingAllowed && !mReorderingAllowed;
     86         mReorderingAllowed = reorderingAllowed;
     87         if (changed) {
     88             notifyCallbacks();
     89         }
     90     }
     91 
     92     private void notifyCallbacks() {
     93         for (int i = 0; i < mCallbacks.size(); i++) {
     94             Callback callback = mCallbacks.get(i);
     95             callback.onReorderingAllowed();
     96         }
     97         mCallbacks.clear();
     98     }
     99 
    100     /**
    101      * @return whether reordering is currently allowed in general.
    102      */
    103     public boolean isReorderingAllowed() {
    104         return mReorderingAllowed;
    105     }
    106 
    107     /**
    108      * @return whether a specific notification is allowed to reorder. Certain notifications are
    109      * allowed to reorder even if {@link #isReorderingAllowed()} returns false, like newly added
    110      * notifications or heads-up notifications that are out of view.
    111      */
    112     public boolean canReorderNotification(ExpandableNotificationRow row) {
    113         if (mReorderingAllowed) {
    114             return true;
    115         }
    116         if (mAddedChildren.contains(row)) {
    117             return true;
    118         }
    119         if (mLowPriorityReorderingViews.contains(row)) {
    120             return true;
    121         }
    122         if (mAllowedReorderViews.contains(row)
    123                 && !mVisibilityLocationProvider.isInVisibleLocation(row)) {
    124             return true;
    125         }
    126         return false;
    127     }
    128 
    129     public void setVisibilityLocationProvider(
    130             VisibilityLocationProvider visibilityLocationProvider) {
    131         mVisibilityLocationProvider = visibilityLocationProvider;
    132     }
    133 
    134     public void onReorderingFinished() {
    135         mAllowedReorderViews.clear();
    136         mAddedChildren.clear();
    137         mLowPriorityReorderingViews.clear();
    138     }
    139 
    140     @Override
    141     public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
    142         if (isHeadsUp) {
    143             // Heads up notifications should in general be allowed to reorder if they are out of
    144             // view and stay at the current location if they aren't.
    145             mAllowedReorderViews.add(entry.row);
    146         }
    147     }
    148 
    149     public void onLowPriorityUpdated(NotificationData.Entry entry) {
    150         mLowPriorityReorderingViews.add(entry.row);
    151     }
    152 
    153     /**
    154      * Notify the visual stability manager that a new view was added and should be allowed to
    155      * reorder next time.
    156      */
    157     public void notifyViewAddition(View view) {
    158         mAddedChildren.add(view);
    159     }
    160 
    161     public interface Callback {
    162         /**
    163          * Called when reordering is allowed again.
    164          */
    165         void onReorderingAllowed();
    166     }
    167 
    168 }
    169