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