StatusBarHeaderView.java revision 235510e67210f90de30c2d5582a2077ccc589619
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.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 AlarmManager.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 updateEverything(); 247 } 248 } 249 250 public void updateEverything() { 251 updateHeights(); 252 updateVisibilities(); 253 updateSystemIconsLayoutParams(); 254 updateClickTargets(); 255 updateMultiUserSwitch(); 256 if (mQSPanel != null) { 257 mQSPanel.setExpanded(mExpanded); 258 } 259 updateClockScale(); 260 updateAvatarScale(); 261 updateClockLp(); 262 requestCaptureValues(); 263 } 264 265 private void updateHeights() { 266 int height = mExpanded ? mExpandedHeight : mCollapsedHeight; 267 ViewGroup.LayoutParams lp = getLayoutParams(); 268 if (lp.height != height) { 269 lp.height = height; 270 setLayoutParams(lp); 271 } 272 } 273 274 private void updateVisibilities() { 275 mDateCollapsed.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); 276 mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE); 277 mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE); 278 mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE); 279 mQsDetailHeader.setVisibility(mExpanded ? View.VISIBLE : View.GONE); 280 if (mSignalCluster != null) { 281 updateSignalClusterDetachment(); 282 } 283 mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE); 284 mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE); 285 } 286 287 private void updateSignalClusterDetachment() { 288 boolean detached = mExpanded; 289 if (detached != mSignalClusterDetached) { 290 if (detached) { 291 getOverlay().add(mSignalCluster); 292 } else { 293 reattachSignalCluster(); 294 } 295 } 296 mSignalClusterDetached = detached; 297 } 298 299 private void reattachSignalCluster() { 300 getOverlay().remove(mSignalCluster); 301 mSystemIcons.addView(mSignalCluster, 1); 302 } 303 304 private void updateSystemIconsLayoutParams() { 305 RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams(); 306 int rule = mExpanded 307 ? mSettingsButton.getId() 308 : mMultiUserSwitch.getId(); 309 if (rule != lp.getRules()[RelativeLayout.START_OF]) { 310 lp.addRule(RelativeLayout.START_OF, rule); 311 mSystemIconsSuperContainer.setLayoutParams(lp); 312 } 313 } 314 315 private void updateListeners() { 316 if (mListening) { 317 mBatteryController.addStateChangedCallback(this); 318 mNextAlarmController.addStateChangedCallback(this); 319 } else { 320 mBatteryController.removeStateChangedCallback(this); 321 mNextAlarmController.removeStateChangedCallback(this); 322 } 323 } 324 325 private void updateAvatarScale() { 326 if (mExpanded) { 327 mMultiUserAvatar.setScaleX(1f); 328 mMultiUserAvatar.setScaleY(1f); 329 } else { 330 mMultiUserAvatar.setScaleX(mAvatarCollapsedScaleFactor); 331 mMultiUserAvatar.setScaleY(mAvatarCollapsedScaleFactor); 332 } 333 } 334 335 private void updateClockScale() { 336 mAmPm.setScaleX(mClockCollapsedScaleFactor); 337 mAmPm.setScaleY(mClockCollapsedScaleFactor); 338 mTime.setScaleX(getTimeScale()); 339 mTime.setScaleY(getTimeScale()); 340 updateAmPmTranslation(); 341 } 342 343 private float getTimeScale() { 344 return !mExpanded ? mClockCollapsedScaleFactor : 1f; 345 } 346 347 private void updateAmPmTranslation() { 348 boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; 349 mAmPm.setTranslationX((rtl ? 1 : -1) * mTime.getWidth() * (1 - mTime.getScaleX())); 350 } 351 352 @Override 353 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { 354 mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); 355 } 356 357 @Override 358 public void onPowerSaveChanged() { 359 // could not care less 360 } 361 362 @Override 363 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { 364 mNextAlarm = nextAlarm; 365 if (nextAlarm != null) { 366 mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm)); 367 } 368 mAlarmShowing = nextAlarm != null; 369 updateVisibilities(); 370 requestCaptureValues(); 371 } 372 373 private void updateClickTargets() { 374 mMultiUserSwitch.setClickable(mExpanded); 375 mSystemIconsSuperContainer.setClickable(mExpanded); 376 mAlarmStatus.setClickable(mNextAlarm != null && mNextAlarm.getShowIntent() != null); 377 } 378 379 private void updateClockLp() { 380 int marginBottom = mExpanded 381 ? mClockMarginBottomExpanded 382 : mClockMarginBottomCollapsed; 383 LayoutParams lp = (LayoutParams) mDateGroup.getLayoutParams(); 384 if (marginBottom != lp.bottomMargin) { 385 lp.bottomMargin = marginBottom; 386 mDateGroup.setLayoutParams(lp); 387 } 388 } 389 390 private void updateMultiUserSwitch() { 391 int marginEnd; 392 int width; 393 if (mExpanded) { 394 marginEnd = mMultiUserExpandedMargin; 395 width = mMultiUserSwitchWidthExpanded; 396 } else { 397 marginEnd = mMultiUserCollapsedMargin; 398 width = mMultiUserSwitchWidthCollapsed; 399 } 400 MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams(); 401 if (marginEnd != lp.getMarginEnd() || lp.width != width) { 402 lp.setMarginEnd(marginEnd); 403 lp.width = width; 404 mMultiUserSwitch.setLayoutParams(lp); 405 } 406 } 407 408 public void setExpansion(float t) { 409 if (!mExpanded) { 410 t = 0f; 411 } 412 mCurrentT = t; 413 float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight); 414 if (height < mCollapsedHeight) { 415 height = mCollapsedHeight; 416 } 417 if (height > mExpandedHeight) { 418 height = mExpandedHeight; 419 } 420 setClipping(height); 421 updateLayoutValues(t); 422 } 423 424 private void updateLayoutValues(float t) { 425 if (mCaptureValues) { 426 return; 427 } 428 mCurrentValues.interpoloate(mCollapsedValues, mExpandedValues, t); 429 applyLayoutValues(mCurrentValues); 430 } 431 432 private void setClipping(float height) { 433 mClipBounds.set(getPaddingLeft(), 0, getWidth() - getPaddingRight(), (int) height); 434 setClipBounds(mClipBounds); 435 invalidateOutline(); 436 } 437 438 public void attachSystemIcons(LinearLayout systemIcons) { 439 mSystemIconsContainer.addView(systemIcons); 440 mStatusIcons = systemIcons.findViewById(R.id.statusIcons); 441 mSignalCluster = systemIcons.findViewById(R.id.signal_cluster); 442 mSystemIcons = systemIcons; 443 updateVisibilities(); 444 if (mStatusIcons != null) { 445 mStatusIcons.setVisibility(View.GONE); 446 } 447 } 448 449 public void onSystemIconsDetached() { 450 if (mSignalClusterDetached) { 451 reattachSignalCluster(); 452 mSignalClusterDetached = false; 453 } 454 if (mStatusIcons != null) { 455 mStatusIcons.setVisibility(View.VISIBLE); 456 } 457 if (mSignalCluster != null) { 458 mSignalCluster.setVisibility(View.VISIBLE); 459 mSignalCluster.setAlpha(1f); 460 mSignalCluster.setTranslationX(0f); 461 mSignalCluster.setTranslationY(0f); 462 } 463 mStatusIcons = null; 464 mSignalCluster = null; 465 mSystemIcons = null; 466 } 467 468 public void setUserInfoController(UserInfoController userInfoController) { 469 userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() { 470 @Override 471 public void onUserInfoChanged(String name, Drawable picture) { 472 mMultiUserAvatar.setImageDrawable(picture); 473 } 474 }); 475 } 476 477 @Override 478 public void onClick(View v) { 479 if (v == mSettingsButton) { 480 startSettingsActivity(); 481 } else if (v == mSystemIconsSuperContainer) { 482 startBatteryActivity(); 483 } else if (v == mAlarmStatus && mNextAlarm != null) { 484 PendingIntent showIntent = mNextAlarm.getShowIntent(); 485 if (showIntent != null && showIntent.isActivity()) { 486 mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */); 487 } 488 } 489 } 490 491 private void startSettingsActivity() { 492 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS), 493 true /* dismissShade */); 494 } 495 496 private void startBatteryActivity() { 497 mActivityStarter.startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY), 498 true /* dismissShade */); 499 } 500 501 public void setQSPanel(QSPanel qsp) { 502 mQSPanel = qsp; 503 if (mQSPanel != null) { 504 mQSPanel.setCallback(mQsPanelCallback); 505 } 506 mMultiUserSwitch.setQsPanel(qsp); 507 } 508 509 @Override 510 public boolean shouldDelayChildPressedState() { 511 return true; 512 } 513 514 public void setShowEmergencyCallsOnly(boolean show) { 515 mShowEmergencyCallsOnly = show; 516 if (mExpanded) { 517 updateVisibilities(); 518 requestCaptureValues(); 519 } 520 } 521 522 @Override 523 protected void dispatchSetPressed(boolean pressed) { 524 // We don't want that everything lights up when we click on the header, so block the request 525 // here. 526 } 527 528 private void captureLayoutValues(LayoutValues target) { 529 target.timeScale = mTime.getScaleX(); 530 target.clockY = mClock.getTop(); 531 target.dateY = mDateGroup.getTop(); 532 target.emergencyCallsOnlyAlpha = getAlphaForVisibility(mEmergencyCallsOnly); 533 target.alarmStatusAlpha = getAlphaForVisibility(mAlarmStatus); 534 target.dateCollapsedAlpha = getAlphaForVisibility(mDateCollapsed); 535 target.dateExpandedAlpha = getAlphaForVisibility(mDateExpanded); 536 target.avatarScale = mMultiUserAvatar.getScaleX(); 537 target.avatarX = mMultiUserSwitch.getLeft() + mMultiUserAvatar.getLeft(); 538 target.avatarY = mMultiUserSwitch.getTop() + mMultiUserAvatar.getTop(); 539 target.batteryX = mSystemIconsSuperContainer.getLeft() + mSystemIconsContainer.getRight(); 540 target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop(); 541 target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel); 542 target.settingsAlpha = getAlphaForVisibility(mSettingsButton); 543 target.settingsTranslation = mExpanded 544 ? 0 545 : mMultiUserSwitch.getLeft() - mSettingsButton.getLeft(); 546 target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f; 547 target.settingsRotation = !mExpanded ? 90f : 0f; 548 } 549 550 private float getAlphaForVisibility(View v) { 551 return v == null || v.getVisibility() == View.VISIBLE ? 1f : 0f; 552 } 553 554 private void applyAlpha(View v, float alpha) { 555 if (v == null) { 556 return; 557 } 558 if (alpha == 0f) { 559 v.setVisibility(View.INVISIBLE); 560 } else { 561 v.setVisibility(View.VISIBLE); 562 v.setAlpha(alpha); 563 } 564 } 565 566 private void applyLayoutValues(LayoutValues values) { 567 mTime.setScaleX(values.timeScale); 568 mTime.setScaleY(values.timeScale); 569 mClock.setY(values.clockY); 570 mDateGroup.setY(values.dateY); 571 mAlarmStatus.setY(values.dateY - mAlarmStatus.getPaddingTop()); 572 mMultiUserAvatar.setScaleX(values.avatarScale); 573 mMultiUserAvatar.setScaleY(values.avatarScale); 574 mMultiUserAvatar.setX(values.avatarX - mMultiUserSwitch.getLeft()); 575 mMultiUserAvatar.setY(values.avatarY - mMultiUserSwitch.getTop()); 576 mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getRight()); 577 mSystemIconsSuperContainer.setY(values.batteryY - mSystemIconsContainer.getTop()); 578 if (mSignalCluster != null && mExpanded) { 579 mSignalCluster.setX(mSystemIconsSuperContainer.getX() 580 - mSignalCluster.getWidth()); 581 mSignalCluster.setY( 582 mSystemIconsSuperContainer.getY() + mSystemIconsSuperContainer.getHeight()/2 583 - mSignalCluster.getHeight()/2); 584 } else if (mSignalCluster != null) { 585 mSignalCluster.setTranslationX(0f); 586 mSignalCluster.setTranslationY(0f); 587 } 588 mSettingsButton.setTranslationY(mSystemIconsSuperContainer.getTranslationY()); 589 mSettingsButton.setTranslationX(values.settingsTranslation); 590 mSettingsButton.setRotation(values.settingsRotation); 591 applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha); 592 applyAlpha(mAlarmStatus, values.alarmStatusAlpha); 593 applyAlpha(mDateCollapsed, values.dateCollapsedAlpha); 594 applyAlpha(mDateExpanded, values.dateExpandedAlpha); 595 applyAlpha(mBatteryLevel, values.batteryLevelAlpha); 596 applyAlpha(mSettingsButton, values.settingsAlpha); 597 applyAlpha(mSignalCluster, values.signalClusterAlpha); 598 updateAmPmTranslation(); 599 } 600 601 /** 602 * Captures all layout values (position, visibility) for a certain state. This is used for 603 * animations. 604 */ 605 private static final class LayoutValues { 606 607 float dateExpandedAlpha; 608 float dateCollapsedAlpha; 609 float emergencyCallsOnlyAlpha; 610 float alarmStatusAlpha; 611 float timeScale = 1f; 612 float clockY; 613 float dateY; 614 float avatarScale; 615 float avatarX; 616 float avatarY; 617 float batteryX; 618 float batteryY; 619 float batteryLevelAlpha; 620 float settingsAlpha; 621 float settingsTranslation; 622 float signalClusterAlpha; 623 float settingsRotation; 624 625 public void interpoloate(LayoutValues v1, LayoutValues v2, float t) { 626 timeScale = v1.timeScale * (1 - t) + v2.timeScale * t; 627 clockY = v1.clockY * (1 - t) + v2.clockY * t; 628 dateY = v1.dateY * (1 - t) + v2.dateY * t; 629 avatarScale = v1.avatarScale * (1 - t) + v2.avatarScale * t; 630 avatarX = v1.avatarX * (1 - t) + v2.avatarX * t; 631 avatarY = v1.avatarY * (1 - t) + v2.avatarY * t; 632 batteryX = v1.batteryX * (1 - t) + v2.batteryX * t; 633 batteryY = v1.batteryY * (1 - t) + v2.batteryY * t; 634 settingsTranslation = v1.settingsTranslation * (1 - t) + v2.settingsTranslation * t; 635 636 float t1 = Math.max(0, t - 0.5f) * 2; 637 settingsRotation = v1.settingsRotation * (1 - t1) + v2.settingsRotation * t1; 638 emergencyCallsOnlyAlpha = 639 v1.emergencyCallsOnlyAlpha * (1 - t1) + v2.emergencyCallsOnlyAlpha * t1; 640 641 float t2 = Math.min(1, 2 * t); 642 signalClusterAlpha = v1.signalClusterAlpha * (1 - t2) + v2.signalClusterAlpha * t2; 643 644 float t3 = Math.max(0, t - 0.7f) / 0.3f; 645 batteryLevelAlpha = v1.batteryLevelAlpha * (1 - t3) + v2.batteryLevelAlpha * t3; 646 settingsAlpha = v1.settingsAlpha * (1 - t3) + v2.settingsAlpha * t3; 647 dateExpandedAlpha = v1.dateExpandedAlpha * (1 - t3) + v2.dateExpandedAlpha * t3; 648 dateCollapsedAlpha = v1.dateCollapsedAlpha * (1 - t3) + v2.dateCollapsedAlpha * t3; 649 alarmStatusAlpha = v1.alarmStatusAlpha * (1 - t3) + v2.alarmStatusAlpha * t3; 650 } 651 } 652 653 private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() { 654 @Override 655 public void onToggleStateChanged(final boolean state) { 656 post(new Runnable() { 657 @Override 658 public void run() { 659 handleToggleStateChanged(state); 660 } 661 }); 662 } 663 664 @Override 665 public void onShowingDetail(final QSTile.DetailAdapter detail) { 666 post(new Runnable() { 667 @Override 668 public void run() { 669 handleShowingDetail(detail); 670 } 671 }); 672 } 673 674 @Override 675 public void onScanStateChanged(final boolean state) { 676 post(new Runnable() { 677 @Override 678 public void run() { 679 handleScanStateChanged(state); 680 } 681 }); 682 } 683 684 private void handleToggleStateChanged(boolean state) { 685 mQsDetailHeaderSwitch.setChecked(state); 686 } 687 688 private void handleScanStateChanged(boolean state) { 689 // TODO - waiting on framework asset 690 } 691 692 private void handleShowingDetail(final QSTile.DetailAdapter detail) { 693 final boolean showingDetail = detail != null; 694 transition(mClock, !showingDetail); 695 transition(mDateGroup, !showingDetail); 696 transition(mQsDetailHeader, showingDetail); 697 if (showingDetail) { 698 mQsDetailHeaderTitle.setText(detail.getTitle()); 699 final Boolean toggleState = detail.getToggleState(); 700 if (toggleState == null) { 701 mQsDetailHeaderSwitch.setVisibility(INVISIBLE); 702 mQsDetailHeader.setClickable(false); 703 } else { 704 mQsDetailHeaderSwitch.setVisibility(VISIBLE); 705 mQsDetailHeaderSwitch.setChecked(toggleState); 706 mQsDetailHeader.setClickable(true); 707 mQsDetailHeader.setOnClickListener(new OnClickListener() { 708 @Override 709 public void onClick(View v) { 710 detail.setToggleState(!mQsDetailHeaderSwitch.isChecked()); 711 } 712 }); 713 } 714 } else { 715 mQsDetailHeader.setClickable(false); 716 } 717 } 718 719 private void transition(final View v, final boolean in) { 720 if (in) { 721 v.bringToFront(); 722 } 723 v.animate().alpha(in ? 1 : 0).withLayer().start(); 724 } 725 }; 726} 727