• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * 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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * 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.
15  */
16 
17 package com.android.systemui.qs.car;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorInflater;
21 import android.animation.AnimatorListenerAdapter;
22 import android.animation.AnimatorSet;
23 import android.animation.ObjectAnimator;
24 import android.animation.ValueAnimator;
25 import android.app.Fragment;
26 import android.content.Context;
27 import android.os.Bundle;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.View.OnClickListener;
31 import android.view.ViewGroup;
32 
33 import androidx.annotation.Nullable;
34 import androidx.annotation.VisibleForTesting;
35 import androidx.recyclerview.widget.GridLayoutManager;
36 
37 import com.android.systemui.R;
38 import com.android.systemui.plugins.qs.QS;
39 import com.android.systemui.qs.QSFooter;
40 import com.android.systemui.statusbar.car.UserGridRecyclerView;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 /**
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  */
50 public class CarQSFragment extends Fragment implements QS {
51     private View mHeader;
52     private View mUserSwitcherContainer;
53     private CarQSFooter mFooter;
54     private View mFooterUserName;
55     private View mFooterExpandIcon;
56     private UserGridRecyclerView mUserGridView;
57     private AnimatorSet mAnimatorSet;
58     private UserSwitchCallback mUserSwitchCallback;
59 
60     @Override
onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState)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
onViewCreated(View view, @Nullable Bundle savedInstanceState)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);
71         mFooterUserName = mFooter.findViewById(R.id.user_name);
72         mFooterExpandIcon = mFooter.findViewById(R.id.user_switch_expand_icon);
73 
74         mUserSwitcherContainer = view.findViewById(R.id.user_switcher_container);
75 
76         updateUserSwitcherHeight(0);
77 
78         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));
82         mUserGridView.setLayoutManager(layoutManager);
83         mUserGridView.buildAdapter();
84 
85         mUserSwitchCallback = new UserSwitchCallback();
86         mFooter.setUserSwitchCallback(mUserSwitchCallback);
87     }
88 
89     @Override
hideImmediately()90     public void hideImmediately() {
91         getView().setVisibility(View.INVISIBLE);
92     }
93 
94     @Override
setQsExpansion(float qsExpansionFraction, float headerTranslation)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
getHeader()101     public View getHeader() {
102         return mHeader;
103     }
104 
105     @VisibleForTesting
getFooter()106     QSFooter getFooter() {
107         return mFooter;
108     }
109 
110     @Override
setHeaderListening(boolean listening)111     public void setHeaderListening(boolean listening) {
112         mFooter.setListening(listening);
113     }
114 
115     @Override
setListening(boolean listening)116     public void setListening(boolean listening) {
117         mFooter.setListening(listening);
118     }
119 
120     @Override
getQsMinExpansionHeight()121     public int getQsMinExpansionHeight() {
122         return getView().getHeight();
123     }
124 
125     @Override
getDesiredHeight()126     public int getDesiredHeight() {
127         return getView().getHeight();
128     }
129 
130     @Override
setPanelView(HeightListener notificationPanelView)131     public void setPanelView(HeightListener notificationPanelView) {
132         // No quick settings panel.
133     }
134 
135     @Override
setHeightOverride(int desiredHeight)136     public void setHeightOverride(int desiredHeight) {
137         // No ability to expand quick settings.
138     }
139 
140     @Override
setHeaderClickable(boolean qsExpansionEnabled)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
isCustomizing()147     public boolean isCustomizing() {
148         // No ability to customize the quick settings.
149         return false;
150     }
151 
152     @Override
setOverscrolling(boolean overscrolling)153     public void setOverscrolling(boolean overscrolling) {
154         // No overscrolling to reveal quick settings.
155     }
156 
157     @Override
setExpanded(boolean qsExpanded)158     public void setExpanded(boolean qsExpanded) {
159         // No quick settings to expand
160     }
161 
162     @Override
isShowingDetail()163     public boolean isShowingDetail() {
164         // No detail panel to close.
165         return false;
166     }
167 
168     @Override
closeDetail()169     public void closeDetail() {
170         // No detail panel to close.
171     }
172 
173     @Override
setKeyguardShowing(boolean keyguardShowing)174     public void setKeyguardShowing(boolean keyguardShowing) {
175         // No keyguard to show.
176     }
177 
178     @Override
animateHeaderSlidingIn(long delay)179     public void animateHeaderSlidingIn(long delay) {
180         // No header to animate.
181     }
182 
183     @Override
animateHeaderSlidingOut()184     public void animateHeaderSlidingOut() {
185         // No header to animate.
186     }
187 
188     @Override
notifyCustomizeChanged()189     public void notifyCustomizeChanged() {
190         // There is no ability to customize quick settings.
191     }
192 
193     @Override
setContainer(ViewGroup container)194     public void setContainer(ViewGroup container) {
195         // No quick settings, so no container to set.
196     }
197 
198     @Override
setExpandClickListener(OnClickListener onClickListener)199     public void setExpandClickListener(OnClickListener onClickListener) {
200         // No ability to expand the quick settings.
201     }
202 
203     public class UserSwitchCallback {
204         private boolean mShowing;
205 
isShowing()206         public boolean isShowing() {
207             return mShowing;
208         }
209 
show()210         public void show() {
211             mShowing = true;
212             animateHeightChange(true /* opening */);
213         }
214 
hide()215         public void hide() {
216             mShowing = false;
217             animateHeightChange(false /* opening */);
218         }
219     }
220 
updateUserSwitcherHeight(int height)221     private void updateUserSwitcherHeight(int height) {
222         ViewGroup.LayoutParams layoutParams = mUserSwitcherContainer.getLayoutParams();
223         layoutParams.height = height;
224         mUserSwitcherContainer.requestLayout();
225     }
226 
animateHeightChange(boolean opening)227     private void animateHeightChange(boolean opening) {
228         // Animation in progress; cancel it to avoid contention.
229         if (mAnimatorSet != null) {
230             mAnimatorSet.cancel();
231         }
232 
233         List<Animator> allAnimators = new ArrayList<>();
234         ValueAnimator heightAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(getContext(),
235                 opening ? R.anim.car_user_switcher_open_animation
236                         : R.anim.car_user_switcher_close_animation);
237         heightAnimator.addUpdateListener(valueAnimator -> {
238             updateUserSwitcherHeight((Integer) valueAnimator.getAnimatedValue());
239         });
240         allAnimators.add(heightAnimator);
241 
242         Animator nameAnimator = AnimatorInflater.loadAnimator(getContext(),
243                 opening ? R.anim.car_user_switcher_open_name_animation
244                         : R.anim.car_user_switcher_close_name_animation);
245         nameAnimator.setTarget(mFooterUserName);
246         allAnimators.add(nameAnimator);
247 
248         Animator iconAnimator = AnimatorInflater.loadAnimator(getContext(),
249                 opening ? R.anim.car_user_switcher_open_icon_animation
250                         : R.anim.car_user_switcher_close_icon_animation);
251         iconAnimator.setTarget(mFooterExpandIcon);
252         allAnimators.add(iconAnimator);
253 
254         mAnimatorSet = new AnimatorSet();
255         mAnimatorSet.addListener(new AnimatorListenerAdapter() {
256             @Override
257             public void onAnimationEnd(Animator animation) {
258                 mAnimatorSet = null;
259             }
260         });
261         mAnimatorSet.playTogether(allAnimators.toArray(new Animator[0]));
262 
263         // Setup all values to the start values in the animations, since there are delays, but need
264         // to have all values start at the beginning.
265         setupInitialValues(mAnimatorSet);
266 
267         mAnimatorSet.start();
268     }
269 
setupInitialValues(Animator anim)270     private void setupInitialValues(Animator anim) {
271         if (anim instanceof AnimatorSet) {
272             for (Animator a : ((AnimatorSet) anim).getChildAnimations()) {
273                 setupInitialValues(a);
274             }
275         } else if (anim instanceof ObjectAnimator) {
276             ((ObjectAnimator) anim).setCurrentFraction(0.0f);
277         }
278     }
279 }
280