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.statusbar;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.pm.UserInfo;
24 import android.graphics.drawable.Drawable;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.view.View;
28 import android.widget.ImageView;
29 import android.widget.TextView;
30 
31 import androidx.annotation.MainThread;
32 import androidx.annotation.VisibleForTesting;
33 
34 import com.android.systemui.R;
35 import com.android.systemui.broadcast.BroadcastDispatcher;
36 import com.android.systemui.car.userswitcher.UserIconProvider;
37 import com.android.systemui.dagger.SysUISingleton;
38 import com.android.systemui.settings.UserTracker;
39 
40 import java.util.ArrayList;
41 
42 import javax.inject.Inject;
43 
44 /**
45  * Controls TextView and ImageView for the current logged in user.
46  * User icon image consists of the first letter of user name.
47  * Therefore, the user name and icon have to be changed at the same time.
48  */
49 @SysUISingleton
50 public class UserNameViewController {
51     private static final String TAG = "UserNameViewController";
52 
53     private Context mContext;
54     private UserTracker mUserTracker;
55     private UserManager mUserManager;
56     private BroadcastDispatcher mBroadcastDispatcher;
57     private String mLastUserName;
58 
59     @VisibleForTesting
60     UserIconProvider mUserIconProvider;
61 
62     @VisibleForTesting
63     ArrayList<TextView> mUserNameViews = new ArrayList<TextView>();
64     @VisibleForTesting
65     ArrayList<ImageView> mUserIconViews = new ArrayList<ImageView>();
66 
67     private final BroadcastReceiver mUserUpdateReceiver = new BroadcastReceiver() {
68         @Override
69         public void onReceive(Context context, Intent intent) {
70             updateUser(mUserTracker.getUserId());
71         }
72     };
73 
74     private boolean mUserLifecycleListenerRegistered = false;
75 
76     private final UserTracker.Callback mUserChangedCallback =
77             new UserTracker.Callback() {
78                 @Override
79                 public void onUserChanged(int newUser, Context userContext) {
80                     updateUser(newUser);
81                 }
82             };
83 
84     @Inject
UserNameViewController(Context context, UserTracker userTracker, UserManager userManager, BroadcastDispatcher broadcastDispatcher)85     public UserNameViewController(Context context, UserTracker userTracker,
86             UserManager userManager, BroadcastDispatcher broadcastDispatcher) {
87         mContext = context;
88         mUserTracker = userTracker;
89         mUserManager = userManager;
90         mBroadcastDispatcher = broadcastDispatcher;
91         mUserIconProvider = new UserIconProvider();
92     }
93 
94     /**
95      * Find the {@link ImageView} or {@link TextView} for the user from a view
96      * and if found set them with the current user name and icon.
97      */
98      @MainThread
addUserNameView(View v)99     public void addUserNameView(View v) {
100         TextView userNameView = v.findViewById(R.id.user_name_text);
101         if (userNameView != null) {
102             ImageView userIconView = v.findViewById(R.id.user_icon);
103 
104             if (mUserNameViews.size() == 0
105                     || (userIconView != null && mUserIconViews.size() == 0)) {
106                 registerForUserChangeEvents();
107             }
108 
109             if (!mUserNameViews.contains(userNameView)) {
110                 mUserNameViews.add(userNameView);
111             }
112 
113             if (userIconView != null && !mUserIconViews.contains(userIconView)) {
114                 mUserIconViews.add(userIconView);
115             }
116 
117             updateUser(mUserTracker.getUserId());
118         }
119     }
120 
121     /**
122      * Find the {@link ImageView} or {@link TextView} for the user from a view and if found remove
123      * them from the user views list.
124      */
removeUserNameView(View v)125     public void removeUserNameView(View v) {
126         TextView userNameView = v.findViewById(R.id.user_name_text);
127         if (userNameView != null && mUserNameViews.contains(userNameView)) {
128             mUserNameViews.remove(userNameView);
129         }
130 
131         ImageView userIconView = v.findViewById(R.id.user_icon);
132         if (userIconView != null && mUserIconViews.contains(userIconView)) {
133             mUserIconViews.remove(userIconView);
134         }
135     }
136 
137     /**
138      * Clean up the controller and unregister receiver.
139      */
removeAll()140     public void removeAll() {
141         mUserNameViews.clear();
142         mUserIconViews.clear();
143         if (mUserLifecycleListenerRegistered) {
144             mBroadcastDispatcher.unregisterReceiver(mUserUpdateReceiver);
145             mUserTracker.removeCallback(mUserChangedCallback);
146             mUserLifecycleListenerRegistered = false;
147         }
148     }
149 
registerForUserChangeEvents()150     private void registerForUserChangeEvents() {
151         // Register for user switching
152         if (!mUserLifecycleListenerRegistered) {
153             mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
154             mUserLifecycleListenerRegistered = true;
155         }
156         // Also register for user info changing
157         IntentFilter filter = new IntentFilter();
158         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
159         mBroadcastDispatcher.registerReceiver(mUserUpdateReceiver, filter, /* executor= */ null,
160                 UserHandle.ALL);
161     }
162 
updateUser(int userId)163     private void updateUser(int userId) {
164         UserInfo currentUserInfo = mUserManager.getUserInfo(userId);
165 
166         // Update user name
167         for (int i = 0; i < mUserNameViews.size(); i++) {
168             mUserNameViews.get(i).setText(currentUserInfo.name);
169         }
170 
171         // Update user icon with the first letter of the user name
172         if (mLastUserName == null || !mLastUserName.equals(currentUserInfo.name)) {
173             mLastUserName = currentUserInfo.name;
174             mUserIconProvider.setRoundedUserIcon(currentUserInfo, mContext);
175         }
176 
177         for (int i = 0; i < mUserIconViews.size(); i++) {
178             updateUserIcon(mUserIconViews.get(i), currentUserInfo);
179         }
180     }
181 
updateUserIcon(ImageView userIconView, UserInfo currentUserInfo)182     private void updateUserIcon(ImageView userIconView, UserInfo currentUserInfo) {
183         Drawable circleIcon = mUserIconProvider.getRoundedUserIcon(currentUserInfo, mContext);
184         userIconView.setImageDrawable(circleIcon);
185     }
186 }
187