OSDN Git Service

Remove unnecessary casts on calls to findViewById
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / qs / QSDetail.java
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14
15 package com.android.systemui.qs;
16
17 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_QS_MORE_SETTINGS;
18
19 import android.animation.Animator;
20 import android.animation.Animator.AnimatorListener;
21 import android.animation.AnimatorListenerAdapter;
22 import android.annotation.Nullable;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.res.Configuration;
26 import android.graphics.drawable.Animatable;
27 import android.util.AttributeSet;
28 import android.util.SparseArray;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.view.accessibility.AccessibilityEvent;
32 import android.widget.ImageView;
33 import android.widget.LinearLayout;
34 import android.widget.Switch;
35 import android.widget.TextView;
36
37 import com.android.internal.logging.MetricsLogger;
38 import com.android.systemui.Dependency;
39 import com.android.systemui.FontSizeUtils;
40 import com.android.systemui.R;
41 import com.android.systemui.SysUiServiceProvider;
42 import com.android.systemui.plugins.ActivityStarter;
43 import com.android.systemui.plugins.qs.DetailAdapter;
44 import com.android.systemui.statusbar.CommandQueue;
45
46 public class QSDetail extends LinearLayout {
47
48     private static final String TAG = "QSDetail";
49     private static final long FADE_DURATION = 300;
50
51     private final SparseArray<View> mDetailViews = new SparseArray<>();
52
53     private ViewGroup mDetailContent;
54     protected TextView mDetailSettingsButton;
55     protected TextView mDetailDoneButton;
56     private QSDetailClipper mClipper;
57     private DetailAdapter mDetailAdapter;
58     private QSPanel mQsPanel;
59
60     protected View mQsDetailHeader;
61     protected TextView mQsDetailHeaderTitle;
62     protected Switch mQsDetailHeaderSwitch;
63     protected ImageView mQsDetailHeaderProgress;
64
65     protected QSTileHost mHost;
66
67     private boolean mScanState;
68     private boolean mClosingDetail;
69     private boolean mFullyExpanded;
70     private QuickStatusBarHeader mHeader;
71     private boolean mTriggeredExpand;
72     private int mOpenX;
73     private int mOpenY;
74     private boolean mAnimatingOpen;
75     private boolean mSwitchState;
76
77     public QSDetail(Context context, @Nullable AttributeSet attrs) {
78         super(context, attrs);
79     }
80
81     @Override
82     protected void onConfigurationChanged(Configuration newConfig) {
83         super.onConfigurationChanged(newConfig);
84         FontSizeUtils.updateFontSize(mDetailDoneButton, R.dimen.qs_detail_button_text_size);
85         FontSizeUtils.updateFontSize(mDetailSettingsButton, R.dimen.qs_detail_button_text_size);
86
87         for (int i = 0; i < mDetailViews.size(); i++) {
88             mDetailViews.valueAt(i).dispatchConfigurationChanged(newConfig);
89         }
90     }
91
92     @Override
93     protected void onFinishInflate() {
94         super.onFinishInflate();
95         mDetailContent = findViewById(android.R.id.content);
96         mDetailSettingsButton = findViewById(android.R.id.button2);
97         mDetailDoneButton = findViewById(android.R.id.button1);
98
99         mQsDetailHeader = findViewById(R.id.qs_detail_header);
100         mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
101         mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
102         mQsDetailHeaderProgress = findViewById(R.id.qs_detail_header_progress);
103
104         updateDetailText();
105
106         mClipper = new QSDetailClipper(this);
107
108         final OnClickListener doneListener = new OnClickListener() {
109             @Override
110             public void onClick(View v) {
111                 announceForAccessibility(
112                         mContext.getString(R.string.accessibility_desc_quick_settings));
113                 mQsPanel.closeDetail();
114             }
115         };
116         mDetailDoneButton.setOnClickListener(doneListener);
117     }
118
119     public void setQsPanel(QSPanel panel, QuickStatusBarHeader header) {
120         mQsPanel = panel;
121         mHeader = header;
122         mHeader.setCallback(mQsPanelCallback);
123         mQsPanel.setCallback(mQsPanelCallback);
124     }
125
126     public void setHost(QSTileHost host) {
127         mHost = host;
128     }
129     public boolean isShowingDetail() {
130         return mDetailAdapter != null;
131     }
132
133     public void setFullyExpanded(boolean fullyExpanded) {
134         mFullyExpanded = fullyExpanded;
135     }
136
137     public void setExpanded(boolean qsExpanded) {
138         if (!qsExpanded) {
139             mTriggeredExpand = false;
140         }
141     }
142
143     private void updateDetailText() {
144         mDetailDoneButton.setText(R.string.quick_settings_done);
145         mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
146     }
147
148     public void updateResources() {
149         updateDetailText();
150     }
151
152     public boolean isClosingDetail() {
153         return mClosingDetail;
154     }
155
156     public interface Callback {
157         void onShowingDetail(DetailAdapter detail, int x, int y);
158         void onToggleStateChanged(boolean state);
159         void onScanStateChanged(boolean state);
160     }
161
162     public void handleShowingDetail(final DetailAdapter adapter, int x, int y,
163             boolean toggleQs) {
164         final boolean showingDetail = adapter != null;
165         setClickable(showingDetail);
166         if (showingDetail) {
167             setupDetailHeader(adapter);
168             if (toggleQs && !mFullyExpanded) {
169                 mTriggeredExpand = true;
170                 SysUiServiceProvider.getComponent(mContext, CommandQueue.class)
171                         .animateExpandSettingsPanel(null);
172             } else {
173                 mTriggeredExpand = false;
174             }
175             mOpenX = x;
176             mOpenY = y;
177         } else {
178             // Ensure we collapse into the same point we opened from.
179             x = mOpenX;
180             y = mOpenY;
181             if (toggleQs && mTriggeredExpand) {
182                 SysUiServiceProvider.getComponent(mContext, CommandQueue.class)
183                         .animateCollapsePanels();
184                 mTriggeredExpand = false;
185             }
186         }
187
188         boolean visibleDiff = (mDetailAdapter != null) != (adapter != null);
189         if (!visibleDiff && mDetailAdapter == adapter) return;  // already in right state
190         AnimatorListener listener = null;
191         if (adapter != null) {
192             int viewCacheIndex = adapter.getMetricsCategory();
193             View detailView = adapter.createDetailView(mContext, mDetailViews.get(viewCacheIndex),
194                     mDetailContent);
195             if (detailView == null) throw new IllegalStateException("Must return detail view");
196
197             setupDetailFooter(adapter);
198
199             mDetailContent.removeAllViews();
200             mDetailContent.addView(detailView);
201             mDetailViews.put(viewCacheIndex, detailView);
202             Dependency.get(MetricsLogger.class).visible(adapter.getMetricsCategory());
203             announceForAccessibility(mContext.getString(
204                     R.string.accessibility_quick_settings_detail,
205                     adapter.getTitle()));
206             mDetailAdapter = adapter;
207             listener = mHideGridContentWhenDone;
208             setVisibility(View.VISIBLE);
209         } else {
210             if (mDetailAdapter != null) {
211                 Dependency.get(MetricsLogger.class).hidden(mDetailAdapter.getMetricsCategory());
212             }
213             mClosingDetail = true;
214             mDetailAdapter = null;
215             listener = mTeardownDetailWhenDone;
216             mHeader.setVisibility(View.VISIBLE);
217             mQsPanel.setGridContentVisibility(true);
218             mQsPanelCallback.onScanStateChanged(false);
219         }
220         sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
221
222         animateDetailVisibleDiff(x, y, visibleDiff, listener);
223     }
224
225     protected void animateDetailVisibleDiff(int x, int y, boolean visibleDiff, AnimatorListener listener) {
226         if (visibleDiff) {
227             mAnimatingOpen = mDetailAdapter != null;
228             if (mFullyExpanded || mDetailAdapter != null) {
229                 setAlpha(1);
230                 mClipper.animateCircularClip(x, y, mDetailAdapter != null, listener);
231             } else {
232                 animate().alpha(0)
233                         .setDuration(FADE_DURATION)
234                         .setListener(listener)
235                         .start();
236             }
237         }
238     }
239
240     protected void setupDetailFooter(DetailAdapter adapter) {
241         final Intent settingsIntent = adapter.getSettingsIntent();
242         mDetailSettingsButton.setVisibility(settingsIntent != null ? VISIBLE : GONE);
243         mDetailSettingsButton.setOnClickListener(v -> {
244             Dependency.get(MetricsLogger.class).action(ACTION_QS_MORE_SETTINGS,
245                     adapter.getMetricsCategory());
246             Dependency.get(ActivityStarter.class)
247                     .postStartActivityDismissingKeyguard(settingsIntent, 0);
248         });
249     }
250
251     protected void setupDetailHeader(final DetailAdapter adapter) {
252         mQsDetailHeaderTitle.setText(adapter.getTitle());
253         final Boolean toggleState = adapter.getToggleState();
254         if (toggleState == null) {
255             mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
256             mQsDetailHeader.setClickable(false);
257         } else {
258             mQsDetailHeaderSwitch.setVisibility(VISIBLE);
259             handleToggleStateChanged(toggleState, adapter.getToggleEnabled());
260             mQsDetailHeader.setClickable(true);
261             mQsDetailHeader.setOnClickListener(new OnClickListener() {
262                 @Override
263                 public void onClick(View v) {
264                     boolean checked = !mQsDetailHeaderSwitch.isChecked();
265                     mQsDetailHeaderSwitch.setChecked(checked);
266                     adapter.setToggleState(checked);
267                 }
268             });
269         }
270     }
271
272     private void handleToggleStateChanged(boolean state, boolean toggleEnabled) {
273         mSwitchState = state;
274         if (mAnimatingOpen) {
275             return;
276         }
277         mQsDetailHeaderSwitch.setChecked(state);
278         mQsDetailHeader.setEnabled(toggleEnabled);
279         mQsDetailHeaderSwitch.setEnabled(toggleEnabled);
280     }
281
282     private void handleScanStateChanged(boolean state) {
283         if (mScanState == state) return;
284         mScanState = state;
285         final Animatable anim = (Animatable) mQsDetailHeaderProgress.getDrawable();
286         if (state) {
287             mQsDetailHeaderProgress.animate().alpha(1f);
288             anim.start();
289         } else {
290             mQsDetailHeaderProgress.animate().alpha(0f);
291             anim.stop();
292         }
293     }
294
295     private void checkPendingAnimations() {
296         handleToggleStateChanged(mSwitchState,
297                             mDetailAdapter != null && mDetailAdapter.getToggleEnabled());
298     }
299
300     protected Callback mQsPanelCallback = new Callback() {
301         @Override
302         public void onToggleStateChanged(final boolean state) {
303             post(new Runnable() {
304                 @Override
305                 public void run() {
306                     handleToggleStateChanged(state,
307                             mDetailAdapter != null && mDetailAdapter.getToggleEnabled());
308                 }
309             });
310         }
311
312         @Override
313         public void onShowingDetail(final DetailAdapter detail, final int x, final int y) {
314             post(new Runnable() {
315                 @Override
316                 public void run() {
317                     handleShowingDetail(detail, x, y, true /* toggleQs */);
318                 }
319             });
320         }
321
322         @Override
323         public void onScanStateChanged(final boolean state) {
324             post(new Runnable() {
325                 @Override
326                 public void run() {
327                     handleScanStateChanged(state);
328                 }
329             });
330         }
331     };
332
333     private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() {
334         public void onAnimationCancel(Animator animation) {
335             // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
336             // called, this will avoid accidentally turning off the grid when we don't want to.
337             animation.removeListener(this);
338             mAnimatingOpen = false;
339             checkPendingAnimations();
340         };
341
342         @Override
343         public void onAnimationEnd(Animator animation) {
344             // Only hide content if still in detail state.
345             if (mDetailAdapter != null) {
346                 mQsPanel.setGridContentVisibility(false);
347                 mHeader.setVisibility(View.INVISIBLE);
348             }
349             mAnimatingOpen = false;
350             checkPendingAnimations();
351         }
352     };
353
354     private final AnimatorListenerAdapter mTeardownDetailWhenDone = new AnimatorListenerAdapter() {
355         public void onAnimationEnd(Animator animation) {
356             mDetailContent.removeAllViews();
357             setVisibility(View.INVISIBLE);
358             mClosingDetail = false;
359         };
360     };
361 }