1 /*
2  * Copyright (C) 2018 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.settingslib;
18 
19 import android.app.admin.DevicePolicyManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.os.Build;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.provider.Settings;
28 
29 import androidx.annotation.Nullable;
30 import androidx.annotation.RequiresApi;
31 
32 import java.util.Objects;
33 
34 /**
35  * Utility class to host methods usable in adding a restricted padlock icon and showing admin
36  * support message dialog.
37  */
38 public class RestrictedLockUtils {
39     /**
40      * Gets EnforcedAdmin from DevicePolicyManager
41      */
42     @RequiresApi(Build.VERSION_CODES.M)
getProfileOrDeviceOwner(Context context, UserHandle user)43     public static EnforcedAdmin getProfileOrDeviceOwner(Context context, UserHandle user) {
44         return getProfileOrDeviceOwner(context, null, user);
45     }
46 
47     /**
48      * Gets EnforcedAdmin from DevicePolicyManager
49      */
50     @RequiresApi(Build.VERSION_CODES.M)
getProfileOrDeviceOwner( Context context, String enforcedRestriction, UserHandle user)51     public static EnforcedAdmin getProfileOrDeviceOwner(
52             Context context, String enforcedRestriction, UserHandle user) {
53         if (user == null) {
54             return null;
55         }
56         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
57                 Context.DEVICE_POLICY_SERVICE);
58         if (dpm == null) {
59             return null;
60         }
61 
62         Context userContext;
63         try {
64             userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);
65         } catch (PackageManager.NameNotFoundException e) {
66             throw new IllegalStateException(e);
67         }
68 
69         ComponentName adminComponent = userContext.getSystemService(
70                 DevicePolicyManager.class).getProfileOwner();
71         if (adminComponent != null) {
72             return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
73         }
74         if (Objects.equals(dpm.getDeviceOwnerUser(), user)) {
75             adminComponent = dpm.getDeviceOwnerComponentOnAnyUser();
76             if (adminComponent != null) {
77                 return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
78             }
79         }
80         return null;
81     }
82 
83     /**
84      * Sends the intent to trigger the {@code android.settings.ShowAdminSupportDetailsDialog}.
85      */
86     @RequiresApi(Build.VERSION_CODES.M)
sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin)87     public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
88         final Intent intent = getShowAdminSupportDetailsIntent(admin);
89         int targetUserId = UserHandle.myUserId();
90         if (admin != null) {
91             if (admin.user != null
92                     && isCurrentUserOrProfile(context, admin.user.getIdentifier())) {
93                 targetUserId = admin.user.getIdentifier();
94             }
95             intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction);
96         }
97         context.startActivityAsUser(intent, UserHandle.of(targetUserId));
98     }
99 
100     /**
101      * @deprecated No context needed. Use {@link #getShowAdminSupportDetailsIntent(EnforcedAdmin)}.
102      */
getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin)103     public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
104         return getShowAdminSupportDetailsIntent(admin);
105     }
106 
107     /**
108      * Gets the intent to trigger the {@code android.settings.ShowAdminSupportDetailsDialog}.
109      */
getShowAdminSupportDetailsIntent(EnforcedAdmin admin)110     public static Intent getShowAdminSupportDetailsIntent(EnforcedAdmin admin) {
111         final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
112         if (admin != null) {
113             if (admin.component != null) {
114                 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
115             }
116             intent.putExtra(Intent.EXTRA_USER, admin.user);
117         }
118         return intent;
119     }
120 
121     /**
122      * Checks if current user is profile or not
123      */
124     @RequiresApi(Build.VERSION_CODES.M)
isCurrentUserOrProfile(Context context, int userId)125     public static boolean isCurrentUserOrProfile(Context context, int userId) {
126         UserManager um = context.getSystemService(UserManager.class);
127         return um.getUserProfiles().contains(UserHandle.of(userId));
128     }
129 
130     /**
131      * A admin for the restriction enforced.
132      */
133     public static class EnforcedAdmin {
134         @Nullable
135         public ComponentName component = null;
136         /**
137          * The restriction enforced by admin. It could be any user restriction or policy like
138          * {@link DevicePolicyManager#POLICY_DISABLE_CAMERA}.
139          */
140         @Nullable
141         public String enforcedRestriction = null;
142         @Nullable
143         public UserHandle user = null;
144 
145         /**
146          * We use this to represent the case where a policy is enforced by multiple admins.
147          */
148         public static final EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
149 
150         /**
151          * The restriction enforced by admin with restriction.
152          */
createDefaultEnforcedAdminWithRestriction( String enforcedRestriction)153         public static EnforcedAdmin createDefaultEnforcedAdminWithRestriction(
154                 String enforcedRestriction) {
155             final EnforcedAdmin enforcedAdmin = new EnforcedAdmin();
156             enforcedAdmin.enforcedRestriction = enforcedRestriction;
157             return enforcedAdmin;
158         }
159 
EnforcedAdmin(ComponentName component, UserHandle user)160         public EnforcedAdmin(ComponentName component, UserHandle user) {
161             this.component = component;
162             this.user = user;
163         }
164 
EnforcedAdmin(ComponentName component, String enforcedRestriction, UserHandle user)165         public EnforcedAdmin(ComponentName component, String enforcedRestriction, UserHandle user) {
166             this.component = component;
167             this.enforcedRestriction = enforcedRestriction;
168             this.user = user;
169         }
170 
EnforcedAdmin(EnforcedAdmin other)171         public EnforcedAdmin(EnforcedAdmin other) {
172             if (other == null) {
173                 throw new IllegalArgumentException();
174             }
175             this.component = other.component;
176             this.enforcedRestriction = other.enforcedRestriction;
177             this.user = other.user;
178         }
179 
EnforcedAdmin()180         public EnforcedAdmin() {}
181 
182         /**
183          * Combines two {@link EnforcedAdmin} into one: if one of them is null, then just return
184          * the other. If both of them are the same, then return that. Otherwise return the symbolic
185          * {@link #MULTIPLE_ENFORCED_ADMIN}
186          */
combine(EnforcedAdmin admin1, EnforcedAdmin admin2)187         public static EnforcedAdmin combine(EnforcedAdmin admin1, EnforcedAdmin admin2) {
188             if (admin1 == null) {
189                 return admin2;
190             }
191             if (admin2 == null) {
192                 return admin1;
193             }
194             if (admin1.equals(admin2)) {
195                 return admin1;
196             }
197             if (!admin1.enforcedRestriction.equals(admin2.enforcedRestriction)) {
198                 throw new IllegalArgumentException(
199                         "Admins with different restriction cannot be combined");
200             }
201             return MULTIPLE_ENFORCED_ADMIN;
202         }
203 
204         @Override
equals(Object o)205         public boolean equals(Object o) {
206             if (this == o) return true;
207             if (o == null || getClass() != o.getClass()) return false;
208             EnforcedAdmin that = (EnforcedAdmin) o;
209             return Objects.equals(user, that.user)
210                     && Objects.equals(component, that.component)
211                     && Objects.equals(enforcedRestriction, that.enforcedRestriction);
212         }
213 
214         @Override
hashCode()215         public int hashCode() {
216             return Objects.hash(component, enforcedRestriction, user);
217         }
218 
219         @Override
toString()220         public String toString() {
221             return "EnforcedAdmin{"
222                     + "component=" + component
223                     + ", enforcedRestriction='" + enforcedRestriction
224                     + ", user=" + user
225                     + '}';
226         }
227     }
228 
229     /**
230      * Shows restricted setting dialog.
231      *
232      * @deprecated TODO(b/308921175): This will be deleted with the
233      * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
234      * code.
235      */
236     @Deprecated
237     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
sendShowRestrictedSettingDialogIntent(Context context, String packageName, int uid)238     public static void sendShowRestrictedSettingDialogIntent(Context context,
239                                                              String packageName, int uid) {
240         final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
241         context.startActivity(intent);
242     }
243 
244     /**
245      * Gets restricted settings dialog intent.
246      *
247      * @deprecated TODO(b/308921175): This will be deleted with the
248      * {@link android.security.Flags#extendEcmToAllSettings} feature flag. Do not use for any new
249      * code.
250      */
251     @Deprecated
getShowRestrictedSettingsIntent(String packageName, int uid)252     private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
253         final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
254         intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
255         intent.putExtra(Intent.EXTRA_UID, uid);
256         return intent;
257     }
258 }
259