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