• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.launcher3.pm;
18 
19 import static com.android.launcher3.Utilities.ATLEAST_U;
20 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
21 
22 import android.content.Context;
23 import android.content.Intent;
24 import android.os.Process;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.util.ArrayMap;
28 
29 import androidx.annotation.AnyThread;
30 import androidx.annotation.NonNull;
31 import androidx.annotation.WorkerThread;
32 
33 import com.android.launcher3.util.MainThreadInitializedObject;
34 import com.android.launcher3.util.SafeCloseable;
35 import com.android.launcher3.util.SimpleBroadcastReceiver;
36 
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.function.BiConsumer;
42 
43 /**
44  * Class which manages a local cache of user handles to avoid system rpc
45  */
46 public class UserCache implements SafeCloseable {
47 
48     public static final String ACTION_PROFILE_ADDED = ATLEAST_U
49             ? Intent.ACTION_PROFILE_ADDED : Intent.ACTION_MANAGED_PROFILE_ADDED;
50     public static final String ACTION_PROFILE_REMOVED = ATLEAST_U
51             ? Intent.ACTION_PROFILE_REMOVED : Intent.ACTION_MANAGED_PROFILE_REMOVED;
52 
53     public static final String ACTION_PROFILE_UNLOCKED = ATLEAST_U
54             ? Intent.ACTION_PROFILE_ACCESSIBLE : Intent.ACTION_MANAGED_PROFILE_UNLOCKED;
55     public static final String ACTION_PROFILE_LOCKED = ATLEAST_U
56             ? Intent.ACTION_PROFILE_INACCESSIBLE : Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE;
57 
58     public static final MainThreadInitializedObject<UserCache> INSTANCE =
59             new MainThreadInitializedObject<>(UserCache::new);
60 
61     private final List<BiConsumer<UserHandle, String>> mUserEventListeners = new ArrayList<>();
62     private final SimpleBroadcastReceiver mUserChangeReceiver =
63             new SimpleBroadcastReceiver(this::onUsersChanged);
64 
65     private final Context mContext;
66 
67     @NonNull
68     private Map<UserHandle, Long> mUserToSerialMap;
69 
UserCache(Context context)70     private UserCache(Context context) {
71         mContext = context;
72         mUserToSerialMap = Collections.emptyMap();
73         MODEL_EXECUTOR.execute(this::initAsync);
74     }
75 
76     @Override
close()77     public void close() {
78         MODEL_EXECUTOR.execute(() -> mUserChangeReceiver.unregisterReceiverSafely(mContext));
79     }
80 
81     @WorkerThread
initAsync()82     private void initAsync() {
83         mUserChangeReceiver.register(mContext,
84                 Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
85                 Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
86                 ACTION_PROFILE_ADDED,
87                 ACTION_PROFILE_REMOVED,
88                 ACTION_PROFILE_UNLOCKED,
89                 ACTION_PROFILE_LOCKED);
90         updateCache();
91     }
92 
93     @AnyThread
onUsersChanged(Intent intent)94     private void onUsersChanged(Intent intent) {
95         MODEL_EXECUTOR.execute(this::updateCache);
96         UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
97         if (user == null) {
98             return;
99         }
100         String action = intent.getAction();
101         mUserEventListeners.forEach(l -> l.accept(user, action));
102     }
103 
104     @WorkerThread
updateCache()105     private void updateCache() {
106         mUserToSerialMap = queryAllUsers(mContext.getSystemService(UserManager.class));
107     }
108 
109     /**
110      * Adds a listener for user additions and removals
111      */
addUserEventListener(BiConsumer<UserHandle, String> listener)112     public SafeCloseable addUserEventListener(BiConsumer<UserHandle, String> listener) {
113         mUserEventListeners.add(listener);
114         return () -> mUserEventListeners.remove(listener);
115     }
116 
117     /**
118      * @see UserManager#getSerialNumberForUser(UserHandle)
119      */
getSerialNumberForUser(UserHandle user)120     public long getSerialNumberForUser(UserHandle user) {
121         Long serial = mUserToSerialMap.get(user);
122         return serial == null ? 0 : serial;
123     }
124 
125     /**
126      * @see UserManager#getUserForSerialNumber(long)
127      */
getUserForSerialNumber(long serialNumber)128     public UserHandle getUserForSerialNumber(long serialNumber) {
129         Long value = serialNumber;
130         return mUserToSerialMap
131                 .entrySet()
132                 .stream()
133                 .filter(entry -> value.equals(entry.getValue()))
134                 .findFirst()
135                 .map(Map.Entry::getKey)
136                 .orElse(Process.myUserHandle());
137     }
138 
139     /**
140      * @see UserManager#getUserProfiles()
141      */
getUserProfiles()142     public List<UserHandle> getUserProfiles() {
143         return List.copyOf(mUserToSerialMap.keySet());
144     }
145 
queryAllUsers(UserManager userManager)146     private static Map<UserHandle, Long> queryAllUsers(UserManager userManager) {
147         Map<UserHandle, Long> users = new ArrayMap<>();
148         List<UserHandle> usersActual = userManager.getUserProfiles();
149         if (usersActual != null) {
150             for (UserHandle user : usersActual) {
151                 long serial = userManager.getSerialNumberForUser(user);
152                 users.put(user, serial);
153             }
154         }
155         return users;
156     }
157 }
158