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.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> mAddedChildren = new ArraySet<>(); 42 43 /** 44 * Add a callback to invoke when reordering is allowed again. 45 * @param callback 46 */ addReorderingAllowedCallback(Callback callback)47 public void addReorderingAllowedCallback(Callback callback) { 48 if (mCallbacks.contains(callback)) { 49 return; 50 } 51 mCallbacks.add(callback); 52 } 53 54 /** 55 * Set the panel to be expanded. 56 */ setPanelExpanded(boolean expanded)57 public void setPanelExpanded(boolean expanded) { 58 mPanelExpanded = expanded; 59 updateReorderingAllowed(); 60 } 61 62 /** 63 * @param screenOn whether the screen is on 64 */ setScreenOn(boolean screenOn)65 public void setScreenOn(boolean screenOn) { 66 mScreenOn = screenOn; 67 updateReorderingAllowed(); 68 } 69 updateReorderingAllowed()70 private void updateReorderingAllowed() { 71 boolean reorderingAllowed = !mScreenOn || !mPanelExpanded; 72 boolean changed = reorderingAllowed && !mReorderingAllowed; 73 mReorderingAllowed = reorderingAllowed; 74 if (changed) { 75 notifyCallbacks(); 76 } 77 } 78 notifyCallbacks()79 private void notifyCallbacks() { 80 for (int i = 0; i < mCallbacks.size(); i++) { 81 Callback callback = mCallbacks.get(i); 82 callback.onReorderingAllowed(); 83 } 84 mCallbacks.clear(); 85 } 86 87 /** 88 * @return whether reordering is currently allowed in general. 89 */ isReorderingAllowed()90 public boolean isReorderingAllowed() { 91 return mReorderingAllowed; 92 } 93 94 /** 95 * @return whether a specific notification is allowed to reorder. Certain notifications are 96 * allowed to reorder even if {@link #isReorderingAllowed()} returns false, like newly added 97 * notifications or heads-up notifications that are out of view. 98 */ canReorderNotification(ExpandableNotificationRow row)99 public boolean canReorderNotification(ExpandableNotificationRow row) { 100 if (mReorderingAllowed) { 101 return true; 102 } 103 if (mAddedChildren.contains(row)) { 104 return true; 105 } 106 if (mAllowedReorderViews.contains(row) 107 && !mVisibilityLocationProvider.isInVisibleLocation(row)) { 108 return true; 109 } 110 return false; 111 } 112 setVisibilityLocationProvider( VisibilityLocationProvider visibilityLocationProvider)113 public void setVisibilityLocationProvider( 114 VisibilityLocationProvider visibilityLocationProvider) { 115 mVisibilityLocationProvider = visibilityLocationProvider; 116 } 117 onReorderingFinished()118 public void onReorderingFinished() { 119 mAllowedReorderViews.clear(); 120 mAddedChildren.clear(); 121 } 122 123 @Override onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp)124 public void onHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) { 125 if (isHeadsUp) { 126 // Heads up notifications should in general be allowed to reorder if they are out of 127 // view and stay at the current location if they aren't. 128 mAllowedReorderViews.add(entry.row); 129 } 130 } 131 132 /** 133 * Notify the visual stability manager that a new view was added and should be allowed to 134 * reorder next time. 135 */ notifyViewAddition(View view)136 public void notifyViewAddition(View view) { 137 mAddedChildren.add(view); 138 } 139 140 public interface Callback { 141 /** 142 * Called when reordering is allowed again. 143 */ onReorderingAllowed()144 void onReorderingAllowed(); 145 } 146 147 } 148