1 /*
2  * Copyright (C) 2011 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.cts.verifier.admin;
18 
19 import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
20 import com.android.cts.verifier.PassFailButtons;
21 import com.android.cts.verifier.R;
22 
23 import android.app.AlertDialog;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.SharedPreferences;
29 import android.content.SharedPreferences.Editor;
30 import android.content.pm.PackageManager;
31 import android.os.Bundle;
32 import android.view.View;
33 import android.view.View.OnClickListener;
34 import android.view.ViewGroup;
35 import android.widget.ArrayAdapter;
36 import android.widget.ListView;
37 import android.widget.TextView;
38 import android.widget.Toast;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Random;
43 
44 /**
45  * Test that checks that device policies are properly saved and loaded across reboots. The user
46  * clicks a button to generate a random policy and is then asked to reboot the device. When
47  * returning to the test, the activity checks that the device manager is reporting the values
48  * it set before the user rebooted the device.
49  */
50 public class PolicySerializationTestActivity extends PassFailButtons.ListActivity {
51 
52     /**
53      * Whether or not to load the expected policy from the preferences and check against
54      * what the {@link DevicePolicyManager} reports.
55      */
56     private static final String LOAD_EXPECTED_POLICY_PREFERENCE = "load-expected-policy";
57 
58     private static final int ADD_DEVICE_ADMIN_REQUEST_CODE = 1;
59 
60     private DevicePolicyManager mDevicePolicyManager;
61     private ComponentName mAdmin;
62 
63     private List<PolicyItem<?>> mPolicyItems = new ArrayList<PolicyItem<?>>();
64     private PolicyAdapter mAdapter;
65 
66     private View mGeneratePolicyButton;
67     private View mApplyPolicyButton;
68 
69     @Override
onCreate(Bundle savedInstanceState)70     protected void onCreate(Bundle savedInstanceState) {
71         super.onCreate(savedInstanceState);
72         setContentView(R.layout.da_policy_main);
73         setInfoResources(R.string.da_policy_serialization_test,
74                 R.string.da_policy_serialization_info, -1);
75         setPassFailButtonClickListeners();
76 
77         mDevicePolicyManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
78         mAdmin = DeviceAdminTestReceiver.getReceiverComponentName();
79 
80         mGeneratePolicyButton = findViewById(R.id.generate_policy_button);
81         mGeneratePolicyButton.setOnClickListener(new OnClickListener() {
82             @Override
83             public void onClick(View v) {
84                 generateRandomPolicy();
85                 updateWidgets();
86             }
87         });
88 
89         mApplyPolicyButton = findViewById(R.id.apply_policy_button);
90         mApplyPolicyButton.setOnClickListener(new OnClickListener() {
91             @Override
92             public void onClick(View v) {
93                 applyPolicy();
94             }
95         });
96 
97         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)) {
98             mPolicyItems.add(new MaximumFailedPasswordsForWipePolicy(this));
99         }
100 
101         mPolicyItems.add(new MaximumTimeToLockPolicy(this));
102         mAdapter = new PolicyAdapter(this);
103         setListAdapter(mAdapter);
104 
105         loadPolicy();
106         updateWidgets();
107     }
108 
loadPolicy()109     private void loadPolicy() {
110         mAdapter.clear();
111         SharedPreferences prefs = getPreferences(MODE_PRIVATE);
112         if (prefs.getBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false)) {
113             for (PolicyItem<?> item : mPolicyItems) {
114                 item.loadExpectedValue(prefs);
115                 item.loadActualValue(mDevicePolicyManager, mAdmin);
116                 mAdapter.add(item);
117             }
118         }
119     }
120 
generateRandomPolicy()121     private void generateRandomPolicy() {
122         Random random = new Random();
123         mAdapter.clear();
124         for (PolicyItem<?> item : mPolicyItems) {
125             item.setRandomExpectedValue(random);
126             item.resetActualValue();
127             mAdapter.add(item);
128         }
129 
130         SharedPreferences prefs = getPreferences(MODE_PRIVATE);
131         SharedPreferences.Editor editor = prefs.edit();
132         editor.clear();
133         editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, false);
134         editor.apply();
135 
136         Toast.makeText(this, R.string.da_random_policy, Toast.LENGTH_SHORT).show();
137     }
138 
applyPolicy()139     private void applyPolicy() {
140         Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
141         intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
142                 DeviceAdminTestReceiver.getReceiverComponentName());
143         startActivityForResult(intent, ADD_DEVICE_ADMIN_REQUEST_CODE);
144     }
145 
146     @Override
onActivityResult(int requestCode, int resultCode, Intent data)147     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
148         super.onActivityResult(requestCode, resultCode, data);
149         switch (requestCode) {
150             case ADD_DEVICE_ADMIN_REQUEST_CODE:
151                 handleAddDeviceAdminResult(resultCode, data);
152                 break;
153         }
154     }
155 
handleAddDeviceAdminResult(int resultCode, Intent data)156     private void handleAddDeviceAdminResult(int resultCode, Intent data) {
157         if (resultCode == RESULT_OK) {
158             ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
159             for (PolicyItem<?> item : mPolicyItems) {
160                 item.applyExpectedValue(mDevicePolicyManager, admin);
161             }
162 
163             SharedPreferences prefs = getPreferences(MODE_PRIVATE);
164             SharedPreferences.Editor editor = prefs.edit();
165             editor.clear();
166             editor.putBoolean(LOAD_EXPECTED_POLICY_PREFERENCE, true);
167             for (PolicyItem<?> item : mPolicyItems) {
168                 item.saveExpectedValue(editor);
169             }
170             editor.apply();
171             showRebootDialog();
172         }
173     }
174 
showRebootDialog()175     private void showRebootDialog() {
176         new AlertDialog.Builder(this)
177             .setIcon(android.R.drawable.ic_dialog_info)
178             .setTitle(R.string.da_policy_serialization_test)
179             .setMessage(R.string.da_policy_reboot)
180             .setPositiveButton(android.R.string.ok, null)
181             .show();
182     }
183 
updateWidgets()184     private void updateWidgets() {
185         mApplyPolicyButton.setEnabled(!mAdapter.isEmpty());
186 
187         // All items need to have been serialized properly for the pass button to activate.
188         boolean enablePass = !mAdapter.isEmpty();
189         int numItems = mAdapter.getCount();
190         for (int i = 0; i < numItems; i++) {
191             PolicyItem<?> item = mAdapter.getItem(i);
192             if (!item.matchesExpectedValue()) {
193                 enablePass = false;
194             }
195         }
196         getPassButton().setEnabled(enablePass);
197     }
198 
199     @Override
onListItemClick(ListView l, View v, int position, long id)200     protected void onListItemClick(ListView l, View v, int position, long id) {
201         super.onListItemClick(l, v, position, id);
202         PolicyItem<?> item = mAdapter.getItem(position);
203         new AlertDialog.Builder(this)
204             .setIcon(android.R.drawable.ic_dialog_info)
205             .setTitle(item.getDisplayName())
206             .setMessage(getString(R.string.da_policy_info,
207                     item.getDisplayExpectedValue(),
208                     item.getDisplayActualValue()))
209             .setPositiveButton(android.R.string.ok, null)
210             .show();
211     }
212 
213     static class PolicyAdapter extends ArrayAdapter<PolicyItem<?>> {
214 
PolicyAdapter(Context context)215         public PolicyAdapter(Context context) {
216             super(context, android.R.layout.simple_list_item_1);
217         }
218 
219         @Override
getView(int position, View convertView, ViewGroup parent)220         public View getView(int position, View convertView, ViewGroup parent) {
221             TextView view = (TextView) super.getView(position, convertView, parent);
222 
223             PolicyItem<?> item = getItem(position);
224             int backgroundResource = 0;
225             int iconResource = 0;
226             if (item.getExpectedValue() != null && item.getActualValue() != null) {
227                 if (item.matchesExpectedValue()) {
228                     backgroundResource = R.drawable.test_pass_gradient;
229                     iconResource = R.drawable.fs_good;
230                 } else {
231                     backgroundResource = R.drawable.test_fail_gradient;
232                     iconResource = R.drawable.fs_error;
233                 }
234             }
235             view.setBackgroundResource(backgroundResource);
236             view.setPadding(10, 0, 10, 0);
237             view.setCompoundDrawablePadding(10);
238             view.setCompoundDrawablesWithIntrinsicBounds(0, 0, iconResource, 0);
239 
240             return view;
241         }
242     }
243 
244     interface PolicyItem<T> {
245 
setRandomExpectedValue(Random random)246         void setRandomExpectedValue(Random random);
247 
applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin)248         void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin);
249 
loadExpectedValue(SharedPreferences prefs)250         void loadExpectedValue(SharedPreferences prefs);
251 
saveExpectedValue(SharedPreferences.Editor editor)252         void saveExpectedValue(SharedPreferences.Editor editor);
253 
resetActualValue()254         void resetActualValue();
255 
loadActualValue(DevicePolicyManager deviceManager, ComponentName admin)256         void loadActualValue(DevicePolicyManager deviceManager, ComponentName admin);
257 
getDisplayName()258         String getDisplayName();
259 
getExpectedValue()260         T getExpectedValue();
261 
getDisplayExpectedValue()262         String getDisplayExpectedValue();
263 
getActualValue()264         T getActualValue();
265 
getDisplayActualValue()266         String getDisplayActualValue();
267 
matchesExpectedValue()268         boolean matchesExpectedValue();
269     }
270 
271     static abstract class BasePolicyItem<T> implements PolicyItem<T> {
272         private String mDisplayName;
273         private T mExpectedValue;
274         private T mActualValue;
275 
BasePolicyItem(Context context, int nameResId)276         BasePolicyItem(Context context, int nameResId) {
277             mDisplayName = context.getString(nameResId);
278         }
279 
280         @Override
setRandomExpectedValue(Random random)281         public final void setRandomExpectedValue(Random random) {
282             mExpectedValue = getRandomExpectedValue(random);
283         }
284 
getRandomExpectedValue(Random random)285         protected abstract T getRandomExpectedValue(Random random);
286 
287         @Override
loadExpectedValue(SharedPreferences prefs)288         public final void loadExpectedValue(SharedPreferences prefs) {
289             mExpectedValue = getPreferencesValue(prefs);
290         }
291 
getPreferencesValue(SharedPreferences prefs)292         protected abstract T getPreferencesValue(SharedPreferences prefs);
293 
294         @Override
loadActualValue(DevicePolicyManager deviceManager, ComponentName admin)295         public final void loadActualValue(DevicePolicyManager deviceManager, ComponentName admin) {
296             mActualValue = getDeviceManagerValue(deviceManager, admin);
297         }
298 
getDeviceManagerValue(DevicePolicyManager deviceManager, ComponentName admin)299         protected abstract T getDeviceManagerValue(DevicePolicyManager deviceManager,
300                 ComponentName admin);
301 
302         @Override
resetActualValue()303         public final void resetActualValue() {
304             mActualValue = null;
305         }
306 
307         @Override
getDisplayName()308         public final String getDisplayName() {
309             return mDisplayName;
310         }
311 
312         @Override
getExpectedValue()313         public final T getExpectedValue() {
314             return mExpectedValue;
315         }
316 
317         @Override
getDisplayExpectedValue()318         public final String getDisplayExpectedValue() {
319             return mExpectedValue != null ? getDisplayValue(mExpectedValue) : "";
320         }
321 
322         @Override
getActualValue()323         public final T getActualValue() {
324             return mActualValue;
325         }
326 
327         @Override
getDisplayActualValue()328         public final String getDisplayActualValue() {
329             return mActualValue != null ? getDisplayValue(mActualValue) : "";
330         }
331 
getDisplayValue(T value)332         protected String getDisplayValue(T value) {
333             return "" + value;
334         }
335 
336         @Override
matchesExpectedValue()337         public final boolean matchesExpectedValue() {
338             return mExpectedValue != null && mExpectedValue.equals(mActualValue);
339         }
340 
341         @Override
toString()342         public String toString() {
343             return getDisplayName();
344         }
345     }
346 
347     static abstract class IntegerPolicyItem extends BasePolicyItem<Integer> {
348 
349         private String mPreferenceKey;
350 
IntegerPolicyItem(Context context, int nameResId, String preferenceKey)351         IntegerPolicyItem(Context context, int nameResId, String preferenceKey) {
352             super(context, nameResId);
353             mPreferenceKey = preferenceKey;
354         }
355 
356         @Override
getPreferencesValue(SharedPreferences prefs)357         protected final Integer getPreferencesValue(SharedPreferences prefs) {
358             return prefs.getInt(mPreferenceKey, -1);
359         }
360 
361         @Override
saveExpectedValue(Editor editor)362         public final void saveExpectedValue(Editor editor) {
363             editor.putInt(mPreferenceKey, getExpectedValue());
364         }
365     }
366 
367     static abstract class LongPolicyItem extends BasePolicyItem<Long> {
368 
369         private String mPreferenceKey;
370 
LongPolicyItem(Context context, int nameResId, String preferenceKey)371         LongPolicyItem(Context context, int nameResId, String preferenceKey) {
372             super(context, nameResId);
373             mPreferenceKey = preferenceKey;
374         }
375 
376         @Override
getPreferencesValue(SharedPreferences prefs)377         protected final Long getPreferencesValue(SharedPreferences prefs) {
378             return prefs.getLong(mPreferenceKey, -1);
379         }
380 
381         @Override
saveExpectedValue(Editor editor)382         public final void saveExpectedValue(Editor editor) {
383             editor.putLong(mPreferenceKey, getExpectedValue());
384         }
385     }
386 
387     static class PasswordQualityPolicy extends IntegerPolicyItem {
388 
389         private final Context mContext;
390 
PasswordQualityPolicy(Context context)391         public PasswordQualityPolicy(Context context) {
392             super(context, R.string.da_password_quality, "password-quality");
393             mContext = context;
394         }
395 
396         @Override
getRandomExpectedValue(Random random)397         protected Integer getRandomExpectedValue(Random random) {
398             int[] passwordQualities = new int[] {
399                     DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
400                     DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
401                     DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,
402                     DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
403             };
404 
405             int index = random.nextInt(passwordQualities.length);
406             return passwordQualities[index];
407         }
408 
409         @Override
applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin)410         public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
411             deviceManager.setPasswordQuality(admin, getExpectedValue());
412         }
413 
414         @Override
getDeviceManagerValue(DevicePolicyManager deviceManager, ComponentName admin)415         protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
416                 ComponentName admin) {
417             return deviceManager.getPasswordQuality(admin);
418         }
419 
420         @Override
getDisplayValue(Integer value)421         protected String getDisplayValue(Integer value) {
422             switch (value) {
423                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
424                     return mContext.getString(R.string.da_password_quality_alphabetic);
425                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
426                     return mContext.getString(R.string.da_password_quality_alphanumeric);
427                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
428                     return mContext.getString(R.string.da_password_quality_numeric);
429                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
430                     return mContext.getString(R.string.da_password_quality_something);
431                 default:
432                     return Integer.toString(value);
433             }
434         }
435     }
436 
437     static class PasswordMinimumLengthPolicy extends IntegerPolicyItem {
438 
PasswordMinimumLengthPolicy(Context context)439         PasswordMinimumLengthPolicy(Context context) {
440             super(context, R.string.da_password_minimum_length, "password-minimum-length");
441         }
442 
443         @Override
getRandomExpectedValue(Random random)444         protected Integer getRandomExpectedValue(Random random) {
445             return random.nextInt(50);
446         }
447 
448         @Override
applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin)449         public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
450             deviceManager.setPasswordMinimumLength(admin, getExpectedValue());
451         }
452 
453         @Override
getDeviceManagerValue(DevicePolicyManager deviceManager, ComponentName admin)454         protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
455                 ComponentName admin) {
456             return deviceManager.getPasswordMinimumLength(admin);
457         }
458     }
459 
460     static class MaximumFailedPasswordsForWipePolicy extends IntegerPolicyItem {
461 
MaximumFailedPasswordsForWipePolicy(Context context)462         MaximumFailedPasswordsForWipePolicy(Context context) {
463             super(context, R.string.da_maximum_failed_passwords_for_wipe,
464                     "maximum-failed-passwords-for-wipe");
465         }
466 
467         @Override
getRandomExpectedValue(Random random)468         protected Integer getRandomExpectedValue(Random random) {
469             return random.nextInt(50);
470         }
471 
472         @Override
applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin)473         public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
474             deviceManager.setMaximumFailedPasswordsForWipe(admin, getExpectedValue());
475         }
476 
477         @Override
getDeviceManagerValue(DevicePolicyManager deviceManager, ComponentName admin)478         protected Integer getDeviceManagerValue(DevicePolicyManager deviceManager,
479                 ComponentName admin) {
480             return deviceManager.getMaximumFailedPasswordsForWipe(admin);
481         }
482     }
483 
484     static class MaximumTimeToLockPolicy extends LongPolicyItem {
485 
MaximumTimeToLockPolicy(Context context)486         MaximumTimeToLockPolicy(Context context) {
487             super(context, R.string.da_maximum_time_to_lock, "maximum-time-to-lock");
488         }
489 
490         @Override
getRandomExpectedValue(Random random)491         protected Long getRandomExpectedValue(Random random) {
492             return (long)(1000 + random.nextInt(60 * 60 * 1000));
493         }
494 
495         @Override
applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin)496         public void applyExpectedValue(DevicePolicyManager deviceManager, ComponentName admin) {
497             deviceManager.setMaximumTimeToLock(admin, getExpectedValue());
498         }
499 
500         @Override
getDeviceManagerValue(DevicePolicyManager deviceManager, ComponentName admin)501         protected Long getDeviceManagerValue(DevicePolicyManager deviceManager,
502                 ComponentName admin) {
503             return deviceManager.getMaximumTimeToLock(admin);
504         }
505     }
506 }
507