StatusBarHeaderView.java revision 7af40415dc2aa510bdb483519726aa3ae75bd765
1/* 2 * Copyright (C) 2014 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.phone; 18 19import android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.content.Context; 22import android.content.Intent; 23import android.graphics.Outline; 24import android.graphics.Rect; 25import android.graphics.drawable.Animatable; 26import android.graphics.drawable.Drawable; 27import android.util.AttributeSet; 28import android.util.TypedValue; 29import android.view.View; 30import android.view.ViewGroup; 31import android.view.ViewOutlineProvider; 32import android.widget.ImageView; 33import android.widget.LinearLayout; 34import android.widget.RelativeLayout; 35import android.widget.Switch; 36import android.widget.TextView; 37 38import com.android.keyguard.KeyguardStatusView; 39import com.android.systemui.R; 40import com.android.systemui.qs.QSPanel; 41import com.android.systemui.qs.QSTile; 42import com.android.systemui.statusbar.policy.BatteryController; 43import com.android.systemui.statusbar.policy.NextAlarmController; 44import com.android.systemui.statusbar.policy.UserInfoController; 45 46/** 47 * The view to manage the header area in the expanded status bar. 48 */ 49public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener, 50 BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback { 51 52 private boolean mExpanded; 53 private boolean mListening; 54 55 private ViewGroup mSystemIconsContainer; 56 private View mSystemIconsSuperContainer; 57 private View mDateGroup; 58 private View mClock; 59 private TextView mTime; 60 private View mAmPm; 61 private MultiUserSwitch mMultiUserSwitch; 62 private ImageView mMultiUserAvatar; 63 private View mDateCollapsed; 64 private View mDateExpanded; 65 private LinearLayout mSystemIcons; 66 private View mStatusIcons; 67 private View mSignalCluster; 68 private View mSettingsButton; 69 private View mQsDetailHeader; 70 private TextView mQsDetailHeaderTitle; 71 private Switch mQsDetailHeaderSwitch; 72 private ImageView mQsDetailHeaderProgress; 73 private View mEmergencyCallsOnly; 74 private TextView mBatteryLevel; 75 private TextView mAlarmStatus; 76 77 private boolean mShowEmergencyCallsOnly; 78 private boolean mAlarmShowing; 79 private AlarmManager.AlarmClockInfo mNextAlarm; 80 81 private int mCollapsedHeight; 82 private int mExpandedHeight; 83 84 private int mMultiUserExpandedMargin; 85 private int mMultiUserCollapsedMargin; 86 87 private int mClockMarginBottomExpanded; 88 private int mClockMarginBottomCollapsed; 89 private int mMultiUserSwitchWidthCollapsed; 90 private int mMultiUserSwitchWidthExpanded; 91 92 private int mClockCollapsedSize; 93 private int mClockExpandedSize; 94 95 /** 96 * In collapsed QS, the clock and avatar are scaled down a bit post-layout to allow for a nice 97 * transition. These values determine that factor. 98 */ 99 private float mClockCollapsedScaleFactor; 100 private float mAvatarCollapsedScaleFactor; 101 102 private ActivityStarter mActivityStarter; 103 private BatteryController mBatteryController; 104 private NextAlarmController mNextAlarmController; 105 private QSPanel mQSPanel; 106 107 108 private final Rect mClipBounds = new Rect(); 109 110 private boolean mCaptureValues; 111 private boolean mSignalClusterDetached; 112 private final LayoutValues mCollapsedValues = new LayoutValues(); 113 private final LayoutValues mExpandedValues = new LayoutValues(); 114 private final LayoutValues mCurrentValues = new LayoutValues(); 115 116 private float mCurrentT; 117 private boolean mShowingDetail; 118 119 public StatusBarHeaderView(Context context, AttributeSet attrs) { 120 super(context, attrs); 121 } 122 123 @Override 124 protected void onFinishInflate() { 125 super.onFinishInflate(); 126 mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container); 127 mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container); 128 mSystemIconsSuperContainer.setOnClickListener(this); 129 mDateGroup = findViewById(R.id.date_group); 130 mClock = findViewById(R.id.clock); 131 mTime = (TextView) findViewById(R.id.time_view); 132 mAmPm = findViewById(R.id.am_pm_view); 133 mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch); 134 mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar); 135 mDateCollapsed = findViewById(R.id.date_collapsed); 136 mDateExpanded = findViewById(R.id.date_expanded); 137 mSettingsButton = findViewById(R.id.settings_button); 138 mSettingsButton.setOnClickListener(this); 139 mQsDetailHeader = findViewById(R.id.qs_detail_header); 140 mQsDetailHeader.setAlpha(0); 141 mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title); 142 mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle); 143 mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress); 144 mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only); 145 mBatteryLevel = (TextView) findViewById(R.id.battery_level); 146 mAlarmStatus = (TextView) findViewById(R.id.alarm_status); 147 mAlarmStatus.setOnClickListener(this); 148 loadDimens(); 149 updateVisibilities(); 150 updateClockScale(); 151 updateAvatarScale(); 152 addOnLayoutChangeListener(new View.OnLayoutChangeListener() { 153 @Override 154 public void onLayoutChange(View v, int left, int top, int right, 155 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 156 if ((right - left) != (oldRight - oldLeft)) { 157 // width changed, update clipping 158 setClipping(getHeight()); 159 } 160 boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; 161 mTime.setPivotX(rtl ? mTime.getWidth() : 0); 162 mTime.setPivotY(mTime.getBaseline()); 163 updateAmPmTranslation(); 164 } 165 }); 166 setOutlineProvider(new ViewOutlineProvider() { 167 @Override 168 public void getOutline(View view, Outline outline) { 169 outline.setRect(mClipBounds); 170 } 171 }); 172 requestCaptureValues(); 173 } 174 175 @Override 176 protected void onLayout(boolean changed, int l, int t, int r, int b) { 177 super.onLayout(changed, l, t, r, b); 178 if (mCaptureValues) { 179 if (mExpanded) { 180 captureLayoutValues(mExpandedValues); 181 } else { 182 captureLayoutValues(mCollapsedValues); 183 } 184 mCaptureValues = false; 185 updateLayoutValues(mCurrentT); 186 } 187 mAlarmStatus.setX(mDateGroup.getLeft() + mDateCollapsed.getRight()); 188 } 189 190 private void requestCaptureValues() { 191 mCaptureValues = true; 192 requestLayout(); 193 } 194 195 private void loadDimens() { 196 mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height); 197 mExpandedHeight = getResources().getDimensionPixelSize( 198 R.dimen.status_bar_header_height_expanded); 199 mMultiUserExpandedMargin = 200 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin); 201 mMultiUserCollapsedMargin = 202 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_collapsed_margin); 203 204 mClockMarginBottomExpanded = 205 getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin); 206 mClockMarginBottomCollapsed = 207 getResources().getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin); 208 mMultiUserSwitchWidthCollapsed = 209 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed); 210 mMultiUserSwitchWidthExpanded = 211 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_expanded); 212 mAvatarCollapsedScaleFactor = 213 getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_collapsed_size) 214 / (float) mMultiUserAvatar.getLayoutParams().width; 215 mClockCollapsedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size); 216 mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size); 217 mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize; 218 219 } 220 221 public void setActivityStarter(ActivityStarter activityStarter) { 222 mActivityStarter = activityStarter; 223 } 224 225 public void setBatteryController(BatteryController batteryController) { 226 mBatteryController = batteryController; 227 } 228 229 public void setNextAlarmController(NextAlarmController nextAlarmController) { 230 mNextAlarmController = nextAlarmController; 231 } 232 233 public int getCollapsedHeight() { 234 return mCollapsedHeight; 235 } 236 237 public int getExpandedHeight() { 238 return mExpandedHeight; 239 } 240 241 public void setListening(boolean listening) { 242 if (listening == mListening) { 243 return; 244 } 245 mListening = listening; 246 updateListeners(); 247 } 248 249 public void setExpanded(boolean expanded) { 250 boolean changed = expanded != mExpanded; 251 mExpanded = expanded; 252 if (changed) { 253 updateEverything(); 254 } 255 } 256 257 public void updateEverything() { 258 updateHeights(); 259 updateVisibilities(); 260 updateSystemIconsLayoutParams(); 261 updateClickTargets(); 262 updateMultiUserSwitch(); 263 if (mQSPanel != null) { 264 mQSPanel.setExpanded(mExpanded); 265 } 266 updateClockScale(); 267 updateAvatarScale(); 268 updateClockLp(); 269 requestCaptureValues(); 270 } 271 272 private void updateHeights() { 273 int height = mExpanded ? mExpandedHeight : mCollapsedHeight; 274 ViewGroup.LayoutParams lp = getLayoutParams(); 275 if (lp.height != height) { 276 lp.height = height; 277 setLayoutParams(lp); 278 } 279 } 280 281 private void updateVisibilities() { 282 mDateCollapsed.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); 283 mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE); 284 mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); 285 mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE); 286 mQsDetailHeader.setVisibility(mExpanded && mShowingDetail? View.VISIBLE : View.INVISIBLE); 287 if (mSignalCluster != null) { 288 updateSignalClusterDetachment(); 289 } 290 mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE); 291 mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE); 292 } 293 294 private void updateSignalClusterDetachment() { 295 boolean detached = mExpanded; 296 if (detached != mSignalClusterDetached) { 297 if (detached) { 298 getOverlay().add(mSignalCluster); 299 } else { 300 reattachSignalCluster(); 301 } 302 } 303 mSignalClusterDetached = detached; 304 } 305 306 private void reattachSignalCluster() { 307 getOverlay().remove(mSignalCluster); 308 mSystemIcons.addView(mSignalCluster, 1); 309 } 310 311 private void updateSystemIconsLayoutParams() { 312 RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams(); 313 int rule = mExpanded 314 ? mSettingsButton.getId() 315 : mMultiUserSwitch.getId(); 316 if (rule != lp.getRules()[RelativeLayout.START_OF]) { 317 lp.addRule(RelativeLayout.START_OF, rule); 318 mSystemIconsSuperContainer.setLayoutParams(lp); 319 } 320 } 321 322 private void updateListeners() { 323 if (mListening) { 324 mBatteryController.addStateChangedCallback(this); 325 mNextAlarmController.addStateChangedCallback(this); 326 } else { 327 mBatteryController.removeStateChangedCallback(this); 328 mNextAlarmController.removeStateChangedCallback(this); 329 } 330 } 331 332 private void updateAvatarScale() { 333 if (mExpanded) { 334 mMultiUserAvatar.setScaleX(1f); 335 mMultiUserAvatar.setScaleY(1f); 336 } else { 337 mMultiUserAvatar.setScaleX(mAvatarCollapsedScaleFactor); 338 mMultiUserAvatar.setScaleY(mAvatarCollapsedScaleFactor); 339 } 340 } 341 342 private void updateClockScale() { 343 mTime.setTextSize(TypedValue.COMPLEX_UNIT_PX, mExpanded 344 ? mClockExpandedSize 345 : mClockCollapsedSize); 346 mTime.setScaleX(1f); 347 mTime.setScaleY(1f); 348 updateAmPmTranslation(); 349 } 350 351 private void updateAmPmTranslation() { 352 boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; 353 mAmPm.setTranslationX((rtl ? 1 : -1) * mTime.getWidth() * (1 - mTime.getScaleX())); 354 } 355 356 @Override 357 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 358 mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); 359 } 360 361 @Override 362 public void onPowerSaveChanged() { 363 // could not care less 364 } 365 366 @Override 367 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { 368 mNextAlarm = nextAlarm; 369 if (nextAlarm != null) { 370 mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm)); 371 } 372 mAlarmShowing = nextAlarm != null; 373 updateEverything(); 374 requestCaptureValues(); 375 } 376 377 private void updateClickTargets() { 378 mMultiUserSwitch.setClickable(mExpanded); 379 mMultiUserSwitch.setFocusable(mExpanded); 380 mSystemIconsSuperContainer.setClickable(mExpanded); 381 mSystemIconsSuperContainer.setFocusable(mExpanded); 382 mAlarmStatus.setClickable(mNextAlarm != null && mNextAlarm.getShowIntent() != null); 383 } 384 385 private void updateClockLp() { 386 int marginBottom = mExpanded 387 ? mClockMarginBottomExpanded 388 : mClockMarginBottomCollapsed; 389 LayoutParams lp = (LayoutParams) mDateGroup.getLayoutParams(); 390 if (marginBottom != lp.bottomMargin) { 391 lp.bottomMargin = marginBottom; 392 mDateGroup.setLayoutParams(lp); 393 } 394 } 395 396 private void updateMultiUserSwitch() { 397 int marginEnd; 398 int width; 399 if (mExpanded) { 400 marginEnd = mMultiUserExpandedMargin; 401 width = mMultiUserSwitchWidthExpanded; 402 } else { 403 marginEnd = mMultiUserCollapsedMargin; 404 width = mMultiUserSwitchWidthCollapsed; 405 } 406 MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams(); 407 if (marginEnd != lp.getMarginEnd() || lp.width != width) { 408 lp.setMarginEnd(marginEnd); 409 lp.width = width; 410 mMultiUserSwitch.setLayoutParams(lp); 411 } 412 } 413 414 public void setExpansion(float t) { 415 if (!mExpanded) { 416 t = 0f; 417 } 418 mCurrentT = t; 419 float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight); 420 if (height < mCollapsedHeight) { 421 height = mCollapsedHeight; 422 } 423 if (height > mExpandedHeight) { 424 height = mExpandedHeight; 425 } 426 setClipping(height); 427 updateLayoutValues(t); 428 } 429 430 private void updateLayoutValues(float t) { 431 if (mCaptureValues) { 432 return; 433 } 434 mCurrentValues.interpoloate(mCollapsedValues, mExpandedValues, t); 435 applyLayoutValues(mCurrentValues); 436 } 437 438 private void setClipping(float height) { 439 mClipBounds.set(getPaddingLeft(), 0, getWidth() - getPaddingRight(), (int) height); 440 setClipBounds(mClipBounds); 441 invalidateOutline(); 442 } 443 444 public void attachSystemIcons(LinearLayout systemIcons) { 445 mSystemIconsContainer.addView(systemIcons); 446 mStatusIcons = systemIcons.findViewById(R.id.statusIcons); 447 mSignalCluster = systemIcons.findViewById(R.id.signal_cluster); 448 mSystemIcons = systemIcons; 449 updateVisibilities(); 450 if (mStatusIcons != null) { 451 mStatusIcons.setVisibility(View.GONE); 452 } 453 } 454 455 public void onSystemIconsDetached() { 456 if (mSignalClusterDetached) { 457 reattachSignalCluster(); 458 mSignalClusterDetached = false; 459 } 460 if (mStatusIcons != null) { 461 mStatusIcons.setVisibility(View.VISIBLE); 462 } 463 if (mSignalCluster != null) { 464 mSignalCluster.setVisibility(View.VISIBLE); 465 mSignalCluster.setAlpha(1f); 466 mSignalCluster.setTranslationX(0f); 467 mSignalCluster.setTranslationY(0f); 468 } 469 mStatusIcons = null; 470 mSignalCluster = null; 471 mSystemIcons = null; 472 } 473 474 public void setUserInfoController(UserInfoController userInfoController) { 475 userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() { 476 @Override 477 public void onUserInfoChanged(String name, Drawable picture) { 478 mMultiUserAvatar.setImageDrawable(picture); 479 } 480 }); 481 } 482 483 @Override 484 public void onClick(View v) { 485 if (v == mSettingsButton) { 486 startSettingsActivity(); 487 } else if (v == mSystemIconsSuperContainer) { 488 startBatteryActivity(); 489 } else if (v == mAlarmStatus && mNextAlarm != null) { 490 PendingIntent showIntent = mNextAlarm.getShowIntent(); 491 if (showIntent != null && showIntent.isActivity()) { 492 mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */); 493 } 494 } 495 } 496 497 private void startSettingsActivity() { 498 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), 499 true /* dismissShade */); 500 } 501 502 private void startBatteryActivity() { 503 mActivityStarter.startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY), 504 true /* dismissShade */); 505 } 506 507 public void setQSPanel(QSPanel qsp) { 508 mQSPanel = qsp; 509 if (mQSPanel != null) { 510 mQSPanel.setCallback(mQsPanelCallback); 511 } 512 mMultiUserSwitch.setQsPanel(qsp); 513 } 514 515 @Override 516 public boolean shouldDelayChildPressedState() { 517 return true; 518 } 519 520 public void setShowEmergencyCallsOnly(boolean show) { 521 boolean changed = show != mShowEmergencyCallsOnly; 522 if (changed) { 523 mShowEmergencyCallsOnly = show; 524 if (mExpanded) { 525 updateEverything(); 526 requestCaptureValues(); 527 } 528 } 529 } 530 531 @Override 532 protected void dispatchSetPressed(boolean pressed) { 533 // We don't want that everything lights up when we click on the header, so block the request 534 // here. 535 } 536 537 private void captureLayoutValues(LayoutValues target) { 538 target.timeScale = mExpanded ? 1f : mClockCollapsedScaleFactor; 539 target.clockY = mClock.getBottom(); 540 target.dateY = mDateGroup.getTop(); 541 target.emergencyCallsOnlyAlpha = getAlphaForVisibility(mEmergencyCallsOnly); 542 target.alarmStatusAlpha = getAlphaForVisibility(mAlarmStatus); 543 target.dateCollapsedAlpha = getAlphaForVisibility(mDateCollapsed); 544 target.dateExpandedAlpha = getAlphaForVisibility(mDateExpanded); 545 target.avatarScale = mMultiUserAvatar.getScaleX(); 546 target.avatarX = mMultiUserSwitch.getLeft() + mMultiUserAvatar.getLeft(); 547 target.avatarY = mMultiUserSwitch.getTop() + mMultiUserAvatar.getTop(); 548 if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) { 549 target.batteryX = mSystemIconsSuperContainer.getLeft() 550 + mSystemIconsContainer.getRight(); 551 } else { 552 target.batteryX = mSystemIconsSuperContainer.getLeft() 553 + mSystemIconsContainer.getLeft(); 554 } 555 target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop(); 556 target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel); 557 target.settingsAlpha = getAlphaForVisibility(mSettingsButton); 558 target.settingsTranslation = mExpanded 559 ? 0 560 : mMultiUserSwitch.getLeft() - mSettingsButton.getLeft(); 561 target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f; 562 target.settingsRotation = !mExpanded ? 90f : 0f; 563 } 564 565 private float getAlphaForVisibility(View v) { 566 return v == null || v.getVisibility() == View.VISIBLE ? 1f : 0f; 567 } 568 569 private void applyAlpha(View v, float alpha) { 570 if (v == null || v.getVisibility() == View.GONE) { 571 return; 572 } 573 if (alpha == 0f) { 574 v.setVisibility(View.INVISIBLE); 575 } else { 576 v.setVisibility(View.VISIBLE); 577 v.setAlpha(alpha); 578 } 579 } 580 581 private void applyLayoutValues(LayoutValues values) { 582 mTime.setScaleX(values.timeScale); 583 mTime.setScaleY(values.timeScale); 584 mClock.setY(values.clockY - mClock.getHeight()); 585 mDateGroup.setY(values.dateY); 586 mAlarmStatus.setY(values.dateY - mAlarmStatus.getPaddingTop()); 587 mMultiUserAvatar.setScaleX(values.avatarScale); 588 mMultiUserAvatar.setScaleY(values.avatarScale); 589 mMultiUserAvatar.setX(values.avatarX - mMultiUserSwitch.getLeft()); 590 mMultiUserAvatar.setY(values.avatarY - mMultiUserSwitch.getTop()); 591 if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) { 592 mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getRight()); 593 } else { 594 mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getLeft()); 595 } 596 mSystemIconsSuperContainer.setY(values.batteryY - mSystemIconsContainer.getTop()); 597 if (mSignalCluster != null && mExpanded) { 598 if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) { 599 mSignalCluster.setX(mSystemIconsSuperContainer.getX() 600 - mSignalCluster.getWidth()); 601 } else { 602 mSignalCluster.setX(mSystemIconsSuperContainer.getX() 603 + mSystemIconsSuperContainer.getWidth()); 604 } 605 mSignalCluster.setY( 606 mSystemIconsSuperContainer.getY() + mSystemIconsSuperContainer.getHeight()/2 607 - mSignalCluster.getHeight()/2); 608 } else if (mSignalCluster != null) { 609 mSignalCluster.setTranslationX(0f); 610 mSignalCluster.setTranslationY(0f); 611 } 612 mSettingsButton.setTranslationY(mSystemIconsSuperContainer.getTranslationY()); 613 mSettingsButton.setTranslationX(values.settingsTranslation); 614 mSettingsButton.setRotation(values.settingsRotation); 615 applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha); 616 applyAlpha(mAlarmStatus, values.alarmStatusAlpha); 617 applyAlpha(mDateCollapsed, values.dateCollapsedAlpha); 618 applyAlpha(mDateExpanded, values.dateExpandedAlpha); 619 applyAlpha(mBatteryLevel, values.batteryLevelAlpha); 620 applyAlpha(mSettingsButton, values.settingsAlpha); 621 applyAlpha(mSignalCluster, values.signalClusterAlpha); 622 if (!mExpanded) { 623 mTime.setScaleX(1f); 624 mTime.setScaleY(1f); 625 } 626 updateAmPmTranslation(); 627 } 628 629 /** 630 * Captures all layout values (position, visibility) for a certain state. This is used for 631 * animations. 632 */ 633 private static final class LayoutValues { 634 635 float dateExpandedAlpha; 636 float dateCollapsedAlpha; 637 float emergencyCallsOnlyAlpha; 638 float alarmStatusAlpha; 639 float timeScale = 1f; 640 float clockY; 641 float dateY; 642 float avatarScale; 643 float avatarX; 644 float avatarY; 645 float batteryX; 646 float batteryY; 647 float batteryLevelAlpha; 648 float settingsAlpha; 649 float settingsTranslation; 650 float signalClusterAlpha; 651 float settingsRotation; 652 653 public void interpoloate(LayoutValues v1, LayoutValues v2, float t) { 654 timeScale = v1.timeScale * (1 - t) + v2.timeScale * t; 655 clockY = v1.clockY * (1 - t) + v2.clockY * t; 656 dateY = v1.dateY * (1 - t) + v2.dateY * t; 657 avatarScale = v1.avatarScale * (1 - t) + v2.avatarScale * t; 658 avatarX = v1.avatarX * (1 - t) + v2.avatarX * t; 659 avatarY = v1.avatarY * (1 - t) + v2.avatarY * t; 660 batteryX = v1.batteryX * (1 - t) + v2.batteryX * t; 661 batteryY = v1.batteryY * (1 - t) + v2.batteryY * t; 662 settingsTranslation = v1.settingsTranslation * (1 - t) + v2.settingsTranslation * t; 663 664 float t1 = Math.max(0, t - 0.5f) * 2; 665 settingsRotation = v1.settingsRotation * (1 - t1) + v2.settingsRotation * t1; 666 emergencyCallsOnlyAlpha = 667 v1.emergencyCallsOnlyAlpha * (1 - t1) + v2.emergencyCallsOnlyAlpha * t1; 668 669 float t2 = Math.min(1, 2 * t); 670 signalClusterAlpha = v1.signalClusterAlpha * (1 - t2) + v2.signalClusterAlpha * t2; 671 672 float t3 = Math.max(0, t - 0.7f) / 0.3f; 673 batteryLevelAlpha = v1.batteryLevelAlpha * (1 - t3) + v2.batteryLevelAlpha * t3; 674 settingsAlpha = v1.settingsAlpha * (1 - t3) + v2.settingsAlpha * t3; 675 dateExpandedAlpha = v1.dateExpandedAlpha * (1 - t3) + v2.dateExpandedAlpha * t3; 676 dateCollapsedAlpha = v1.dateCollapsedAlpha * (1 - t3) + v2.dateCollapsedAlpha * t3; 677 alarmStatusAlpha = v1.alarmStatusAlpha * (1 - t3) + v2.alarmStatusAlpha * t3; 678 } 679 } 680 681 private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() { 682 private boolean mScanState; 683 684 @Override 685 public void onToggleStateChanged(final boolean state) { 686 post(new Runnable() { 687 @Override 688 public void run() { 689 handleToggleStateChanged(state); 690 } 691 }); 692 } 693 694 @Override 695 public void onShowingDetail(final QSTile.DetailAdapter detail) { 696 post(new Runnable() { 697 @Override 698 public void run() { 699 handleShowingDetail(detail); 700 } 701 }); 702 } 703 704 @Override 705 public void onScanStateChanged(final boolean state) { 706 post(new Runnable() { 707 @Override 708 public void run() { 709 handleScanStateChanged(state); 710 } 711 }); 712 } 713 714 private void handleToggleStateChanged(boolean state) { 715 mQsDetailHeaderSwitch.setChecked(state); 716 } 717 718 private void handleScanStateChanged(boolean state) { 719 if (mScanState == state) return; 720 mScanState = state; 721 final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable(); 722 if (state) { 723 mQsDetailHeaderProgress.animate().alpha(1f); 724 anim.start(); 725 } else { 726 mQsDetailHeaderProgress.animate().alpha(0f); 727 anim.stop(); 728 } 729 } 730 731 private void handleShowingDetail(final QSTile.DetailAdapter detail) { 732 final boolean showingDetail = detail != null; 733 transition(mClock, !showingDetail); 734 transition(mDateGroup, !showingDetail); 735 transition(mAlarmStatus, !showingDetail); 736 transition(mQsDetailHeader, showingDetail); 737 mShowingDetail = showingDetail; 738 if (showingDetail) { 739 mQsDetailHeaderTitle.setText(detail.getTitle()); 740 final Boolean toggleState = detail.getToggleState(); 741 if (toggleState == null) { 742 mQsDetailHeaderSwitch.setVisibility(INVISIBLE); 743 mQsDetailHeader.setClickable(false); 744 } else { 745 mQsDetailHeaderSwitch.setVisibility(VISIBLE); 746 mQsDetailHeaderSwitch.setChecked(toggleState); 747 mQsDetailHeader.setClickable(true); 748 mQsDetailHeader.setOnClickListener(new OnClickListener() { 749 @Override 750 public void onClick(View v) { 751 detail.setToggleState(!mQsDetailHeaderSwitch.isChecked()); 752 } 753 }); 754 } 755 } else { 756 mQsDetailHeader.setClickable(false); 757 } 758 } 759 760 private void transition(final View v, final boolean in) { 761 if (in) { 762 v.bringToFront(); 763 v.setVisibility(VISIBLE); 764 } 765 v.animate() 766 .alpha(in ? 1 : 0) 767 .withLayer() 768 .withEndAction(new Runnable() { 769 @Override 770 public void run() { 771 if (!in) { 772 v.setVisibility(INVISIBLE); 773 } 774 } 775 }) 776 .start(); 777 } 778 }; 779} 780