blob: 5b09267a9e682154d9594008c1288c6b8f7b07ae [file] [log] [blame]
Jason Monk0ceef212016-11-02 14:05:23 -04001/*
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
15package com.android.systemui.qs;
16
Amin Shaikhf09450b2018-04-06 17:32:45 -040017import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
18
Jason Monk0ceef212016-11-02 14:05:23 -040019import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
Jason Monk0ceef212016-11-02 14:05:23 -040021import android.content.res.Configuration;
22import android.graphics.Rect;
23import android.os.Bundle;
24import android.util.Log;
Jason Monk9a376bc2017-05-10 09:52:10 -040025import android.view.ContextThemeWrapper;
Jason Monk0ceef212016-11-02 14:05:23 -040026import android.view.LayoutInflater;
Jason Monk231b0522018-01-04 10:49:55 -050027import android.view.MotionEvent;
Jason Monk0ceef212016-11-02 14:05:23 -040028import android.view.View;
Jason Monke5b770e2017-03-03 21:49:29 -050029import android.view.View.OnClickListener;
Jason Monk0ceef212016-11-02 14:05:23 -040030import android.view.ViewGroup;
31import android.view.ViewTreeObserver;
32import android.widget.FrameLayout.LayoutParams;
33
Gus Prevasab336792018-11-14 13:52:20 -050034import androidx.annotation.Nullable;
35import androidx.annotation.VisibleForTesting;
36
Jason Monk0ceef212016-11-02 14:05:23 -040037import com.android.systemui.Interpolators;
38import com.android.systemui.R;
Jason Monkb4cc7b12017-05-09 13:50:47 -040039import com.android.systemui.R.id;
Jason Monk0ceef212016-11-02 14:05:23 -040040import com.android.systemui.plugins.qs.QS;
Selim Cinekb0fada62019-06-17 19:03:59 -070041import com.android.systemui.plugins.statusbar.StatusBarStateController;
Jason Monk0ceef212016-11-02 14:05:23 -040042import com.android.systemui.qs.customize.QSCustomizer;
Amin Shaikhf09450b2018-04-06 17:32:45 -040043import com.android.systemui.statusbar.CommandQueue;
Selim Cinekb0fada62019-06-17 19:03:59 -070044import com.android.systemui.statusbar.StatusBarState;
Gus Prevasab336792018-11-14 13:52:20 -050045import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
Jason Monk0ceef212016-11-02 14:05:23 -040046import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
sanryhuang63787862018-05-18 15:57:43 +080047import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
Jason Monkea54e8a2018-12-20 10:01:48 -050048import com.android.systemui.util.InjectionInflationController;
Jason Monk8966d992018-12-20 14:16:29 -050049import com.android.systemui.util.LifecycleFragment;
Jason Monk0ceef212016-11-02 14:05:23 -040050
Jason Monk48f85be2018-12-19 15:16:44 -050051import javax.inject.Inject;
52
Selim Cinekb0fada62019-06-17 19:03:59 -070053public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Callbacks,
54 StatusBarStateController.StateListener {
Jason Monk0ceef212016-11-02 14:05:23 -040055 private static final String TAG = "QS";
56 private static final boolean DEBUG = false;
Jason Monk64b214e2017-03-27 13:40:59 -040057 private static final String EXTRA_EXPANDED = "expanded";
58 private static final String EXTRA_LISTENING = "listening";
Jason Monk0ceef212016-11-02 14:05:23 -040059
60 private final Rect mQsBounds = new Rect();
Selim Cinekb0fada62019-06-17 19:03:59 -070061 private final StatusBarStateController mStatusBarStateController;
Jason Monk0ceef212016-11-02 14:05:23 -040062 private boolean mQsExpanded;
63 private boolean mHeaderAnimating;
Jason Monk0ceef212016-11-02 14:05:23 -040064 private boolean mStackScrollerOverscrolling;
65
66 private long mDelay;
67
68 private QSAnimator mQSAnimator;
69 private HeightListener mPanelView;
70 protected QuickStatusBarHeader mHeader;
71 private QSCustomizer mQSCustomizer;
72 protected QSPanel mQSPanel;
73 private QSDetail mQSDetail;
74 private boolean mListening;
75 private QSContainerImpl mContainer;
76 private int mLayoutDirection;
Jason Monke5b770e2017-03-03 21:49:29 -050077 private QSFooter mFooter;
Selim Cinek1a891a92017-12-04 17:41:27 +010078 private float mLastQSExpansion = -1;
Amin Shaikhf09450b2018-04-06 17:32:45 -040079 private boolean mQsDisabled;
Jason Monk0ceef212016-11-02 14:05:23 -040080
Jason Monk48f85be2018-12-19 15:16:44 -050081 private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
Jason Monkea54e8a2018-12-20 10:01:48 -050082 private final InjectionInflationController mInjectionInflater;
Dave Mankoffc4fe6c42019-11-18 17:03:29 -050083 private final QSContainerImplController.Builder mQSContainerImplControllerBuilder;
Jason Monk5d577202018-12-26 15:43:06 -050084 private final QSTileHost mHost;
Selim Cinekb0fada62019-06-17 19:03:59 -070085 private boolean mShowCollapsedOnKeyguard;
86 private boolean mLastKeyguardAndExpanded;
87 /**
88 * The last received state from the controller. This should not be used directly to check if
89 * we're on keyguard but use {@link #isKeyguardShowing()} instead since that is more accurate
90 * during state transitions which often call into us.
91 */
92 private int mState;
Dave Mankoffc4fe6c42019-11-18 17:03:29 -050093 private QSContainerImplController mQSContainerImplController;
Jason Monk48f85be2018-12-19 15:16:44 -050094
95 @Inject
Jason Monkea54e8a2018-12-20 10:01:48 -050096 public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
Dave Mankoffc4fe6c42019-11-18 17:03:29 -050097 InjectionInflationController injectionInflater, QSTileHost qsTileHost,
98 StatusBarStateController statusBarStateController, CommandQueue commandQueue,
99 QSContainerImplController.Builder qsContainerImplControllerBuilder) {
Jason Monk48f85be2018-12-19 15:16:44 -0500100 mRemoteInputQuickSettingsDisabler = remoteInputQsDisabler;
Jason Monkea54e8a2018-12-20 10:01:48 -0500101 mInjectionInflater = injectionInflater;
Dave Mankoffc4fe6c42019-11-18 17:03:29 -0500102 mQSContainerImplControllerBuilder = qsContainerImplControllerBuilder;
Dave Mankoffbcaca8a2019-10-31 18:04:08 -0400103 commandQueue.observe(getLifecycle(), this);
Jason Monk5d577202018-12-26 15:43:06 -0500104 mHost = qsTileHost;
Selim Cinekb0fada62019-06-17 19:03:59 -0700105 mStatusBarStateController = statusBarStateController;
Jason Monk48f85be2018-12-19 15:16:44 -0500106 }
sanryhuang63787862018-05-18 15:57:43 +0800107
Jason Monk0ceef212016-11-02 14:05:23 -0400108 @Override
109 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
110 Bundle savedInstanceState) {
Jason Monkea54e8a2018-12-20 10:01:48 -0500111 inflater = mInjectionInflater.injectable(
112 inflater.cloneInContext(new ContextThemeWrapper(getContext(), R.style.qs_theme)));
Jason Monk0ceef212016-11-02 14:05:23 -0400113 return inflater.inflate(R.layout.qs_panel, container, false);
114 }
115
116 @Override
117 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
118 super.onViewCreated(view, savedInstanceState);
Jason Monke5b770e2017-03-03 21:49:29 -0500119 mQSPanel = view.findViewById(R.id.quick_settings_panel);
120 mQSDetail = view.findViewById(R.id.qs_detail);
121 mHeader = view.findViewById(R.id.header);
122 mFooter = view.findViewById(R.id.qs_footer);
Jason Monkb4cc7b12017-05-09 13:50:47 -0400123 mContainer = view.findViewById(id.quick_settings_container);
Jason Monk0ceef212016-11-02 14:05:23 -0400124
Dave Mankoffc4fe6c42019-11-18 17:03:29 -0500125 mQSContainerImplController = mQSContainerImplControllerBuilder
126 .setQSContainerImpl((QSContainerImpl) view)
127 .build();
128
129
Anthony Chen54daefe2017-04-07 17:19:54 -0700130 mQSDetail.setQsPanel(mQSPanel, mHeader, (View) mFooter);
131 mQSAnimator = new QSAnimator(this,
132 mHeader.findViewById(R.id.quick_qs_panel), mQSPanel);
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800133
Jason Monke5b770e2017-03-03 21:49:29 -0500134 mQSCustomizer = view.findViewById(R.id.qs_customize);
Jason Monk0ceef212016-11-02 14:05:23 -0400135 mQSCustomizer.setQs(this);
Jason Monk64b214e2017-03-27 13:40:59 -0400136 if (savedInstanceState != null) {
137 setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
138 setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
Fabian Kozynski0db39af2018-08-31 15:56:45 -0400139 setEditLocation(view);
Selim Cinek707e2072017-06-30 18:32:40 +0200140 mQSCustomizer.restoreInstanceState(savedInstanceState);
Fabian Kozynski407ddb22018-10-03 15:04:56 -0400141 if (mQsExpanded) {
142 mQSPanel.getTileLayout().restoreInstanceState(savedInstanceState);
143 }
Jason Monk64b214e2017-03-27 13:40:59 -0400144 }
Jason Monk5d577202018-12-26 15:43:06 -0500145 setHost(mHost);
Selim Cinekb0fada62019-06-17 19:03:59 -0700146 mStatusBarStateController.addCallback(this);
147 onStateChanged(mStatusBarStateController.getState());
Jason Monk64b214e2017-03-27 13:40:59 -0400148 }
149
150 @Override
151 public void onDestroy() {
152 super.onDestroy();
Selim Cinekb0fada62019-06-17 19:03:59 -0700153 mStatusBarStateController.removeCallback(this);
Jason Monk64b214e2017-03-27 13:40:59 -0400154 if (mListening) {
155 setListening(false);
156 }
157 }
158
159 @Override
160 public void onSaveInstanceState(Bundle outState) {
161 super.onSaveInstanceState(outState);
162 outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
163 outState.putBoolean(EXTRA_LISTENING, mListening);
Selim Cinek707e2072017-06-30 18:32:40 +0200164 mQSCustomizer.saveInstanceState(outState);
Fabian Kozynski407ddb22018-10-03 15:04:56 -0400165 if (mQsExpanded) {
166 mQSPanel.getTileLayout().saveInstanceState(outState);
167 }
Jason Monk64b214e2017-03-27 13:40:59 -0400168 }
169
170 @VisibleForTesting
171 boolean isListening() {
172 return mListening;
173 }
174
175 @VisibleForTesting
176 boolean isExpanded() {
177 return mQsExpanded;
Jason Monk0ceef212016-11-02 14:05:23 -0400178 }
179
Jason Monke5b770e2017-03-03 21:49:29 -0500180 @Override
181 public View getHeader() {
182 return mHeader;
183 }
184
Jason Monk4de5d3c2017-05-24 14:57:10 -0400185 @Override
186 public void setHasNotifications(boolean hasNotifications) {
Jason Monk4de5d3c2017-05-24 14:57:10 -0400187 }
188
Anthony Chen54daefe2017-04-07 17:19:54 -0700189 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400190 public void setPanelView(HeightListener panelView) {
191 mPanelView = panelView;
192 }
193
194 @Override
195 public void onConfigurationChanged(Configuration newConfig) {
196 super.onConfigurationChanged(newConfig);
Fabian Kozynski0db39af2018-08-31 15:56:45 -0400197 setEditLocation(getView());
Jason Monk0ceef212016-11-02 14:05:23 -0400198 if (newConfig.getLayoutDirection() != mLayoutDirection) {
199 mLayoutDirection = newConfig.getLayoutDirection();
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800200 if (mQSAnimator != null) {
201 mQSAnimator.onRtlChanged();
202 }
Jason Monk0ceef212016-11-02 14:05:23 -0400203 }
204 }
205
Fabian Kozynski0db39af2018-08-31 15:56:45 -0400206 private void setEditLocation(View view) {
Fabian Kozynski0db39af2018-08-31 15:56:45 -0400207 View edit = view.findViewById(android.R.id.edit);
208 int[] loc = edit.getLocationOnScreen();
209 int x = loc[0] + edit.getWidth() / 2;
210 int y = loc[1] + edit.getHeight() / 2;
211 mQSCustomizer.setEditLocation(x, y);
212 }
213
Jason Monk0ceef212016-11-02 14:05:23 -0400214 @Override
215 public void setContainer(ViewGroup container) {
216 if (container instanceof NotificationsQuickSettingsContainer) {
217 mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
218 }
219 }
220
Anthony Chen54daefe2017-04-07 17:19:54 -0700221 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400222 public boolean isCustomizing() {
223 return mQSCustomizer.isCustomizing();
224 }
225
226 public void setHost(QSTileHost qsh) {
227 mQSPanel.setHost(qsh, mQSCustomizer);
228 mHeader.setQSPanel(mQSPanel);
Jason Monke5b770e2017-03-03 21:49:29 -0500229 mFooter.setQSPanel(mQSPanel);
Jason Monk0ceef212016-11-02 14:05:23 -0400230 mQSDetail.setHost(qsh);
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800231
232 if (mQSAnimator != null) {
233 mQSAnimator.setHost(qsh);
234 }
Jason Monk0ceef212016-11-02 14:05:23 -0400235 }
236
Amin Shaikhf09450b2018-04-06 17:32:45 -0400237 @Override
Charles Chenf3d295c2018-11-30 18:15:21 +0800238 public void disable(int displayId, int state1, int state2, boolean animate) {
239 if (displayId != getContext().getDisplayId()) {
240 return;
241 }
sanryhuang63787862018-05-18 15:57:43 +0800242 state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
243
Amin Shaikhf09450b2018-04-06 17:32:45 -0400244 final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
245 if (disabled == mQsDisabled) return;
246 mQsDisabled = disabled;
247 mContainer.disable(state1, state2, animate);
248 mHeader.disable(state1, state2, animate);
249 mFooter.disable(state1, state2, animate);
250 updateQsState();
251 }
252
Jason Monk0ceef212016-11-02 14:05:23 -0400253 private void updateQsState() {
254 final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling
255 || mHeaderAnimating;
256 mQSPanel.setExpanded(mQsExpanded);
257 mQSDetail.setExpanded(mQsExpanded);
Selim Cinekb0fada62019-06-17 19:03:59 -0700258 boolean keyguardShowing = isKeyguardShowing();
259 mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
260 || mShowCollapsedOnKeyguard)
Jason Monk0ceef212016-11-02 14:05:23 -0400261 ? View.VISIBLE
262 : View.INVISIBLE);
Selim Cinekb0fada62019-06-17 19:03:59 -0700263 mHeader.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
Jason Monk0ceef212016-11-02 14:05:23 -0400264 || (mQsExpanded && !mStackScrollerOverscrolling));
Amin Shaikhe04505e2018-04-18 10:45:13 -0400265 mFooter.setVisibility(
Selim Cinekb0fada62019-06-17 19:03:59 -0700266 !mQsDisabled && (mQsExpanded || !keyguardShowing || mHeaderAnimating
267 || mShowCollapsedOnKeyguard)
Jason Monke5b770e2017-03-03 21:49:29 -0500268 ? View.VISIBLE
269 : View.INVISIBLE);
Selim Cinekb0fada62019-06-17 19:03:59 -0700270 mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
Jason Monke5b770e2017-03-03 21:49:29 -0500271 || (mQsExpanded && !mStackScrollerOverscrolling));
Amin Shaikhe04505e2018-04-18 10:45:13 -0400272 mQSPanel.setVisibility(!mQsDisabled && expandVisually ? View.VISIBLE : View.INVISIBLE);
Jason Monk0ceef212016-11-02 14:05:23 -0400273 }
274
Selim Cinekb0fada62019-06-17 19:03:59 -0700275 private boolean isKeyguardShowing() {
276 // We want the freshest state here since otherwise we'll have some weirdness if earlier
277 // listeners trigger updates
278 return mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
279 }
280
281 @Override
282 public void setShowCollapsedOnKeyguard(boolean showCollapsedOnKeyguard) {
283 if (showCollapsedOnKeyguard != mShowCollapsedOnKeyguard) {
284 mShowCollapsedOnKeyguard = showCollapsedOnKeyguard;
285 updateQsState();
286 if (mQSAnimator != null) {
287 mQSAnimator.setShowCollapsedOnKeyguard(showCollapsedOnKeyguard);
288 }
289 if (!showCollapsedOnKeyguard && isKeyguardShowing()) {
290 setQsExpansion(mLastQSExpansion, 0);
291 }
292 }
293 }
294
Jason Monk0ceef212016-11-02 14:05:23 -0400295 public QSPanel getQsPanel() {
296 return mQSPanel;
297 }
298
299 public QSCustomizer getCustomizer() {
300 return mQSCustomizer;
301 }
302
Anthony Chen54daefe2017-04-07 17:19:54 -0700303 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400304 public boolean isShowingDetail() {
305 return mQSPanel.isShowingCustomize() || mQSDetail.isShowingDetail();
306 }
307
Anthony Chen54daefe2017-04-07 17:19:54 -0700308 @Override
Jason Monk231b0522018-01-04 10:49:55 -0500309 public boolean onInterceptTouchEvent(MotionEvent event) {
Amin Shaikh15781d62018-02-16 16:00:13 -0500310 return isCustomizing();
Jason Monk231b0522018-01-04 10:49:55 -0500311 }
312
313 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400314 public void setHeaderClickable(boolean clickable) {
315 if (DEBUG) Log.d(TAG, "setHeaderClickable " + clickable);
Jason Monk0ceef212016-11-02 14:05:23 -0400316 }
317
Anthony Chen54daefe2017-04-07 17:19:54 -0700318 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400319 public void setExpanded(boolean expanded) {
320 if (DEBUG) Log.d(TAG, "setExpanded " + expanded);
321 mQsExpanded = expanded;
Fabian Kozynskib9dc0c72018-09-20 13:00:17 -0400322 mQSPanel.setListening(mListening, mQsExpanded);
Jason Monk0ceef212016-11-02 14:05:23 -0400323 updateQsState();
324 }
325
Selim Cinekb0fada62019-06-17 19:03:59 -0700326 private void setKeyguardShowing(boolean keyguardShowing) {
Jason Monk0ceef212016-11-02 14:05:23 -0400327 if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
Selim Cinek1a891a92017-12-04 17:41:27 +0100328 mLastQSExpansion = -1;
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800329
330 if (mQSAnimator != null) {
331 mQSAnimator.setOnKeyguard(keyguardShowing);
332 }
333
Jason Monk9dac1122017-05-30 15:21:29 -0400334 mFooter.setKeyguardShowing(keyguardShowing);
Jason Monk0ceef212016-11-02 14:05:23 -0400335 updateQsState();
336 }
337
Anthony Chen54daefe2017-04-07 17:19:54 -0700338 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400339 public void setOverscrolling(boolean stackScrollerOverscrolling) {
340 if (DEBUG) Log.d(TAG, "setOverscrolling " + stackScrollerOverscrolling);
341 mStackScrollerOverscrolling = stackScrollerOverscrolling;
342 updateQsState();
343 }
344
Anthony Chen54daefe2017-04-07 17:19:54 -0700345 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400346 public void setListening(boolean listening) {
347 if (DEBUG) Log.d(TAG, "setListening " + listening);
348 mListening = listening;
Dave Mankoffc4fe6c42019-11-18 17:03:29 -0500349 mQSContainerImplController.setListening(listening);
Jason Monk0ceef212016-11-02 14:05:23 -0400350 mHeader.setListening(listening);
Jason Monke5b770e2017-03-03 21:49:29 -0500351 mFooter.setListening(listening);
Fabian Kozynskib9dc0c72018-09-20 13:00:17 -0400352 mQSPanel.setListening(mListening, mQsExpanded);
Jason Monk0ceef212016-11-02 14:05:23 -0400353 }
354
Anthony Chen54daefe2017-04-07 17:19:54 -0700355 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400356 public void setHeaderListening(boolean listening) {
357 mHeader.setListening(listening);
Jason Monke5b770e2017-03-03 21:49:29 -0500358 mFooter.setListening(listening);
Jason Monk0ceef212016-11-02 14:05:23 -0400359 }
360
Anthony Chen54daefe2017-04-07 17:19:54 -0700361 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400362 public void setQsExpansion(float expansion, float headerTranslation) {
363 if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
364 mContainer.setExpansion(expansion);
365 final float translationScaleY = expansion - 1;
Selim Cinekb0fada62019-06-17 19:03:59 -0700366 boolean onKeyguardAndExpanded = isKeyguardShowing() && !mShowCollapsedOnKeyguard;
367 if (!mHeaderAnimating && !headerWillBeAnimating()) {
Rohan Shahd3cf7562018-02-23 11:12:28 -0800368 getView().setTranslationY(
Selim Cinekb0fada62019-06-17 19:03:59 -0700369 onKeyguardAndExpanded
Rohan Shahd3cf7562018-02-23 11:12:28 -0800370 ? translationScaleY * mHeader.getHeight()
371 : headerTranslation);
Jason Monk0ceef212016-11-02 14:05:23 -0400372 }
Selim Cinekb0fada62019-06-17 19:03:59 -0700373 if (expansion == mLastQSExpansion && mLastKeyguardAndExpanded == onKeyguardAndExpanded) {
Selim Cinek1a891a92017-12-04 17:41:27 +0100374 return;
375 }
376 mLastQSExpansion = expansion;
Selim Cinekb0fada62019-06-17 19:03:59 -0700377 mLastKeyguardAndExpanded = onKeyguardAndExpanded;
Rohan Shahd3cf7562018-02-23 11:12:28 -0800378
379 boolean fullyExpanded = expansion == 1;
Jason Monkbdefffd2017-06-26 11:22:21 -0400380 int heightDiff = mQSPanel.getBottom() - mHeader.getBottom() + mHeader.getPaddingBottom()
381 + mFooter.getHeight();
Rohan Shahd3cf7562018-02-23 11:12:28 -0800382 float panelTranslationY = translationScaleY * heightDiff;
383
384 // Let the views animate their contents correctly by giving them the necessary context.
Selim Cinekb0fada62019-06-17 19:03:59 -0700385 mHeader.setExpansion(onKeyguardAndExpanded, expansion,
386 panelTranslationY);
387 mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
Amin Shaikha07a17b2018-02-23 16:02:52 -0500388 mQSPanel.getQsTileRevealController().setExpansion(expansion);
Amin Shaikh0f8ea5432018-03-27 11:09:27 -0400389 mQSPanel.getTileLayout().setExpansion(expansion);
Jason Monke5b770e2017-03-03 21:49:29 -0500390 mQSPanel.setTranslationY(translationScaleY * heightDiff);
Amin Shaikhacd021e2018-01-25 17:25:11 -0500391 mQSDetail.setFullyExpanded(fullyExpanded);
Rohan Shahd3cf7562018-02-23 11:12:28 -0800392
Amin Shaikhacd021e2018-01-25 17:25:11 -0500393 if (fullyExpanded) {
394 // Always draw within the bounds of the view when fully expanded.
395 mQSPanel.setClipBounds(null);
396 } else {
397 // Set bounds on the QS panel so it doesn't run over the header when animating.
398 mQsBounds.top = (int) -mQSPanel.getTranslationY();
399 mQsBounds.right = mQSPanel.getWidth();
400 mQsBounds.bottom = mQSPanel.getHeight();
401 mQSPanel.setClipBounds(mQsBounds);
402 }
Anthony Chen3cb3ad92016-12-01 10:58:47 -0800403
404 if (mQSAnimator != null) {
405 mQSAnimator.setPosition(expansion);
406 }
Jason Monk0ceef212016-11-02 14:05:23 -0400407 }
408
Selim Cinekb0fada62019-06-17 19:03:59 -0700409 private boolean headerWillBeAnimating() {
410 return mState == StatusBarState.KEYGUARD && mShowCollapsedOnKeyguard
411 && !isKeyguardShowing();
412 }
413
Anthony Chen54daefe2017-04-07 17:19:54 -0700414 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400415 public void animateHeaderSlidingIn(long delay) {
416 if (DEBUG) Log.d(TAG, "animateHeaderSlidingIn");
417 // If the QS is already expanded we don't need to slide in the header as it's already
418 // visible.
Selim Cinekb0fada62019-06-17 19:03:59 -0700419 if (!mQsExpanded && getView().getTranslationY() != 0) {
Jason Monk0ceef212016-11-02 14:05:23 -0400420 mHeaderAnimating = true;
421 mDelay = delay;
422 getView().getViewTreeObserver().addOnPreDrawListener(mStartHeaderSlidingIn);
423 }
424 }
425
Anthony Chen54daefe2017-04-07 17:19:54 -0700426 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400427 public void animateHeaderSlidingOut() {
428 if (DEBUG) Log.d(TAG, "animateHeaderSlidingOut");
Selim Cinekb0fada62019-06-17 19:03:59 -0700429 if (getView().getY() == -mHeader.getHeight()) {
430 return;
431 }
Jason Monk0ceef212016-11-02 14:05:23 -0400432 mHeaderAnimating = true;
433 getView().animate().y(-mHeader.getHeight())
434 .setStartDelay(0)
435 .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
436 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
437 .setListener(new AnimatorListenerAdapter() {
438 @Override
439 public void onAnimationEnd(Animator animation) {
Fabian Kozynskiae460222018-09-27 09:36:58 -0400440 if (getView() != null) {
441 // The view could be destroyed before the animation completes when
442 // switching users.
443 getView().animate().setListener(null);
444 }
Jason Monk0ceef212016-11-02 14:05:23 -0400445 mHeaderAnimating = false;
446 updateQsState();
447 }
448 })
449 .start();
450 }
451
452 @Override
Jason Monke5b770e2017-03-03 21:49:29 -0500453 public void setExpandClickListener(OnClickListener onClickListener) {
Amin Shaikh8a3e23c2018-04-17 11:14:32 -0400454 mFooter.setExpandClickListener(onClickListener);
Jason Monke5b770e2017-03-03 21:49:29 -0500455 }
456
457 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400458 public void closeDetail() {
459 mQSPanel.closeDetail();
460 }
461
462 public void notifyCustomizeChanged() {
463 // The customize state changed, so our height changed.
Jason Monk4de5d3c2017-05-24 14:57:10 -0400464 mContainer.updateExpansion();
Jason Monk0ceef212016-11-02 14:05:23 -0400465 mQSPanel.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
Jason Monke5b770e2017-03-03 21:49:29 -0500466 mFooter.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
Jason Monk0ceef212016-11-02 14:05:23 -0400467 // Let the panel know the position changed and it needs to update where notifications
468 // and whatnot are.
469 mPanelView.onQsHeightChanged();
470 }
471
472 /**
473 * The height this view wants to be. This is different from {@link #getMeasuredHeight} such that
474 * during closing the detail panel, this already returns the smaller height.
475 */
Anthony Chen54daefe2017-04-07 17:19:54 -0700476 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400477 public int getDesiredHeight() {
478 if (mQSCustomizer.isCustomizing()) {
479 return getView().getHeight();
480 }
481 if (mQSDetail.isClosingDetail()) {
Jason Monke5b770e2017-03-03 21:49:29 -0500482 LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
483 int panelHeight = layoutParams.topMargin + layoutParams.bottomMargin +
Jason Monk0ceef212016-11-02 14:05:23 -0400484 + mQSPanel.getMeasuredHeight();
Jason Monk232ac2b2017-06-02 12:50:24 -0400485 return panelHeight + getView().getPaddingBottom();
Jason Monk0ceef212016-11-02 14:05:23 -0400486 } else {
Jason Monk232ac2b2017-06-02 12:50:24 -0400487 return getView().getMeasuredHeight();
Jason Monk0ceef212016-11-02 14:05:23 -0400488 }
489 }
490
491 @Override
492 public void setHeightOverride(int desiredHeight) {
Jason Monk232ac2b2017-06-02 12:50:24 -0400493 mContainer.setHeightOverride(desiredHeight);
Jason Monk0ceef212016-11-02 14:05:23 -0400494 }
495
Anthony Chen54daefe2017-04-07 17:19:54 -0700496 @Override
Jason Monk0ceef212016-11-02 14:05:23 -0400497 public int getQsMinExpansionHeight() {
Jason Monk4de5d3c2017-05-24 14:57:10 -0400498 return mHeader.getHeight();
Jason Monk0ceef212016-11-02 14:05:23 -0400499 }
500
501 @Override
502 public void hideImmediately() {
503 getView().animate().cancel();
504 getView().setY(-mHeader.getHeight());
505 }
506
507 private final ViewTreeObserver.OnPreDrawListener mStartHeaderSlidingIn
508 = new ViewTreeObserver.OnPreDrawListener() {
509 @Override
510 public boolean onPreDraw() {
511 getView().getViewTreeObserver().removeOnPreDrawListener(this);
512 getView().animate()
513 .translationY(0f)
514 .setStartDelay(mDelay)
515 .setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
516 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
517 .setListener(mAnimateHeaderSlidingInListener)
518 .start();
Jason Monk0ceef212016-11-02 14:05:23 -0400519 return true;
520 }
521 };
522
523 private final Animator.AnimatorListener mAnimateHeaderSlidingInListener
524 = new AnimatorListenerAdapter() {
525 @Override
526 public void onAnimationEnd(Animator animation) {
527 mHeaderAnimating = false;
528 updateQsState();
529 }
530 };
Selim Cinekb0fada62019-06-17 19:03:59 -0700531
532 @Override
533 public void onStateChanged(int newState) {
534 mState = newState;
535 setKeyguardShowing(newState == StatusBarState.KEYGUARD);
536 }
Jason Monk0ceef212016-11-02 14:05:23 -0400537}