1377e7ad8dc0562c6f445594288e451c377824e4cJason Monk/*
2377e7ad8dc0562c6f445594288e451c377824e4cJason Monk * Copyright (C) 2016 The Android Open Source Project
3377e7ad8dc0562c6f445594288e451c377824e4cJason Monk *
4377e7ad8dc0562c6f445594288e451c377824e4cJason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5377e7ad8dc0562c6f445594288e451c377824e4cJason Monk * except in compliance with the License. You may obtain a copy of the License at
6377e7ad8dc0562c6f445594288e451c377824e4cJason Monk *
7377e7ad8dc0562c6f445594288e451c377824e4cJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
8377e7ad8dc0562c6f445594288e451c377824e4cJason Monk *
9377e7ad8dc0562c6f445594288e451c377824e4cJason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
10377e7ad8dc0562c6f445594288e451c377824e4cJason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11377e7ad8dc0562c6f445594288e451c377824e4cJason Monk * KIND, either express or implied. See the License for the specific language governing
12377e7ad8dc0562c6f445594288e451c377824e4cJason Monk * permissions and limitations under the License.
13377e7ad8dc0562c6f445594288e451c377824e4cJason Monk */
14377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
15377e7ad8dc0562c6f445594288e451c377824e4cJason Monkpackage com.android.systemui.qs;
16377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
17377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.animation.Animator;
18377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.animation.Animator.AnimatorListener;
19377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.animation.AnimatorListenerAdapter;
20377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.annotation.Nullable;
21377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.content.Context;
22377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.content.Intent;
23377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.content.res.Configuration;
24377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.graphics.drawable.Animatable;
25377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.util.AttributeSet;
26377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.util.SparseArray;
27377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.view.View;
28377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.view.ViewGroup;
29377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.view.accessibility.AccessibilityEvent;
30377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.widget.ImageView;
31377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.widget.LinearLayout;
32377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.widget.Switch;
33377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport android.widget.TextView;
3466448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen
35377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport com.android.internal.logging.MetricsLogger;
36377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport com.android.systemui.FontSizeUtils;
37377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport com.android.systemui.R;
38377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport com.android.systemui.qs.QSTile.DetailAdapter;
39589bb70a77767980b6241ae676491edb42dedef5Jason Monkimport com.android.systemui.statusbar.phone.BaseStatusBarHeader;
40377e7ad8dc0562c6f445594288e451c377824e4cJason Monkimport com.android.systemui.statusbar.phone.QSTileHost;
41377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
42377e7ad8dc0562c6f445594288e451c377824e4cJason Monkpublic class QSDetail extends LinearLayout {
43377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
44377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private static final String TAG = "QSDetail";
45377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private static final long FADE_DURATION = 300;
46377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
47377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private final SparseArray<View> mDetailViews = new SparseArray<>();
48377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
49377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private ViewGroup mDetailContent;
50377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private TextView mDetailSettingsButton;
51377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private TextView mDetailDoneButton;
52377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private QSDetailClipper mClipper;
53377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private DetailAdapter mDetailAdapter;
54377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private QSPanel mQsPanel;
55377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
56377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private View mQsDetailHeader;
57377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private TextView mQsDetailHeaderTitle;
58377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private Switch mQsDetailHeaderSwitch;
59377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private ImageView mQsDetailHeaderProgress;
60377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
61377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private QSTileHost mHost;
62377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
63377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private boolean mScanState;
64377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private boolean mClosingDetail;
65377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private boolean mFullyExpanded;
66589bb70a77767980b6241ae676491edb42dedef5Jason Monk    private BaseStatusBarHeader mHeader;
6766448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen    private boolean mTriggeredExpand;
6866448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen    private int mOpenX;
6966448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen    private int mOpenY;
7035a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk    private boolean mAnimatingOpen;
7148e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk    private boolean mSwitchState;
72377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
73377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    public QSDetail(Context context, @Nullable AttributeSet attrs) {
74377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        super(context, attrs);
75377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
76377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
77377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    @Override
78377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    protected void onConfigurationChanged(Configuration newConfig) {
79377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        super.onConfigurationChanged(newConfig);
80377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size);
81377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size);
82377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
83377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        for (int i = 0; i < mDetailViews.size(); i++) {
84377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailViews.valueAt(i).dispatchConfigurationChanged(newConfig);
85377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
86377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
87377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
88377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    @Override
89377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    protected void onFinishInflate() {
90377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        super.onFinishInflate();
91377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mDetailContent = (ViewGroup) findViewById(android.R.id.content);
92377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mDetailSettingsButton = (TextView) findViewById(android.R.id.button2);
93377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mDetailDoneButton = (TextView) findViewById(android.R.id.button1);
94377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
95377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQsDetailHeader = findViewById(R.id.qs_detail_header);
96377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
97377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
98377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQsDetailHeaderProgress = (ImageView) findViewById(R.id.qs_detail_header_progress);
99377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
100377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        updateDetailText();
101377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
102377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mClipper = new QSDetailClipper(this);
103377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
104377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        final OnClickListener doneListener = new OnClickListener() {
105377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            @Override
106377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            public void onClick(View v) {
107377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                announceForAccessibility(
108377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                        mContext.getString(R.string.accessibility_desc_quick_settings));
109377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mQsPanel.closeDetail();
110377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            }
111377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        };
112377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mDetailDoneButton.setOnClickListener(doneListener);
113377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
114377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
115589bb70a77767980b6241ae676491edb42dedef5Jason Monk    public void setQsPanel(QSPanel panel, BaseStatusBarHeader header) {
116377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQsPanel = panel;
117589bb70a77767980b6241ae676491edb42dedef5Jason Monk        mHeader = header;
11866448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen        mHeader.setCallback(mQsPanelCallback);
119377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQsPanel.setCallback(mQsPanelCallback);
120377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
121377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
122377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    public void setHost(QSTileHost host) {
123377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mHost = host;
124377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
125377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    public boolean isShowingDetail() {
126377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        return mDetailAdapter != null;
127377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
128377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
129377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    public void setFullyExpanded(boolean fullyExpanded) {
130377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mFullyExpanded = fullyExpanded;
131377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
132377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
13366448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen    public void setExpanded(boolean qsExpanded) {
13466448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen        if (!qsExpanded) {
13566448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            mTriggeredExpand = false;
13666448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen        }
13766448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen    }
13866448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen
139377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private void updateDetailText() {
140377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mDetailDoneButton.setText(R.string.quick_settings_done);
141377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
142377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
143377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
144377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    public void updateResources() {
145377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        updateDetailText();
146377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
147377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
148377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    public boolean isClosingDetail() {
149377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        return mClosingDetail;
150377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
151377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
152377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private void handleShowingDetail(final QSTile.DetailAdapter adapter, int x, int y) {
153377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        final boolean showingDetail = adapter != null;
154377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        setClickable(showingDetail);
155377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        if (showingDetail) {
156377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mQsDetailHeaderTitle.setText(adapter.getTitle());
157377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            final Boolean toggleState = adapter.getToggleState();
158377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            if (toggleState == null) {
159377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
160377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mQsDetailHeader.setClickable(false);
161377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            } else {
162377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mQsDetailHeaderSwitch.setVisibility(VISIBLE);
16335a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk                handleToggleStateChanged(toggleState, adapter.getToggleEnabled());
164377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mQsDetailHeader.setClickable(true);
165377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mQsDetailHeader.setOnClickListener(new OnClickListener() {
166377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    @Override
167377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    public void onClick(View v) {
168377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                        boolean checked = !mQsDetailHeaderSwitch.isChecked();
169377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                        mQsDetailHeaderSwitch.setChecked(checked);
170377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                        adapter.setToggleState(checked);
171377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    }
172377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                });
173377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            }
17466448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            if (!mFullyExpanded) {
17566448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen                mTriggeredExpand = true;
17666448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen                mHost.animateToggleQSExpansion();
17766448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            } else {
17866448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen                mTriggeredExpand = false;
17966448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            }
18066448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            mOpenX = x;
18166448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            mOpenY = y;
18266448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen        } else {
18366448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            // Ensure we collapse into the same point we opened from.
18466448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            x = mOpenX;
18566448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            y = mOpenY;
18666448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            if (mTriggeredExpand) {
18766448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen                mHost.animateToggleQSExpansion();
18866448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen                mTriggeredExpand = false;
18966448936dc7cb981effb5a741caa080278bcd6efXiaohui Chen            }
190377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
191377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
192377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        boolean visibleDiff = (mDetailAdapter != null) != (adapter != null);
193377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        if (!visibleDiff && mDetailAdapter == adapter) return;  // already in right state
194377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        AnimatorListener listener = null;
195377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        if (adapter != null) {
196377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            int viewCacheIndex = adapter.getMetricsCategory();
197377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            View detailView = adapter.createDetailView(mContext, mDetailViews.get(viewCacheIndex),
198377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    mDetailContent);
199377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            if (detailView == null) throw new IllegalStateException("Must return detail view");
200377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
201377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            final Intent settingsIntent = adapter.getSettingsIntent();
202377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
203377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailSettingsButton.setOnClickListener(new OnClickListener() {
204377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                @Override
205377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                public void onClick(View v) {
206377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    mHost.startActivityDismissingKeyguard(settingsIntent);
207377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                }
208377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            });
209377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
210377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailContent.removeAllViews();
211377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailContent.addView(detailView);
212377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailViews.put(viewCacheIndex, detailView);
213377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            MetricsLogger.visible(mContext, adapter.getMetricsCategory());
214377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            announceForAccessibility(mContext.getString(
215377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    R.string.accessibility_quick_settings_detail,
216377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    adapter.getTitle()));
217377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailAdapter = adapter;
218377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            listener = mHideGridContentWhenDone;
219377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            setVisibility(View.VISIBLE);
220377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        } else {
221377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            if (mDetailAdapter != null) {
222377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                MetricsLogger.hidden(mContext, mDetailAdapter.getMetricsCategory());
223377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            }
224377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mClosingDetail = true;
225377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailAdapter = null;
226377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            listener = mTeardownDetailWhenDone;
227589bb70a77767980b6241ae676491edb42dedef5Jason Monk            mHeader.setVisibility(View.VISIBLE);
228377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mQsPanel.setGridContentVisibility(true);
229377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mQsPanelCallback.onScanStateChanged(false);
230377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
231377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
232377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        if (visibleDiff) {
23335a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk            mAnimatingOpen = adapter != null;
234377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            if (mFullyExpanded || mDetailAdapter != null) {
235377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                setAlpha(1);
236377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mClipper.animateCircularClip(x, y, mDetailAdapter != null, listener);
237377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            } else {
238377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                animate().alpha(0)
239377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                        .setDuration(FADE_DURATION)
240377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                        .setListener(listener)
241377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                        .start();
242377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            }
243377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
244377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
245377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
24635a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk    private void handleToggleStateChanged(boolean state, boolean toggleEnabled) {
24748e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk        mSwitchState = state;
24835a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk        if (mAnimatingOpen) {
24948e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk            return;
25048e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk        }
251377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mQsDetailHeaderSwitch.setChecked(state);
252fac2538e463138a8a1a92bc94af3f310d28718b4Jason Monk        mQsDetailHeader.setEnabled(toggleEnabled);
253fac2538e463138a8a1a92bc94af3f310d28718b4Jason Monk        mQsDetailHeaderSwitch.setEnabled(toggleEnabled);
254377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
255377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
256377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private void handleScanStateChanged(boolean state) {
257377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        if (mScanState == state) return;
258377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        mScanState = state;
259377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
260377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        if (state) {
261377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mQsDetailHeaderProgress.animate().alpha(1f);
262377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            anim.start();
263377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        } else {
264377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mQsDetailHeaderProgress.animate().alpha(0f);
265377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            anim.stop();
266377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
267377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    }
268377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
26948e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk    private void checkPendingAnimations() {
27035a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk        handleToggleStateChanged(mSwitchState,
27135a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk                            mDetailAdapter != null && mDetailAdapter.getToggleEnabled());
27248e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk    }
27348e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk
274377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private final QSPanel.Callback mQsPanelCallback = new QSPanel.Callback() {
275377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        @Override
276377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        public void onToggleStateChanged(final boolean state) {
277377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            post(new Runnable() {
278377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                @Override
279377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                public void run() {
28035a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk                    handleToggleStateChanged(state,
28135a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk                            mDetailAdapter != null && mDetailAdapter.getToggleEnabled());
282377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                }
283377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            });
284377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
285377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
286377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        @Override
287377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        public void onShowingDetail(final DetailAdapter detail, final int x, final int y) {
288377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            post(new Runnable() {
289377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                @Override
290377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                public void run() {
291377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    handleShowingDetail(detail, x, y);
292377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                }
293377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            });
294377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
295377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
296377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        @Override
297377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        public void onScanStateChanged(final boolean state) {
298377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            post(new Runnable() {
299377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                @Override
300377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                public void run() {
301377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                    handleScanStateChanged(state);
302377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                }
303377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            });
304377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
305377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    };
306377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
307377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() {
308377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        public void onAnimationCancel(Animator animation) {
309377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
310377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            // called, this will avoid accidentally turning off the grid when we don't want to.
311377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            animation.removeListener(this);
31235a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk            mAnimatingOpen = false;
31348e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk            checkPendingAnimations();
314377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        };
315377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
316377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        @Override
317377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        public void onAnimationEnd(Animator animation) {
318377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            // Only hide content if still in detail state.
319377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            if (mDetailAdapter != null) {
320377e7ad8dc0562c6f445594288e451c377824e4cJason Monk                mQsPanel.setGridContentVisibility(false);
321589bb70a77767980b6241ae676491edb42dedef5Jason Monk                mHeader.setVisibility(View.INVISIBLE);
322377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            }
32335a9c14cc689e417d6dccbd4831c6fcadb0ecc8eJason Monk            mAnimatingOpen = false;
32448e093e6dfceab58ea53f1f996d55e9a1dc51358Jason Monk            checkPendingAnimations();
325377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        }
326377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    };
327377e7ad8dc0562c6f445594288e451c377824e4cJason Monk
328377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
329377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        public void onAnimationEnd(Animator animation) {
330377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mDetailContent.removeAllViews();
331377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            setVisibility(View.INVISIBLE);
332377e7ad8dc0562c6f445594288e451c377824e4cJason Monk            mClosingDetail = false;
333377e7ad8dc0562c6f445594288e451c377824e4cJason Monk        };
334377e7ad8dc0562c6f445594288e451c377824e4cJason Monk    };
335377e7ad8dc0562c6f445594288e451c377824e4cJason Monk}
336