Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 1 | /* |
Brad Stenning | 8d1a51c | 2018-11-20 17:34:16 -0800 | [diff] [blame] | 2 | * Copyright (C) 2018 The Android Open Source Project |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 3 | * |
Brad Stenning | 8d1a51c | 2018-11-20 17:34:16 -0800 | [diff] [blame] | 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 |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
Brad Stenning | 8d1a51c | 2018-11-20 17:34:16 -0800 | [diff] [blame] | 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. |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 15 | */ |
Brad Stenning | 8d1a51c | 2018-11-20 17:34:16 -0800 | [diff] [blame] | 16 | |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 17 | package com.android.systemui.qs.car; |
| 18 | |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 19 | import android.animation.Animator; |
| 20 | import android.animation.AnimatorInflater; |
| 21 | import android.animation.AnimatorListenerAdapter; |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 22 | import android.animation.AnimatorSet; |
| 23 | import android.animation.ObjectAnimator; |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 24 | import android.animation.ValueAnimator; |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 25 | import android.app.Fragment; |
Aarthi Balachander | d8bf249 | 2018-03-30 11:15:59 -0700 | [diff] [blame] | 26 | import android.content.Context; |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 27 | import android.os.Bundle; |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 28 | import android.view.LayoutInflater; |
| 29 | import android.view.View; |
| 30 | import android.view.View.OnClickListener; |
| 31 | import android.view.ViewGroup; |
| 32 | |
Gus Prevas | ab33679 | 2018-11-14 13:52:20 -0500 | [diff] [blame] | 33 | import androidx.annotation.Nullable; |
| 34 | import androidx.annotation.VisibleForTesting; |
| 35 | import androidx.recyclerview.widget.GridLayoutManager; |
| 36 | |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 37 | import com.android.systemui.R; |
| 38 | import com.android.systemui.plugins.qs.QS; |
| 39 | import com.android.systemui.qs.QSFooter; |
Aarthi Balachander | d8bf249 | 2018-03-30 11:15:59 -0700 | [diff] [blame] | 40 | import com.android.systemui.statusbar.car.UserGridRecyclerView; |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 41 | |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 42 | import java.util.ArrayList; |
| 43 | import java.util.List; |
| 44 | |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 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; |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 52 | private View mUserSwitcherContainer; |
Bryan Eyler | 2ff9584 | 2017-08-08 16:53:33 -0700 | [diff] [blame] | 53 | private CarQSFooter mFooter; |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 54 | private View mFooterUserName; |
Bryan Eyler | ba88b3e | 2017-11-02 12:22:26 -0700 | [diff] [blame] | 55 | private View mFooterExpandIcon; |
Aarthi Balachander | d8bf249 | 2018-03-30 11:15:59 -0700 | [diff] [blame] | 56 | private UserGridRecyclerView mUserGridView; |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 57 | private AnimatorSet mAnimatorSet; |
Bryan Eyler | 204fbcb | 2017-10-12 15:01:36 -0700 | [diff] [blame] | 58 | private UserSwitchCallback mUserSwitchCallback; |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 59 | |
| 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 Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 71 | mFooterUserName = mFooter.findViewById(R.id.user_name); |
Bryan Eyler | ba88b3e | 2017-11-02 12:22:26 -0700 | [diff] [blame] | 72 | mFooterExpandIcon = mFooter.findViewById(R.id.user_switch_expand_icon); |
Bryan Eyler | 2ff9584 | 2017-08-08 16:53:33 -0700 | [diff] [blame] | 73 | |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 74 | mUserSwitcherContainer = view.findViewById(R.id.user_switcher_container); |
Bryan Eyler | 2ff9584 | 2017-08-08 16:53:33 -0700 | [diff] [blame] | 75 | |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 76 | updateUserSwitcherHeight(0); |
| 77 | |
Aarthi Balachander | d8bf249 | 2018-03-30 11:15:59 -0700 | [diff] [blame] | 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)); |
Heemin Seog | 0d5e018 | 2019-03-13 13:49:24 -0700 | [diff] [blame] | 82 | mUserGridView.setLayoutManager(layoutManager); |
Aarthi Balachander | d8bf249 | 2018-03-30 11:15:59 -0700 | [diff] [blame] | 83 | mUserGridView.buildAdapter(); |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 84 | |
Bryan Eyler | 204fbcb | 2017-10-12 15:01:36 -0700 | [diff] [blame] | 85 | mUserSwitchCallback = new UserSwitchCallback(); |
| 86 | mFooter.setUserSwitchCallback(mUserSwitchCallback); |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 87 | } |
| 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 Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 174 | 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 Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 197 | |
| 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 Stenning | 8d1a51c | 2018-11-20 17:34:16 -0800 | [diff] [blame] | 224 | if (mAnimatorSet != null) { |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 225 | mAnimatorSet.cancel(); |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 226 | } |
| 227 | |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 228 | List<Animator> allAnimators = new ArrayList<>(); |
| 229 | ValueAnimator heightAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(getContext(), |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 230 | opening ? R.anim.car_user_switcher_open_animation |
| 231 | : R.anim.car_user_switcher_close_animation); |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 232 | heightAnimator.addUpdateListener(valueAnimator -> { |
| 233 | updateUserSwitcherHeight((Integer) valueAnimator.getAnimatedValue()); |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 234 | }); |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 235 | allAnimators.add(heightAnimator); |
| 236 | |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 237 | 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 Eyler | ba88b3e | 2017-11-02 12:22:26 -0700 | [diff] [blame] | 243 | 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 Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 249 | mAnimatorSet = new AnimatorSet(); |
| 250 | mAnimatorSet.addListener(new AnimatorListenerAdapter() { |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 251 | @Override |
| 252 | public void onAnimationEnd(Animator animation) { |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 253 | mAnimatorSet = null; |
Bryan Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 254 | } |
| 255 | }); |
Bryan Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 256 | 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 Eyler | ab28b99 | 2017-10-10 16:06:02 -0700 | [diff] [blame] | 262 | 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 Eyler | 715bdbc | 2017-10-10 11:56:21 -0700 | [diff] [blame] | 273 | } |
Anthony Chen | 54daefe | 2017-04-07 17:19:54 -0700 | [diff] [blame] | 274 | } |