StatusBarHeaderView.java revision 7e6809ad643fa4a70cfb647191731c68f07789cd
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 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(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()); 487 } 488 } 489 } 490 491 private void startSettingsActivity() { 492 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS)); 493 } 494 495 private void startBatteryActivity() { 496 mActivityStarter.startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY)); 497 } 498 499 public void setQSPanel(QSPanel qsp) { 500 mQSPanel = qsp; 501 if (mQSPanel != null) { 502 mQSPanel.setCallback(mQsPanelCallback); 503 } 504 mMultiUserSwitch.setQsPanel(qsp); 505 } 506 507 @Override 508 public boolean shouldDelayChildPressedState() { 509 return true; 510 } 511 512 public void setShowEmergencyCallsOnly(boolean show) { 513 mShowEmergencyCallsOnly = show; 514 if (mExpanded) { 515 updateVisibilities(); 516 requestCaptureValues(); 517 } 518 } 519 520 @Override 521 protected void dispatchSetPressed(boolean pressed) { 522 // We don't want that everything lights up when we click on the header, so block the request 523 // here. 524 } 525 526 private void captureLayoutValues(LayoutValues target) { 527 target.timeScale = mTime.getScaleX(); 528 target.clockY = mClock.getTop(); 529 target.dateY = mDateGroup.getTop(); 530 target.emergencyCallsOnlyAlpha = getAlphaForVisibility(mEmergencyCallsOnly); 531 target.alarmStatusAlpha = getAlphaForVisibility(mAlarmStatus); 532 target.dateCollapsedAlpha = getAlphaForVisibility(mDateCollapsed); 533 target.dateExpandedAlpha = getAlphaForVisibility(mDateExpanded); 534 target.avatarScale = mMultiUserAvatar.getScaleX(); 535 target.avatarX = mMultiUserSwitch.getLeft() + mMultiUserAvatar.getLeft(); 536 target.avatarY = mMultiUserSwitch.getTop() + mMultiUserAvatar.getTop(); 537 target.batteryX = mSystemIconsSuperContainer.getLeft() + mSystemIconsContainer.getRight(); 538 target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop(); 539 target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel); 540 target.settingsAlpha = getAlphaForVisibility(mSettingsButton); 541 target.settingsTranslation = mExpanded 542 ? 0 543 : mMultiUserSwitch.getLeft() - mSettingsButton.getLeft(); 544 target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f; 545 target.settingsRotation = !mExpanded ? 90f : 0f; 546 } 547 548 private float getAlphaForVisibility(View v) { 549 return v == null || v.getVisibility() == View.VISIBLE ? 1f : 0f; 550 } 551 552 private void applyAlpha(View v, float alpha) { 553 if (v == null) { 554 return; 555 } 556 if (alpha == 0f) { 557 v.setVisibility(View.INVISIBLE); 558 } else { 559 v.setVisibility(View.VISIBLE); 560 v.setAlpha(alpha); 561 } 562 } 563 564 private void applyLayoutValues(LayoutValues values) { 565 mTime.setScaleX(values.timeScale); 566 mTime.setScaleY(values.timeScale); 567 mClock.setY(values.clockY); 568 mDateGroup.setY(values.dateY); 569 mAlarmStatus.setY(values.dateY - mAlarmStatus.getPaddingTop()); 570 mMultiUserAvatar.setScaleX(values.avatarScale); 571 mMultiUserAvatar.setScaleY(values.avatarScale); 572 mMultiUserAvatar.setX(values.avatarX - mMultiUserSwitch.getLeft()); 573 mMultiUserAvatar.setY(values.avatarY - mMultiUserSwitch.getTop()); 574 mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getRight()); 575 mSystemIconsSuperContainer.setY(values.batteryY - mSystemIconsContainer.getTop()); 576 if (mSignalCluster != null && mExpanded) { 577 mSignalCluster.setX(mSystemIconsSuperContainer.getX() 578 - mSignalCluster.getWidth()); 579 mSignalCluster.setY( 580 mSystemIconsSuperContainer.getY() + mSystemIconsSuperContainer.getHeight()/2 581 - mSignalCluster.getHeight()/2); 582 } else if (mSignalCluster != null) { 583 mSignalCluster.setTranslationX(0f); 584 mSignalCluster.setTranslationY(0f); 585 } 586 mSettingsButton.setTranslationY(mSystemIconsSuperContainer.getTranslationY()); 587 mSettingsButton.setTranslationX(values.settingsTranslation); 588 mSettingsButton.setRotation(values.settingsRotation); 589 applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha); 590 applyAlpha(mAlarmStatus, values.alarmStatusAlpha); 591 applyAlpha(mDateCollapsed, values.dateCollapsedAlpha); 592 applyAlpha(mDateExpanded, values.dateExpandedAlpha); 593 applyAlpha(mBatteryLevel, values.batteryLevelAlpha); 594 applyAlpha(mSettingsButton, values.settingsAlpha); 595 applyAlpha(mSignalCluster, values.signalClusterAlpha); 596 updateAmPmTranslation(); 597 } 598 599 /** 600 * Captures all layout values (position, visibility) for a certain state. This is used for 601 * animations. 602 */ 603 private static final class LayoutValues { 604 605 float dateExpandedAlpha; 606 float dateCollapsedAlpha; 607 float emergencyCallsOnlyAlpha; 608 float alarmStatusAlpha; 609 float timeScale = 1f; 610 float clockY; 611 float dateY; 612 float avatarScale; 613 float avatarX; 614 float avatarY; 615 float batteryX; 616 float batteryY; 617 float batteryLevelAlpha; 618 float settingsAlpha; 619 float settingsTranslation; 620 float signalClusterAlpha; 621 float settingsRotation; 622 623 public void interpoloate(LayoutValues v1, LayoutValues v2, float t) { 624 timeScale = v1.timeScale * (1 - t) + v2.timeScale * t; 625 clockY = v1.clockY * (1 - t) + v2.clockY * t; 626 dateY = v1.dateY * (1 - t) + v2.dateY * t; 627 avatarScale = v1.avatarScale * (1 - t) + v2.avatarScale * t; 628 avatarX = v1.avatarX * (1 - t) + v2.avatarX * t; 629 avatarY = v1.avatarY * (1 - t) + v2.avatarY * t; 630 batteryX = v1.batteryX * (1 - t) + v2.batteryX * t; 631 batteryY = v1.batteryY * (1 - t) + v2.batteryY * t; 632 settingsTranslation = v1.settingsTranslation * (1 - t) + v2.settingsTranslation * t; 633 634 float t1 = Math.max(0, t - 0.5f) * 2; 635 settingsRotation = v1.settingsRotation * (1 - t1) + v2.settingsRotation * t1; 636 emergencyCallsOnlyAlpha = 637 v1.emergencyCallsOnlyAlpha * (1 - t1) + v2.emergencyCallsOnlyAlpha * t1; 638 639 float t2 = Math.min(1, 2 * t); 640 signalClusterAlpha = v1.signalClusterAlpha * (1 - t2) + v2.signalClusterAlpha * t2; 641 642 float t3 = Math.max(0, t - 0.7f) / 0.3f; 643 batteryLevelAlpha = v1.batteryLevelAlpha * (1 - t3) + v2.batteryLevelAlpha * t3; 644 settingsAlpha = v1.settingsAlpha * (1 - t3) + v2.settingsAlpha * t3; 645 dateExpandedAlpha = v1.dateExpandedAlpha * (1 - t3) + v2.dateExpandedAlpha * t3; 646 dateCollapsedAlpha = v1.dateCollapsedAlpha * (1 - t3) + v2.dateCollapsedAlpha * t3; 647 alarmStatusAlpha = v1.alarmStatusAlpha * (1 - t3) + v2.alarmStatusAlpha * t3; 648 } 649 } 650 651 private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() { 652 @Override 653 public void onToggleStateChanged(final boolean state) { 654 post(new Runnable() { 655 @Override 656 public void run() { 657 handleToggleStateChanged(state); 658 } 659 }); 660 } 661 662 @Override 663 public void onShowingDetail(final QSTile.DetailAdapter detail) { 664 post(new Runnable() { 665 @Override 666 public void run() { 667 handleShowingDetail(detail); 668 } 669 }); 670 } 671 672 @Override 673 public void onScanStateChanged(final boolean state) { 674 post(new Runnable() { 675 @Override 676 public void run() { 677 handleScanStateChanged(state); 678 } 679 }); 680 } 681 682 private void handleToggleStateChanged(boolean state) { 683 mQsDetailHeaderSwitch.setChecked(state); 684 } 685 686 private void handleScanStateChanged(boolean state) { 687 // TODO - waiting on framework asset 688 } 689 690 private void handleShowingDetail(final QSTile.DetailAdapter detail) { 691 final boolean showingDetail = detail != null; 692 transition(mClock, !showingDetail); 693 transition(mDateGroup, !showingDetail); 694 transition(mQsDetailHeader, showingDetail); 695 if (showingDetail) { 696 mQsDetailHeaderTitle.setText(detail.getTitle()); 697 final Boolean toggleState = detail.getToggleState(); 698 if (toggleState == null) { 699 mQsDetailHeaderSwitch.setVisibility(INVISIBLE); 700 mQsDetailHeader.setClickable(false); 701 } else { 702 mQsDetailHeaderSwitch.setVisibility(VISIBLE); 703 mQsDetailHeaderSwitch.setChecked(toggleState); 704 mQsDetailHeader.setClickable(true); 705 mQsDetailHeader.setOnClickListener(new OnClickListener() { 706 @Override 707 public void onClick(View v) { 708 detail.setToggleState(!mQsDetailHeaderSwitch.isChecked()); 709 } 710 }); 711 } 712 } else { 713 mQsDetailHeader.setClickable(false); 714 } 715 } 716 717 private void transition(final View v, final boolean in) { 718 if (in) { 719 v.bringToFront(); 720 } 721 v.animate().alpha(in ? 1 : 0).withLayer().start(); 722 } 723 }; 724} 725