1 /*
2  * Copyright (C) 2020 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.car.userswitcher;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.car.Car;
22 import android.car.user.CarUserManager;
23 import android.content.Context;
24 import android.content.pm.ActivityInfo;
25 import android.content.res.Configuration;
26 import android.content.res.Resources;
27 import android.view.KeyEvent;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.ViewGroup;
31 
32 import androidx.recyclerview.widget.GridLayoutManager;
33 
34 import com.android.settingslib.applications.InterestingConfigChanges;
35 import com.android.systemui.R;
36 import com.android.systemui.car.CarServiceProvider;
37 import com.android.systemui.car.window.OverlayViewController;
38 import com.android.systemui.car.window.OverlayViewGlobalStateController;
39 import com.android.systemui.dagger.SysUISingleton;
40 import com.android.systemui.dagger.qualifiers.Main;
41 import com.android.systemui.settings.UserTracker;
42 import com.android.systemui.statusbar.policy.ConfigurationController;
43 
44 import javax.inject.Inject;
45 
46 /**
47  * Controller for {@link R.layout#car_fullscreen_user_switcher}.
48  */
49 @SysUISingleton
50 public class FullScreenUserSwitcherViewController extends OverlayViewController
51         implements ConfigurationController.ConfigurationListener {
52     private final Context mContext;
53     private final UserTracker mUserTracker;
54     private final Resources mResources;
55     private final CarServiceProvider mCarServiceProvider;
56     private final int mShortAnimationDuration;
57     private CarUserManager mCarUserManager;
58     private UserGridRecyclerView mUserGridView;
59     private UserGridRecyclerView.UserSelectionListener mUserSelectionListener;
60     private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges(
61             ActivityInfo.CONFIG_UI_MODE);
62 
63 
64     @Inject
FullScreenUserSwitcherViewController( Context context, UserTracker userTracker, @Main Resources resources, ConfigurationController configurationController, CarServiceProvider carServiceProvider, OverlayViewGlobalStateController overlayViewGlobalStateController)65     public FullScreenUserSwitcherViewController(
66             Context context,
67             UserTracker userTracker,
68             @Main Resources resources,
69             ConfigurationController configurationController,
70             CarServiceProvider carServiceProvider,
71             OverlayViewGlobalStateController overlayViewGlobalStateController) {
72         super(R.id.fullscreen_user_switcher_stub, overlayViewGlobalStateController);
73         mContext = context;
74         mUserTracker = userTracker;
75         mResources = resources;
76         mCarServiceProvider = carServiceProvider;
77         mCarServiceProvider.addListener(car -> {
78             mCarUserManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE);
79             registerCarUserManagerIfPossible();
80         });
81         mShortAnimationDuration = mResources.getInteger(android.R.integer.config_shortAnimTime);
82         mConfigChanges.applyNewConfig(mContext.getResources());
83         configurationController.addCallback(this);
84     }
85 
86     @Override
onFinishInflate()87     protected void onFinishInflate() {
88         initializeViews();
89     }
90 
91     @Override
onConfigChanged(Configuration configuration)92     public void onConfigChanged(Configuration configuration) {
93         if (mConfigChanges.applyNewConfig(mContext.getResources())) {
94             // prerequisites
95             if (getLayout() == null) return;
96             UserSwitcherContainer container = getLayout().findViewById(
97                     R.id.user_switcher_container);
98             if (container == null) return;
99             ViewGroup viewGroupParent = (ViewGroup) container.getParent();
100 
101             // store index
102             int viewIndex = viewGroupParent.indexOfChild(container);
103 
104             // reinflate
105             viewGroupParent.removeView(container);
106             UserSwitcherContainer newContainer = (UserSwitcherContainer) LayoutInflater.from(
107                     mContext).inflate(R.layout.car_fullscreen_user_switcher,
108                     viewGroupParent, /* attachToRoot= */ false);
109             viewGroupParent.addView(newContainer, viewIndex);
110             initializeViews();
111         }
112     }
113 
114     @Override
getFocusAreaViewId()115     protected int getFocusAreaViewId() {
116         return R.id.user_switcher_focus_area;
117     }
118 
119     @Override
shouldFocusWindow()120     protected boolean shouldFocusWindow() {
121         return true;
122     }
123 
124     @Override
showInternal()125     protected void showInternal() {
126         getLayout().setVisibility(View.VISIBLE);
127     }
128 
129     @Override
hideInternal()130     protected void hideInternal() {
131         // Switching is about to happen, since it takes time, fade out the switcher gradually.
132         fadeOut();
133     }
134 
initializeViews()135     private void initializeViews() {
136         // Intercept back button.
137         UserSwitcherContainer container = getLayout().findViewById(R.id.user_switcher_container);
138         container.setKeyEventHandler(event -> {
139             if (event.getKeyCode() != KeyEvent.KEYCODE_BACK) {
140                 return false;
141             }
142 
143             if (event.getAction() == KeyEvent.ACTION_UP && getLayout().isVisibleToUser()) {
144                 stop();
145             }
146             return true;
147         });
148 
149         mUserGridView = getLayout().findViewById(R.id.user_grid);
150         GridLayoutManager layoutManager = new GridLayoutManager(mContext,
151                 mResources.getInteger(R.integer.user_fullscreen_switcher_num_col));
152         mUserGridView.setLayoutManager(layoutManager);
153         mUserGridView.setUserTracker(mUserTracker);
154         mUserGridView.buildAdapter();
155         mUserGridView.setUserSelectionListener(mUserSelectionListener);
156         registerCarUserManagerIfPossible();
157     }
158 
fadeOut()159     private void fadeOut() {
160         mUserGridView.animate()
161                 .alpha(0.0f)
162                 .setDuration(mShortAnimationDuration)
163                 .setListener(new AnimatorListenerAdapter() {
164                     @Override
165                     public void onAnimationEnd(Animator animation) {
166                         getLayout().setVisibility(View.GONE);
167                         mUserGridView.setAlpha(1.0f);
168                     }
169                 });
170 
171     }
172 
173     /**
174      * Set {@link UserGridRecyclerView.UserSelectionListener}.
175      */
setUserGridSelectionListener( UserGridRecyclerView.UserSelectionListener userGridSelectionListener)176     void setUserGridSelectionListener(
177             UserGridRecyclerView.UserSelectionListener userGridSelectionListener) {
178         mUserSelectionListener = userGridSelectionListener;
179     }
180 
registerCarUserManagerIfPossible()181     private void registerCarUserManagerIfPossible() {
182         if (mUserGridView != null && mCarUserManager != null) {
183             mUserGridView.setCarUserManager(mCarUserManager);
184         }
185     }
186 }
187