ExpandableNotificationRow.java revision 343e6e258ab6a9f647eabebaed05ce3acafd2ff1
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.ViewGroup; 23import android.widget.FrameLayout; 24 25import com.android.internal.widget.SizeAdaptiveLayout; 26import com.android.systemui.R; 27 28public class ExpandableNotificationRow extends FrameLayout 29 implements LatestItemView.OnActivatedListener { 30 private int mRowMinHeight; 31 private int mRowMaxHeight; 32 33 /** Does this row contain layouts that can adapt to row expansion */ 34 private boolean mExpandable; 35 /** Has the user actively changed the expansion state of this row */ 36 private boolean mHasUserChangedExpansion; 37 /** If {@link #mHasUserChangedExpansion}, has the user expanded this row */ 38 private boolean mUserExpanded; 39 /** Is the user touching this row */ 40 private boolean mUserLocked; 41 /** Are we showing the "public" version */ 42 private boolean mShowingPublic; 43 44 private LatestItemView mLatestItemView; 45 46 /** 47 * Is this notification expanded by the system. The expansion state can be overridden by the 48 * user expansion. 49 */ 50 private boolean mIsSystemExpanded; 51 private SizeAdaptiveLayout mPublicLayout; 52 private SizeAdaptiveLayout mPrivateLayout; 53 private int mMaxExpandHeight; 54 private boolean mMaxHeightNeedsUpdate; 55 private NotificationActivator mActivator; 56 private LatestItemView.OnActivatedListener mOnActivatedListener; 57 private boolean mSelfInitiatedLayout; 58 59 public ExpandableNotificationRow(Context context, AttributeSet attrs) { 60 super(context, attrs); 61 } 62 63 @Override 64 protected void onFinishInflate() { 65 super.onFinishInflate(); 66 mPublicLayout = (SizeAdaptiveLayout) findViewById(R.id.expandedPublic); 67 mPrivateLayout = (SizeAdaptiveLayout) findViewById(R.id.expanded); 68 mLatestItemView = (LatestItemView) findViewById(R.id.container); 69 70 mActivator = new NotificationActivator(this); 71 mLatestItemView.setOnActivatedListener(this); 72 } 73 74 public void setHeightRange(int rowMinHeight, int rowMaxHeight) { 75 mRowMinHeight = rowMinHeight; 76 mRowMaxHeight = rowMaxHeight; 77 mMaxHeightNeedsUpdate = true; 78 } 79 80 public boolean isExpandable() { 81 return mExpandable; 82 } 83 84 public void setExpandable(boolean expandable) { 85 mExpandable = expandable; 86 } 87 88 /** 89 * @return whether the user has changed the expansion state 90 */ 91 public boolean hasUserChangedExpansion() { 92 return mHasUserChangedExpansion; 93 } 94 95 public boolean isUserExpanded() { 96 return mUserExpanded; 97 } 98 99 /** 100 * Set this notification to be expanded by the user 101 * 102 * @param userExpanded whether the user wants this notification to be expanded 103 */ 104 public void setUserExpanded(boolean userExpanded) { 105 mHasUserChangedExpansion = true; 106 mUserExpanded = userExpanded; 107 } 108 109 public boolean isUserLocked() { 110 return mUserLocked; 111 } 112 113 public void setUserLocked(boolean userLocked) { 114 mUserLocked = userLocked; 115 } 116 117 /** 118 * @return has the system set this notification to be expanded 119 */ 120 public boolean isSystemExpanded() { 121 return mIsSystemExpanded; 122 } 123 124 /** 125 * Set this notification to be expanded by the system. 126 * 127 * @param expand whether the system wants this notification to be expanded. 128 */ 129 public void setSystemExpanded(boolean expand) { 130 mIsSystemExpanded = expand; 131 applyExpansionToLayout(expand); 132 } 133 134 /** 135 * Apply an expansion state to the layout. 136 * 137 * @param expand should the layout be in the expanded state 138 */ 139 public void applyExpansionToLayout(boolean expand) { 140 ViewGroup.LayoutParams lp = getLayoutParams(); 141 if (expand && mExpandable) { 142 lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; 143 } else { 144 lp.height = mRowMinHeight; 145 } 146 setLayoutParams(lp); 147 } 148 149 /** 150 * If {@link #isExpanded()} then this is the greatest possible height this view can 151 * get and otherwise it is {@link #mRowMinHeight}. 152 * 153 * @return the maximum allowed expansion height of this view. 154 */ 155 public int getMaximumAllowedExpandHeight() { 156 boolean inExpansionState = isExpanded(); 157 if (!inExpansionState) { 158 // not expanded, so we return the collapsed size 159 return mRowMinHeight; 160 } 161 162 return mShowingPublic ? mRowMinHeight : getMaxExpandHeight(); 163 } 164 165 private void updateMaxExpandHeight() { 166 167 // We don't want this method to trigger a layout of the whole view hierarchy, 168 // as the layout parameters in the end are the same which they were in the beginning. 169 // Otherwise a loop may occur if this method is called on the layout of a parent. 170 mSelfInitiatedLayout = true; 171 ViewGroup.LayoutParams lp = getLayoutParams(); 172 int oldHeight = lp.height; 173 lp.height = ViewGroup.LayoutParams.WRAP_CONTENT; 174 setLayoutParams(lp); 175 measure(View.MeasureSpec.makeMeasureSpec(getMeasuredWidth(), View.MeasureSpec.EXACTLY), 176 View.MeasureSpec.makeMeasureSpec(mRowMaxHeight, View.MeasureSpec.AT_MOST)); 177 lp.height = oldHeight; 178 setLayoutParams(lp); 179 mMaxExpandHeight = getMeasuredHeight(); 180 mSelfInitiatedLayout = false; 181 } 182 183 @Override 184 public void requestLayout() { 185 if (!mSelfInitiatedLayout) { 186 super.requestLayout(); 187 } 188 } 189 190 /** 191 * Check whether the view state is currently expanded. This is given by the system in {@link 192 * #setSystemExpanded(boolean)} and can be overridden by user expansion or 193 * collapsing in {@link #setUserExpanded(boolean)}. Note that the visual appearance of this 194 * view can differ from this state, if layout params are modified from outside. 195 * 196 * @return whether the view state is currently expanded. 197 */ 198 private boolean isExpanded() { 199 return !hasUserChangedExpansion() && isSystemExpanded() || isUserExpanded(); 200 } 201 202 @Override 203 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 204 super.onLayout(changed, left, top, right, bottom); 205 mMaxHeightNeedsUpdate = true; 206 } 207 208 public void setShowingPublic(boolean show) { 209 mShowingPublic = show; 210 211 // bail out if no public version 212 if (mPublicLayout.getChildCount() == 0) return; 213 214 // TODO: animation? 215 mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE); 216 mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE); 217 } 218 219 /** 220 * Sets the notification as dimmed, meaning that it will appear in a more gray variant. 221 */ 222 public void setDimmed(boolean dimmed) { 223 mLatestItemView.setDimmed(dimmed); 224 mActivator.setDimmed(dimmed); 225 } 226 227 public int getMaxExpandHeight() { 228 if (mMaxHeightNeedsUpdate) { 229 updateMaxExpandHeight(); 230 mMaxHeightNeedsUpdate = false; 231 } 232 return mMaxExpandHeight; 233 } 234 235 /** 236 * Sets the notification as locked. In the locked state, the first tap will produce a quantum 237 * ripple to make the notification brighter and only the second tap will cause a click. 238 */ 239 public void setLocked(boolean locked) { 240 mLatestItemView.setLocked(locked); 241 } 242 243 public void setOnActivatedListener(LatestItemView.OnActivatedListener listener) { 244 mOnActivatedListener = listener; 245 } 246 247 public NotificationActivator getActivator() { 248 return mActivator; 249 } 250 251 @Override 252 public void onActivated(View view) { 253 if (mOnActivatedListener != null) { 254 mOnActivatedListener.onActivated(this); 255 } 256 } 257 258 @Override 259 public void onReset(View view) { 260 if (mOnActivatedListener != null) { 261 mOnActivatedListener.onReset(this); 262 } 263 } 264 265 /** 266 * Sets the resource id for the background of this notification. 267 * 268 * @param bgResId The background resource to use in normal state. 269 * @param dimmedBgResId The background resource to use in dimmed state. 270 */ 271 public void setBackgroundResourceIds(int bgResId, int dimmedBgResId) { 272 mLatestItemView.setBackgroundResourceIds(bgResId, dimmedBgResId); 273 } 274 275 /** 276 * @return the potential height this view could expand in addition. 277 */ 278 public int getExpandPotential() { 279 return getMaximumAllowedExpandHeight() - getHeight(); 280 } 281} 282