StatusBarHeaderView.java revision 312b792421f243eb1db08534a554a4630ba2ea55
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.content.Context;
20import android.content.Intent;
21import android.graphics.Outline;
22import android.graphics.Rect;
23import android.graphics.drawable.Drawable;
24import android.util.AttributeSet;
25import android.view.View;
26import android.view.ViewGroup;
27import android.view.ViewOutlineProvider;
28import android.widget.ImageView;
29import android.widget.LinearLayout;
30import android.widget.RelativeLayout;
31import android.widget.Switch;
32import android.widget.TextView;
33
34import com.android.systemui.R;
35import com.android.systemui.qs.QSPanel;
36import com.android.systemui.qs.QSTile;
37import com.android.systemui.statusbar.policy.BatteryController;
38import com.android.systemui.statusbar.policy.UserInfoController;
39
40/**
41 * The view to manage the header area in the expanded status bar.
42 */
43public class StatusBarHeaderView extends RelativeLayout implements View.OnClickListener,
44        BatteryController.BatteryStateChangeCallback {
45
46    private boolean mExpanded;
47    private boolean mListening;
48    private boolean mOverscrolled;
49    private boolean mKeyguardShowing;
50    private boolean mCharging;
51
52    private ViewGroup mSystemIconsContainer;
53    private View mSystemIconsSuperContainer;
54    private View mDateTime;
55    private View mTime;
56    private View mAmPm;
57    private View mKeyguardCarrierText;
58    private MultiUserSwitch mMultiUserSwitch;
59    private ImageView mMultiUserAvatar;
60    private View mDateCollapsed;
61    private View mDateExpanded;
62    private View mStatusIcons;
63    private View mSignalCluster;
64    private View mSettingsButton;
65    private View mQsDetailHeader;
66    private TextView mQsDetailHeaderTitle;
67    private Switch mQsDetailHeaderSwitch;
68    private View mEmergencyCallsOnly;
69    private TextView mBatteryLevel;
70
71    private boolean mShowEmergencyCallsOnly;
72    private boolean mKeyguardUserSwitcherShowing;
73
74    private int mCollapsedHeight;
75    private int mExpandedHeight;
76    private int mKeyguardHeight;
77
78    private int mKeyguardWidth = ViewGroup.LayoutParams.MATCH_PARENT;
79    private int mNormalWidth;
80    private int mPadding;
81    private int mMultiUserExpandedMargin;
82    private int mMultiUserCollapsedMargin;
83    private int mMultiUserKeyguardMargin;
84    private int mSystemIconsSwitcherHiddenExpandedMargin;
85    private int mClockMarginBottomExpanded;
86    private int mMultiUserSwitchWidthCollapsed;
87    private int mMultiUserSwitchWidthExpanded;
88    private int mBatteryPaddingEnd;
89
90    /**
91     * In collapsed QS, the clock and avatar are scaled down a bit post-layout to allow for a nice
92     * transition. These values determine that factor.
93     */
94    private float mClockCollapsedScaleFactor;
95    private float mAvatarCollapsedScaleFactor;
96
97    private ActivityStarter mActivityStarter;
98    private BatteryController mBatteryController;
99    private QSPanel mQSPanel;
100
101    private final Rect mClipBounds = new Rect();
102    private final StatusIconClipper mStatusIconClipper = new StatusIconClipper();
103
104    public StatusBarHeaderView(Context context, AttributeSet attrs) {
105        super(context, attrs);
106    }
107
108    @Override
109    protected void onFinishInflate() {
110        super.onFinishInflate();
111        mSystemIconsSuperContainer = findViewById(R.id.system_icons_super_container);
112        mSystemIconsContainer = (ViewGroup) findViewById(R.id.system_icons_container);
113        mSystemIconsSuperContainer.setOnClickListener(this);
114        mDateTime = findViewById(R.id.datetime);
115        mTime = findViewById(R.id.time_view);
116        mAmPm = findViewById(R.id.am_pm_view);
117        mKeyguardCarrierText = findViewById(R.id.keyguard_carrier_text);
118        mMultiUserSwitch = (MultiUserSwitch) findViewById(R.id.multi_user_switch);
119        mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
120        mDateCollapsed = findViewById(R.id.date_collapsed);
121        mDateExpanded = findViewById(R.id.date_expanded);
122        mSettingsButton = findViewById(R.id.settings_button);
123        mSettingsButton.setOnClickListener(this);
124        mQsDetailHeader = findViewById(R.id.qs_detail_header);
125        mQsDetailHeader.setAlpha(0);
126        mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
127        mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
128        mEmergencyCallsOnly = findViewById(R.id.header_emergency_calls_only);
129        mBatteryLevel = (TextView) findViewById(R.id.battery_level);
130        loadDimens();
131        updateVisibilities();
132        updateClockScale();
133        updateAvatarScale();
134        addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
135            @Override
136            public void onLayoutChange(View v, int left, int top, int right,
137                    int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
138                if ((right - left) != (oldRight - oldLeft)) {
139                    // width changed, update clipping
140                    setClipping(getHeight());
141                }
142                boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
143                mTime.setPivotX(rtl ? mTime.getWidth() : 0);
144                mTime.setPivotY(mTime.getBaseline());
145                mAmPm.setPivotX(rtl ? mAmPm.getWidth() : 0);
146                mAmPm.setPivotY(mAmPm.getBaseline());
147                updateAmPmTranslation();
148            }
149        });
150        setOutlineProvider(new ViewOutlineProvider() {
151            @Override
152            public void getOutline(View view, Outline outline) {
153                outline.setRect(mClipBounds);
154            }
155        });
156    }
157
158    private void loadDimens() {
159        mCollapsedHeight = getResources().getDimensionPixelSize(R.dimen.status_bar_header_height);
160        mExpandedHeight = getResources().getDimensionPixelSize(
161                R.dimen.status_bar_header_height_expanded);
162        mKeyguardHeight = getResources().getDimensionPixelSize(
163                R.dimen.status_bar_header_height_keyguard);
164        mNormalWidth = getLayoutParams().width;
165        mPadding = getResources().getDimensionPixelSize(R.dimen.notification_side_padding);
166        mMultiUserExpandedMargin =
167                getResources().getDimensionPixelSize(R.dimen.multi_user_switch_expanded_margin);
168        mMultiUserCollapsedMargin =
169                getResources().getDimensionPixelSize(R.dimen.multi_user_switch_collapsed_margin);
170        mMultiUserKeyguardMargin =
171                getResources().getDimensionPixelSize(R.dimen.multi_user_switch_keyguard_margin);
172        mSystemIconsSwitcherHiddenExpandedMargin = getResources().getDimensionPixelSize(
173                R.dimen.system_icons_switcher_hidden_expanded_margin);
174        mClockMarginBottomExpanded =
175                getResources().getDimensionPixelSize(R.dimen.clock_expanded_bottom_margin);
176        mMultiUserSwitchWidthCollapsed =
177                getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_collapsed);
178        mMultiUserSwitchWidthExpanded =
179                getResources().getDimensionPixelSize(R.dimen.multi_user_switch_width_expanded);
180        mAvatarCollapsedScaleFactor =
181                getResources().getDimensionPixelSize(R.dimen.multi_user_avatar_collapsed_size)
182                / (float) mMultiUserAvatar.getLayoutParams().width;
183        mClockCollapsedScaleFactor =
184                (float) getResources().getDimensionPixelSize(R.dimen.qs_time_collapsed_size)
185                / (float) getResources().getDimensionPixelSize(R.dimen.qs_time_expanded_size);
186        mBatteryPaddingEnd =
187                getResources().getDimensionPixelSize(R.dimen.battery_level_padding_end);
188    }
189
190    public void setActivityStarter(ActivityStarter activityStarter) {
191        mActivityStarter = activityStarter;
192    }
193
194    public void setBatteryController(BatteryController batteryController) {
195        mBatteryController = batteryController;
196    }
197
198    public int getCollapsedHeight() {
199        return mKeyguardShowing ? mKeyguardHeight : mCollapsedHeight;
200    }
201
202    public int getExpandedHeight() {
203        return mExpandedHeight;
204    }
205
206    public void setListening(boolean listening) {
207        if (listening == mListening) {
208            return;
209        }
210        mListening = listening;
211        updateBatteryListening();
212    }
213
214    public void setExpanded(boolean expanded, boolean overscrolled) {
215        boolean changed = expanded != mExpanded;
216        boolean overscrollChanged = overscrolled != mOverscrolled;
217        mExpanded = expanded;
218        mOverscrolled = overscrolled;
219        if (changed || overscrollChanged) {
220            updateHeights();
221            updateVisibilities();
222            updateSystemIconsLayoutParams();
223            updateZTranslation();
224            updateClickTargets();
225            updateWidth();
226            updatePadding();
227            updateMultiUserSwitch();
228            if (mQSPanel != null) {
229                mQSPanel.setExpanded(expanded && !overscrolled);
230            }
231            updateClockScale();
232            updateAvatarScale();
233            updateClockLp();
234            updateBatteryLevelPaddingEnd();
235            mStatusIconClipper.update();
236        }
237    }
238
239    private void updateHeights() {
240        boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
241        int height;
242        if (mExpanded) {
243            height = mExpandedHeight;
244        } else if (onKeyguardAndCollapsed) {
245            height = mKeyguardHeight;
246        } else {
247            height = mCollapsedHeight;
248        }
249        ViewGroup.LayoutParams lp = getLayoutParams();
250        if (lp.height != height) {
251            lp.height = height;
252            setLayoutParams(lp);
253        }
254        int systemIconsContainerHeight = onKeyguardAndCollapsed ? mKeyguardHeight : mCollapsedHeight;
255        lp = mSystemIconsSuperContainer.getLayoutParams();
256        if (lp.height != systemIconsContainerHeight) {
257            lp.height = systemIconsContainerHeight;
258            mSystemIconsSuperContainer.setLayoutParams(lp);
259        }
260        lp = mMultiUserSwitch.getLayoutParams();
261        if (lp.height != systemIconsContainerHeight) {
262            lp.height = systemIconsContainerHeight;
263            mMultiUserSwitch.setLayoutParams(lp);
264        }
265    }
266
267    private void updateWidth() {
268        int width = (mKeyguardShowing && !mExpanded) ? mKeyguardWidth : mNormalWidth;
269        ViewGroup.LayoutParams lp = getLayoutParams();
270        if (width != lp.width) {
271            lp.width = width;
272            setLayoutParams(lp);
273        }
274    }
275
276    private void updateVisibilities() {
277        boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
278        if (onKeyguardAndCollapsed) {
279            setBackground(null);
280        } else {
281            setBackgroundResource(R.drawable.notification_header_bg);
282        }
283        mDateTime.setVisibility(onKeyguardAndCollapsed ? View.INVISIBLE : View.VISIBLE);
284        mKeyguardCarrierText.setVisibility(onKeyguardAndCollapsed ? View.VISIBLE : View.GONE);
285        mDateCollapsed.setVisibility(mExpanded && !mOverscrolled ? View.GONE : View.VISIBLE);
286        mDateExpanded.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE);
287        mSettingsButton.setVisibility(mExpanded && !mOverscrolled ? View.VISIBLE : View.GONE);
288        mQsDetailHeader.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
289        if (mStatusIcons != null) {
290            mStatusIcons.setVisibility(!mExpanded || mOverscrolled ? View.VISIBLE : View.GONE);
291        }
292        if (mSignalCluster != null) {
293            mSignalCluster.setVisibility(!mExpanded || mOverscrolled ? View.VISIBLE : View.GONE);
294        }
295        mEmergencyCallsOnly.setVisibility(mExpanded && !mOverscrolled && mShowEmergencyCallsOnly
296                ? VISIBLE : GONE);
297        mMultiUserSwitch.setVisibility(mExpanded || !mKeyguardUserSwitcherShowing
298                ? VISIBLE : GONE);
299        mBatteryLevel.setVisibility(mKeyguardShowing && mCharging || mExpanded && !mOverscrolled
300                ? View.VISIBLE : View.GONE);
301    }
302
303    private void updateSystemIconsLayoutParams() {
304        RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams();
305        lp.addRule(RelativeLayout.START_OF, mExpanded && !mOverscrolled
306                ? mSettingsButton.getId()
307                : mMultiUserSwitch.getId());
308        lp.removeRule(ALIGN_PARENT_START);
309        if (mMultiUserSwitch.getVisibility() == GONE) {
310            lp.setMarginEnd(mSystemIconsSwitcherHiddenExpandedMargin);
311        } else {
312            lp.setMarginEnd(0);
313        }
314        mSystemIconsSuperContainer.setLayoutParams(lp);
315    }
316
317    private void updateBatteryListening() {
318        if (mListening) {
319            mBatteryController.addStateChangedCallback(this);
320        } else {
321            mBatteryController.removeStateChangedCallback(this);
322        }
323    }
324
325    private void updateAvatarScale() {
326        if (!mExpanded || mOverscrolled) {
327            mMultiUserSwitch.setScaleX(mAvatarCollapsedScaleFactor);
328            mMultiUserSwitch.setScaleY(mAvatarCollapsedScaleFactor);
329        } else {
330            mMultiUserSwitch.setScaleX(1f);
331            mMultiUserSwitch.setScaleY(1f);
332        }
333    }
334
335    private void updateClockScale() {
336        mAmPm.setScaleX(mClockCollapsedScaleFactor);
337        mAmPm.setScaleY(mClockCollapsedScaleFactor);
338        if (!mExpanded || mOverscrolled) {
339            mTime.setScaleX(mClockCollapsedScaleFactor);
340            mTime.setScaleY(mClockCollapsedScaleFactor);
341        } else {
342            mTime.setScaleX(1f);
343            mTime.setScaleY(1f);
344        }
345        updateAmPmTranslation();
346    }
347
348    private void updateAmPmTranslation() {
349        boolean rtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
350        mAmPm.setTranslationX((rtl ? 1 : -1) * mTime.getWidth() * (1 - mTime.getScaleX()));
351    }
352
353    private void updateBatteryLevelPaddingEnd() {
354        mBatteryLevel.setPaddingRelative(0, 0,
355                mKeyguardShowing && !mExpanded ? 0 : mBatteryPaddingEnd, 0);
356    }
357
358    @Override
359    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
360        mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level));
361        boolean changed = mCharging != charging;
362        mCharging = charging;
363        if (changed) {
364            updateVisibilities();
365        }
366    }
367
368    @Override
369    public void onPowerSaveChanged() {
370        // could not care less
371    }
372
373    private void updateClickTargets() {
374        setClickable(!mKeyguardShowing || mExpanded);
375        mDateTime.setClickable(mExpanded);
376        mMultiUserSwitch.setClickable(mExpanded);
377        mSystemIconsSuperContainer.setClickable(mExpanded);
378    }
379
380    private void updateZTranslation() {
381
382        // If we are on the Keyguard, we need to set our z position to zero, so we don't get
383        // shadows.
384        if (mKeyguardShowing && !mExpanded) {
385            setZ(0);
386        } else {
387            setTranslationZ(0);
388        }
389    }
390
391    private void updatePadding() {
392        boolean padded = !mKeyguardShowing || mExpanded;
393        int padding = padded ? mPadding : 0;
394        setPaddingRelative(padding, 0, padding, 0);
395    }
396
397    private void updateClockLp() {
398        int marginBottom = mExpanded && !mOverscrolled ? mClockMarginBottomExpanded : 0;
399        LayoutParams lp = (LayoutParams) mDateTime.getLayoutParams();
400        int rule = mExpanded && !mOverscrolled ? TRUE : 0;
401        if (marginBottom != lp.bottomMargin
402                || lp.getRules()[RelativeLayout.ALIGN_PARENT_BOTTOM] != rule) {
403            lp.bottomMargin = marginBottom;
404            lp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, rule);
405            mDateTime.setLayoutParams(lp);
406        }
407    }
408
409    private void updateMultiUserSwitch() {
410        int marginEnd;
411        if (mExpanded && !mOverscrolled) {
412            marginEnd = mMultiUserExpandedMargin;
413        } else if (mKeyguardShowing) {
414            marginEnd = mMultiUserKeyguardMargin;
415        } else {
416            marginEnd = mMultiUserCollapsedMargin;
417        }
418        int width = mExpanded && !mOverscrolled
419                ? mMultiUserSwitchWidthExpanded
420                : mMultiUserSwitchWidthCollapsed;
421        MarginLayoutParams lp = (MarginLayoutParams) mMultiUserSwitch.getLayoutParams();
422        if (marginEnd != lp.getMarginEnd() || lp.width != width) {
423            lp.setMarginEnd(marginEnd);
424            lp.width = width;
425            mMultiUserSwitch.setLayoutParams(lp);
426        }
427    }
428
429    public void setExpansion(float t) {
430        float height = mCollapsedHeight + t * (mExpandedHeight - mCollapsedHeight);
431        if (height < mCollapsedHeight) {
432            height = mCollapsedHeight;
433        }
434        if (height > mExpandedHeight) {
435            height = mExpandedHeight;
436        }
437        setClipping(height);
438    }
439
440    private void setClipping(float height) {
441        mClipBounds.set(getPaddingLeft(), 0, getWidth() - getPaddingRight(), (int) height);
442        setClipBounds(mClipBounds);
443        invalidateOutline();
444    }
445
446    public void attachSystemIcons(LinearLayout systemIcons) {
447        mSystemIconsContainer.addView(systemIcons);
448        mStatusIcons = systemIcons.findViewById(R.id.statusIcons);
449        mSignalCluster = systemIcons.findViewById(R.id.signal_cluster);
450        mSignalCluster.addOnLayoutChangeListener(mStatusIconClipper);
451    }
452
453    public void onSystemIconsDetached() {
454        if (mStatusIcons != null) {
455            mStatusIcons.setVisibility(View.VISIBLE);
456        }
457        if (mSignalCluster != null) {
458            mSignalCluster.removeOnLayoutChangeListener(mStatusIconClipper);
459            mSignalCluster.setVisibility(View.VISIBLE);
460        }
461        mStatusIcons = null;
462        mSignalCluster = null;
463    }
464
465    public void setKeyguardShowing(boolean keyguardShowing) {
466        mKeyguardShowing = keyguardShowing;
467        updateHeights();
468        updateWidth();
469        updateVisibilities();
470        updateZTranslation();
471        updatePadding();
472        updateMultiUserSwitch();
473        updateClickTargets();
474        updateBatteryLevelPaddingEnd();
475        mStatusIconClipper.update();
476    }
477
478    public void setUserInfoController(UserInfoController userInfoController) {
479        userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
480            @Override
481            public void onUserInfoChanged(String name, Drawable picture) {
482                mMultiUserAvatar.setImageDrawable(picture);
483            }
484        });
485    }
486
487    @Override
488    public void onClick(View v) {
489        if (v == mSettingsButton) {
490            startSettingsActivity();
491        } else if (v == mSystemIconsSuperContainer) {
492            startBatteryActivity();
493        }
494    }
495
496    private void startSettingsActivity() {
497        mActivityStarter.startActivity(new Intent(android.provider.Settings.ACTION_SETTINGS));
498    }
499
500    private void startBatteryActivity() {
501        mActivityStarter.startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY));
502    }
503
504    public void setQSPanel(QSPanel qsp) {
505        mQSPanel = qsp;
506        if (mQSPanel != null) {
507            mQSPanel.setCallback(mQsPanelCallback);
508        }
509        mMultiUserSwitch.setQsPanel(qsp);
510    }
511
512    @Override
513    public boolean shouldDelayChildPressedState() {
514        return true;
515    }
516
517    public void setShowEmergencyCallsOnly(boolean show) {
518        mShowEmergencyCallsOnly = show;
519        if (mExpanded) {
520            updateVisibilities();
521        }
522    }
523
524    public void setKeyguardUserSwitcherShowing(boolean showing) {
525        // STOPSHIP: NOT CALLED PROPERLY WHEN GOING TO FULL SHADE AND RETURNING!?!
526        mKeyguardUserSwitcherShowing = showing;
527        updateVisibilities();
528        updateSystemIconsLayoutParams();
529    }
530
531    @Override
532    public boolean hasOverlappingRendering() {
533        return !mKeyguardShowing || mExpanded;
534    }
535
536    @Override
537    protected void dispatchSetPressed(boolean pressed) {
538        // We don't want that everything lights up when we click on the header, so block the request
539        // here.
540    }
541
542    private final class StatusIconClipper implements OnLayoutChangeListener {
543        private final Rect mClipBounds = new Rect();
544
545        @Override
546        public void onLayoutChange(View v, int left, int top, int right,
547                int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
548            // Hide the statusIcons in the header by clipping them.  Can't touch visibility since
549            // they are mirrored to the real status bar.
550            mClipBounds.set(left, 0, mSystemIconsContainer.getWidth(),
551                    mSystemIconsContainer.getHeight());
552            update();
553        }
554
555        public void update() {
556            final boolean onKeyguardAndCollapsed = mKeyguardShowing && !mExpanded;
557            mSystemIconsContainer.setClipBounds(onKeyguardAndCollapsed ? null : mClipBounds);
558        }
559    }
560
561    private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
562        @Override
563        public void onToggleStateChanged(final boolean state) {
564            post(new Runnable() {
565                @Override
566                public void run() {
567                    handleToggleStateChanged(state);
568                }
569            });
570        }
571
572        @Override
573        public void onShowingDetail(final QSTile.DetailAdapter detail) {
574            post(new Runnable() {
575                @Override
576                public void run() {
577                    handleShowingDetail(detail);
578                }
579            });
580        }
581
582        @Override
583        public void onScanStateChanged(final boolean state) {
584            post(new Runnable() {
585                @Override
586                public void run() {
587                    handleScanStateChanged(state);
588                }
589            });
590        }
591
592        private void handleToggleStateChanged(boolean state) {
593            mQsDetailHeaderSwitch.setChecked(state);
594        }
595
596        private void handleScanStateChanged(boolean state) {
597            // TODO - waiting on framework asset
598        }
599
600        private void handleShowingDetail(final QSTile.DetailAdapter detail) {
601            final boolean showingDetail = detail != null;
602            transition(mDateTime, !showingDetail);
603            transition(mQsDetailHeader, showingDetail);
604            if (showingDetail) {
605                mQsDetailHeaderTitle.setText(detail.getTitle());
606                final Boolean toggleState = detail.getToggleState();
607                if (toggleState == null) {
608                    mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
609                    mQsDetailHeader.setClickable(false);
610                } else {
611                    mQsDetailHeaderSwitch.setVisibility(VISIBLE);
612                    mQsDetailHeaderSwitch.setChecked(toggleState);
613                    mQsDetailHeader.setClickable(true);
614                    mQsDetailHeader.setOnClickListener(new OnClickListener() {
615                        @Override
616                        public void onClick(View v) {
617                            detail.setToggleState(!mQsDetailHeaderSwitch.isChecked());
618                        }
619                    });
620                }
621            } else {
622                mQsDetailHeader.setClickable(false);
623            }
624        }
625
626        private void transition(final View v, final boolean in) {
627            if (in) {
628                v.bringToFront();
629            }
630            v.animate().alpha(in ? 1 : 0).withLayer().start();
631        }
632    };
633}
634