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(context, 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      * Gets the intent to trigger the {@code android.settings.ShowAdminSupportDetailsDialog}.
102      */
getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin)103     public static Intent getShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
104         final Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
105         if (admin != null) {
106             if (admin.component != null) {
107                 intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin.component);
108             }
109             intent.putExtra(Intent.EXTRA_USER, admin.user);
110         }
111         return intent;
112     }
113 
114     /**
115      * Shows restricted setting dialog.
116      */
117     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
sendShowRestrictedSettingDialogIntent(Context context, String packageName, int uid)118     public static void sendShowRestrictedSettingDialogIntent(Context context,
119             String packageName, int uid) {
120         final Intent intent = getShowRestrictedSettingsIntent(packageName, uid);
121         context.startActivity(intent);
122     }
123 
124     /**
125      * Gets restricted settings dialog intent.
126      */
getShowRestrictedSettingsIntent(String packageName, int uid)127     private static Intent getShowRestrictedSettingsIntent(String packageName, int uid) {
128         final Intent intent = new Intent(Settings.ACTION_SHOW_RESTRICTED_SETTING_DIALOG);
129         intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
130         intent.putExtra(Intent.EXTRA_UID, uid);
131         return intent;
132     }
133 
134     /**
135      * Checks if current user is profile or not
136      */
137     @RequiresApi(Build.VERSION_CODES.M)
isCurrentUserOrProfile(Context context, int userId)138     public static boolean isCurrentUserOrProfile(Context context, int userId) {
139         UserManager um = context.getSystemService(UserManager.class);
140         return um.getUserProfiles().contains(UserHandle.of(userId));
141     }
142 
143     /**
144      * A admin for the restriction enforced.
145      */
146     public static class EnforcedAdmin {
147         @Nullable
148         public ComponentName component = null;
149         /**
150          * The restriction enforced by admin. It could be any user restriction or policy like
151          * {@link DevicePolicyManager#POLICY_DISABLE_CAMERA}.
152          */
153         @Nullable
154         public String enforcedRestriction = null;
155         @Nullable
156         public UserHandle user = null;
157 
158         /**
159          * We use this to represent the case where a policy is enforced by multiple admins.
160          */
161         public static final EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
162 
163         /**
164          * The restriction enforced by admin with restriction.
165          */
createDefaultEnforcedAdminWithRestriction( String enforcedRestriction)166         public static EnforcedAdmin createDefaultEnforcedAdminWithRestriction(
167                 String enforcedRestriction) {
168             final EnforcedAdmin enforcedAdmin = new EnforcedAdmin();
169             enforcedAdmin.enforcedRestriction = enforcedRestriction;
170             return enforcedAdmin;
171         }
172 
EnforcedAdmin(ComponentName component, UserHandle user)173         public EnforcedAdmin(ComponentName component, UserHandle user) {
174             this.component = component;
175             this.user = user;
176         }
177 
EnforcedAdmin(ComponentName component, String enforcedRestriction, UserHandle user)178         public EnforcedAdmin(ComponentName component, String enforcedRestriction, UserHandle user) {
179             this.component = component;
180             this.enforcedRestriction = enforcedRestriction;
181             this.user = user;
182         }
183 
EnforcedAdmin(EnforcedAdmin other)184         public EnforcedAdmin(EnforcedAdmin other) {
185             if (other == null) {
186                 throw new IllegalArgumentException();
187             }
188             this.component = other.component;
189             this.enforcedRestriction = other.enforcedRestriction;
190             this.user = other.user;
191         }
192 
EnforcedAdmin()193         public EnforcedAdmin() {}
194 
195         /**
196          * Combines two {@link EnforcedAdmin} into one: if one of them is null, then just return
197          * the other. If both of them are the same, then return that. Otherwise return the symbolic
198          * {@link #MULTIPLE_ENFORCED_ADMIN}
199          */
combine(EnforcedAdmin admin1, EnforcedAdmin admin2)200         public static EnforcedAdmin combine(EnforcedAdmin admin1, EnforcedAdmin admin2) {
201             if (admin1 == null) {
202                 return admin2;
203             }
204             if (admin2 == null) {
205                 return admin1;
206             }
207             if (admin1.equals(admin2)) {
208                 return admin1;
209             }
210             if (!admin1.enforcedRestriction.equals(admin2.enforcedRestriction)) {
211                 throw new IllegalArgumentException(
212                         "Admins with different restriction cannot be combined");
213             }
214             return MULTIPLE_ENFORCED_ADMIN;
215         }
216 
217         @Override
equals(Object o)218         public boolean equals(Object o) {
219             if (this == o) return true;
220             if (o == null || getClass() != o.getClass()) return false;
221             EnforcedAdmin that = (EnforcedAdmin) o;
222             return Objects.equals(user, that.user)
223                     && Objects.equals(component, that.component)
224                     && Objects.equals(enforcedRestriction, that.enforcedRestriction);
225         }
226 
227         @Override
hashCode()228         public int hashCode() {
229             return Objects.hash(component, enforcedRestriction, user);
230         }
231 
232         @Override
toString()233         public String toString() {
234             return "EnforcedAdmin{"
235                     + "component=" + component
236                     + ", enforcedRestriction='" + enforcedRestriction
237                     + ", user=" + user
238                     + '}';
239         }
240     }
241 }
242