1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui.qs; 16 17 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; 18 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 19 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.content.res.Resources; 23 import android.graphics.Color; 24 import android.graphics.Rect; 25 import android.util.AttributeSet; 26 import android.util.Pair; 27 import android.view.DisplayCutout; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.view.WindowInsets; 31 import android.widget.FrameLayout; 32 import android.widget.LinearLayout; 33 import android.widget.Space; 34 35 import androidx.annotation.NonNull; 36 37 import com.android.internal.policy.SystemBarUtils; 38 import com.android.settingslib.Utils; 39 import com.android.systemui.R; 40 import com.android.systemui.battery.BatteryMeterView; 41 import com.android.systemui.qs.QSDetail.Callback; 42 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider; 43 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; 44 import com.android.systemui.statusbar.phone.StatusIconContainer; 45 import com.android.systemui.statusbar.policy.Clock; 46 import com.android.systemui.statusbar.policy.VariableDateView; 47 48 import java.util.List; 49 50 /** 51 * View that contains the top-most bits of the QS panel (primarily the status bar with date, time, 52 * battery, carrier info and privacy icons) and also contains the {@link QuickQSPanel}. 53 */ 54 public class QuickStatusBarHeader extends FrameLayout { 55 56 private boolean mExpanded; 57 private boolean mQsDisabled; 58 59 private TouchAnimator mAlphaAnimator; 60 private TouchAnimator mTranslationAnimator; 61 private TouchAnimator mIconsAlphaAnimator; 62 private TouchAnimator mIconsAlphaAnimatorFixed; 63 64 protected QuickQSPanel mHeaderQsPanel; 65 private View mDatePrivacyView; 66 private View mDateView; 67 // DateView next to clock. Visible on QQS 68 private VariableDateView mClockDateView; 69 private View mSecurityHeaderView; 70 private View mStatusIconsView; 71 private View mContainer; 72 73 private View mQSCarriers; 74 private ViewGroup mClockContainer; 75 private Clock mClockView; 76 private Space mDatePrivacySeparator; 77 private View mClockIconsSeparator; 78 private boolean mShowClockIconsSeparator; 79 private View mRightLayout; 80 private View mDateContainer; 81 private View mPrivacyContainer; 82 83 private BatteryMeterView mBatteryRemainingIcon; 84 private StatusIconContainer mIconContainer; 85 private View mPrivacyChip; 86 87 private TintedIconManager mTintedIconManager; 88 private QSExpansionPathInterpolator mQSExpansionPathInterpolator; 89 private StatusBarContentInsetsProvider mInsetsProvider; 90 91 private int mRoundedCornerPadding = 0; 92 private int mWaterfallTopInset; 93 private int mCutOutPaddingLeft; 94 private int mCutOutPaddingRight; 95 private float mKeyguardExpansionFraction; 96 private int mTextColorPrimary = Color.TRANSPARENT; 97 private int mTopViewMeasureHeight; 98 99 @NonNull 100 private List<String> mRssiIgnoredSlots; 101 private boolean mIsSingleCarrier; 102 103 private boolean mHasCenterCutout; 104 private boolean mConfigShowBatteryEstimate; 105 106 private boolean mUseCombinedQSHeader; 107 QuickStatusBarHeader(Context context, AttributeSet attrs)108 public QuickStatusBarHeader(Context context, AttributeSet attrs) { 109 super(context, attrs); 110 } 111 112 /** 113 * How much the view containing the clock and QQS will translate down when QS is fully expanded. 114 * 115 * This matches the measured height of the view containing the date and privacy icons. 116 */ getOffsetTranslation()117 public int getOffsetTranslation() { 118 return mTopViewMeasureHeight; 119 } 120 121 @Override onFinishInflate()122 protected void onFinishInflate() { 123 super.onFinishInflate(); 124 125 mHeaderQsPanel = findViewById(R.id.quick_qs_panel); 126 mDatePrivacyView = findViewById(R.id.quick_status_bar_date_privacy); 127 mStatusIconsView = findViewById(R.id.quick_qs_status_icons); 128 mQSCarriers = findViewById(R.id.carrier_group); 129 mContainer = findViewById(R.id.qs_container); 130 mIconContainer = findViewById(R.id.statusIcons); 131 mPrivacyChip = findViewById(R.id.privacy_chip); 132 mDateView = findViewById(R.id.date); 133 mClockDateView = findViewById(R.id.date_clock); 134 mSecurityHeaderView = findViewById(R.id.header_text_container); 135 mClockIconsSeparator = findViewById(R.id.separator); 136 mRightLayout = findViewById(R.id.rightLayout); 137 mDateContainer = findViewById(R.id.date_container); 138 mPrivacyContainer = findViewById(R.id.privacy_container); 139 140 mClockContainer = findViewById(R.id.clock_container); 141 mClockView = findViewById(R.id.clock); 142 mDatePrivacySeparator = findViewById(R.id.space); 143 // Tint for the battery icons are handled in setupHost() 144 mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon); 145 146 updateResources(); 147 Configuration config = mContext.getResources().getConfiguration(); 148 setDatePrivacyContainersWidth(config.orientation == Configuration.ORIENTATION_LANDSCAPE); 149 setSecurityHeaderContainerVisibility( 150 config.orientation == Configuration.ORIENTATION_LANDSCAPE); 151 152 // QS will always show the estimate, and BatteryMeterView handles the case where 153 // it's unavailable or charging 154 mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); 155 156 mIconsAlphaAnimatorFixed = new TouchAnimator.Builder() 157 .addFloat(mIconContainer, "alpha", 0, 1) 158 .addFloat(mBatteryRemainingIcon, "alpha", 0, 1) 159 .build(); 160 } 161 onAttach(TintedIconManager iconManager, QSExpansionPathInterpolator qsExpansionPathInterpolator, List<String> rssiIgnoredSlots, boolean useCombinedQSHeader, StatusBarContentInsetsProvider insetsProvider)162 void onAttach(TintedIconManager iconManager, 163 QSExpansionPathInterpolator qsExpansionPathInterpolator, 164 List<String> rssiIgnoredSlots, 165 boolean useCombinedQSHeader, 166 StatusBarContentInsetsProvider insetsProvider) { 167 mUseCombinedQSHeader = useCombinedQSHeader; 168 mTintedIconManager = iconManager; 169 mRssiIgnoredSlots = rssiIgnoredSlots; 170 mInsetsProvider = insetsProvider; 171 int fillColor = Utils.getColorAttrDefaultColor(getContext(), 172 android.R.attr.textColorPrimary); 173 174 // Set the correct tint for the status icons so they contrast 175 iconManager.setTint(fillColor); 176 177 mQSExpansionPathInterpolator = qsExpansionPathInterpolator; 178 updateAnimators(); 179 } 180 setIsSingleCarrier(boolean isSingleCarrier)181 void setIsSingleCarrier(boolean isSingleCarrier) { 182 mIsSingleCarrier = isSingleCarrier; 183 updateAlphaAnimator(); 184 } 185 getHeaderQsPanel()186 public QuickQSPanel getHeaderQsPanel() { 187 return mHeaderQsPanel; 188 } 189 190 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)191 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 192 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 193 if (mDatePrivacyView.getMeasuredHeight() != mTopViewMeasureHeight) { 194 mTopViewMeasureHeight = mDatePrivacyView.getMeasuredHeight(); 195 post(this::updateAnimators); 196 } 197 } 198 199 @Override onConfigurationChanged(Configuration newConfig)200 protected void onConfigurationChanged(Configuration newConfig) { 201 super.onConfigurationChanged(newConfig); 202 updateResources(); 203 setDatePrivacyContainersWidth(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE); 204 setSecurityHeaderContainerVisibility( 205 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE); 206 } 207 208 @Override onRtlPropertiesChanged(int layoutDirection)209 public void onRtlPropertiesChanged(int layoutDirection) { 210 super.onRtlPropertiesChanged(layoutDirection); 211 updateResources(); 212 } 213 setDatePrivacyContainersWidth(boolean landscape)214 private void setDatePrivacyContainersWidth(boolean landscape) { 215 LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mDateContainer.getLayoutParams(); 216 lp.width = landscape ? WRAP_CONTENT : 0; 217 lp.weight = landscape ? 0f : 1f; 218 mDateContainer.setLayoutParams(lp); 219 220 lp = (LinearLayout.LayoutParams) mPrivacyContainer.getLayoutParams(); 221 lp.width = landscape ? WRAP_CONTENT : 0; 222 lp.weight = landscape ? 0f : 1f; 223 mPrivacyContainer.setLayoutParams(lp); 224 } 225 setSecurityHeaderContainerVisibility(boolean landscape)226 private void setSecurityHeaderContainerVisibility(boolean landscape) { 227 mSecurityHeaderView.setVisibility(landscape ? VISIBLE : GONE); 228 } 229 updateBatteryMode()230 private void updateBatteryMode() { 231 if (mConfigShowBatteryEstimate && !mHasCenterCutout) { 232 mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); 233 } else { 234 mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ON); 235 } 236 } 237 updateResources()238 void updateResources() { 239 Resources resources = mContext.getResources(); 240 // status bar is already displayed out of QS in split shade 241 boolean shouldUseSplitShade = 242 resources.getBoolean(R.bool.config_use_split_notification_shade); 243 244 boolean gone = shouldUseSplitShade || mUseCombinedQSHeader || mQsDisabled; 245 mStatusIconsView.setVisibility(gone ? View.GONE : View.VISIBLE); 246 mDatePrivacyView.setVisibility(gone ? View.GONE : View.VISIBLE); 247 248 mConfigShowBatteryEstimate = resources.getBoolean(R.bool.config_showBatteryEstimateQSBH); 249 250 mRoundedCornerPadding = resources.getDimensionPixelSize( 251 R.dimen.rounded_corner_content_padding); 252 253 int qsOffsetHeight = SystemBarUtils.getQuickQsOffsetHeight(mContext); 254 255 mDatePrivacyView.getLayoutParams().height = 256 Math.max(qsOffsetHeight, mDatePrivacyView.getMinimumHeight()); 257 mDatePrivacyView.setLayoutParams(mDatePrivacyView.getLayoutParams()); 258 259 mStatusIconsView.getLayoutParams().height = 260 Math.max(qsOffsetHeight, mStatusIconsView.getMinimumHeight()); 261 mStatusIconsView.setLayoutParams(mStatusIconsView.getLayoutParams()); 262 263 ViewGroup.LayoutParams lp = getLayoutParams(); 264 if (mQsDisabled) { 265 lp.height = mStatusIconsView.getLayoutParams().height; 266 } else { 267 lp.height = WRAP_CONTENT; 268 } 269 setLayoutParams(lp); 270 271 int textColor = Utils.getColorAttrDefaultColor(mContext, android.R.attr.textColorPrimary); 272 if (textColor != mTextColorPrimary) { 273 int textColorSecondary = Utils.getColorAttrDefaultColor(mContext, 274 android.R.attr.textColorSecondary); 275 mTextColorPrimary = textColor; 276 mClockView.setTextColor(textColor); 277 if (mTintedIconManager != null) { 278 mTintedIconManager.setTint(textColor); 279 } 280 mBatteryRemainingIcon.updateColors(mTextColorPrimary, textColorSecondary, 281 mTextColorPrimary); 282 } 283 284 MarginLayoutParams qqsLP = (MarginLayoutParams) mHeaderQsPanel.getLayoutParams(); 285 qqsLP.topMargin = shouldUseSplitShade || !mUseCombinedQSHeader ? mContext.getResources() 286 .getDimensionPixelSize(R.dimen.qqs_layout_margin_top) : qsOffsetHeight; 287 mHeaderQsPanel.setLayoutParams(qqsLP); 288 289 updateBatteryMode(); 290 updateHeadersPadding(); 291 updateAnimators(); 292 293 updateClockDatePadding(); 294 } 295 updateClockDatePadding()296 private void updateClockDatePadding() { 297 int startPadding = mContext.getResources() 298 .getDimensionPixelSize(R.dimen.status_bar_left_clock_starting_padding); 299 int endPadding = mContext.getResources() 300 .getDimensionPixelSize(R.dimen.status_bar_left_clock_end_padding); 301 mClockView.setPaddingRelative( 302 startPadding, 303 mClockView.getPaddingTop(), 304 endPadding, 305 mClockView.getPaddingBottom() 306 ); 307 308 MarginLayoutParams lp = (MarginLayoutParams) mClockDateView.getLayoutParams(); 309 lp.setMarginStart(endPadding); 310 mClockDateView.setLayoutParams(lp); 311 } 312 updateAnimators()313 private void updateAnimators() { 314 if (mUseCombinedQSHeader) { 315 mTranslationAnimator = null; 316 return; 317 } 318 updateAlphaAnimator(); 319 int offset = mTopViewMeasureHeight; 320 321 mTranslationAnimator = new TouchAnimator.Builder() 322 .addFloat(mContainer, "translationY", 0, offset) 323 .setInterpolator(mQSExpansionPathInterpolator != null 324 ? mQSExpansionPathInterpolator.getYInterpolator() 325 : null) 326 .build(); 327 } 328 updateAlphaAnimator()329 private void updateAlphaAnimator() { 330 if (mUseCombinedQSHeader) { 331 mAlphaAnimator = null; 332 return; 333 } 334 TouchAnimator.Builder builder = new TouchAnimator.Builder() 335 .addFloat(mSecurityHeaderView, "alpha", 0, 1) 336 // These views appear on expanding down 337 .addFloat(mDateView, "alpha", 0, 0, 1) 338 .addFloat(mClockDateView, "alpha", 1, 0, 0) 339 .addFloat(mQSCarriers, "alpha", 0, 1) 340 .setListener(new TouchAnimator.ListenerAdapter() { 341 @Override 342 public void onAnimationAtEnd() { 343 super.onAnimationAtEnd(); 344 if (!mIsSingleCarrier) { 345 mIconContainer.addIgnoredSlots(mRssiIgnoredSlots); 346 } 347 // Make it gone so there's enough room for carrier names 348 mClockDateView.setVisibility(View.GONE); 349 } 350 351 @Override 352 public void onAnimationStarted() { 353 mClockDateView.setVisibility(View.VISIBLE); 354 mClockDateView.setFreezeSwitching(true); 355 setSeparatorVisibility(false); 356 if (!mIsSingleCarrier) { 357 mIconContainer.addIgnoredSlots(mRssiIgnoredSlots); 358 } 359 } 360 361 @Override 362 public void onAnimationAtStart() { 363 super.onAnimationAtStart(); 364 mClockDateView.setFreezeSwitching(false); 365 mClockDateView.setVisibility(View.VISIBLE); 366 setSeparatorVisibility(mShowClockIconsSeparator); 367 // In QQS we never ignore RSSI. 368 mIconContainer.removeIgnoredSlots(mRssiIgnoredSlots); 369 } 370 }); 371 mAlphaAnimator = builder.build(); 372 } 373 setChipVisibility(boolean visibility)374 void setChipVisibility(boolean visibility) { 375 if (visibility) { 376 // Animates the icons and battery indicator from alpha 0 to 1, when the chip is visible 377 mIconsAlphaAnimator = mIconsAlphaAnimatorFixed; 378 mIconsAlphaAnimator.setPosition(mKeyguardExpansionFraction); 379 } else { 380 mIconsAlphaAnimator = null; 381 mIconContainer.setAlpha(1); 382 mBatteryRemainingIcon.setAlpha(1); 383 } 384 385 } 386 387 /** */ setExpanded(boolean expanded, QuickQSPanelController quickQSPanelController)388 public void setExpanded(boolean expanded, QuickQSPanelController quickQSPanelController) { 389 if (mExpanded == expanded) return; 390 mExpanded = expanded; 391 quickQSPanelController.setExpanded(expanded); 392 updateEverything(); 393 } 394 395 /** 396 * Animates the inner contents based on the given expansion details. 397 * 398 * @param forceExpanded whether we should show the state expanded forcibly 399 * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f) 400 * @param panelTranslationY how much the panel has physically moved down vertically (required 401 * for keyguard animations only) 402 */ setExpansion(boolean forceExpanded, float expansionFraction, float panelTranslationY)403 public void setExpansion(boolean forceExpanded, float expansionFraction, 404 float panelTranslationY) { 405 final float keyguardExpansionFraction = forceExpanded ? 1f : expansionFraction; 406 407 if (mAlphaAnimator != null) { 408 mAlphaAnimator.setPosition(keyguardExpansionFraction); 409 } 410 if (mTranslationAnimator != null) { 411 mTranslationAnimator.setPosition(keyguardExpansionFraction); 412 } 413 if (mIconsAlphaAnimator != null) { 414 mIconsAlphaAnimator.setPosition(keyguardExpansionFraction); 415 } 416 // If forceExpanded (we are opening QS from lockscreen), the animators have been set to 417 // position = 1f. 418 if (forceExpanded) { 419 setTranslationY(panelTranslationY); 420 } else { 421 setTranslationY(0); 422 } 423 424 mKeyguardExpansionFraction = keyguardExpansionFraction; 425 } 426 disable(int state1, int state2, boolean animate)427 public void disable(int state1, int state2, boolean animate) { 428 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0; 429 if (disabled == mQsDisabled) return; 430 mQsDisabled = disabled; 431 mHeaderQsPanel.setDisabledByPolicy(disabled); 432 mStatusIconsView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE); 433 updateResources(); 434 } 435 436 @Override onApplyWindowInsets(WindowInsets insets)437 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 438 // Handle padding of the views 439 DisplayCutout cutout = insets.getDisplayCutout(); 440 441 Pair<Integer, Integer> sbInsets = mInsetsProvider 442 .getStatusBarContentInsetsForCurrentRotation(); 443 boolean hasCornerCutout = mInsetsProvider.currentRotationHasCornerCutout(); 444 445 mDatePrivacyView.setPadding(sbInsets.first, 0, sbInsets.second, 0); 446 mStatusIconsView.setPadding(sbInsets.first, 0, sbInsets.second, 0); 447 LinearLayout.LayoutParams datePrivacySeparatorLayoutParams = 448 (LinearLayout.LayoutParams) mDatePrivacySeparator.getLayoutParams(); 449 LinearLayout.LayoutParams mClockIconsSeparatorLayoutParams = 450 (LinearLayout.LayoutParams) mClockIconsSeparator.getLayoutParams(); 451 if (cutout != null) { 452 Rect topCutout = cutout.getBoundingRectTop(); 453 if (topCutout.isEmpty() || hasCornerCutout) { 454 datePrivacySeparatorLayoutParams.width = 0; 455 mDatePrivacySeparator.setVisibility(View.GONE); 456 mClockIconsSeparatorLayoutParams.width = 0; 457 setSeparatorVisibility(false); 458 mShowClockIconsSeparator = false; 459 mHasCenterCutout = false; 460 } else { 461 datePrivacySeparatorLayoutParams.width = topCutout.width(); 462 mDatePrivacySeparator.setVisibility(View.VISIBLE); 463 mClockIconsSeparatorLayoutParams.width = topCutout.width(); 464 mShowClockIconsSeparator = true; 465 setSeparatorVisibility(mKeyguardExpansionFraction == 0f); 466 mHasCenterCutout = true; 467 } 468 } 469 mDatePrivacySeparator.setLayoutParams(datePrivacySeparatorLayoutParams); 470 mClockIconsSeparator.setLayoutParams(mClockIconsSeparatorLayoutParams); 471 mCutOutPaddingLeft = sbInsets.first; 472 mCutOutPaddingRight = sbInsets.second; 473 mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top; 474 475 updateBatteryMode(); 476 updateHeadersPadding(); 477 return super.onApplyWindowInsets(insets); 478 } 479 480 /** 481 * Sets the visibility of the separator between clock and icons. 482 * 483 * This separator is "visible" when there is a center cutout, to block that space. In that 484 * case, the clock and the layout on the right (containing the icons and the battery meter) are 485 * set to weight 1 to take the available space. 486 * @param visible whether the separator between clock and icons should be visible. 487 */ setSeparatorVisibility(boolean visible)488 private void setSeparatorVisibility(boolean visible) { 489 int newVisibility = visible ? View.VISIBLE : View.GONE; 490 if (mClockIconsSeparator.getVisibility() == newVisibility) return; 491 492 mClockIconsSeparator.setVisibility(visible ? View.VISIBLE : View.GONE); 493 mQSCarriers.setVisibility(visible ? View.GONE : View.VISIBLE); 494 495 LinearLayout.LayoutParams lp = 496 (LinearLayout.LayoutParams) mClockContainer.getLayoutParams(); 497 lp.width = visible ? 0 : WRAP_CONTENT; 498 lp.weight = visible ? 1f : 0f; 499 mClockContainer.setLayoutParams(lp); 500 501 lp = (LinearLayout.LayoutParams) mRightLayout.getLayoutParams(); 502 lp.width = visible ? 0 : WRAP_CONTENT; 503 lp.weight = visible ? 1f : 0f; 504 mRightLayout.setLayoutParams(lp); 505 } 506 updateHeadersPadding()507 private void updateHeadersPadding() { 508 setContentMargins(mDatePrivacyView, 0, 0); 509 setContentMargins(mStatusIconsView, 0, 0); 510 int paddingLeft = 0; 511 int paddingRight = 0; 512 513 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); 514 int leftMargin = lp.leftMargin; 515 int rightMargin = lp.rightMargin; 516 517 // The clock might collide with cutouts, let's shift it out of the way. 518 // We only do that if the inset is bigger than our own padding, since it's nicer to 519 // align with 520 if (mCutOutPaddingLeft > 0) { 521 // if there's a cutout, let's use at least the rounded corner inset 522 int cutoutPadding = Math.max(mCutOutPaddingLeft, mRoundedCornerPadding); 523 paddingLeft = Math.max(cutoutPadding - leftMargin, 0); 524 } 525 if (mCutOutPaddingRight > 0) { 526 // if there's a cutout, let's use at least the rounded corner inset 527 int cutoutPadding = Math.max(mCutOutPaddingRight, mRoundedCornerPadding); 528 paddingRight = Math.max(cutoutPadding - rightMargin, 0); 529 } 530 531 mDatePrivacyView.setPadding(paddingLeft, 532 mWaterfallTopInset, 533 paddingRight, 534 0); 535 mStatusIconsView.setPadding(paddingLeft, 536 mWaterfallTopInset, 537 paddingRight, 538 0); 539 } 540 updateEverything()541 public void updateEverything() { 542 post(() -> setClickable(!mExpanded)); 543 } 544 setCallback(Callback qsPanelCallback)545 public void setCallback(Callback qsPanelCallback) { 546 mHeaderQsPanel.setCallback(qsPanelCallback); 547 } 548 setContentMargins(View view, int marginStart, int marginEnd)549 private void setContentMargins(View view, int marginStart, int marginEnd) { 550 MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams(); 551 lp.setMarginStart(marginStart); 552 lp.setMarginEnd(marginEnd); 553 view.setLayoutParams(lp); 554 } 555 556 /** 557 * Scroll the headers away. 558 * 559 * @param scrollY the scroll of the QSPanel container 560 */ setExpandedScrollAmount(int scrollY)561 public void setExpandedScrollAmount(int scrollY) { 562 mStatusIconsView.setScrollY(scrollY); 563 mDatePrivacyView.setScrollY(scrollY); 564 } 565 } 566