ExpandableNotificationRow.java revision 0d3e62f3e07a69f21c1b1dfa2c8c0fb8b6c95655
1/* 2 * Copyright (C) 2013 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 17package com.android.systemui.statusbar; 18 19import android.content.Context; 20import android.util.AttributeSet; 21import android.view.View; 22import android.view.accessibility.AccessibilityEvent; 23 24import com.android.systemui.R; 25 26public class ExpandableNotificationRow extends ActivatableNotificationView { 27 private int mRowMinHeight; 28 private int mRowMaxHeight; 29 30 /** Does this row contain layouts that can adapt to row expansion */ 31 private boolean mExpandable; 32 /** Has the user actively changed the expansion state of this row */ 33 private boolean mHasUserChangedExpansion; 34 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */ 35 private boolean mUserExpanded; 36 /** Is the user touching this row */ 37 private boolean mUserLocked; 38 /** Are we showing the "public" version */ 39 private boolean mShowingPublic; 40 41 /** 42 * Is this notification expanded by the system. The expansion state can be overridden by the 43 * user expansion. 44 */ 45 private boolean mIsSystemExpanded; 46 47 /** 48 * Whether the notification expansion is disabled. This is the case on Keyguard. 49 */ 50 private boolean mExpansionDisabled; 51 52 private NotificationContentView mPublicLayout; 53 private NotificationContentView mPrivateLayout; 54 private int mMaxExpandHeight; 55 private View mVetoButton; 56 private boolean mClearable; 57 58 public ExpandableNotificationRow(Context context, AttributeSet attrs) { 59 super(context, attrs); 60 } 61 62 /** 63 * Resets this view so it can be re-used for an updated notification. 64 */ 65 public void reset() { 66 mRowMinHeight = 0; 67 mRowMaxHeight = 0; 68 mExpandable = false; 69 mHasUserChangedExpansion = false; 70 mUserLocked = false; 71 mShowingPublic = false; 72 mIsSystemExpanded = false; 73 mExpansionDisabled = false; 74 mPublicLayout.reset(); 75 mPrivateLayout.reset(); 76 mMaxExpandHeight = 0; 77 } 78 79 @Override 80 protected void onFinishInflate() { 81 super.onFinishInflate(); 82 mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic); 83 mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded); 84 mVetoButton = findViewById(R.id.veto); 85 } 86 87 @Override 88 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { 89 if (super.onRequestSendAccessibilityEvent(child, event)) { 90 // Add a record for the entire layout since its content is somehow small. 91 // The event comes from a leaf view that is interacted with. 92 AccessibilityEvent record = AccessibilityEvent.obtain(); 93 onInitializeAccessibilityEvent(record); 94 dispatchPopulateAccessibilityEvent(record); 95 event.appendRecord(record); 96 return true; 97 } 98 return false; 99 } 100 101 public void setHeightRange(int rowMinHeight, int rowMaxHeight) { 102 mRowMinHeight = rowMinHeight; 103 mRowMaxHeight = rowMaxHeight; 104 } 105 106 public boolean isExpandable() { 107 return mExpandable; 108 } 109 110 public void setExpandable(boolean expandable) { 111 mExpandable = expandable; 112 } 113 114 /** 115 * @return whether the user has changed the expansion state 116 */ 117 public boolean hasUserChangedExpansion() { 118 return mHasUserChangedExpansion; 119 } 120 121 public boolean isUserExpanded() { 122 return mUserExpanded; 123 } 124 125 /** 126 * Set this notification to be expanded by the user 127 * 128 * @param userExpanded whether the user wants this notification to be expanded 129 */ 130 public void setUserExpanded(boolean userExpanded) { 131 if (userExpanded && !mExpandable) return; 132 mHasUserChangedExpansion = true; 133 mUserExpanded = userExpanded; 134 } 135 136 public boolean isUserLocked() { 137 return mUserLocked; 138 } 139 140 public void setUserLocked(boolean userLocked) { 141 mUserLocked = userLocked; 142 } 143 144 /** 145 * @return has the system set this notification to be expanded 146 */ 147 public boolean isSystemExpanded() { 148 return mIsSystemExpanded; 149 } 150 151 /** 152 * Set this notification to be expanded by the system. 153 * 154 * @param expand whether the system wants this notification to be expanded. 155 */ 156 public void setSystemExpanded(boolean expand) { 157 mIsSystemExpanded = expand; 158 notifyHeightChanged(); 159 } 160 161 /** 162 * @param expansionDisabled whether to prevent notification expansion 163 */ 164 public void setExpansionDisabled(boolean expansionDisabled) { 165 mExpansionDisabled = expansionDisabled; 166 notifyHeightChanged(); 167 } 168 169 /** 170 * @return Can the underlying notification be cleared? 171 */ 172 public boolean isClearable() { 173 return mClearable; 174 } 175 176 /** 177 * Set whether the notification can be cleared. 178 * 179 * @param clearable 180 */ 181 public void setClearable(boolean clearable) { 182 mClearable = clearable; 183 updateVetoButton(); 184 } 185 186 /** 187 * Apply an expansion state to the layout. 188 */ 189 public void applyExpansionToLayout() { 190 boolean expand = isExpanded(); 191 if (expand && mExpandable) { 192 setActualHeight(mMaxExpandHeight); 193 } else { 194 setActualHeight(mRowMinHeight); 195 } 196 } 197 198 @Override 199 public int getIntrinsicHeight() { 200 if (isUserLocked()) { 201 return getActualHeight(); 202 } 203 boolean inExpansionState = isExpanded(); 204 if (!inExpansionState) { 205 // not expanded, so we return the collapsed size 206 return mRowMinHeight; 207 } 208 209 return mShowingPublic ? mRowMinHeight : getMaxExpandHeight(); 210 } 211 212 /** 213 * Check whether the view state is currently expanded. This is given by the system in {@link 214 * #setSystemExpanded(boolean)} and can be overridden by user expansion or 215 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this 216 * view can differ from this state, if layout params are modified from outside. 217 * 218 * @return whether the view state is currently expanded. 219 */ 220 private boolean isExpanded() { 221 return !mExpansionDisabled 222 && (!hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded()); 223 } 224 225 @Override 226 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 227 super.onLayout(changed, left, top, right, bottom); 228 boolean updateExpandHeight = mMaxExpandHeight == 0; 229 mMaxExpandHeight = mPrivateLayout.getMaxHeight(); 230 if (updateExpandHeight) { 231 applyExpansionToLayout(); 232 } 233 } 234 235 public void setShowingPublic(boolean show) { 236 mShowingPublic = show; 237 238 // bail out if no public version 239 if (mPublicLayout.getChildCount() == 0) return; 240 241 // TODO: animation? 242 mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE); 243 mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE); 244 245 updateVetoButton(); 246 } 247 248 private void updateVetoButton() { 249 // public versions cannot be dismissed 250 mVetoButton.setVisibility(isClearable() && !mShowingPublic ? View.VISIBLE : View.GONE); 251 } 252 253 public int getMaxExpandHeight() { 254 return mShowingPublic ? mRowMinHeight : mMaxExpandHeight; 255 } 256 257 @Override 258 public boolean isContentExpandable() { 259 NotificationContentView showingLayout = getShowingLayout(); 260 return showingLayout.isContentExpandable(); 261 } 262 263 @Override 264 public void setActualHeight(int height, boolean notifyListeners) { 265 mPrivateLayout.setActualHeight(height); 266 mPublicLayout.setActualHeight(height); 267 invalidate(); 268 super.setActualHeight(height, notifyListeners); 269 } 270 271 @Override 272 public int getMaxHeight() { 273 NotificationContentView showingLayout = getShowingLayout(); 274 return showingLayout.getMaxHeight(); 275 } 276 277 @Override 278 public int getMinHeight() { 279 NotificationContentView showingLayout = getShowingLayout(); 280 return showingLayout.getMinHeight(); 281 } 282 283 @Override 284 public void setClipTopAmount(int clipTopAmount) { 285 super.setClipTopAmount(clipTopAmount); 286 mPrivateLayout.setClipTopAmount(clipTopAmount); 287 mPublicLayout.setClipTopAmount(clipTopAmount); 288 } 289 290 public void notifyContentUpdated() { 291 mPublicLayout.notifyContentUpdated(); 292 mPrivateLayout.notifyContentUpdated(); 293 } 294 295 public boolean isShowingLayoutLayouted() { 296 NotificationContentView showingLayout = getShowingLayout(); 297 return showingLayout.getWidth() != 0; 298 } 299 300 private NotificationContentView getShowingLayout() { 301 return mShowingPublic ? mPublicLayout : mPrivateLayout; 302 } 303} 304