NotificationChildrenContainer.java revision c897bd3e91ed442b0f32c3a5b9918e9e580b62b1
1/* 2 * Copyright (C) 2015 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.stack; 18 19import android.content.Context; 20import android.content.res.Configuration; 21import android.util.AttributeSet; 22import android.view.LayoutInflater; 23import android.view.View; 24import android.view.ViewGroup; 25import android.widget.TextView; 26 27import com.android.systemui.R; 28import com.android.systemui.ViewInvertHelper; 29import com.android.systemui.statusbar.CrossFadeHelper; 30import com.android.systemui.statusbar.ExpandableNotificationRow; 31import com.android.systemui.statusbar.notification.HybridGroupManager; 32import com.android.systemui.statusbar.notification.HybridNotificationView; 33import com.android.systemui.statusbar.notification.NotificationUtils; 34import com.android.systemui.statusbar.phone.NotificationPanelView; 35 36import java.util.ArrayList; 37import java.util.List; 38 39/** 40 * A container containing child notifications 41 */ 42public class NotificationChildrenContainer extends ViewGroup { 43 44 private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2; 45 private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5; 46 private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8; 47 48 private final List<View> mDividers = new ArrayList<>(); 49 private final List<ExpandableNotificationRow> mChildren = new ArrayList<>(); 50 private final HybridGroupManager mHybridGroupManager; 51 private int mChildPadding; 52 private int mDividerHeight; 53 private int mMaxNotificationHeight; 54 private int mNotificationHeaderHeight; 55 private int mNotificatonTopPadding; 56 private float mCollapsedBottompadding; 57 private ViewInvertHelper mOverflowInvertHelper; 58 private boolean mChildrenExpanded; 59 private ExpandableNotificationRow mNotificationParent; 60 private TextView mOverflowNumber; 61 private ViewState mGroupOverFlowState; 62 private int mRealHeight; 63 private boolean mUserLocked; 64 private int mActualHeight; 65 private boolean mNeverAppliedGroupState; 66 67 public NotificationChildrenContainer(Context context) { 68 this(context, null); 69 } 70 71 public NotificationChildrenContainer(Context context, AttributeSet attrs) { 72 this(context, attrs, 0); 73 } 74 75 public NotificationChildrenContainer(Context context, AttributeSet attrs, int defStyleAttr) { 76 this(context, attrs, defStyleAttr, 0); 77 } 78 79 public NotificationChildrenContainer(Context context, AttributeSet attrs, int defStyleAttr, 80 int defStyleRes) { 81 super(context, attrs, defStyleAttr, defStyleRes); 82 initDimens(); 83 mHybridGroupManager = new HybridGroupManager(getContext(), this); 84 } 85 86 private void initDimens() { 87 mChildPadding = getResources().getDimensionPixelSize( 88 R.dimen.notification_children_padding); 89 mDividerHeight = Math.max(1, getResources().getDimensionPixelSize( 90 R.dimen.notification_divider_height)); 91 mMaxNotificationHeight = getResources().getDimensionPixelSize( 92 R.dimen.notification_max_height); 93 mNotificationHeaderHeight = getResources().getDimensionPixelSize( 94 com.android.internal.R.dimen.notification_content_margin_top); 95 mNotificatonTopPadding = getResources().getDimensionPixelSize( 96 R.dimen.notification_children_container_top_padding); 97 mCollapsedBottompadding = getResources().getDimensionPixelSize( 98 com.android.internal.R.dimen.notification_content_margin_bottom); 99 } 100 101 @Override 102 protected void onLayout(boolean changed, int l, int t, int r, int b) { 103 int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); 104 for (int i = 0; i < childCount; i++) { 105 View child = mChildren.get(i); 106 if (child.getVisibility() == View.GONE) { 107 continue; 108 } 109 child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight()); 110 mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight); 111 } 112 if (mOverflowNumber != null) { 113 mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(), 114 mOverflowNumber.getMeasuredHeight()); 115 } 116 } 117 118 @Override 119 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 120 int ownMaxHeight = mMaxNotificationHeight; 121 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 122 boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY; 123 boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST; 124 int size = MeasureSpec.getSize(heightMeasureSpec); 125 if (hasFixedHeight || isHeightLimited) { 126 ownMaxHeight = Math.min(ownMaxHeight, size); 127 } 128 int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST); 129 int width = MeasureSpec.getSize(widthMeasureSpec); 130 if (mOverflowNumber != null) { 131 mOverflowNumber.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), 132 newHeightSpec); 133 } 134 int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY); 135 int height = mNotificationHeaderHeight + mNotificatonTopPadding; 136 int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); 137 int collapsedChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */); 138 int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1; 139 for (int i = 0; i < childCount; i++) { 140 ExpandableNotificationRow child = mChildren.get(i); 141 boolean isOverflow = i == overflowIndex; 142 child.setSingleLineWidthIndention(isOverflow ? mOverflowNumber.getMeasuredWidth() : 0); 143 child.measure(widthMeasureSpec, newHeightSpec); 144 height += child.getMeasuredHeight(); 145 146 // layout the divider 147 View divider = mDividers.get(i); 148 divider.measure(widthMeasureSpec, dividerHeightSpec); 149 height += mDividerHeight; 150 } 151 mRealHeight = height; 152 if (heightMode != MeasureSpec.UNSPECIFIED) { 153 height = Math.min(height, size); 154 } 155 setMeasuredDimension(width, height); 156 } 157 158 @Override 159 public boolean pointInView(float localX, float localY, float slop) { 160 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 161 localY < (mRealHeight + slop); 162 } 163 164 /** 165 * Add a child notification to this view. 166 * 167 * @param row the row to add 168 * @param childIndex the index to add it at, if -1 it will be added at the end 169 */ 170 public void addNotification(ExpandableNotificationRow row, int childIndex) { 171 int newIndex = childIndex < 0 ? mChildren.size() : childIndex; 172 mChildren.add(newIndex, row); 173 addView(row); 174 row.setUserLocked(mUserLocked); 175 176 View divider = inflateDivider(); 177 addView(divider); 178 mDividers.add(newIndex, divider); 179 180 updateGroupOverflow(); 181 } 182 183 public void removeNotification(ExpandableNotificationRow row) { 184 int childIndex = mChildren.indexOf(row); 185 mChildren.remove(row); 186 removeView(row); 187 188 final View divider = mDividers.remove(childIndex); 189 removeView(divider); 190 getOverlay().add(divider); 191 CrossFadeHelper.fadeOut(divider, new Runnable() { 192 @Override 193 public void run() { 194 getOverlay().remove(divider); 195 } 196 }); 197 198 row.setSystemChildExpanded(false); 199 row.setUserLocked(false); 200 updateGroupOverflow(); 201 } 202 203 public void updateGroupOverflow() { 204 int childCount = mChildren.size(); 205 int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */); 206 if (childCount > maxAllowedVisibleChildren) { 207 mOverflowNumber = mHybridGroupManager.bindOverflowNumber( 208 mOverflowNumber, childCount - maxAllowedVisibleChildren); 209 if (mOverflowInvertHelper == null) { 210 mOverflowInvertHelper= new ViewInvertHelper(mOverflowNumber, 211 NotificationPanelView.DOZE_ANIMATION_DURATION); 212 } 213 if (mGroupOverFlowState == null) { 214 mGroupOverFlowState = new ViewState(); 215 mNeverAppliedGroupState = true; 216 } 217 } else if (mOverflowNumber != null) { 218 removeView(mOverflowNumber); 219 if (isShown()) { 220 final View removedOverflowNumber = mOverflowNumber; 221 addTransientView(removedOverflowNumber, getTransientViewCount()); 222 CrossFadeHelper.fadeOut(removedOverflowNumber, new Runnable() { 223 @Override 224 public void run() { 225 removeTransientView(removedOverflowNumber); 226 } 227 }); 228 } 229 mOverflowNumber = null; 230 mOverflowInvertHelper = null; 231 mGroupOverFlowState = null; 232 } 233 } 234 235 @Override 236 protected void onConfigurationChanged(Configuration newConfig) { 237 super.onConfigurationChanged(newConfig); 238 updateGroupOverflow(); 239 } 240 241 private View inflateDivider() { 242 return LayoutInflater.from(mContext).inflate( 243 R.layout.notification_children_divider, this, false); 244 } 245 246 public List<ExpandableNotificationRow> getNotificationChildren() { 247 return mChildren; 248 } 249 250 /** 251 * Apply the order given in the list to the children. 252 * 253 * @param childOrder the new list order 254 * @return whether the list order has changed 255 */ 256 public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder) { 257 if (childOrder == null) { 258 return false; 259 } 260 boolean result = false; 261 for (int i = 0; i < mChildren.size() && i < childOrder.size(); i++) { 262 ExpandableNotificationRow child = mChildren.get(i); 263 ExpandableNotificationRow desiredChild = childOrder.get(i); 264 if (child != desiredChild) { 265 mChildren.remove(desiredChild); 266 mChildren.add(i, desiredChild); 267 result = true; 268 } 269 } 270 updateExpansionStates(); 271 return result; 272 } 273 274 private void updateExpansionStates() { 275 if (mChildrenExpanded || mUserLocked) { 276 // we don't modify it the group is expanded or if we are expanding it 277 return; 278 } 279 int size = mChildren.size(); 280 for (int i = 0; i < size; i++) { 281 ExpandableNotificationRow child = mChildren.get(i); 282 child.setSystemChildExpanded(i == 0 && size == 1); 283 } 284 } 285 286 /** 287 * 288 * @return the intrinsic size of this children container, i.e the natural fully expanded state 289 */ 290 public int getIntrinsicHeight() { 291 int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(); 292 return getIntrinsicHeight(maxAllowedVisibleChildren); 293 } 294 295 /** 296 * @return the intrinsic height with a number of children given 297 * in @param maxAllowedVisibleChildren 298 */ 299 private int getIntrinsicHeight(float maxAllowedVisibleChildren) { 300 int intrinsicHeight = mNotificationHeaderHeight; 301 int visibleChildren = 0; 302 int childCount = mChildren.size(); 303 boolean firstChild = true; 304 float expandFactor = 0; 305 if (mUserLocked) { 306 expandFactor = getChildExpandFraction(); 307 } 308 for (int i = 0; i < childCount; i++) { 309 if (visibleChildren >= maxAllowedVisibleChildren) { 310 break; 311 } 312 if (!firstChild) { 313 if (mUserLocked) { 314 intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight, 315 expandFactor); 316 } else { 317 intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding; 318 } 319 } else { 320 if (mUserLocked) { 321 intrinsicHeight += NotificationUtils.interpolate( 322 0, 323 mNotificatonTopPadding + mDividerHeight, 324 expandFactor); 325 } else { 326 intrinsicHeight += mChildrenExpanded 327 ? mNotificatonTopPadding + mDividerHeight 328 : 0; 329 } 330 firstChild = false; 331 } 332 ExpandableNotificationRow child = mChildren.get(i); 333 intrinsicHeight += child.getIntrinsicHeight(); 334 visibleChildren++; 335 } 336 if (mUserLocked) { 337 intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f, 338 expandFactor); 339 } else if (!mChildrenExpanded) { 340 intrinsicHeight += mCollapsedBottompadding; 341 } 342 return intrinsicHeight; 343 } 344 345 /** 346 * Update the state of all its children based on a linear layout algorithm. 347 * 348 * @param resultState the state to update 349 * @param parentState the state of the parent 350 */ 351 public void getState(StackScrollState resultState, StackViewState parentState) { 352 int childCount = mChildren.size(); 353 int yPosition = mNotificationHeaderHeight; 354 boolean firstChild = true; 355 int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(); 356 boolean hasOverflow = !mChildrenExpanded && childCount > maxAllowedVisibleChildren 357 && maxAllowedVisibleChildren != NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED; 358 int lastVisibleIndex = maxAllowedVisibleChildren - 1; 359 float expandFactor = 0; 360 if (mUserLocked) { 361 expandFactor = getChildExpandFraction(); 362 } 363 for (int i = 0; i < childCount; i++) { 364 ExpandableNotificationRow child = mChildren.get(i); 365 if (!firstChild) { 366 if (mUserLocked) { 367 yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight, 368 expandFactor); 369 } else { 370 yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding; 371 } 372 } else { 373 if (mUserLocked) { 374 yPosition += NotificationUtils.interpolate( 375 0, 376 mNotificatonTopPadding + mDividerHeight, 377 expandFactor); 378 } else { 379 yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0; 380 } 381 firstChild = false; 382 } 383 StackViewState childState = resultState.getViewStateForView(child); 384 int intrinsicHeight = child.getIntrinsicHeight(); 385 childState.yTranslation = yPosition; 386 childState.zTranslation = 0; 387 childState.height = intrinsicHeight; 388 childState.dimmed = parentState.dimmed; 389 childState.dark = parentState.dark; 390 childState.hideSensitive = parentState.hideSensitive; 391 childState.belowSpeedBump = parentState.belowSpeedBump; 392 childState.clipTopAmount = 0; 393 childState.topOverLap = 0; 394 boolean visible = i <= lastVisibleIndex; 395 childState.alpha = visible ? 1 : 0; 396 childState.location = parentState.location; 397 yPosition += intrinsicHeight; 398 } 399 if (mOverflowNumber != null) { 400 ExpandableNotificationRow overflowView = mChildren.get(Math.min( 401 getMaxAllowedVisibleChildren(true /* likeCollpased */), childCount) - 1); 402 mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView)); 403 if (!mChildrenExpanded) { 404 if (mUserLocked) { 405 HybridNotificationView singleLineView = overflowView.getSingleLineView(); 406 View mirrorView = singleLineView.getTextView(); 407 if (mirrorView.getVisibility() == GONE) { 408 mirrorView = singleLineView.getTitleView(); 409 } 410 if (mirrorView.getVisibility() == GONE) { 411 mirrorView = singleLineView; 412 } 413 mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset( 414 mirrorView, overflowView); 415 mGroupOverFlowState.alpha = mirrorView.getAlpha(); 416 } 417 } else { 418 mGroupOverFlowState.yTranslation += mNotificationHeaderHeight; 419 mGroupOverFlowState.alpha = 0.0f; 420 } 421 } 422 } 423 424 private int getMaxAllowedVisibleChildren() { 425 return getMaxAllowedVisibleChildren(false /* likeCollapsed */); 426 } 427 428 private int getMaxAllowedVisibleChildren(boolean likeCollapsed) { 429 if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) { 430 return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED; 431 } 432 if (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp()) { 433 return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED; 434 } 435 return NUMBER_OF_CHILDREN_WHEN_COLLAPSED; 436 } 437 438 public void applyState(StackScrollState state) { 439 int childCount = mChildren.size(); 440 ViewState tmpState = new ViewState(); 441 float expandFraction = 0.0f; 442 if (mUserLocked) { 443 expandFraction = getChildExpandFraction(); 444 } 445 for (int i = 0; i < childCount; i++) { 446 ExpandableNotificationRow child = mChildren.get(i); 447 StackViewState viewState = state.getViewStateForView(child); 448 state.applyState(child, viewState); 449 450 // layout the divider 451 View divider = mDividers.get(i); 452 tmpState.initFrom(divider); 453 tmpState.yTranslation = viewState.yTranslation - mDividerHeight; 454 float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0; 455 if (mUserLocked && viewState.alpha != 0) { 456 alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction); 457 } 458 tmpState.alpha = alpha; 459 state.applyViewState(divider, tmpState); 460 // There is no fake shadow to be drawn on the children 461 child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0); 462 } 463 if (mOverflowNumber != null) { 464 state.applyViewState(mOverflowNumber, mGroupOverFlowState); 465 mNeverAppliedGroupState = false; 466 } 467 } 468 469 /** 470 * This is called when the children expansion has changed and positions the children properly 471 * for an appear animation. 472 * 473 * @param state the new state we animate to 474 */ 475 public void prepareExpansionChanged(StackScrollState state) { 476 // TODO: do something that makes sense, like placing the invisible views correctly 477 return; 478 } 479 480 public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator, 481 long baseDelay, long duration) { 482 int childCount = mChildren.size(); 483 ViewState tmpState = new ViewState(); 484 float expandFraction = getChildExpandFraction(); 485 for (int i = childCount - 1; i >= 0; i--) { 486 ExpandableNotificationRow child = mChildren.get(i); 487 StackViewState viewState = state.getViewStateForView(child); 488 stateAnimator.startStackAnimations(child, viewState, state, -1, baseDelay); 489 490 // layout the divider 491 View divider = mDividers.get(i); 492 tmpState.initFrom(divider); 493 tmpState.yTranslation = viewState.yTranslation - mDividerHeight; 494 float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0; 495 if (mUserLocked && viewState.alpha != 0) { 496 alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction); 497 } 498 tmpState.alpha = alpha; 499 stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration); 500 // There is no fake shadow to be drawn on the children 501 child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0); 502 } 503 if (mOverflowNumber != null) { 504 if (mNeverAppliedGroupState) { 505 float alpha = mGroupOverFlowState.alpha; 506 mGroupOverFlowState.alpha = 0; 507 state.applyViewState(mOverflowNumber, mGroupOverFlowState); 508 mGroupOverFlowState.alpha = alpha; 509 mNeverAppliedGroupState = false; 510 } 511 stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState, 512 baseDelay, duration); 513 } 514 } 515 516 public ExpandableNotificationRow getViewAtPosition(float y) { 517 // find the view under the pointer, accounting for GONE views 518 final int count = mChildren.size(); 519 for (int childIdx = 0; childIdx < count; childIdx++) { 520 ExpandableNotificationRow slidingChild = mChildren.get(childIdx); 521 float childTop = slidingChild.getTranslationY(); 522 float top = childTop + slidingChild.getClipTopAmount(); 523 float bottom = childTop + slidingChild.getActualHeight(); 524 if (y >= top && y <= bottom) { 525 return slidingChild; 526 } 527 } 528 return null; 529 } 530 531 public void setChildrenExpanded(boolean childrenExpanded) { 532 mChildrenExpanded = childrenExpanded; 533 updateExpansionStates(); 534 } 535 536 public void setNotificationParent(ExpandableNotificationRow parent) { 537 mNotificationParent = parent; 538 } 539 540 public int getMaxContentHeight() { 541 int maxContentHeight = mNotificationHeaderHeight + mNotificatonTopPadding; 542 int visibleChildren = 0; 543 int childCount = mChildren.size(); 544 for (int i = 0; i < childCount; i++) { 545 if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) { 546 break; 547 } 548 ExpandableNotificationRow child = mChildren.get(i); 549 float childHeight = child.isExpanded(true /* allowOnKeyguard */) 550 ? child.getMaxExpandHeight() 551 : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */); 552 maxContentHeight += childHeight; 553 visibleChildren++; 554 } 555 if (visibleChildren > 0) { 556 maxContentHeight += visibleChildren * mDividerHeight; 557 } 558 return maxContentHeight; 559 } 560 561 public void setActualHeight(int actualHeight) { 562 if (!mUserLocked) { 563 return; 564 } 565 mActualHeight = actualHeight; 566 float fraction = getChildExpandFraction(); 567 int childCount = mChildren.size(); 568 for (int i = 0; i < childCount; i++) { 569 ExpandableNotificationRow child = mChildren.get(i); 570 float childHeight = child.isExpanded(true /* allowOnKeyguard */) 571 ? child.getMaxExpandHeight() 572 : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */); 573 float singleLineHeight = child.getShowingLayout().getMinHeight( 574 false /* likeGroupExpanded */); 575 child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight, childHeight, 576 fraction), false); 577 } 578 } 579 580 public float getChildExpandFraction() { 581 int allChildrenVisibleHeight = getChildrenExpandStartHeight(); 582 int maxContentHeight = getMaxContentHeight(); 583 float factor = (mActualHeight - allChildrenVisibleHeight) 584 / (float) (maxContentHeight - allChildrenVisibleHeight); 585 return Math.max(0.0f, Math.min(1.0f, factor)); 586 } 587 588 private int getChildrenExpandStartHeight() { 589 int intrinsicHeight = mNotificationHeaderHeight; 590 int visibleChildren = 0; 591 int childCount = mChildren.size(); 592 for (int i = 0; i < childCount; i++) { 593 if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) { 594 break; 595 } 596 ExpandableNotificationRow child = mChildren.get(i); 597 intrinsicHeight += child.getMinHeight(); 598 visibleChildren++; 599 } 600 if (visibleChildren > 0) { 601 intrinsicHeight += (visibleChildren - 1) * mChildPadding; 602 } 603 intrinsicHeight += mCollapsedBottompadding; 604 return intrinsicHeight; 605 } 606 607 public int getMinHeight() { 608 return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED); 609 } 610 611 public int getMinExpandHeight(boolean onKeyguard) { 612 int maxAllowedVisibleChildren = onKeyguard ? NUMBER_OF_CHILDREN_WHEN_COLLAPSED 613 : getMaxAllowedVisibleChildren(true /* forceCollapsed */); 614 int minExpandHeight = mNotificationHeaderHeight; 615 int visibleChildren = 0; 616 boolean firstChild = true; 617 int childCount = mChildren.size(); 618 for (int i = 0; i < childCount; i++) { 619 if (visibleChildren >= maxAllowedVisibleChildren) { 620 break; 621 } 622 if (!firstChild) { 623 minExpandHeight += mChildPadding; 624 } else { 625 firstChild = false; 626 } 627 ExpandableNotificationRow child = mChildren.get(i); 628 minExpandHeight += child.getMinHeight(); 629 visibleChildren++; 630 } 631 minExpandHeight += mCollapsedBottompadding; 632 return minExpandHeight; 633 } 634 635 public void setDark(boolean dark, boolean fade, long delay) { 636 if (mOverflowNumber != null) { 637 mOverflowInvertHelper.setInverted(dark, fade, delay); 638 } 639 } 640 641 public void reInflateViews() { 642 initDimens(); 643 for (int i = 0; i < mDividers.size(); i++) { 644 View prevDivider = mDividers.get(i); 645 int index = indexOfChild(prevDivider); 646 removeView(prevDivider); 647 View divider = inflateDivider(); 648 addView(divider, index); 649 mDividers.set(i, divider); 650 } 651 } 652 653 public void setUserLocked(boolean userLocked) { 654 mUserLocked = userLocked; 655 int childCount = mChildren.size(); 656 for (int i = 0; i < childCount; i++) { 657 ExpandableNotificationRow child = mChildren.get(i); 658 child.setUserLocked(userLocked); 659 } 660 } 661 662 public void onNotificationUpdated() { 663 mHybridGroupManager.setOverflowNumberColor(mOverflowNumber, 664 mNotificationParent.getNotificationColor()); 665 } 666} 667