1 /*
2  * Copyright (C) 2021 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.tv.settings.enterprise;
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.content.pm.ResolveInfo;
25 import android.content.pm.UserInfo;
26 import android.content.res.Resources;
27 import android.net.ConnectivityManager;
28 import android.net.VpnManager;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.provider.Settings;
32 import android.text.SpannableStringBuilder;
33 import android.text.style.ClickableSpan;
34 import android.view.View;
35 
36 import com.android.tv.settings.R;
37 
38 import java.util.Date;
39 import java.util.List;
40 
41 public class EnterprisePrivacyFeatureProviderImpl implements EnterprisePrivacyFeatureProvider {
42 
43     public static final String ACTION_PARENTAL_CONTROLS = "android.settings.SHOW_PARENTAL_CONTROLS";
44 
45     private final Context mContext;
46     private final DevicePolicyManager mDpm;
47     private final PackageManager mPm;
48     private final UserManager mUm;
49     private final ConnectivityManager mCm;
50     private final VpnManager mVm;
51     private final Resources mResources;
52 
53     private static final int MY_USER_ID = UserHandle.myUserId();
54 
EnterprisePrivacyFeatureProviderImpl(Context context, DevicePolicyManager dpm, PackageManager pm, UserManager um, ConnectivityManager cm, VpnManager vm, Resources resources)55     public EnterprisePrivacyFeatureProviderImpl(Context context, DevicePolicyManager dpm,
56             PackageManager pm, UserManager um, ConnectivityManager cm, VpnManager vm,
57             Resources resources) {
58         mContext = context.getApplicationContext();
59         mDpm = dpm;
60         mPm = pm;
61         mUm = um;
62         mCm = cm;
63         mVm = vm;
64         mResources = resources;
65     }
66 
67     @Override
hasDeviceOwner()68     public boolean hasDeviceOwner() {
69         return getDeviceOwnerComponent() != null;
70     }
71 
72     @Override
isInCompMode()73     public boolean isInCompMode() {
74         return hasDeviceOwner() && getManagedProfileUserId() != UserHandle.USER_NULL;
75     }
76 
77     @Override
getDeviceOwnerOrganizationName()78     public String getDeviceOwnerOrganizationName() {
79         final CharSequence organizationName = mDpm.getDeviceOwnerOrganizationName();
80         if (organizationName == null) {
81             return null;
82         } else {
83             return organizationName.toString();
84         }
85     }
86 
87     @Override
getDeviceOwnerDisclosure()88     public CharSequence getDeviceOwnerDisclosure() {
89         if (!hasDeviceOwner()) {
90             return null;
91         }
92 
93         final SpannableStringBuilder disclosure = new SpannableStringBuilder();
94         final CharSequence organizationName = mDpm.getDeviceOwnerOrganizationName();
95         if (organizationName != null) {
96             disclosure.append(mResources.getString(R.string.do_disclosure_with_name,
97                     organizationName));
98         } else {
99             disclosure.append(mResources.getString(R.string.do_disclosure_generic));
100         }
101         disclosure.append(mResources.getString(R.string.do_disclosure_learn_more_separator));
102         disclosure.append(mResources.getString(R.string.learn_more),
103                 new EnterprisePrivacySpan(mContext), 0);
104         return disclosure;
105     }
106 
107     @Override
getLastSecurityLogRetrievalTime()108     public Date getLastSecurityLogRetrievalTime() {
109         final long timestamp = mDpm.getLastSecurityLogRetrievalTime();
110         return timestamp < 0 ? null : new Date(timestamp);
111     }
112 
113     @Override
getLastBugReportRequestTime()114     public Date getLastBugReportRequestTime() {
115         final long timestamp = mDpm.getLastBugReportRequestTime();
116         return timestamp < 0 ? null : new Date(timestamp);
117     }
118 
119     @Override
getLastNetworkLogRetrievalTime()120     public Date getLastNetworkLogRetrievalTime() {
121         final long timestamp = mDpm.getLastNetworkLogRetrievalTime();
122         return timestamp < 0 ? null : new Date(timestamp);
123     }
124 
125     @Override
isSecurityLoggingEnabled()126     public boolean isSecurityLoggingEnabled() {
127         return mDpm.isSecurityLoggingEnabled(null);
128     }
129 
130     @Override
isNetworkLoggingEnabled()131     public boolean isNetworkLoggingEnabled() {
132         return mDpm.isNetworkLoggingEnabled(null);
133     }
134 
135     @Override
isAlwaysOnVpnSetInCurrentUser()136     public boolean isAlwaysOnVpnSetInCurrentUser() {
137         return mVm.getAlwaysOnVpnPackageForUser(MY_USER_ID) != null;
138     }
139 
140     @Override
isAlwaysOnVpnSetInManagedProfile()141     public boolean isAlwaysOnVpnSetInManagedProfile() {
142         final int managedProfileUserId = getManagedProfileUserId();
143         return managedProfileUserId != UserHandle.USER_NULL && (mVm.getAlwaysOnVpnPackageForUser(
144                 managedProfileUserId) != null);
145     }
146 
147     @Override
getMaximumFailedPasswordsBeforeWipeInCurrentUser()148     public int getMaximumFailedPasswordsBeforeWipeInCurrentUser() {
149         ComponentName owner = mDpm.getDeviceOwnerComponentOnCallingUser();
150         if (owner == null) {
151             owner = mDpm.getProfileOwnerAsUser(MY_USER_ID);
152         }
153         if (owner == null) {
154             return 0;
155         }
156         return mDpm.getMaximumFailedPasswordsForWipe(owner, MY_USER_ID);
157     }
158 
159     @Override
getMaximumFailedPasswordsBeforeWipeInManagedProfile()160     public int getMaximumFailedPasswordsBeforeWipeInManagedProfile() {
161         final int userId = getManagedProfileUserId();
162         if (userId == UserHandle.USER_NULL) {
163             return 0;
164         }
165         final ComponentName profileOwner = mDpm.getProfileOwnerAsUser(userId);
166         if (profileOwner == null) {
167             return 0;
168         }
169         return mDpm.getMaximumFailedPasswordsForWipe(profileOwner, userId);
170     }
171 
172     @Override
getImeLabelIfOwnerSet()173     public String getImeLabelIfOwnerSet() {
174         if (!mDpm.isCurrentInputMethodSetByOwner()) {
175             return null;
176         }
177         final String packageName = Settings.Secure.getStringForUser(mContext.getContentResolver(),
178                 Settings.Secure.DEFAULT_INPUT_METHOD, MY_USER_ID);
179         if (packageName == null) {
180             return null;
181         }
182         try {
183             return mPm.getApplicationInfoAsUser(packageName, 0 /* flags */, MY_USER_ID)
184                     .loadLabel(mPm).toString();
185         } catch (PackageManager.NameNotFoundException e) {
186             return null;
187         }
188     }
189 
190     @Override
getNumberOfOwnerInstalledCaCertsForCurrentUser()191     public int getNumberOfOwnerInstalledCaCertsForCurrentUser() {
192         final List<String> certs = mDpm.getOwnerInstalledCaCerts(new UserHandle(MY_USER_ID));
193         if (certs == null) {
194             return 0;
195         }
196         return certs.size();
197     }
198 
199     @Override
getNumberOfOwnerInstalledCaCertsForManagedProfile()200     public int getNumberOfOwnerInstalledCaCertsForManagedProfile() {
201         final int userId = getManagedProfileUserId();
202         if (userId == UserHandle.USER_NULL) {
203             return 0;
204         }
205         final List<String> certs = mDpm.getOwnerInstalledCaCerts(new UserHandle(userId));
206         if (certs == null) {
207             return 0;
208         }
209         return certs.size();
210     }
211 
212     @Override
getNumberOfActiveDeviceAdminsForCurrentUserAndManagedProfile()213     public int getNumberOfActiveDeviceAdminsForCurrentUserAndManagedProfile() {
214         int activeAdmins = 0;
215         for (final UserInfo userInfo : mUm.getProfiles(MY_USER_ID)) {
216             final List<ComponentName> activeAdminsForUser = mDpm.getActiveAdminsAsUser(userInfo.id);
217             if (activeAdminsForUser != null) {
218                 activeAdmins += activeAdminsForUser.size();
219             }
220         }
221         return activeAdmins;
222     }
223 
224     @Override
hasWorkPolicyInfo()225     public boolean hasWorkPolicyInfo() {
226         return (getWorkPolicyInfoIntentDO() != null) || (getWorkPolicyInfoIntentPO() != null);
227     }
228 
229     @Override
showWorkPolicyInfo()230     public boolean showWorkPolicyInfo() {
231         Intent intent = getWorkPolicyInfoIntentDO();
232         if (intent != null) {
233             mContext.startActivity(intent);
234             return true;
235         }
236 
237         intent = getWorkPolicyInfoIntentPO();
238         final UserInfo userInfo = getManagedProfileUserInfo();
239         if (intent != null && userInfo != null) {
240             mContext.startActivityAsUser(intent, userInfo.getUserHandle());
241             return true;
242         }
243 
244         return false;
245     }
246 
247     @Override
showParentalControls()248     public boolean showParentalControls() {
249         Intent intent = getParentalControlsIntent();
250         if (intent != null) {
251             mContext.startActivity(intent);
252             return true;
253         }
254 
255         return false;
256     }
257 
getParentalControlsIntent()258     private Intent getParentalControlsIntent() {
259         final ComponentName componentName =
260                 mDpm.getProfileOwnerOrDeviceOwnerSupervisionComponent(new UserHandle(MY_USER_ID));
261         if (componentName == null) {
262             return null;
263         }
264 
265         final Intent intent = new Intent(ACTION_PARENTAL_CONTROLS)
266                 .setPackage(componentName.getPackageName())
267                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
268         final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(intent, 0, MY_USER_ID);
269         if (activities.size() != 0) {
270             return intent;
271         }
272         return null;
273     }
274 
getDeviceOwnerComponent()275     private ComponentName getDeviceOwnerComponent() {
276         if (!mPm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
277             return null;
278         }
279         return mDpm.getDeviceOwnerComponentOnAnyUser();
280     }
281 
getManagedProfileUserInfo()282     private UserInfo getManagedProfileUserInfo() {
283         for (final UserInfo userInfo : mUm.getProfiles(MY_USER_ID)) {
284             if (userInfo.isManagedProfile()) {
285                 return userInfo;
286             }
287         }
288         return null;
289     }
290 
getManagedProfileUserId()291     private int getManagedProfileUserId() {
292         final UserInfo userInfo = getManagedProfileUserInfo();
293         if (userInfo != null) {
294             return userInfo.id;
295         }
296         return UserHandle.USER_NULL;
297     }
298 
getWorkPolicyInfoIntentDO()299     private Intent getWorkPolicyInfoIntentDO() {
300         final ComponentName ownerComponent = getDeviceOwnerComponent();
301         if (ownerComponent == null) {
302             return null;
303         }
304 
305         // Only search for the required action in the Device Owner's package
306         final Intent intent =
307                 new Intent(Settings.ACTION_SHOW_WORK_POLICY_INFO)
308                         .setPackage(ownerComponent.getPackageName())
309                         .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
310         final List<ResolveInfo> activities = mPm.queryIntentActivities(intent, 0);
311         if (activities.size() != 0) {
312             return intent;
313         }
314 
315         return null;
316     }
317 
getWorkPolicyInfoIntentPO()318     private Intent getWorkPolicyInfoIntentPO() {
319         final int userId = getManagedProfileUserId();
320         if (userId == UserHandle.USER_NULL) {
321             return null;
322         }
323 
324         final ComponentName ownerComponent = mDpm.getProfileOwnerAsUser(userId);
325         if (ownerComponent == null) {
326             return null;
327         }
328 
329         // Only search for the required action in the Profile Owner's package
330         final Intent intent =
331                 new Intent(Settings.ACTION_SHOW_WORK_POLICY_INFO)
332                         .setPackage(ownerComponent.getPackageName())
333                         .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
334         final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(intent, 0, userId);
335         if (activities.size() != 0) {
336             return intent;
337         }
338 
339         return null;
340     }
341 
342     protected static class EnterprisePrivacySpan extends ClickableSpan {
343         private final Context mContext;
344 
EnterprisePrivacySpan(Context context)345         public EnterprisePrivacySpan(Context context) {
346             mContext = context;
347         }
348 
349         @Override
onClick(View widget)350         public void onClick(View widget) {
351             mContext.startActivity(new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)
352                     .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
353         }
354 
355         @Override
equals(Object object)356         public boolean equals(Object object) {
357             return object instanceof EnterprisePrivacySpan
358                     && ((EnterprisePrivacySpan) object).mContext == mContext;
359         }
360     }
361 }
362