2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.systemui.statusbar.phone;
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.res.Configuration;
24 import android.content.res.Resources;
25 import android.graphics.Outline;
26 import android.graphics.Rect;
27 import android.graphics.drawable.Animatable;
28 import android.graphics.drawable.Drawable;
29 import android.util.AttributeSet;
30 import android.util.MathUtils;
31 import android.util.TypedValue;
32 import android.view.View;
33 import android.view.ViewGroup;
34 import android.view.ViewOutlineProvider;
35 import android.widget.ImageView;
36 import android.widget.LinearLayout;
37 import android.widget.RelativeLayout;
38 import android.widget.Switch;
39 import android.widget.TextView;
41 import com.android.keyguard.KeyguardStatusView;
42 import com.android.systemui.BatteryMeterView;
43 import com.android.systemui.FontSizeUtils;
44 import com.android.systemui.R;
45 import com.android.systemui.qs.QSPanel;
46 import com.android.systemui.qs.QSTile;
47 import com.android.systemui.statusbar.policy.BatteryController;
48 import com.android.systemui.statusbar.policy.NextAlarmController;
49 import com.android.systemui.statusbar.policy.UserInfoController;
51 import java.text.NumberFormat;
54 * The view to manage the header area in the expanded status bar.
56 public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener,
57 BatteryController.BatteryStateChangeCallback, NextAlarmController.NextAlarmChangeCallback {
59 private boolean mExpanded;
60 private boolean mListening;
62 private ViewGroup mSystemIconsContainer;
63 private View mSystemIconsSuperContainer;
64 private View mDateGroup;
66 private TextView mTime;
67 private TextView mAmPm;
68 private MultiUserSwitch mMultiUserSwitch;
69 private ImageView mMultiUserAvatar;
70 private TextView mDateCollapsed;
71 private TextView mDateExpanded;
72 private LinearLayout mSystemIcons;
73 private View mSignalCluster;
74 private View mSettingsButton;
75 private View mQsDetailHeader;
76 private TextView mQsDetailHeaderTitle;
77 private Switch mQsDetailHeaderSwitch;
78 private ImageView mQsDetailHeaderProgress;
79 private TextView mEmergencyCallsOnly;
80 private TextView mBatteryLevel;
81 private TextView mAlarmStatus;
83 private boolean mShowEmergencyCallsOnly;
84 private boolean mAlarmShowing;
85 private AlarmManager.AlarmClockInfo mNextAlarm;
87 private int mCollapsedHeight;
88 private int mExpandedHeight;
90 private int mMultiUserExpandedMargin;
91 private int mMultiUserCollapsedMargin;
93 private int mClockMarginBottomExpanded;
94 private int mClockMarginBottomCollapsed;
95 private int mMultiUserSwitchWidthCollapsed;
96 private int mMultiUserSwitchWidthExpanded;
98 private int mClockCollapsedSize;
99 private int mClockExpandedSize;
102 * In collapsed QS, the clock and avatar are scaled down a bit post-layout to allow for a nice
103 * transition. These values determine that factor.
105 private float mClockCollapsedScaleFactor;
106 private float mAvatarCollapsedScaleFactor;
108 private ActivityStarter mActivityStarter;
109 private BatteryController mBatteryController;
110 private NextAlarmController mNextAlarmController;
111 private QSPanel mQSPanel;
114 private final Rect mClipBounds = new Rect();
116 private boolean mCaptureValues;
117 private boolean mSignalClusterDetached;
118 private final LayoutValues mCollapsedValues = new LayoutValues();
119 private final LayoutValues mExpandedValues = new LayoutValues();
120 private final LayoutValues mCurrentValues = new LayoutValues();
122 private float mCurrentT;
123 private boolean mShowingDetail;
125 public StatusBarHeaderView(Context context, AttributeSet attrs) {
126 super(context, attrs);
130 protected void onFinishInflate() {
131 super.onFinishInflate();
132 mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container);
133 mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
134 mSystemIconsSuperContainer.setOnClickListener(this);
135 mDateGroup = findViewById(R.id.date_group);
136 mClock = findViewById(R.id.clock);
137 mTime = (TextView) findViewById(R.id.time_view);
138 mAmPm = (TextView) findViewById(R.id.am_pm_view);
139 mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
140 mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
141 mDateCollapsed = (TextView) findViewById(R.id.date_collapsed);
142 mDateExpanded = (TextView) findViewById(R.id.date_expanded);
143 mSettingsButton = findViewById(R.id.settings_button);
144 mSettingsButton.setOnClickListener(this);
145 mQsDetailHeader = findViewById(R.id.qs_detail_header);
146 mQsDetailHeader.setAlpha(0);
147 mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
148 mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
149 mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
150 mEmergencyCallsOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
151 mBatteryLevel = (TextView) findViewById(R.id.battery_level);
152 mAlarmStatus = (TextView) findViewById(R.id.alarm_status);
153 mAlarmStatus.setOnClickListener(this);
154 mSignalCluster = findViewById(R.id.signal_cluster);
155 mSystemIcons = (LinearLayout) findViewById(R.id.system_icons);
157 updateVisibilities();
160 addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
162 public void onLayoutChange(View v, int left, int top, int right,
163 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
164 if ((right - left) != (oldRight - oldLeft)) {
165 // width changed, update clipping
166 setClipping(getHeight());
168 boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
169 mTime.setPivotX(rtl ? mTime.getWidth() : 0);
170 mTime.setPivotY(mTime.getBaseline());
171 updateAmPmTranslation();
174 setOutlineProvider(new ViewOutlineProvider() {
176 public void getOutline(View view, Outline outline) {
177 outline.setRect(mClipBounds);
180 requestCaptureValues();
184 protected void onLayout(boolean changed, int l, int t, int r, int b) {
185 super.onLayout(changed, l, t, r, b);
186 if (mCaptureValues) {
188 captureLayoutValues(mExpandedValues);
190 captureLayoutValues(mCollapsedValues);
192 mCaptureValues = false;
193 updateLayoutValues(mCurrentT);
195 mAlarmStatus.setX(mDateGroup.getLeft() + mDateCollapsed.getRight());
199 protected void onConfigurationChanged(Configuration newConfig) {
200 super.onConfigurationChanged(newConfig);
201 FontSizeUtils.updateFontSize(mBatteryLevel, R.dimen.battery_level_text_size);
202 FontSizeUtils.updateFontSize(mEmergencyCallsOnly,
203 R.dimen.qs_emergency_calls_only_text_size);
204 FontSizeUtils.updateFontSize(mDateCollapsed, R.dimen.qs_date_collapsed_size);
205 FontSizeUtils.updateFontSize(mDateExpanded, R.dimen.qs_date_collapsed_size);
206 FontSizeUtils.updateFontSize(mAlarmStatus, R.dimen.qs_date_collapsed_size);
207 FontSizeUtils.updateFontSize(this, android.R.id.title, R.dimen.qs_detail_header_text_size);
208 FontSizeUtils.updateFontSize(this, android.R.id.toggle, R.dimen.qs_detail_header_text_size);
209 FontSizeUtils.updateFontSize(mAmPm, R.dimen.qs_time_collapsed_size);
210 FontSizeUtils.updateFontSize(this, R.id.empty_time_view, R.dimen.qs_time_expanded_size);
212 mEmergencyCallsOnly.setText(com.android.internal.R.string.emergency_calls_only);
214 mClockCollapsedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size);
215 mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
216 mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize;
219 updateClockCollapsedMargin();
222 private void updateClockCollapsedMargin() {
223 Resources res = getResources();
224 int padding = res.getDimensionPixelSize(R.dimen.clock_collapsed_bottom_margin);
225 int largePadding = res.getDimensionPixelSize(
226 R.dimen.clock_collapsed_bottom_margin_large_text);
227 float largeFactor = (MathUtils.constrain(getResources().getConfiguration().fontScale, 1.0f,
228 FontSizeUtils.LARGE_TEXT_SCALE) - 1f) / (FontSizeUtils.LARGE_TEXT_SCALE - 1f);
229 mClockMarginBottomCollapsed = Math.round((1 - largeFactor) * padding + largeFactor * largePadding);
233 private void requestCaptureValues() {
234 mCaptureValues = true;
238 private void loadDimens() {
239 mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
240 mExpandedHeight = getResources().getDimensionPixelSize(
241 R.dimen.status_bar_header_height_expanded);
242 mMultiUserExpandedMargin =
243 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
244 mMultiUserCollapsedMargin =
245 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_collapsed_margin);
246 mClockMarginBottomExpanded =
247 getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin);
248 updateClockCollapsedMargin();
249 mMultiUserSwitchWidthCollapsed =
250 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed);
251 mMultiUserSwitchWidthExpanded =
252 getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_expanded);
253 mAvatarCollapsedScaleFactor =
254 getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_collapsed_size)
255 / (float) mMultiUserAvatar.getLayoutParams().width;
256 mClockCollapsedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size);
257 mClockExpandedSize = getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
258 mClockCollapsedScaleFactor = (float) mClockCollapsedSize / (float) mClockExpandedSize;
262 public void setActivityStarter(ActivityStarter activityStarter) {
263 mActivityStarter = activityStarter;
266 public void setBatteryController(BatteryController batteryController) {
267 mBatteryController = batteryController;
268 ((BatteryMeterView) findViewById(R.id.battery)).setBatteryController(batteryController);
271 public void setNextAlarmController(NextAlarmController nextAlarmController) {
272 mNextAlarmController = nextAlarmController;
275 public int getCollapsedHeight() {
276 return mCollapsedHeight;
279 public int getExpandedHeight() {
280 return mExpandedHeight;
283 public void setListening(boolean listening) {
284 if (listening == mListening) {
287 mListening = listening;
291 public void setExpanded(boolean expanded) {
292 boolean changed = expanded != mExpanded;
293 mExpanded = expanded;
299 public void updateEverything() {
301 updateVisibilities();
302 updateSystemIconsLayoutParams();
303 updateClickTargets();
304 updateMultiUserSwitch();
308 requestCaptureValues();
311 private void updateHeights() {
312 int height = mExpanded ? mExpandedHeight : mCollapsedHeight;
313 ViewGroup.LayoutParams lp = getLayoutParams();
314 if (lp.height != height) {
320 private void updateVisibilities() {
321 mDateCollapsed.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
322 mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE);
323 mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
324 mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE);
325 mQsDetailHeader.setVisibility(mExpanded && mShowingDetail? View.VISIBLE : View.INVISIBLE);
326 if (mSignalCluster != null) {
327 updateSignalClusterDetachment();
329 mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE);
330 mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
333 private void updateSignalClusterDetachment() {
334 boolean detached = mExpanded;
335 if (detached != mSignalClusterDetached) {
337 getOverlay().add(mSignalCluster);
339 reattachSignalCluster();
342 mSignalClusterDetached = detached;
345 private void reattachSignalCluster() {
346 getOverlay().remove(mSignalCluster);
347 mSystemIcons.addView(mSignalCluster, 1);
350 private void updateSystemIconsLayoutParams() {
351 RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams();
353 ? mSettingsButton.getId()
354 : mMultiUserSwitch.getId();
355 if (rule != lp.getRules()[RelativeLayout.START_OF]) {
356 lp.addRule(RelativeLayout.START_OF, rule);
357 mSystemIconsSuperContainer.setLayoutParams(lp);
361 private void updateListeners() {
363 mBatteryController.addStateChangedCallback(this);
364 mNextAlarmController.addStateChangedCallback(this);
366 mBatteryController.removeStateChangedCallback(this);
367 mNextAlarmController.removeStateChangedCallback(this);
371 private void updateAvatarScale() {
373 mMultiUserAvatar.setScaleX(1f);
374 mMultiUserAvatar.setScaleY(1f);
376 mMultiUserAvatar.setScaleX(mAvatarCollapsedScaleFactor);
377 mMultiUserAvatar.setScaleY(mAvatarCollapsedScaleFactor);
381 private void updateClockScale() {
382 mTime.setTextSize(TypedValue.COMPLEX_UNIT_PX, mExpanded
384 : mClockCollapsedSize);
387 updateAmPmTranslation();
390 private void updateAmPmTranslation() {
391 boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
392 mAmPm.setTranslationX((rtl ? 1 : -1) * mTime.getWidth() * (1 - mTime.getScaleX()));
396 public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
397 String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
398 mBatteryLevel.setText(percentage);
402 public void onPowerSaveChanged() {
403 // could not care less
407 public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
408 mNextAlarm = nextAlarm;
409 if (nextAlarm != null) {
410 mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
412 mAlarmShowing = nextAlarm != null;
414 requestCaptureValues();
417 private void updateClickTargets() {
418 mMultiUserSwitch.setClickable(mExpanded);
419 mMultiUserSwitch.setFocusable(mExpanded);
420 mSystemIconsSuperContainer.setClickable(mExpanded);
421 mSystemIconsSuperContainer.setFocusable(mExpanded);
422 mAlarmStatus.setClickable(mNextAlarm != null && mNextAlarm.getShowIntent() != null);
425 private void updateClockLp() {
426 int marginBottom = mExpanded
427 ? mClockMarginBottomExpanded
428 : mClockMarginBottomCollapsed;
429 LayoutParams lp = (LayoutParams) mDateGroup.getLayoutParams();
430 if (marginBottom != lp.bottomMargin) {
431 lp.bottomMargin = marginBottom;
432 mDateGroup.setLayoutParams(lp);
436 private void updateMultiUserSwitch() {
440 marginEnd = mMultiUserExpandedMargin;
441 width = mMultiUserSwitchWidthExpanded;
443 marginEnd = mMultiUserCollapsedMargin;
444 width = mMultiUserSwitchWidthCollapsed;
446 MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams();
447 if (marginEnd != lp.getMarginEnd() || lp.width != width) {
448 lp.setMarginEnd(marginEnd);
450 mMultiUserSwitch.setLayoutParams(lp);
454 public void setExpansion(float t) {
459 float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight);
460 if (height < mCollapsedHeight) {
461 height = mCollapsedHeight;
463 if (height > mExpandedHeight) {
464 height = mExpandedHeight;
467 updateLayoutValues(t);
470 private void updateLayoutValues(float t) {
471 if (mCaptureValues) {
474 mCurrentValues.interpoloate(mCollapsedValues, mExpandedValues, t);
475 applyLayoutValues(mCurrentValues);
478 private void setClipping(float height) {
479 mClipBounds.set(getPaddingLeft(), 0, getWidth() - getPaddingRight(), (int) height);
480 setClipBounds(mClipBounds);
484 public void setUserInfoController(UserInfoController userInfoController) {
485 userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
487 public void onUserInfoChanged(String name, Drawable picture) {
488 mMultiUserAvatar.setImageDrawable(picture);
494 public void onClick(View v) {
495 if (v == mSettingsButton) {
496 startSettingsActivity();
497 } else if (v == mSystemIconsSuperContainer) {
498 startBatteryActivity();
499 } else if (v == mAlarmStatus && mNextAlarm != null) {
500 PendingIntent showIntent = mNextAlarm.getShowIntent();
501 if (showIntent != null) {
502 mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
507 private void startSettingsActivity() {
508 mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS),
509 true /* dismissShade */);
512 private void startBatteryActivity() {
513 mActivityStarter.startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY),
514 true /* dismissShade */);
517 public void setQSPanel(QSPanel qsp) {
519 if (mQSPanel != null) {
520 mQSPanel.setCallback(mQsPanelCallback);
522 mMultiUserSwitch.setQsPanel(qsp);
526 public boolean shouldDelayChildPressedState() {
530 public void setShowEmergencyCallsOnly(boolean show) {
531 boolean changed = show != mShowEmergencyCallsOnly;
533 mShowEmergencyCallsOnly = show;
536 requestCaptureValues();
542 protected void dispatchSetPressed(boolean pressed) {
543 // We don't want that everything lights up when we click on the header, so block the request
547 private void captureLayoutValues(LayoutValues target) {
548 target.timeScale = mExpanded ? 1f : mClockCollapsedScaleFactor;
549 target.clockY = mClock.getBottom();
550 target.dateY = mDateGroup.getTop();
551 target.emergencyCallsOnlyAlpha = getAlphaForVisibility(mEmergencyCallsOnly);
552 target.alarmStatusAlpha = getAlphaForVisibility(mAlarmStatus);
553 target.dateCollapsedAlpha = getAlphaForVisibility(mDateCollapsed);
554 target.dateExpandedAlpha = getAlphaForVisibility(mDateExpanded);
555 target.avatarScale = mMultiUserAvatar.getScaleX();
556 target.avatarX = mMultiUserSwitch.getLeft() + mMultiUserAvatar.getLeft();
557 target.avatarY = mMultiUserSwitch.getTop() + mMultiUserAvatar.getTop();
558 if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
559 target.batteryX = mSystemIconsSuperContainer.getLeft()
560 + mSystemIconsContainer.getRight();
562 target.batteryX = mSystemIconsSuperContainer.getLeft()
563 + mSystemIconsContainer.getLeft();
565 target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop();
566 target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel);
567 target.settingsAlpha = getAlphaForVisibility(mSettingsButton);
568 target.settingsTranslation = mExpanded
570 : mMultiUserSwitch.getLeft() - mSettingsButton.getLeft();
571 target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f;
572 target.settingsRotation = !mExpanded ? 90f : 0f;
575 private float getAlphaForVisibility(View v) {
576 return v == null || v.getVisibility() == View.VISIBLE ? 1f : 0f;
579 private void applyAlpha(View v, float alpha) {
580 if (v == null || v.getVisibility() == View.GONE) {
584 v.setVisibility(View.INVISIBLE);
586 v.setVisibility(View.VISIBLE);
591 private void applyLayoutValues(LayoutValues values) {
592 mTime.setScaleX(values.timeScale);
593 mTime.setScaleY(values.timeScale);
594 mClock.setY(values.clockY - mClock.getHeight());
595 mDateGroup.setY(values.dateY);
596 mAlarmStatus.setY(values.dateY - mAlarmStatus.getPaddingTop());
597 mMultiUserAvatar.setScaleX(values.avatarScale);
598 mMultiUserAvatar.setScaleY(values.avatarScale);
599 mMultiUserAvatar.setX(values.avatarX - mMultiUserSwitch.getLeft());
600 mMultiUserAvatar.setY(values.avatarY - mMultiUserSwitch.getTop());
601 if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
602 mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getRight());
604 mSystemIconsSuperContainer.setX(values.batteryX - mSystemIconsContainer.getLeft());
606 mSystemIconsSuperContainer.setY(values.batteryY - mSystemIconsContainer.getTop());
607 if (mSignalCluster != null && mExpanded) {
608 if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
609 mSignalCluster.setX(mSystemIconsSuperContainer.getX()
610 - mSignalCluster.getWidth());
612 mSignalCluster.setX(mSystemIconsSuperContainer.getX()
613 + mSystemIconsSuperContainer.getWidth());
616 mSystemIconsSuperContainer.getY() + mSystemIconsSuperContainer.getHeight()/2
617 - mSignalCluster.getHeight()/2);
618 } else if (mSignalCluster != null) {
619 mSignalCluster.setTranslationX(0f);
620 mSignalCluster.setTranslationY(0f);
622 mSettingsButton.setTranslationY(mSystemIconsSuperContainer.getTranslationY());
623 mSettingsButton.setTranslationX(values.settingsTranslation);
624 mSettingsButton.setRotation(values.settingsRotation);
625 applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha);
626 if (!mShowingDetail) {
627 // Otherwise it needs to stay invisible
628 applyAlpha(mAlarmStatus, values.alarmStatusAlpha);
630 applyAlpha(mDateCollapsed, values.dateCollapsedAlpha);
631 applyAlpha(mDateExpanded, values.dateExpandedAlpha);
632 applyAlpha(mBatteryLevel, values.batteryLevelAlpha);
633 applyAlpha(mSettingsButton, values.settingsAlpha);
634 applyAlpha(mSignalCluster, values.signalClusterAlpha);
639 updateAmPmTranslation();
643 * Captures all layout values (position, visibility) for a certain state. This is used for
646 private static final class LayoutValues {
648 float dateExpandedAlpha;
649 float dateCollapsedAlpha;
650 float emergencyCallsOnlyAlpha;
651 float alarmStatusAlpha;
652 float timeScale = 1f;
660 float batteryLevelAlpha;
662 float settingsTranslation;
663 float signalClusterAlpha;
664 float settingsRotation;
666 public void interpoloate(LayoutValues v1, LayoutValues v2, float t) {
667 timeScale = v1.timeScale * (1 - t) + v2.timeScale * t;
668 clockY = v1.clockY * (1 - t) + v2.clockY * t;
669 dateY = v1.dateY * (1 - t) + v2.dateY * t;
670 avatarScale = v1.avatarScale * (1 - t) + v2.avatarScale * t;
671 avatarX = v1.avatarX * (1 - t) + v2.avatarX * t;
672 avatarY = v1.avatarY * (1 - t) + v2.avatarY * t;
673 batteryX = v1.batteryX * (1 - t) + v2.batteryX * t;
674 batteryY = v1.batteryY * (1 - t) + v2.batteryY * t;
675 settingsTranslation = v1.settingsTranslation * (1 - t) + v2.settingsTranslation * t;
677 float t1 = Math.max(0, t - 0.5f) * 2;
678 settingsRotation = v1.settingsRotation * (1 - t1) + v2.settingsRotation * t1;
679 emergencyCallsOnlyAlpha =
680 v1.emergencyCallsOnlyAlpha * (1 - t1) + v2.emergencyCallsOnlyAlpha * t1;
682 float t2 = Math.min(1, 2 * t);
683 signalClusterAlpha = v1.signalClusterAlpha * (1 - t2) + v2.signalClusterAlpha * t2;
685 float t3 = Math.max(0, t - 0.7f) / 0.3f;
686 batteryLevelAlpha = v1.batteryLevelAlpha * (1 - t3) + v2.batteryLevelAlpha * t3;
687 settingsAlpha = v1.settingsAlpha * (1 - t3) + v2.settingsAlpha * t3;
688 dateExpandedAlpha = v1.dateExpandedAlpha * (1 - t3) + v2.dateExpandedAlpha * t3;
689 dateCollapsedAlpha = v1.dateCollapsedAlpha * (1 - t3) + v2.dateCollapsedAlpha * t3;
690 alarmStatusAlpha = v1.alarmStatusAlpha * (1 - t3) + v2.alarmStatusAlpha * t3;
694 private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
695 private boolean mScanState;
698 public void onToggleStateChanged(final boolean state) {
699 post(new Runnable() {
702 handleToggleStateChanged(state);
708 public void onShowingDetail(final QSTile.DetailAdapter detail) {
709 post(new Runnable() {
712 handleShowingDetail(detail);
718 public void onScanStateChanged(final boolean state) {
719 post(new Runnable() {
722 handleScanStateChanged(state);
727 private void handleToggleStateChanged(boolean state) {
728 mQsDetailHeaderSwitch.setChecked(state);
731 private void handleScanStateChanged(boolean state) {
732 if (mScanState == state) return;
734 final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
736 mQsDetailHeaderProgress.animate().alpha(1f);
739 mQsDetailHeaderProgress.animate().alpha(0f);
744 private void handleShowingDetail(final QSTile.DetailAdapter detail) {
745 final boolean showingDetail = detail != null;
746 transition(mClock, !showingDetail);
747 transition(mDateGroup, !showingDetail);
749 transition(mAlarmStatus, !showingDetail);
751 transition(mQsDetailHeader, showingDetail);
752 mShowingDetail = showingDetail;
754 mQsDetailHeaderTitle.setText(detail.getTitle());
755 final Boolean toggleState = detail.getToggleState();
756 if (toggleState == null) {
757 mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
758 mQsDetailHeader.setClickable(false);
760 mQsDetailHeaderSwitch.setVisibility(VISIBLE);
761 mQsDetailHeaderSwitch.setChecked(toggleState);
762 mQsDetailHeader.setClickable(true);
763 mQsDetailHeader.setOnClickListener(new OnClickListener() {
765 public void onClick(View v) {
766 detail.setToggleState(!mQsDetailHeaderSwitch.isChecked());
771 mQsDetailHeader.setClickable(false);
775 private void transition(final View v, final boolean in) {
778 v.setVisibility(VISIBLE);
780 if (v.hasOverlappingRendering()) {
781 v.animate().withLayer();
785 .withEndAction(new Runnable() {
789 v.setVisibility(INVISIBLE);