1 /*
2  * Copyright (C) 2023 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.settings.testutils.shadow;
18 
19 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
20 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
21 import static android.os.Build.VERSION_CODES.O;
22 import static android.os.Build.VERSION_CODES.Q;
23 
24 import android.annotation.UserIdInt;
25 import android.app.admin.DevicePolicyManager;
26 import android.app.admin.DevicePolicyManager.DeviceOwnerType;
27 import android.app.admin.IDevicePolicyManager;
28 import android.app.admin.ManagedSubscriptionsPolicy;
29 import android.app.admin.PasswordMetrics;
30 import android.app.admin.PasswordPolicy;
31 import android.content.ComponentName;
32 import android.content.Context;
33 
34 import androidx.annotation.NonNull;
35 import androidx.annotation.Nullable;
36 import androidx.test.core.app.ApplicationProvider;
37 
38 import org.robolectric.annotation.Implementation;
39 import org.robolectric.annotation.Implements;
40 import org.robolectric.shadow.api.Shadow;
41 
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.List;
45 import java.util.Map;
46 import java.util.Objects;
47 import java.util.Set;
48 
49 @Implements(DevicePolicyManager.class)
50 public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDevicePolicyManager {
51 
52     private final Map<Integer, Long> mProfileTimeouts = new HashMap<>();
53     private final Map<String, Integer> mDeviceOwnerTypes = new HashMap<>();
54     private Map<Integer, CharSequence> mSupportMessagesMap = new HashMap<>();
55     private boolean mIsAdminActiveAsUser = false;
56     private ComponentName mProfileOwner;
57     private ComponentName mDeviceOwnerComponentName;
58     private ManagedSubscriptionsPolicy mManagedSubscriptionsPolicy;
59     private int mDeviceOwnerUserId = -1;
60     private int mPasswordMinQuality = PASSWORD_QUALITY_UNSPECIFIED;
61     private int mPasswordMinLength = 0;
62     private int mPasswordMinSymbols = 0;
63     private Set<String> mCrossProfileCalendarPackages = Collections.emptySet();
64 
65     private List<String> mPermittedAccessibilityServices = null;
66 
67     @Implementation(minSdk = O)
__constructor__(Context context, IDevicePolicyManager service)68     protected void __constructor__(Context context, IDevicePolicyManager service) {
69         super.__constructor__(ApplicationProvider.getApplicationContext(), service);
70     }
71 
setShortSupportMessageForUser(ComponentName admin, int userHandle, String message)72     public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
73         mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
74     }
75 
76     @Implementation
getShortSupportMessageForUser(@onNull ComponentName admin, int userHandle)77     protected @Nullable CharSequence getShortSupportMessageForUser(@NonNull ComponentName admin,
78             int userHandle) {
79         return mSupportMessagesMap.get(Objects.hash(admin, userHandle));
80     }
81 
82     @Implementation
isAdminActiveAsUser(@onNull ComponentName admin, int userId)83     protected boolean isAdminActiveAsUser(@NonNull ComponentName admin, int userId) {
84         return mIsAdminActiveAsUser;
85     }
86 
87     @Implementation
getDeviceOwnerUserId()88     protected int getDeviceOwnerUserId() {
89         return mDeviceOwnerUserId;
90     }
91 
92     @Implementation
getMaximumTimeToLock(ComponentName admin, @UserIdInt int userHandle)93     protected long getMaximumTimeToLock(ComponentName admin, @UserIdInt int userHandle) {
94         return mProfileTimeouts.getOrDefault(userHandle, 0L);
95     }
96 
97     @Implementation
getDeviceOwnerComponentOnAnyUser()98     protected ComponentName getDeviceOwnerComponentOnAnyUser() {
99         return mDeviceOwnerComponentName;
100     }
101 
setIsAdminActiveAsUser(boolean active)102     public void setIsAdminActiveAsUser(boolean active) {
103         mIsAdminActiveAsUser = active;
104     }
105 
setDeviceOwnerUserId(int id)106     public void setDeviceOwnerUserId(int id) {
107         mDeviceOwnerUserId = id;
108     }
109 
setMaximumTimeToLock(@serIdInt int userHandle, Long timeout)110     public void setMaximumTimeToLock(@UserIdInt int userHandle, Long timeout) {
111         mProfileTimeouts.put(userHandle, timeout);
112     }
113 
setDeviceOwnerComponentOnAnyUser(ComponentName admin)114     public void setDeviceOwnerComponentOnAnyUser(ComponentName admin) {
115         mDeviceOwnerComponentName = admin;
116     }
117 
setDeviceOwnerType(@onNull ComponentName admin, @DeviceOwnerType int deviceOwnerType)118     public void setDeviceOwnerType(@NonNull ComponentName admin,
119             @DeviceOwnerType int deviceOwnerType) {
120         mDeviceOwnerTypes.put(admin.getPackageName(), deviceOwnerType);
121     }
122 
setManagedSubscriptionsPolicy(ManagedSubscriptionsPolicy policy)123     public void setManagedSubscriptionsPolicy(ManagedSubscriptionsPolicy policy) {
124         mManagedSubscriptionsPolicy = policy;
125     }
126 
127     @DeviceOwnerType
getDeviceOwnerType(@onNull ComponentName admin)128     public int getDeviceOwnerType(@NonNull ComponentName admin) {
129         return mDeviceOwnerTypes.getOrDefault(admin.getPackageName(), DEVICE_OWNER_TYPE_DEFAULT);
130     }
131 
132     @Implementation
getPasswordMinimumMetrics(int userHandle)133     public PasswordMetrics getPasswordMinimumMetrics(int userHandle) {
134         PasswordPolicy policy = new PasswordPolicy();
135         policy.quality = mPasswordMinQuality;
136         policy.length = mPasswordMinLength;
137         policy.symbols = mPasswordMinSymbols;
138         return policy.getMinMetrics();
139     }
140 
141     @Implementation
getManagedSubscriptionsPolicy()142     public ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy() {
143         return mManagedSubscriptionsPolicy;
144     }
145 
setPasswordQuality(int quality)146     public void setPasswordQuality(int quality) {
147         mPasswordMinQuality = quality;
148     }
149 
setPasswordMinimumLength(int length)150     public void setPasswordMinimumLength(int length) {
151         mPasswordMinLength = length;
152     }
153 
setPasswordMinimumSymbols(int numOfSymbols)154     public void setPasswordMinimumSymbols(int numOfSymbols) {
155         mPasswordMinSymbols = numOfSymbols;
156     }
157 
setPermittedAccessibilityServices(List<String> permittedAccessibilityServices)158     public void setPermittedAccessibilityServices(List<String> permittedAccessibilityServices) {
159         mPermittedAccessibilityServices = permittedAccessibilityServices;
160     }
161 
162     @Implementation
163     @Nullable
getPermittedAccessibilityServices(int userId)164     public List<String> getPermittedAccessibilityServices(int userId) {
165         return mPermittedAccessibilityServices;
166     }
167 
getShadow()168     public static ShadowDevicePolicyManager getShadow() {
169         return (ShadowDevicePolicyManager) Shadow.extract(
170                 ApplicationProvider.getApplicationContext()
171                         .getSystemService(DevicePolicyManager.class));
172     }
173 
174     // BEGIN-INTERNAL
175     @Implementation(minSdk = Q)
getCrossProfileCalendarPackages()176     protected Set<String> getCrossProfileCalendarPackages() {
177         return mCrossProfileCalendarPackages;
178     }
179 
180     @Implementation(minSdk = Q)
setCrossProfileCalendarPackages(ComponentName admin, Set<String> packageNames)181     public void setCrossProfileCalendarPackages(ComponentName admin, Set<String> packageNames) {
182         enforceProfileOwner(admin);
183         mCrossProfileCalendarPackages = packageNames;
184     }
185 
186     /**
187      * Sets the admin as active admin and profile owner.
188      *
189      * @see DevicePolicyManager#getProfileOwner()
190      */
setProfileOwner(ComponentName admin)191     public void setProfileOwner(ComponentName admin) {
192         setActiveAdmin(admin);
193         mProfileOwner = admin;
194     }
195 
enforceProfileOwner(ComponentName admin)196     private void enforceProfileOwner(ComponentName admin) {
197         if (!admin.equals(mProfileOwner)) {
198             throw new SecurityException("[" + admin + "] is not a profile owner");
199         }
200     }
201 }
202