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 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.annotation.ColorInt; 22 import android.app.ActivityManager; 23 import android.app.AlarmManager; 24 import android.content.BroadcastReceiver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.content.res.Configuration; 29 import android.content.res.Resources; 30 import android.graphics.Color; 31 import android.graphics.Rect; 32 import android.media.AudioManager; 33 import android.os.Handler; 34 import android.provider.AlarmClock; 35 import android.service.notification.ZenModeConfig; 36 import android.support.annotation.VisibleForTesting; 37 import android.text.format.DateUtils; 38 import android.util.AttributeSet; 39 import android.util.Log; 40 import android.util.Pair; 41 import android.view.View; 42 import android.view.WindowInsets; 43 import android.widget.ImageView; 44 import android.widget.LinearLayout; 45 import android.widget.RelativeLayout; 46 import android.widget.TextView; 47 48 import com.android.settingslib.Utils; 49 import com.android.systemui.BatteryMeterView; 50 import com.android.systemui.Dependency; 51 import com.android.systemui.Prefs; 52 import com.android.systemui.R; 53 import com.android.systemui.plugins.ActivityStarter; 54 import com.android.systemui.qs.QSDetail.Callback; 55 import com.android.systemui.statusbar.phone.PhoneStatusBarView; 56 import com.android.systemui.statusbar.phone.StatusBarIconController; 57 import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; 58 import com.android.systemui.statusbar.policy.Clock; 59 import com.android.systemui.statusbar.phone.StatusIconContainer; 60 import com.android.systemui.statusbar.policy.DarkIconDispatcher; 61 import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; 62 import com.android.systemui.statusbar.policy.DateView; 63 import com.android.systemui.statusbar.policy.NextAlarmController; 64 import com.android.systemui.statusbar.policy.ZenModeController; 65 66 import java.util.Locale; 67 import java.util.Objects; 68 69 /** 70 * View that contains the top-most bits of the screen (primarily the status bar with date, time, and 71 * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner 72 * contents. 73 */ 74 public class QuickStatusBarHeader extends RelativeLayout implements 75 View.OnClickListener, NextAlarmController.NextAlarmChangeCallback, 76 ZenModeController.Callback { 77 private static final String TAG = "QuickStatusBarHeader"; 78 private static final boolean DEBUG = false; 79 80 /** Delay for auto fading out the long press tooltip after it's fully visible (in ms). */ 81 private static final long AUTO_FADE_OUT_DELAY_MS = DateUtils.SECOND_IN_MILLIS * 6; 82 private static final int FADE_ANIMATION_DURATION_MS = 300; 83 private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0; 84 public static final int MAX_TOOLTIP_SHOWN_COUNT = 2; 85 86 private final Handler mHandler = new Handler(); 87 88 private QSPanel mQsPanel; 89 90 private boolean mExpanded; 91 private boolean mListening; 92 private boolean mQsDisabled; 93 94 protected QuickQSPanel mHeaderQsPanel; 95 protected QSTileHost mHost; 96 private TintedIconManager mIconManager; 97 private TouchAnimator mStatusIconsAlphaAnimator; 98 private TouchAnimator mHeaderTextContainerAlphaAnimator; 99 100 private View mSystemIconsView; 101 private View mQuickQsStatusIcons; 102 private View mHeaderTextContainerView; 103 /** View containing the next alarm and ringer mode info. */ 104 private View mStatusContainer; 105 /** Tooltip for educating users that they can long press on icons to see more details. */ 106 private View mLongPressTooltipView; 107 108 private int mRingerMode = AudioManager.RINGER_MODE_NORMAL; 109 private AlarmManager.AlarmClockInfo mNextAlarm; 110 111 private ImageView mNextAlarmIcon; 112 /** {@link TextView} containing the actual text indicating when the next alarm will go off. */ 113 private TextView mNextAlarmTextView; 114 private View mStatusSeparator; 115 private ImageView mRingerModeIcon; 116 private TextView mRingerModeTextView; 117 private BatteryMeterView mBatteryMeterView; 118 private Clock mClockView; 119 private DateView mDateView; 120 121 private NextAlarmController mAlarmController; 122 private ZenModeController mZenController; 123 /** Counts how many times the long press tooltip has been shown to the user. */ 124 private int mShownCount; 125 126 private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() { 127 @Override 128 public void onReceive(Context context, Intent intent) { 129 mRingerMode = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1); 130 updateStatusText(); 131 } 132 }; 133 134 /** 135 * Runnable for automatically fading out the long press tooltip (as if it were animating away). 136 */ 137 private final Runnable mAutoFadeOutTooltipRunnable = () -> hideLongPressTooltip(false); 138 QuickStatusBarHeader(Context context, AttributeSet attrs)139 public QuickStatusBarHeader(Context context, AttributeSet attrs) { 140 super(context, attrs); 141 mAlarmController = Dependency.get(NextAlarmController.class); 142 mZenController = Dependency.get(ZenModeController.class); 143 mShownCount = getStoredShownCount(); 144 } 145 146 @Override onFinishInflate()147 protected void onFinishInflate() { 148 super.onFinishInflate(); 149 150 mHeaderQsPanel = findViewById(R.id.quick_qs_panel); 151 mSystemIconsView = findViewById(R.id.quick_status_bar_system_icons); 152 mQuickQsStatusIcons = findViewById(R.id.quick_qs_status_icons); 153 StatusIconContainer iconContainer = findViewById(R.id.statusIcons); 154 iconContainer.setShouldRestrictIcons(false); 155 mIconManager = new TintedIconManager(iconContainer); 156 157 // Views corresponding to the header info section (e.g. tooltip and next alarm). 158 mHeaderTextContainerView = findViewById(R.id.header_text_container); 159 mLongPressTooltipView = findViewById(R.id.long_press_tooltip); 160 mStatusContainer = findViewById(R.id.status_container); 161 mStatusSeparator = findViewById(R.id.status_separator); 162 mNextAlarmIcon = findViewById(R.id.next_alarm_icon); 163 mNextAlarmTextView = findViewById(R.id.next_alarm_text); 164 mRingerModeIcon = findViewById(R.id.ringer_mode_icon); 165 mRingerModeTextView = findViewById(R.id.ringer_mode_text); 166 167 updateResources(); 168 169 Rect tintArea = new Rect(0, 0, 0, 0); 170 int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground); 171 float intensity = getColorIntensity(colorForeground); 172 int fillColor = fillColorForIntensity(intensity, getContext()); 173 174 // Set light text on the header icons because they will always be on a black background 175 applyDarkness(R.id.clock, tintArea, 0, DarkIconDispatcher.DEFAULT_ICON_TINT); 176 177 // Set the correct tint for the status icons so they contrast 178 mIconManager.setTint(fillColor); 179 180 mBatteryMeterView = findViewById(R.id.battery); 181 mBatteryMeterView.setForceShowPercent(true); 182 mBatteryMeterView.setOnClickListener(this); 183 mClockView = findViewById(R.id.clock); 184 mClockView.setOnClickListener(this); 185 mDateView = findViewById(R.id.date); 186 } 187 updateStatusText()188 private void updateStatusText() { 189 boolean changed = updateRingerStatus() || updateAlarmStatus(); 190 191 if (changed) { 192 boolean alarmVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE; 193 boolean ringerVisible = mRingerModeTextView.getVisibility() == View.VISIBLE; 194 mStatusSeparator.setVisibility(alarmVisible && ringerVisible ? View.VISIBLE 195 : View.GONE); 196 updateTooltipShow(); 197 } 198 } 199 updateRingerStatus()200 private boolean updateRingerStatus() { 201 boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE; 202 CharSequence originalRingerText = mRingerModeTextView.getText(); 203 204 boolean ringerVisible = false; 205 if (!ZenModeConfig.isZenOverridingRinger(mZenController.getZen(), 206 mZenController.getConfig())) { 207 if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { 208 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate); 209 mRingerModeTextView.setText(R.string.qs_status_phone_vibrate); 210 ringerVisible = true; 211 } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) { 212 mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent); 213 mRingerModeTextView.setText(R.string.qs_status_phone_muted); 214 ringerVisible = true; 215 } 216 } 217 mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); 218 mRingerModeTextView.setVisibility(ringerVisible ? View.VISIBLE : View.GONE); 219 220 return isOriginalVisible != ringerVisible || 221 !Objects.equals(originalRingerText, mRingerModeTextView.getText()); 222 } 223 updateAlarmStatus()224 private boolean updateAlarmStatus() { 225 boolean isOriginalVisible = mNextAlarmTextView.getVisibility() == View.VISIBLE; 226 CharSequence originalAlarmText = mNextAlarmTextView.getText(); 227 228 boolean alarmVisible = false; 229 if (mNextAlarm != null) { 230 alarmVisible = true; 231 mNextAlarmTextView.setText(formatNextAlarm(mNextAlarm)); 232 } 233 mNextAlarmIcon.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); 234 mNextAlarmTextView.setVisibility(alarmVisible ? View.VISIBLE : View.GONE); 235 236 return isOriginalVisible != alarmVisible || 237 !Objects.equals(originalAlarmText, mNextAlarmTextView.getText()); 238 } 239 applyDarkness(int id, Rect tintArea, float intensity, int color)240 private void applyDarkness(int id, Rect tintArea, float intensity, int color) { 241 View v = findViewById(id); 242 if (v instanceof DarkReceiver) { 243 ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color); 244 } 245 } 246 fillColorForIntensity(float intensity, Context context)247 private int fillColorForIntensity(float intensity, Context context) { 248 if (intensity == 0) { 249 return context.getColor(R.color.light_mode_icon_color_single_tone); 250 } 251 return context.getColor(R.color.dark_mode_icon_color_single_tone); 252 } 253 254 @Override onConfigurationChanged(Configuration newConfig)255 protected void onConfigurationChanged(Configuration newConfig) { 256 super.onConfigurationChanged(newConfig); 257 updateResources(); 258 259 // Update color schemes in landscape to use wallpaperTextColor 260 boolean shouldUseWallpaperTextColor = 261 newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE; 262 mBatteryMeterView.useWallpaperTextColor(shouldUseWallpaperTextColor); 263 mClockView.useWallpaperTextColor(shouldUseWallpaperTextColor); 264 } 265 266 @Override onRtlPropertiesChanged(int layoutDirection)267 public void onRtlPropertiesChanged(int layoutDirection) { 268 super.onRtlPropertiesChanged(layoutDirection); 269 updateResources(); 270 } 271 updateResources()272 private void updateResources() { 273 Resources resources = mContext.getResources(); 274 275 // Update height for a few views, especially due to landscape mode restricting space. 276 mHeaderTextContainerView.getLayoutParams().height = 277 resources.getDimensionPixelSize(R.dimen.qs_header_tooltip_height); 278 mHeaderTextContainerView.setLayoutParams(mHeaderTextContainerView.getLayoutParams()); 279 280 mSystemIconsView.getLayoutParams().height = resources.getDimensionPixelSize( 281 com.android.internal.R.dimen.quick_qs_offset_height); 282 mSystemIconsView.setLayoutParams(mSystemIconsView.getLayoutParams()); 283 284 getLayoutParams().height = resources.getDimensionPixelSize(mQsDisabled 285 ? com.android.internal.R.dimen.quick_qs_offset_height 286 : com.android.internal.R.dimen.quick_qs_total_height); 287 setLayoutParams(getLayoutParams()); 288 289 updateStatusIconAlphaAnimator(); 290 updateHeaderTextContainerAlphaAnimator(); 291 } 292 updateStatusIconAlphaAnimator()293 private void updateStatusIconAlphaAnimator() { 294 mStatusIconsAlphaAnimator = new TouchAnimator.Builder() 295 .addFloat(mQuickQsStatusIcons, "alpha", 1, 0) 296 .build(); 297 } 298 updateHeaderTextContainerAlphaAnimator()299 private void updateHeaderTextContainerAlphaAnimator() { 300 mHeaderTextContainerAlphaAnimator = new TouchAnimator.Builder() 301 .addFloat(mHeaderTextContainerView, "alpha", 0, 1) 302 .setStartDelay(.5f) 303 .build(); 304 } 305 setExpanded(boolean expanded)306 public void setExpanded(boolean expanded) { 307 if (mExpanded == expanded) return; 308 mExpanded = expanded; 309 mHeaderQsPanel.setExpanded(expanded); 310 updateEverything(); 311 } 312 313 /** 314 * Animates the inner contents based on the given expansion details. 315 * 316 * @param isKeyguardShowing whether or not we're showing the keyguard (a.k.a. lockscreen) 317 * @param expansionFraction how much the QS panel is expanded/pulled out (up to 1f) 318 * @param panelTranslationY how much the panel has physically moved down vertically (required 319 * for keyguard animations only) 320 */ setExpansion(boolean isKeyguardShowing, float expansionFraction, float panelTranslationY)321 public void setExpansion(boolean isKeyguardShowing, float expansionFraction, 322 float panelTranslationY) { 323 final float keyguardExpansionFraction = isKeyguardShowing ? 1f : expansionFraction; 324 if (mStatusIconsAlphaAnimator != null) { 325 mStatusIconsAlphaAnimator.setPosition(keyguardExpansionFraction); 326 } 327 328 if (isKeyguardShowing) { 329 // If the keyguard is showing, we want to offset the text so that it comes in at the 330 // same time as the panel as it slides down. 331 mHeaderTextContainerView.setTranslationY(panelTranslationY); 332 } else { 333 mHeaderTextContainerView.setTranslationY(0f); 334 } 335 336 if (mHeaderTextContainerAlphaAnimator != null) { 337 mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction); 338 } 339 340 // Check the original expansion fraction - we don't want to show the tooltip until the 341 // panel is pulled all the way out. 342 if (expansionFraction == 1f) { 343 // QS is fully expanded, bring in the tooltip. 344 showLongPressTooltip(); 345 } 346 } 347 348 /** Returns the latest stored tooltip shown count from SharedPreferences. */ getStoredShownCount()349 private int getStoredShownCount() { 350 return Prefs.getInt( 351 mContext, 352 Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, 353 TOOLTIP_NOT_YET_SHOWN_COUNT); 354 } 355 disable(int state1, int state2, boolean animate)356 public void disable(int state1, int state2, boolean animate) { 357 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0; 358 if (disabled == mQsDisabled) return; 359 mQsDisabled = disabled; 360 mHeaderQsPanel.setDisabledByPolicy(disabled); 361 mHeaderTextContainerView.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE); 362 mQuickQsStatusIcons.setVisibility(mQsDisabled ? View.GONE : View.VISIBLE); 363 updateResources(); 364 } 365 366 @Override onAttachedToWindow()367 public void onAttachedToWindow() { 368 super.onAttachedToWindow(); 369 Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager); 370 requestApplyInsets(); 371 } 372 373 @Override onApplyWindowInsets(WindowInsets insets)374 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 375 Pair<Integer, Integer> padding = PhoneStatusBarView.cornerCutoutMargins( 376 insets.getDisplayCutout(), getDisplay()); 377 if (padding == null) { 378 mSystemIconsView.setPaddingRelative( 379 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start), 0, 380 getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end), 0); 381 } else { 382 mSystemIconsView.setPadding(padding.first, 0, padding.second, 0); 383 384 } 385 return super.onApplyWindowInsets(insets); 386 } 387 388 @Override 389 @VisibleForTesting onDetachedFromWindow()390 public void onDetachedFromWindow() { 391 setListening(false); 392 Dependency.get(StatusBarIconController.class).removeIconGroup(mIconManager); 393 super.onDetachedFromWindow(); 394 } 395 setListening(boolean listening)396 public void setListening(boolean listening) { 397 if (listening == mListening) { 398 return; 399 } 400 mHeaderQsPanel.setListening(listening); 401 mListening = listening; 402 403 if (listening) { 404 mZenController.addCallback(this); 405 mAlarmController.addCallback(this); 406 mContext.registerReceiver(mRingerReceiver, 407 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); 408 } else { 409 mZenController.removeCallback(this); 410 mAlarmController.removeCallback(this); 411 mContext.unregisterReceiver(mRingerReceiver); 412 } 413 } 414 415 @Override onClick(View v)416 public void onClick(View v) { 417 if (v == mClockView) { 418 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent( 419 AlarmClock.ACTION_SHOW_ALARMS),0); 420 } else if (v == mBatteryMeterView) { 421 Dependency.get(ActivityStarter.class).postStartActivityDismissingKeyguard(new Intent( 422 Intent.ACTION_POWER_USAGE_SUMMARY),0); 423 } 424 } 425 426 @Override onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm)427 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { 428 mNextAlarm = nextAlarm; 429 updateStatusText(); 430 } 431 432 @Override onZenChanged(int zen)433 public void onZenChanged(int zen) { 434 updateStatusText(); 435 436 } 437 438 @Override onConfigChanged(ZenModeConfig config)439 public void onConfigChanged(ZenModeConfig config) { 440 updateStatusText(); 441 } 442 updateTooltipShow()443 private void updateTooltipShow() { 444 if (hasStatusText()) { 445 hideLongPressTooltip(true /* shouldShowStatusText */); 446 } else { 447 hideStatusText(); 448 } 449 updateHeaderTextContainerAlphaAnimator(); 450 } 451 hasStatusText()452 private boolean hasStatusText() { 453 return mNextAlarmTextView.getVisibility() == View.VISIBLE 454 || mRingerModeTextView.getVisibility() == View.VISIBLE; 455 } 456 457 /** 458 * Animates in the long press tooltip (as long as the next alarm text isn't currently occupying 459 * the space). 460 */ showLongPressTooltip()461 public void showLongPressTooltip() { 462 // If we have status text to show, don't bother fading in the tooltip. 463 if (hasStatusText()) { 464 return; 465 } 466 467 if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) { 468 mLongPressTooltipView.animate().cancel(); 469 mLongPressTooltipView.setVisibility(View.VISIBLE); 470 mLongPressTooltipView.animate() 471 .alpha(1f) 472 .setDuration(FADE_ANIMATION_DURATION_MS) 473 .setListener(new AnimatorListenerAdapter() { 474 @Override 475 public void onAnimationEnd(Animator animation) { 476 mHandler.postDelayed( 477 mAutoFadeOutTooltipRunnable, AUTO_FADE_OUT_DELAY_MS); 478 } 479 }) 480 .start(); 481 482 // Increment and drop the shown count in prefs for the next time we're deciding to 483 // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet 484 // in prefs (say, from a long press). 485 if (getStoredShownCount() <= mShownCount) { 486 Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount); 487 } 488 } 489 } 490 491 /** 492 * Fades out the long press tooltip if it's partially visible - short circuits any running 493 * animation. Additionally has the ability to fade in the status info text. 494 * 495 * @param shouldShowStatusText whether we should fade in the status text 496 */ hideLongPressTooltip(boolean shouldShowStatusText)497 private void hideLongPressTooltip(boolean shouldShowStatusText) { 498 mLongPressTooltipView.animate().cancel(); 499 if (mLongPressTooltipView.getVisibility() == View.VISIBLE 500 && mLongPressTooltipView.getAlpha() != 0f) { 501 mHandler.removeCallbacks(mAutoFadeOutTooltipRunnable); 502 mLongPressTooltipView.animate() 503 .alpha(0f) 504 .setDuration(FADE_ANIMATION_DURATION_MS) 505 .setListener(new AnimatorListenerAdapter() { 506 @Override 507 public void onAnimationEnd(Animator animation) { 508 if (DEBUG) Log.d(TAG, "hideLongPressTooltip: Hid long press tip"); 509 mLongPressTooltipView.setVisibility(View.INVISIBLE); 510 511 if (shouldShowStatusText) { 512 showStatus(); 513 } 514 } 515 }) 516 .start(); 517 } else { 518 mLongPressTooltipView.setVisibility(View.INVISIBLE); 519 if (shouldShowStatusText) { 520 showStatus(); 521 } 522 } 523 } 524 525 /** 526 * Fades in the updated status text. Note that if there's already a status showing, this will 527 * immediately hide it and fade in the updated status. 528 */ showStatus()529 private void showStatus() { 530 mStatusContainer.setAlpha(0f); 531 mStatusContainer.setVisibility(View.VISIBLE); 532 533 // Animate the alarm back in. Make sure to clear the animator listener for the animation! 534 mStatusContainer.animate() 535 .alpha(1f) 536 .setDuration(FADE_ANIMATION_DURATION_MS) 537 .setListener(null) 538 .start(); 539 } 540 541 /** Fades out and hides the status text. */ hideStatusText()542 private void hideStatusText() { 543 if (mStatusContainer.getVisibility() == View.VISIBLE) { 544 mStatusContainer.animate() 545 .alpha(0f) 546 .setListener(new AnimatorListenerAdapter() { 547 @Override 548 public void onAnimationEnd(Animator animation) { 549 if (DEBUG) Log.d(TAG, "hideAlarmText: Hid alarm text"); 550 551 // Reset the alpha regardless of how the animation ends for the next 552 // time we show this view/want to animate it. 553 mStatusContainer.setVisibility(View.INVISIBLE); 554 mStatusContainer.setAlpha(1f); 555 } 556 }) 557 .start(); 558 } 559 } 560 updateEverything()561 public void updateEverything() { 562 post(() -> setClickable(false)); 563 } 564 setQSPanel(final QSPanel qsPanel)565 public void setQSPanel(final QSPanel qsPanel) { 566 mQsPanel = qsPanel; 567 setupHost(qsPanel.getHost()); 568 } 569 setupHost(final QSTileHost host)570 public void setupHost(final QSTileHost host) { 571 mHost = host; 572 //host.setHeaderView(mExpandIndicator); 573 mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this); 574 mHeaderQsPanel.setHost(host, null /* No customization in header */); 575 576 // Use SystemUI context to get battery meter colors, and let it use the default tint (white) 577 mBatteryMeterView.setColorsFromContext(mHost.getContext()); 578 mBatteryMeterView.onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT); 579 } 580 setCallback(Callback qsPanelCallback)581 public void setCallback(Callback qsPanelCallback) { 582 mHeaderQsPanel.setCallback(qsPanelCallback); 583 } 584 formatNextAlarm(AlarmManager.AlarmClockInfo info)585 private String formatNextAlarm(AlarmManager.AlarmClockInfo info) { 586 if (info == null) { 587 return ""; 588 } 589 String skeleton = android.text.format.DateFormat 590 .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma"; 591 String pattern = android.text.format.DateFormat 592 .getBestDateTimePattern(Locale.getDefault(), skeleton); 593 return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString(); 594 } 595 getColorIntensity(@olorInt int color)596 public static float getColorIntensity(@ColorInt int color) { 597 return color == Color.WHITE ? 0 : 1; 598 } 599 setMargins(int sideMargins)600 public void setMargins(int sideMargins) { 601 for (int i = 0; i < getChildCount(); i++) { 602 View v = getChildAt(i); 603 if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel) { 604 continue; 605 } 606 RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams(); 607 lp.leftMargin = sideMargins; 608 lp.rightMargin = sideMargins; 609 } 610 } 611 } 612