• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.documentsui.base;
18 
19 import static androidx.core.util.Preconditions.checkNotNull;
20 
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.graphics.drawable.Drawable;
26 import android.net.Uri;
27 import android.os.Process;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 import android.provider.DocumentsContract;
31 
32 import androidx.annotation.VisibleForTesting;
33 import androidx.loader.content.CursorLoader;
34 
35 import java.io.DataInputStream;
36 import java.io.DataOutputStream;
37 import java.io.IOException;
38 import java.net.ProtocolException;
39 import java.util.Objects;
40 /**
41  * Representation of a {@link UserHandle}.
42  */
43 public final class UserId {
44 
45     // A unspecified user is used as when the user's value is uninitialized. e.g. rootInfo.reset()
46     public static final UserId UNSPECIFIED_USER = UserId.of(UserHandle.of(-1000));
47     // A current user represents the user of the app's process. It is mainly used for comparison.
48     public static final UserId CURRENT_USER = UserId.of(Process.myUserHandle());
49     // A default user represents the user of the app's process. It is mainly used for operation
50     // which supports only the current user only.
51     public static final UserId DEFAULT_USER = CURRENT_USER;
52 
53     private static final int VERSION_INIT = 1;
54 
55     private final UserHandle mUserHandle;
56 
UserId(UserHandle userHandle)57     private UserId(UserHandle userHandle) {
58         checkNotNull(userHandle);
59         mUserHandle = userHandle;
60     }
61 
62     /**
63      * Returns a {@link UserId} for a given {@link UserHandle}.
64      */
of(UserHandle userHandle)65     public static UserId of(UserHandle userHandle) {
66         return new UserId(userHandle);
67     }
68 
69     /**
70      * Returns a {@link UserId} for the given user id identifier.
71      *
72      * @see UserHandle#getIdentifier
73      */
of(int userIdentifier)74     public static UserId of(int userIdentifier) {
75         return of(UserHandle.of(userIdentifier));
76     }
77 
78     /**
79      * Returns the given context if the user is the current user or unspecified. Otherwise, returns
80      * an "android" package context as the user.
81      *
82      * @throws IllegalStateException if android package of the other user does not exist
83      */
84     @VisibleForTesting
asContext(Context context)85     Context asContext(Context context) {
86         if (CURRENT_USER.equals(this) || isUnspecified()) {
87             return context;
88         }
89         try {
90             return context.createPackageContextAsUser("android", /* flags= */ 0, mUserHandle);
91         } catch (PackageManager.NameNotFoundException e) {
92             throw new IllegalStateException("android package not found.");
93         }
94 
95     }
96 
97     /**
98      * Return this User's {@link UserHandle}.
99      */
getUserHandle()100     public UserHandle getUserHandle() {
101         return mUserHandle;
102     }
103 
104     /**
105      * Return a package manager instance of this user.
106      */
getPackageManager(Context context)107     public PackageManager getPackageManager(Context context) {
108         return asContext(context).getPackageManager();
109     }
110 
111     /**
112      * Return a content resolver instance of this user.
113      */
getContentResolver(Context context)114     public ContentResolver getContentResolver(Context context) {
115         return asContext(context).getContentResolver();
116     }
117 
118     /**
119      * Returns a drawable object associated with a particular resource ID in this user.
120      */
getDrawable(Context context, int resId)121     public Drawable getDrawable(Context context, int resId) {
122         return asContext(context).getDrawable(resId);
123     }
124 
125     /**
126      * If this target user is a managed profile, then this returns a badged copy of the given icon
127      * to be able to distinguish it from the original icon.
128      */
getUserBadgedIcon(Context context, Drawable drawable)129     public Drawable getUserBadgedIcon(Context context, Drawable drawable) {
130         return getPackageManager(context).getUserBadgedIcon(drawable, mUserHandle);
131     }
132 
133     /**
134      * Returns the value of {@link PackageManager#getUserBadgedLabel(CharSequence, UserHandle)} for
135      * the user and given label.
136      */
getUserBadgedLabel(Context context, CharSequence label)137     public CharSequence getUserBadgedLabel(Context context, CharSequence label) {
138         return getPackageManager(context).getUserBadgedLabel(label, mUserHandle);
139     }
140 
141     /**
142      * Returns true if this user refers to the system user; false otherwise.
143      */
isSystem()144     public boolean isSystem() {
145         return mUserHandle.isSystem();
146     }
147 
148     /**
149      * Returns true if the this user is a managed profile.
150      */
isManagedProfile(UserManager userManager)151     public boolean isManagedProfile(UserManager userManager) {
152         return userManager.isManagedProfile(mUserHandle.getIdentifier());
153     }
154 
155     /**
156      * Returns true if the this user is in quiet mode.
157      */
isQuietModeEnabled(Context context)158     public boolean isQuietModeEnabled(Context context) {
159         final UserManager userManager = context.getSystemService(UserManager.class);
160         assert userManager != null;
161         return userManager.isQuietModeEnabled(mUserHandle);
162     }
163 
164     /**
165      * Disables quiet mode for a managed profile. The caller should check {@code
166      * MODIFY_QUIET_MODE} permission first.
167      *
168      * @return {@code false} if user's credential is needed in order to turn off quiet mode,
169      * {@code true} otherwise
170      */
requestQuietModeDisabled(Context context)171     public boolean requestQuietModeDisabled(Context context) {
172         final UserManager userManager =
173                 (UserManager) context.getSystemService(Context.USER_SERVICE);
174         return userManager.requestQuietModeEnabled(false, mUserHandle);
175     }
176 
177     /**
178      * Returns a document uri representing this user.
179      */
buildDocumentUriAsUser(String authority, String documentId)180     public Uri buildDocumentUriAsUser(String authority, String documentId) {
181         return DocumentsContract.buildDocumentUriAsUser(authority, documentId, mUserHandle);
182     }
183 
184     /**
185      * Returns a tree document uri representing this user.
186      */
buildTreeDocumentUriAsUser(String authority, String documentId)187     public Uri buildTreeDocumentUriAsUser(String authority, String documentId) {
188         String authorityWithUserInfo = buildDocumentUriAsUser(authority, documentId).getAuthority();
189         Uri treeUri = DocumentsContract.buildTreeDocumentUri(authority, documentId);
190 
191         return treeUri.buildUpon()
192                 .encodedAuthority(authorityWithUserInfo)
193                 .build();
194     }
195 
196     /**
197      * Starts activity for this user
198      */
startActivityAsUser(Context context, Intent intent)199     public void startActivityAsUser(Context context, Intent intent) {
200         context.startActivityAsUser(intent, mUserHandle);
201     }
202 
203     /**
204      * Returns an identifier stored in this user id. This can be used to recreate the {@link UserId}
205      * by {@link UserId#of(int)}.
206      */
getIdentifier()207     public int getIdentifier() {
208         return mUserHandle.getIdentifier();
209     }
210 
isUnspecified()211     private boolean isUnspecified() {
212         return UNSPECIFIED_USER.equals(this);
213     }
214 
215     @Override
toString()216     public String toString() {
217         return isUnspecified() ? "UNSPECIFIED" : String.valueOf(mUserHandle.getIdentifier());
218     }
219 
220     @Override
equals(Object o)221     public boolean equals(Object o) {
222         if (o == null) {
223             return false;
224         }
225 
226         if (this == o) {
227             return true;
228         }
229 
230         if (o instanceof UserId) {
231             UserId other = (UserId) o;
232             return Objects.equals(mUserHandle, other.mUserHandle);
233         }
234 
235         return false;
236     }
237 
238     @Override
hashCode()239     public int hashCode() {
240         return Objects.hash(mUserHandle);
241     }
242 
243     /**
244      * Reads a {@link UserId} from an input stream.
245      */
read(DataInputStream in)246     public static UserId read(DataInputStream in) throws IOException {
247         final int version = in.readInt();
248         switch (version) {
249             case VERSION_INIT:
250                 int userId = in.readInt();
251                 return UserId.of(UserHandle.of(userId));
252             default:
253                 throw new ProtocolException("Unknown version " + version);
254         }
255     }
256 
257     /**
258      * Writes a {@link UserId} to an output stream.
259      */
write(DataOutputStream out, UserId userId)260     public static void write(DataOutputStream out, UserId userId) throws IOException {
261         out.writeInt(VERSION_INIT);
262         out.writeInt(userId.mUserHandle.getIdentifier());
263     }
264 
265     /**
266      * Create a cursor loader of the user for the given uri.
267      */
createCursorLoader(Context context, Uri uri, UserId userId)268     public static CursorLoader createCursorLoader(Context context, Uri uri, UserId userId) {
269         return new CursorLoader(userId.asContext(context), uri, null, null, null, null);
270     }
271 }
272