18bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi/*
28bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
38bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi *
48bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
58bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * you may not use this file except in compliance with the License.
68bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * You may obtain a copy of the License at
78bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi *
88bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
98bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi *
108bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
118bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
128bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * See the License for the specific language governing permissions and
148bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi * limitations under the License
158bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi */
168bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
178bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggipackage com.android.systemui.qs;
188bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
19e1be342615db772ff11d369150349dbd874076f1Jason Monkimport android.animation.Animator;
20e1be342615db772ff11d369150349dbd874076f1Jason Monkimport android.animation.AnimatorListenerAdapter;
218bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggiimport android.content.Context;
228b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monkimport android.graphics.Point;
23f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monkimport android.graphics.Rect;
248bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggiimport android.util.AttributeSet;
25e1be342615db772ff11d369150349dbd874076f1Jason Monkimport android.util.Log;
26e1be342615db772ff11d369150349dbd874076f1Jason Monkimport android.view.View;
27e1be342615db772ff11d369150349dbd874076f1Jason Monkimport android.view.ViewTreeObserver;
288bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggiimport android.widget.FrameLayout;
29e1be342615db772ff11d369150349dbd874076f1Jason Monkimport com.android.systemui.Interpolators;
308bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggiimport com.android.systemui.R;
318b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monkimport com.android.systemui.qs.customize.QSCustomizer;
32e1be342615db772ff11d369150349dbd874076f1Jason Monkimport com.android.systemui.statusbar.phone.BaseStatusBarHeader;
338b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monkimport com.android.systemui.statusbar.phone.NotificationPanelView;
34162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monkimport com.android.systemui.statusbar.phone.QSTileHost;
35e1be342615db772ff11d369150349dbd874076f1Jason Monkimport com.android.systemui.statusbar.stack.StackStateAnimator;
368bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
378bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi/**
38e1be342615db772ff11d369150349dbd874076f1Jason Monk * Wrapper view with background which contains {@link QSPanel} and {@link BaseStatusBarHeader}
39e1be342615db772ff11d369150349dbd874076f1Jason Monk *
40e1be342615db772ff11d369150349dbd874076f1Jason Monk * Also manages animations for the QS Header and Panel.
418bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi */
428bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggipublic class QSContainer extends FrameLayout {
43e1be342615db772ff11d369150349dbd874076f1Jason Monk    private static final String TAG = "QSContainer";
44e1be342615db772ff11d369150349dbd874076f1Jason Monk    private static final boolean DEBUG = false;
458bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
468b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    private final Point mSizePoint = new Point();
47f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monk    private final Rect mQsBounds = new Rect();
488b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk
498bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    private int mHeightOverride = -1;
504fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li    protected QSPanel mQSPanel;
51377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private QSDetail mQSDetail;
52e1be342615db772ff11d369150349dbd874076f1Jason Monk    protected BaseStatusBarHeader mHeader;
534fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li    protected float mQsExpansion;
54e1be342615db772ff11d369150349dbd874076f1Jason Monk    private boolean mQsExpanded;
55e1be342615db772ff11d369150349dbd874076f1Jason Monk    private boolean mHeaderAnimating;
56e1be342615db772ff11d369150349dbd874076f1Jason Monk    private boolean mKeyguardShowing;
57e1be342615db772ff11d369150349dbd874076f1Jason Monk    private boolean mStackScrollerOverscrolling;
58e1be342615db772ff11d369150349dbd874076f1Jason Monk
59e1be342615db772ff11d369150349dbd874076f1Jason Monk    private long mDelay;
60162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk    private QSAnimator mQSAnimator;
618b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    private QSCustomizer mQSCustomizer;
628b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    private NotificationPanelView mPanelView;
63e5107a36b0547135791bfe2b692898994ef0887dJason Monk    private boolean mListening;
648bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
658bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    public QSContainer(Context context, AttributeSet attrs) {
668bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        super(context, attrs);
678bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    }
688bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
698bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    @Override
708bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    protected void onFinishInflate() {
718bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        super.onFinishInflate();
728bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        mQSPanel = (QSPanel) findViewById(R.id.quick_settings_panel);
73377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQSDetail = (QSDetail) findViewById(R.id.qs_detail);
74e1be342615db772ff11d369150349dbd874076f1Jason Monk        mHeader = (BaseStatusBarHeader) findViewById(R.id.header);
75589bb70a77767980b6241ae676491edb42dedef5Jason Monk        mQSDetail.setQsPanel(mQSPanel, mHeader);
76162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk        mQSAnimator = new QSAnimator(this, (QuickQSPanel) mHeader.findViewById(R.id.quick_qs_panel),
77162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk                mQSPanel);
788b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        mQSCustomizer = (QSCustomizer) findViewById(R.id.qs_customize);
798b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        mQSCustomizer.setQsContainer(this);
80162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk    }
81162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk
8251fb85a088ac0c6797d18fed8317d709143b9757Jason Monk    @Override
8351fb85a088ac0c6797d18fed8317d709143b9757Jason Monk    public void onRtlPropertiesChanged(int layoutDirection) {
8451fb85a088ac0c6797d18fed8317d709143b9757Jason Monk        super.onRtlPropertiesChanged(layoutDirection);
8551fb85a088ac0c6797d18fed8317d709143b9757Jason Monk        mQSAnimator.onRtlChanged();
8651fb85a088ac0c6797d18fed8317d709143b9757Jason Monk    }
8751fb85a088ac0c6797d18fed8317d709143b9757Jason Monk
88162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk    public void setHost(QSTileHost qsh) {
898b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        mQSPanel.setHost(qsh, mQSCustomizer);
90162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk        mHeader.setQSPanel(mQSPanel);
91162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk        mQSDetail.setHost(qsh);
92162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk        mQSAnimator.setHost(qsh);
938bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    }
948bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
958b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    public void setPanelView(NotificationPanelView panelView) {
968b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        mPanelView = panelView;
978b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    }
988b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk
998bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    @Override
10083e431fc51fc070901bee85970a5c4bf51f853acJason Monk    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
10183e431fc51fc070901bee85970a5c4bf51f853acJason Monk        // Since we control our own bottom, be whatever size we want.
10283e431fc51fc070901bee85970a5c4bf51f853acJason Monk        // Otherwise the QSPanel ends up with 0 height when the window is only the
10383e431fc51fc070901bee85970a5c4bf51f853acJason Monk        // size of the status bar.
1046573ef20790b0438cfd60c6306e58db0ef85c31bJason Monk        mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(
1056573ef20790b0438cfd60c6306e58db0ef85c31bJason Monk                MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
1066573ef20790b0438cfd60c6306e58db0ef85c31bJason Monk        int width = mQSPanel.getMeasuredWidth();
1076573ef20790b0438cfd60c6306e58db0ef85c31bJason Monk        int height = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
1086573ef20790b0438cfd60c6306e58db0ef85c31bJason Monk                + mQSPanel.getMeasuredHeight();
1096573ef20790b0438cfd60c6306e58db0ef85c31bJason Monk        super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
1106573ef20790b0438cfd60c6306e58db0ef85c31bJason Monk                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
1118b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk
1128b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        // QSCustomizer is always be the height of the screen, but do this after
1138b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        // other measuring to avoid changing the height of the QSContainer.
1148b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        getDisplay().getRealSize(mSizePoint);
1158b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        mQSCustomizer.measure(widthMeasureSpec,
1168b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk                MeasureSpec.makeMeasureSpec(mSizePoint.y, MeasureSpec.EXACTLY));
11783e431fc51fc070901bee85970a5c4bf51f853acJason Monk    }
11883e431fc51fc070901bee85970a5c4bf51f853acJason Monk
11983e431fc51fc070901bee85970a5c4bf51f853acJason Monk    @Override
1208bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
1218bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        super.onLayout(changed, left, top, right, bottom);
1228bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        updateBottom();
1238bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    }
1248bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
1258b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    public boolean isCustomizing() {
1268b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        return mQSCustomizer.isCustomizing();
1278b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    }
1288b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk
1298bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    /**
1308bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     * Overrides the height of this view (post-layout), so that the content is clipped to that
1318bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     * height and the background is set to that height.
1328bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     *
1338bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     * @param heightOverride the overridden height
1348bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     */
1358bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    public void setHeightOverride(int heightOverride) {
1368bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        mHeightOverride = heightOverride;
1378bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        updateBottom();
1388bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    }
1398bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
1408bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    /**
1418bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
1428bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     * during closing the detail panel, this already returns the smaller height.
1438bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi     */
1448bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    public int getDesiredHeight() {
1458b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        if (isCustomizing()) {
1468b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk            return getHeight();
1478b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        }
148377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        if (mQSDetail.isClosingDetail()) {
149dfb851c6cf02ae4f52be116a3cac4f8c9795e1f2Jason Monk            int panelHeight = ((LayoutParams) mQSPanel.getLayoutParams()).topMargin
150dfb851c6cf02ae4f52be116a3cac4f8c9795e1f2Jason Monk                    + mQSPanel.getMeasuredHeight();
151dfb851c6cf02ae4f52be116a3cac4f8c9795e1f2Jason Monk            return panelHeight + getPaddingBottom();
1528bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        } else {
1538bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi            return getMeasuredHeight();
1548bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi        }
1558bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    }
1568bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi
1578b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    public void notifyCustomizeChanged() {
1588b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        // The customize state changed, so our height changed.
1598b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        updateBottom();
16039c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
16139c98e652fd3e0e3ea3a334d60ba6ee979985978Jason Monk        mHeader.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
1628b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        // Let the panel know the position changed and it needs to update where notifications
1638b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        // and whatnot are.
1648b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        mPanelView.onQsHeightChanged();
1658b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    }
1668b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk
1678bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    private void updateBottom() {
1684fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li        int height = calculateContainerHeight();
1694fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li        setBottom(getTop() + height);
1704fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li        mQSDetail.setBottom(getTop() + height);
1714fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li    }
1724fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li
1734fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li    protected int calculateContainerHeight() {
174e1be342615db772ff11d369150349dbd874076f1Jason Monk        int heightOverride = mHeightOverride != -1 ? mHeightOverride : getMeasuredHeight();
1754fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li        return mQSCustomizer.isCustomizing() ? mQSCustomizer.getHeight()
1768b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk                : (int) (mQsExpansion * (heightOverride - mHeader.getCollapsedHeight()))
177e1be342615db772ff11d369150349dbd874076f1Jason Monk                + mHeader.getCollapsedHeight();
1788bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi    }
179e1be342615db772ff11d369150349dbd874076f1Jason Monk
180e1be342615db772ff11d369150349dbd874076f1Jason Monk    private void updateQsState() {
181e1be342615db772ff11d369150349dbd874076f1Jason Monk        boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling || mHeaderAnimating;
182e1be342615db772ff11d369150349dbd874076f1Jason Monk        mQSPanel.setExpanded(mQsExpanded);
18366448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen        mQSDetail.setExpanded(mQsExpanded);
184e1be342615db772ff11d369150349dbd874076f1Jason Monk        mHeader.setVisibility((mQsExpanded || !mKeyguardShowing || mHeaderAnimating)
185e1be342615db772ff11d369150349dbd874076f1Jason Monk                ? View.VISIBLE
186e1be342615db772ff11d369150349dbd874076f1Jason Monk                : View.INVISIBLE);
187e1be342615db772ff11d369150349dbd874076f1Jason Monk        mHeader.setExpanded((mKeyguardShowing && !mHeaderAnimating)
188e1be342615db772ff11d369150349dbd874076f1Jason Monk                || (mQsExpanded && !mStackScrollerOverscrolling));
189e1be342615db772ff11d369150349dbd874076f1Jason Monk        mQSPanel.setVisibility(expandVisually ? View.VISIBLE : View.INVISIBLE);
190e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
191e1be342615db772ff11d369150349dbd874076f1Jason Monk
192e1be342615db772ff11d369150349dbd874076f1Jason Monk    public BaseStatusBarHeader getHeader() {
193e1be342615db772ff11d369150349dbd874076f1Jason Monk        return mHeader;
194e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
195e1be342615db772ff11d369150349dbd874076f1Jason Monk
196e1be342615db772ff11d369150349dbd874076f1Jason Monk    public QSPanel getQsPanel() {
197e1be342615db772ff11d369150349dbd874076f1Jason Monk        return mQSPanel;
198e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
199e1be342615db772ff11d369150349dbd874076f1Jason Monk
2008b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    public QSCustomizer getCustomizer() {
2018b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk        return mQSCustomizer;
2028b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk    }
2038b9d67fb636a89fe6537e7affb9d01a75f263d93Jason Monk
204377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    public boolean isShowingDetail() {
205377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
206377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
207377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
208e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void setHeaderClickable(boolean clickable) {
209e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
210e1be342615db772ff11d369150349dbd874076f1Jason Monk        mHeader.setClickable(clickable);
211e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
212e1be342615db772ff11d369150349dbd874076f1Jason Monk
213e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void setExpanded(boolean expanded) {
214e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
215e1be342615db772ff11d369150349dbd874076f1Jason Monk        mQsExpanded = expanded;
216e5107a36b0547135791bfe2b692898994ef0887dJason Monk        mQSPanel.setListening(mListening && mQsExpanded);
217e1be342615db772ff11d369150349dbd874076f1Jason Monk        updateQsState();
218e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
219e1be342615db772ff11d369150349dbd874076f1Jason Monk
220e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void setKeyguardShowing(boolean keyguardShowing) {
221e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
222e1be342615db772ff11d369150349dbd874076f1Jason Monk        mKeyguardShowing = keyguardShowing;
2238fb7787cf9628284c75d873850a41b660b568348Jason Monk        mQSAnimator.setOnKeyguard(keyguardShowing);
224e1be342615db772ff11d369150349dbd874076f1Jason Monk        updateQsState();
225e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
226e1be342615db772ff11d369150349dbd874076f1Jason Monk
227e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void setOverscrolling(boolean stackScrollerOverscrolling) {
228e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
229e1be342615db772ff11d369150349dbd874076f1Jason Monk        mStackScrollerOverscrolling = stackScrollerOverscrolling;
230e1be342615db772ff11d369150349dbd874076f1Jason Monk        updateQsState();
231e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
232e1be342615db772ff11d369150349dbd874076f1Jason Monk
233e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void setListening(boolean listening) {
234e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "setListening " + listening);
235e5107a36b0547135791bfe2b692898994ef0887dJason Monk        mListening = listening;
236e1be342615db772ff11d369150349dbd874076f1Jason Monk        mHeader.setListening(listening);
237e5107a36b0547135791bfe2b692898994ef0887dJason Monk        mQSPanel.setListening(mListening && mQsExpanded);
238e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
239e1be342615db772ff11d369150349dbd874076f1Jason Monk
240b5ece9a9d6add01b7a0c392372ff8ba061fcb7e7Jason Monk    public void setHeaderListening(boolean listening) {
241b5ece9a9d6add01b7a0c392372ff8ba061fcb7e7Jason Monk        mHeader.setListening(listening);
242b5ece9a9d6add01b7a0c392372ff8ba061fcb7e7Jason Monk    }
243b5ece9a9d6add01b7a0c392372ff8ba061fcb7e7Jason Monk
244e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void setQsExpansion(float expansion, float headerTranslation) {
245e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
246e1be342615db772ff11d369150349dbd874076f1Jason Monk        mQsExpansion = expansion;
247e1be342615db772ff11d369150349dbd874076f1Jason Monk        final float translationScaleY = expansion - 1;
248e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (!mHeaderAnimating) {
249e1be342615db772ff11d369150349dbd874076f1Jason Monk            setTranslationY(mKeyguardShowing ? (translationScaleY * mHeader.getHeight())
250e1be342615db772ff11d369150349dbd874076f1Jason Monk                    : headerTranslation);
251e1be342615db772ff11d369150349dbd874076f1Jason Monk        }
252e1be342615db772ff11d369150349dbd874076f1Jason Monk        mHeader.setExpansion(mKeyguardShowing ? 1 : expansion);
253e1be342615db772ff11d369150349dbd874076f1Jason Monk        mQSPanel.setTranslationY(translationScaleY * mQSPanel.getHeight());
254377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQSDetail.setFullyExpanded(expansion == 1);
255162011ebe8015f44d4d9ced519297a7cfb087af2Jason Monk        mQSAnimator.setPosition(expansion);
256e1be342615db772ff11d369150349dbd874076f1Jason Monk        updateBottom();
257f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monk
258f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monk        // Set bounds on the QS panel so it doesn't run over the header.
259f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monk        mQsBounds.top = (int) (mQSPanel.getHeight() * (1 - expansion));
260f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monk        mQsBounds.right = mQSPanel.getWidth();
261f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monk        mQsBounds.bottom = mQSPanel.getHeight();
262f7d9c49223c4f2fd8a498160914d41801e6b10eaJason Monk        mQSPanel.setClipBounds(mQsBounds);
263e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
264e1be342615db772ff11d369150349dbd874076f1Jason Monk
265e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void animateHeaderSlidingIn(long delay) {
266e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
267e1be342615db772ff11d369150349dbd874076f1Jason Monk        // If the QS is already expanded we don't need to slide in the header as it's already
268e1be342615db772ff11d369150349dbd874076f1Jason Monk        // visible.
269e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (!mQsExpanded) {
270e1be342615db772ff11d369150349dbd874076f1Jason Monk            mHeaderAnimating = true;
271e1be342615db772ff11d369150349dbd874076f1Jason Monk            mDelay = delay;
272e1be342615db772ff11d369150349dbd874076f1Jason Monk            getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
273e1be342615db772ff11d369150349dbd874076f1Jason Monk        }
274e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
275e1be342615db772ff11d369150349dbd874076f1Jason Monk
276e1be342615db772ff11d369150349dbd874076f1Jason Monk    public void animateHeaderSlidingOut() {
277e1be342615db772ff11d369150349dbd874076f1Jason Monk        if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
278e1be342615db772ff11d369150349dbd874076f1Jason Monk        mHeaderAnimating = true;
279e1be342615db772ff11d369150349dbd874076f1Jason Monk        animate().y(-mHeader.getHeight())
280e1be342615db772ff11d369150349dbd874076f1Jason Monk                .setStartDelay(0)
281e1be342615db772ff11d369150349dbd874076f1Jason Monk                .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
282e1be342615db772ff11d369150349dbd874076f1Jason Monk                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
283e1be342615db772ff11d369150349dbd874076f1Jason Monk                .setListener(new AnimatorListenerAdapter() {
284e1be342615db772ff11d369150349dbd874076f1Jason Monk                    @Override
285e1be342615db772ff11d369150349dbd874076f1Jason Monk                    public void onAnimationEnd(Animator animation) {
286e1be342615db772ff11d369150349dbd874076f1Jason Monk                        animate().setListener(null);
287e1be342615db772ff11d369150349dbd874076f1Jason Monk                        mHeaderAnimating = false;
288e1be342615db772ff11d369150349dbd874076f1Jason Monk                        updateQsState();
289e1be342615db772ff11d369150349dbd874076f1Jason Monk                    }
290e1be342615db772ff11d369150349dbd874076f1Jason Monk                })
291e1be342615db772ff11d369150349dbd874076f1Jason Monk                .start();
292e1be342615db772ff11d369150349dbd874076f1Jason Monk    }
293e1be342615db772ff11d369150349dbd874076f1Jason Monk
294e1be342615db772ff11d369150349dbd874076f1Jason Monk    private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
295e1be342615db772ff11d369150349dbd874076f1Jason Monk            = new ViewTreeObserver.OnPreDrawListener() {
296e1be342615db772ff11d369150349dbd874076f1Jason Monk        @Override
297e1be342615db772ff11d369150349dbd874076f1Jason Monk        public boolean onPreDraw() {
298e1be342615db772ff11d369150349dbd874076f1Jason Monk            getViewTreeObserver().removeOnPreDrawListener(this);
299e1be342615db772ff11d369150349dbd874076f1Jason Monk            animate()
300e1be342615db772ff11d369150349dbd874076f1Jason Monk                    .translationY(0f)
301e1be342615db772ff11d369150349dbd874076f1Jason Monk                    .setStartDelay(mDelay)
302e1be342615db772ff11d369150349dbd874076f1Jason Monk                    .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
303e1be342615db772ff11d369150349dbd874076f1Jason Monk                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
304e1be342615db772ff11d369150349dbd874076f1Jason Monk                    .setListener(mAnimateHeaderSlidingInListener)
305e1be342615db772ff11d369150349dbd874076f1Jason Monk                    .start();
306e1be342615db772ff11d369150349dbd874076f1Jason Monk            setY(-mHeader.getHeight());
307e1be342615db772ff11d369150349dbd874076f1Jason Monk            return true;
308e1be342615db772ff11d369150349dbd874076f1Jason Monk        }
309e1be342615db772ff11d369150349dbd874076f1Jason Monk    };
310e1be342615db772ff11d369150349dbd874076f1Jason Monk
311e1be342615db772ff11d369150349dbd874076f1Jason Monk    private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
312e1be342615db772ff11d369150349dbd874076f1Jason Monk            = new AnimatorListenerAdapter() {
313e1be342615db772ff11d369150349dbd874076f1Jason Monk        @Override
314e1be342615db772ff11d369150349dbd874076f1Jason Monk        public void onAnimationEnd(Animator animation) {
315e1be342615db772ff11d369150349dbd874076f1Jason Monk            mHeaderAnimating = false;
316e1be342615db772ff11d369150349dbd874076f1Jason Monk            updateQsState();
317e1be342615db772ff11d369150349dbd874076f1Jason Monk        }
318e1be342615db772ff11d369150349dbd874076f1Jason Monk    };
3194fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li
3204fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li    public int getQsMinExpansionHeight() {
3214fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li        return mHeader.getHeight();
3224fe4a409bca01e16c807f3f76633afc1d9797e2aMuyuan Li    }
3235f2ca6b1a1f739583e4ea9f3d3dfd22931d793e0Selim Cinek
3245f2ca6b1a1f739583e4ea9f3d3dfd22931d793e0Selim Cinek    public void hideImmediately() {
3255f2ca6b1a1f739583e4ea9f3d3dfd22931d793e0Selim Cinek        animate().cancel();
3265f2ca6b1a1f739583e4ea9f3d3dfd22931d793e0Selim Cinek        setY(-mHeader.getHeight());
3275f2ca6b1a1f739583e4ea9f3d3dfd22931d793e0Selim Cinek    }
3288bc983efc439c321c8f548d384d807c31daf9180Jorim Jaggi}
329