blob: f9cfafa5c47129d8c6cf4654633756702f1c3b70 [file] [log] [blame]
Anthony Chen54daefe2017-04-07 17:19:54 -07001/*
Brad Stenning8d1a51c2018-11-20 17:34:16 -08002 * Copyright (C) 2018 The Android Open Source Project
Anthony Chen54daefe2017-04-07 17:19:54 -07003 *
Brad Stenning8d1a51c2018-11-20 17:34:16 -08004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Anthony Chen54daefe2017-04-07 17:19:54 -07007 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
Brad Stenning8d1a51c2018-11-20 17:34:16 -080010 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Anthony Chen54daefe2017-04-07 17:19:54 -070015 */
Brad Stenning8d1a51c2018-11-20 17:34:16 -080016
Anthony Chen54daefe2017-04-07 17:19:54 -070017package com.android.systemui.qs.car;
18
Bryan Eyler715bdbc2017-10-10 11:56:21 -070019import android.animation.Animator;
20import android.animation.AnimatorInflater;
21import android.animation.AnimatorListenerAdapter;
Bryan Eylerab28b992017-10-10 16:06:02 -070022import android.animation.AnimatorSet;
23import android.animation.ObjectAnimator;
Bryan Eyler715bdbc2017-10-10 11:56:21 -070024import android.animation.ValueAnimator;
Anthony Chen54daefe2017-04-07 17:19:54 -070025import android.app.Fragment;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070026import android.content.Context;
Anthony Chen54daefe2017-04-07 17:19:54 -070027import android.os.Bundle;
Anthony Chen54daefe2017-04-07 17:19:54 -070028import android.view.LayoutInflater;
29import android.view.View;
30import android.view.View.OnClickListener;
31import android.view.ViewGroup;
32
Gus Prevasab336792018-11-14 13:52:20 -050033import androidx.annotation.Nullable;
34import androidx.annotation.VisibleForTesting;
35import androidx.recyclerview.widget.GridLayoutManager;
36
Anthony Chen54daefe2017-04-07 17:19:54 -070037import com.android.systemui.R;
38import com.android.systemui.plugins.qs.QS;
39import com.android.systemui.qs.QSFooter;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070040import com.android.systemui.statusbar.car.UserGridRecyclerView;
Anthony Chen54daefe2017-04-07 17:19:54 -070041
Bryan Eylerab28b992017-10-10 16:06:02 -070042import java.util.ArrayList;
43import java.util.List;
44
Anthony Chen54daefe2017-04-07 17:19:54 -070045/**
46 * A quick settings fragment for the car. For auto, there is no row for quick settings or ability
47 * to expand the quick settings panel. Instead, the only thing is that displayed is the
48 * status bar, and a static row with access to the user switcher and settings.
49 */
50public class CarQSFragment extends Fragment implements QS {
51 private View mHeader;
Bryan Eyler715bdbc2017-10-10 11:56:21 -070052 private View mUserSwitcherContainer;
Bryan Eyler2ff95842017-08-08 16:53:33 -070053 private CarQSFooter mFooter;
Bryan Eylerab28b992017-10-10 16:06:02 -070054 private View mFooterUserName;
Bryan Eylerba88b3e2017-11-02 12:22:26 -070055 private View mFooterExpandIcon;
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070056 private UserGridRecyclerView mUserGridView;
Bryan Eylerab28b992017-10-10 16:06:02 -070057 private AnimatorSet mAnimatorSet;
Bryan Eyler204fbcb2017-10-12 15:01:36 -070058 private UserSwitchCallback mUserSwitchCallback;
Anthony Chen54daefe2017-04-07 17:19:54 -070059
60 @Override
61 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
62 Bundle savedInstanceState) {
63 return inflater.inflate(R.layout.car_qs_panel, container, false);
64 }
65
66 @Override
67 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
68 super.onViewCreated(view, savedInstanceState);
69 mHeader = view.findViewById(R.id.header);
70 mFooter = view.findViewById(R.id.qs_footer);
Bryan Eylerab28b992017-10-10 16:06:02 -070071 mFooterUserName = mFooter.findViewById(R.id.user_name);
Bryan Eylerba88b3e2017-11-02 12:22:26 -070072 mFooterExpandIcon = mFooter.findViewById(R.id.user_switch_expand_icon);
Bryan Eyler2ff95842017-08-08 16:53:33 -070073
Bryan Eyler715bdbc2017-10-10 11:56:21 -070074 mUserSwitcherContainer = view.findViewById(R.id.user_switcher_container);
Bryan Eyler2ff95842017-08-08 16:53:33 -070075
Bryan Eyler715bdbc2017-10-10 11:56:21 -070076 updateUserSwitcherHeight(0);
77
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070078 Context context = getContext();
79 mUserGridView = mUserSwitcherContainer.findViewById(R.id.user_grid);
80 GridLayoutManager layoutManager = new GridLayoutManager(context,
81 context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col));
Heemin Seog0d5e0182019-03-13 13:49:24 -070082 mUserGridView.setLayoutManager(layoutManager);
Aarthi Balachanderd8bf2492018-03-30 11:15:59 -070083 mUserGridView.buildAdapter();
Bryan Eyler715bdbc2017-10-10 11:56:21 -070084
Bryan Eyler204fbcb2017-10-12 15:01:36 -070085 mUserSwitchCallback = new UserSwitchCallback();
86 mFooter.setUserSwitchCallback(mUserSwitchCallback);
Anthony Chen54daefe2017-04-07 17:19:54 -070087 }
88
89 @Override
90 public void hideImmediately() {
91 getView().setVisibility(View.INVISIBLE);
92 }
93
94 @Override
95 public void setQsExpansion(float qsExpansionFraction, float headerTranslation) {
96 // If the header is to be completed translated down, then set it to be visible.
97 getView().setVisibility(headerTranslation == 0 ? View.VISIBLE : View.INVISIBLE);
98 }
99
100 @Override
101 public View getHeader() {
102 return mHeader;
103 }
104
105 @VisibleForTesting
106 QSFooter getFooter() {
107 return mFooter;
108 }
109
110 @Override
111 public void setHeaderListening(boolean listening) {
112 mFooter.setListening(listening);
113 }
114
115 @Override
116 public void setListening(boolean listening) {
117 mFooter.setListening(listening);
118 }
119
120 @Override
121 public int getQsMinExpansionHeight() {
122 return getView().getHeight();
123 }
124
125 @Override
126 public int getDesiredHeight() {
127 return getView().getHeight();
128 }
129
130 @Override
131 public void setPanelView(HeightListener notificationPanelView) {
132 // No quick settings panel.
133 }
134
135 @Override
136 public void setHeightOverride(int desiredHeight) {
137 // No ability to expand quick settings.
138 }
139
140 @Override
141 public void setHeaderClickable(boolean qsExpansionEnabled) {
142 // Usually this sets the expand button to be clickable, but there is no quick settings to
143 // expand.
144 }
145
146 @Override
147 public boolean isCustomizing() {
148 // No ability to customize the quick settings.
149 return false;
150 }
151
152 @Override
153 public void setOverscrolling(boolean overscrolling) {
154 // No overscrolling to reveal quick settings.
155 }
156
157 @Override
158 public void setExpanded(boolean qsExpanded) {
159 // No quick settings to expand
160 }
161
162 @Override
163 public boolean isShowingDetail() {
164 // No detail panel to close.
165 return false;
166 }
167
168 @Override
169 public void closeDetail() {
170 // No detail panel to close.
171 }
172
173 @Override
Anthony Chen54daefe2017-04-07 17:19:54 -0700174 public void animateHeaderSlidingIn(long delay) {
175 // No header to animate.
176 }
177
178 @Override
179 public void animateHeaderSlidingOut() {
180 // No header to animate.
181 }
182
183 @Override
184 public void notifyCustomizeChanged() {
185 // There is no ability to customize quick settings.
186 }
187
188 @Override
189 public void setContainer(ViewGroup container) {
190 // No quick settings, so no container to set.
191 }
192
193 @Override
194 public void setExpandClickListener(OnClickListener onClickListener) {
195 // No ability to expand the quick settings.
196 }
Bryan Eyler715bdbc2017-10-10 11:56:21 -0700197
198 public class UserSwitchCallback {
199 private boolean mShowing;
200
201 public boolean isShowing() {
202 return mShowing;
203 }
204
205 public void show() {
206 mShowing = true;
207 animateHeightChange(true /* opening */);
208 }
209
210 public void hide() {
211 mShowing = false;
212 animateHeightChange(false /* opening */);
213 }
214 }
215
216 private void updateUserSwitcherHeight(int height) {
217 ViewGroup.LayoutParams layoutParams = mUserSwitcherContainer.getLayoutParams();
218 layoutParams.height = height;
219 mUserSwitcherContainer.requestLayout();
220 }
221
222 private void animateHeightChange(boolean opening) {
223 // Animation in progress; cancel it to avoid contention.
Brad Stenning8d1a51c2018-11-20 17:34:16 -0800224 if (mAnimatorSet != null) {
Bryan Eylerab28b992017-10-10 16:06:02 -0700225 mAnimatorSet.cancel();
Bryan Eyler715bdbc2017-10-10 11:56:21 -0700226 }
227
Bryan Eylerab28b992017-10-10 16:06:02 -0700228 List<Animator> allAnimators = new ArrayList<>();
229 ValueAnimator heightAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(getContext(),
Bryan Eyler715bdbc2017-10-10 11:56:21 -0700230 opening ? R.anim.car_user_switcher_open_animation
231 : R.anim.car_user_switcher_close_animation);
Bryan Eylerab28b992017-10-10 16:06:02 -0700232 heightAnimator.addUpdateListener(valueAnimator -> {
233 updateUserSwitcherHeight((Integer) valueAnimator.getAnimatedValue());
Bryan Eyler715bdbc2017-10-10 11:56:21 -0700234 });
Bryan Eylerab28b992017-10-10 16:06:02 -0700235 allAnimators.add(heightAnimator);
236
Bryan Eylerab28b992017-10-10 16:06:02 -0700237 Animator nameAnimator = AnimatorInflater.loadAnimator(getContext(),
238 opening ? R.anim.car_user_switcher_open_name_animation
239 : R.anim.car_user_switcher_close_name_animation);
240 nameAnimator.setTarget(mFooterUserName);
241 allAnimators.add(nameAnimator);
242
Bryan Eylerba88b3e2017-11-02 12:22:26 -0700243 Animator iconAnimator = AnimatorInflater.loadAnimator(getContext(),
244 opening ? R.anim.car_user_switcher_open_icon_animation
245 : R.anim.car_user_switcher_close_icon_animation);
246 iconAnimator.setTarget(mFooterExpandIcon);
247 allAnimators.add(iconAnimator);
248
Bryan Eylerab28b992017-10-10 16:06:02 -0700249 mAnimatorSet = new AnimatorSet();
250 mAnimatorSet.addListener(new AnimatorListenerAdapter() {
Bryan Eyler715bdbc2017-10-10 11:56:21 -0700251 @Override
252 public void onAnimationEnd(Animator animation) {
Bryan Eylerab28b992017-10-10 16:06:02 -0700253 mAnimatorSet = null;
Bryan Eyler715bdbc2017-10-10 11:56:21 -0700254 }
255 });
Bryan Eylerab28b992017-10-10 16:06:02 -0700256 mAnimatorSet.playTogether(allAnimators.toArray(new Animator[0]));
257
258 // Setup all values to the start values in the animations, since there are delays, but need
259 // to have all values start at the beginning.
260 setupInitialValues(mAnimatorSet);
261
Bryan Eylerab28b992017-10-10 16:06:02 -0700262 mAnimatorSet.start();
263 }
264
265 private void setupInitialValues(Animator anim) {
266 if (anim instanceof AnimatorSet) {
267 for (Animator a : ((AnimatorSet) anim).getChildAnimations()) {
268 setupInitialValues(a);
269 }
270 } else if (anim instanceof ObjectAnimator) {
271 ((ObjectAnimator) anim).setCurrentFraction(0.0f);
272 }
Bryan Eyler715bdbc2017-10-10 11:56:21 -0700273 }
Anthony Chen54daefe2017-04-07 17:19:54 -0700274}