Skip to content

Commit 5b5ee0d

Browse files
Lenka TrochtovaAndrewScull
authored andcommitted
Add UI for testing forced re-enrollment.
Let the user set/clear the persistent device owner state. BUG: 33100169 Change-Id: I3d92e2deee259165f35f5a5c599d750caf997a53 (cherry picked from commit fe471ff4db4339ceb2b492a7cab9268cbbb0b09e)
1 parent 12359ba commit 5b5ee0d

File tree

7 files changed

+193
-1
lines changed

7 files changed

+193
-1
lines changed

app/src/main/java/com/afwsamples/testdpc/common/Util.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import android.net.Uri;
3131
import android.os.Build;
3232
import android.os.Build.VERSION_CODES;
33+
import android.os.Bundle;
3334
import android.os.UserHandle;
3435
import android.os.UserManager;
3536
import android.support.annotation.RequiresApi;
@@ -56,7 +57,12 @@
5657
*/
5758
public class Util {
5859
private static final String TAG = "Util";
59-
private static final int DEFAULT_BUFFER_SIZE = 4096;
60+
private static final int DEFAULT_BUFFER_SIZE = 4096;
61+
62+
private static final String BROADCAST_ACTION_FRP_CONFIG_CHANGED =
63+
"com.google.android.gms.auth.FRP_CONFIG_CHANGED";
64+
private static final String GMSCORE_PACKAGE = "com.google.android.gms";
65+
private static final String PERSISTENT_DEVICE_OWNER_STATE = "persistentDeviceOwnerState";
6066

6167
/**
6268
* Format a friendly datetime for the current locale according to device policy documentation.
@@ -194,6 +200,42 @@ public static boolean installCaCertificate(InputStream certificateInputStream,
194200
return false;
195201
}
196202

203+
/**
204+
* Returns the persistent device owner state which has been set by the device owner as an app
205+
* restriction on GmsCore or null if there is no such restriction set.
206+
*/
207+
@TargetApi(VERSION_CODES.O)
208+
public static String getPersistentDoStateFromApplicationRestriction(
209+
DevicePolicyManager dpm, ComponentName admin) {
210+
Bundle restrictions = dpm.getApplicationRestrictions(admin, GMSCORE_PACKAGE);
211+
return restrictions.getString(PERSISTENT_DEVICE_OWNER_STATE);
212+
}
213+
214+
/**
215+
* Sets the persistent device owner state by setting a special app restriction on GmsCore and
216+
* notifies GmsCore about the change by sending a broadcast.
217+
*
218+
* @param state The device owner state to be preserved across factory resets. If null, the
219+
* persistent device owner state and the corresponding restiction are cleared.
220+
*/
221+
@TargetApi(VERSION_CODES.O)
222+
public static void setPersistentDoStateWithApplicationRestriction(
223+
Context context, DevicePolicyManager dpm, ComponentName admin, String state) {
224+
Bundle restrictions = dpm.getApplicationRestrictions(admin, GMSCORE_PACKAGE);
225+
if (state == null) {
226+
// Clear the restriction
227+
restrictions.remove(PERSISTENT_DEVICE_OWNER_STATE);
228+
} else {
229+
// Set the restriction
230+
restrictions.putString(PERSISTENT_DEVICE_OWNER_STATE, state);
231+
}
232+
dpm.setApplicationRestrictions(admin, GMSCORE_PACKAGE, restrictions);
233+
Intent broadcastIntent = new Intent(BROADCAST_ACTION_FRP_CONFIG_CHANGED);
234+
broadcastIntent.setPackage(GMSCORE_PACKAGE);
235+
broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
236+
context.sendBroadcast(broadcastIntent);
237+
}
238+
197239
private static DevicePolicyManager getDevicePolicyManager(Context context) {
198240
return (DevicePolicyManager)context.getSystemService(Service.DEVICE_POLICY_SERVICE);
199241
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.afwsamples.testdpc.policy;
2+
3+
import android.annotation.TargetApi;
4+
import android.app.Fragment;
5+
import android.app.admin.DevicePolicyManager;
6+
import android.content.ComponentName;
7+
import android.content.Context;
8+
import android.content.Intent;
9+
import android.os.Build;
10+
import android.os.Bundle;
11+
import android.view.LayoutInflater;
12+
import android.view.View;
13+
import android.view.ViewGroup;
14+
import android.widget.Button;
15+
import android.widget.EditText;
16+
17+
import com.afwsamples.testdpc.DeviceAdminReceiver;
18+
import com.afwsamples.testdpc.R;
19+
import com.afwsamples.testdpc.common.Util;
20+
21+
/**
22+
* Allows the user to set a test persistent device owner state.
23+
*
24+
* <p>For manual testing of forced re-enrollment.
25+
*
26+
* <p>If there is a non-empty peristent device owner state, it will survive the next factory reset,
27+
* TestDPC will be re-installed automatically as device owner and the state will be passed to it
28+
* during the initial device setup.
29+
*/
30+
public class PersistentDeviceOwnerFragment extends Fragment implements View.OnClickListener {
31+
32+
private DevicePolicyManager mDpm;
33+
private ComponentName mAdminComponent;
34+
private EditText mStateEdit;
35+
36+
@Override
37+
public void onCreate(Bundle savedInstanceState) {
38+
super.onCreate(savedInstanceState);
39+
getActivity().getActionBar().setTitle(R.string.persistent_device_owner);
40+
mDpm = (DevicePolicyManager) getActivity().getSystemService(
41+
Context.DEVICE_POLICY_SERVICE);
42+
mAdminComponent = DeviceAdminReceiver.getComponentName(getActivity());
43+
}
44+
45+
@Override
46+
public View onCreateView(
47+
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
48+
View root = inflater.inflate(R.layout.persistent_device_owner_fragment, container, false);
49+
root.findViewById(R.id.clear_persistent_device_owner_button).setOnClickListener(this);
50+
root.findViewById(R.id.set_persistent_device_owner_button).setOnClickListener(this);
51+
mStateEdit = (EditText) root.findViewById(R.id.persistent_device_owner_state_edit);
52+
return root;
53+
}
54+
55+
@Override
56+
public void onClick(View view) {
57+
String message = null;
58+
switch (view.getId()) {
59+
case R.id.clear_persistent_device_owner_button:
60+
mStateEdit.getText().clear();
61+
Util.setPersistentDoStateWithApplicationRestriction(
62+
getActivity(), mDpm, mAdminComponent, null);
63+
break;
64+
case R.id.set_persistent_device_owner_button:
65+
Util.setPersistentDoStateWithApplicationRestriction(
66+
getActivity(), mDpm, mAdminComponent, mStateEdit.getText().toString());
67+
break;
68+
}
69+
}
70+
71+
@Override
72+
public void onResume() {
73+
super.onResume();
74+
String state = Util.getPersistentDoStateFromApplicationRestriction(mDpm, mAdminComponent);
75+
mStateEdit.setText(state == null ? "" : state);
76+
}
77+
}

app/src/main/java/com/afwsamples/testdpc/policy/PolicyManagementFragment.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
298298
private static final String UNHIDE_APPS_KEY = "unhide_apps";
299299
private static final String UNSUSPEND_APPS_KEY = "unsuspend_apps";
300300
private static final String WIPE_DATA_KEY = "wipe_data";
301+
private static final String PERSISTENT_DEVICE_OWNER_KEY = "persistent_device_owner";
301302
private static final String CREATE_WIFI_CONFIGURATION_KEY = "create_wifi_configuration";
302303
private static final String CREATE_EAP_TLS_WIFI_CONFIGURATION_KEY
303304
= "create_eap_tls_wifi_configuration";
@@ -409,6 +410,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
409410
STAY_ON_WHILE_PLUGGED_IN);
410411
mStayOnWhilePluggedInSwitchPreference.setOnPreferenceChangeListener(this);
411412
findPreference(WIPE_DATA_KEY).setOnPreferenceClickListener(this);
413+
findPreference(PERSISTENT_DEVICE_OWNER_KEY).setOnPreferenceClickListener(this);
412414
findPreference(REMOVE_DEVICE_OWNER_KEY).setOnPreferenceClickListener(this);
413415
mEnableBackupServicePreference = (SwitchPreference) findPreference(ENABLE_BACKUP_SERVICE);
414416
mEnableBackupServicePreference.setOnPreferenceChangeListener(this);
@@ -585,6 +587,9 @@ public void onPositiveButtonClicked(String[] lockTaskArray) {
585587
case WIPE_DATA_KEY:
586588
showWipeDataPrompt();
587589
return true;
590+
case PERSISTENT_DEVICE_OWNER_KEY:
591+
showFragment(new PersistentDeviceOwnerFragment());
592+
return true;
588593
case REMOVE_DEVICE_OWNER_KEY:
589594
showRemoveDeviceOwnerPrompt();
590595
return true;

app/src/main/java/com/afwsamples/testdpc/provision/PostProvisioningTask.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import android.util.Log;
3838

3939
import com.afwsamples.testdpc.AddAccountActivity;
40+
import com.afwsamples.testdpc.DeviceAdminReceiver;
4041
import com.afwsamples.testdpc.EnableDeviceOwnerActivity;
4142
import com.afwsamples.testdpc.EnableProfileActivity;
4243
import com.afwsamples.testdpc.common.LaunchIntentUtil;
@@ -66,6 +67,8 @@ public class PostProvisioningTask {
6667
"com.afwsamples.testdpc.SetupManagementLaunchActivity";
6768
private static final String POST_PROV_PREFS = "post_prov_prefs";
6869
private static final String KEY_POST_PROV_DONE = "key_post_prov_done";
70+
private static final String KEY_DEVICE_OWNER_STATE =
71+
"android.app.extra.PERSISTENT_DEVICE_OWNER_STATE";
6972

7073
private final Context mContext;
7174
private final DevicePolicyManager mDevicePolicyManager;
@@ -98,6 +101,16 @@ public boolean performPostProvisioningOperations(Intent intent) {
98101
maybeSetAffiliationIds(extras);
99102
}
100103

104+
// If TestDPC asked GmsCore to store its state in the FRP area before factory reset, the
105+
// state will be handed over to it during the next device setup.
106+
if (BuildCompat.isAtLeastOMR1() && extras.containsKey(KEY_DEVICE_OWNER_STATE)) {
107+
Util.setPersistentDoStateWithApplicationRestriction(
108+
mContext,
109+
mDevicePolicyManager,
110+
DeviceAdminReceiver.getComponentName(mContext),
111+
extras.getString(KEY_DEVICE_OWNER_STATE));
112+
}
113+
101114
// Hide the setup launcher when this app is the admin
102115
mContext.getPackageManager().setComponentEnabledSetting(
103116
new ComponentName(mContext, SETUP_MANAGEMENT_LAUNCH_ACTIVITY),
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright (C) 2017 The Android Open Source Project
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
18+
android:layout_width="match_parent"
19+
android:layout_height="match_parent"
20+
android:padding="10dp"
21+
android:orientation="vertical">
22+
<EditText android:id="@+id/persistent_device_owner_state_edit"
23+
android:layout_height="wrap_content"
24+
android:layout_width="match_parent"
25+
android:lines="5"
26+
android:layout_gravity="center"
27+
android:hint="@string/persistent_device_owner_state_hint"/>
28+
<LinearLayout
29+
android:layout_height="wrap_content"
30+
android:layout_width="wrap_content"
31+
android:layout_gravity="center"
32+
android:orientation="horizontal">
33+
<Button android:id="@+id/clear_persistent_device_owner_button"
34+
android:layout_width="wrap_content"
35+
android:layout_height="wrap_content"
36+
android:text="@string/clear_persistent_device_owner_label"
37+
android:layout_margin="8dp"
38+
android:visibility="visible"/>
39+
<Button android:id="@+id/set_persistent_device_owner_button"
40+
android:layout_width="wrap_content"
41+
android:layout_height="wrap_content"
42+
android:text="@string/set_persistent_device_owner_label"
43+
android:layout_margin="8dp"
44+
android:visibility="visible"/>
45+
</LinearLayout>
46+
</LinearLayout>

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,17 @@
119119
<string name="wipe_data_title">Wipe data?</string>
120120
<string name="wipe_data_confirmation">Are you sure you want to wipe the data?</string>
121121
<string name="wipe_data_include">Also wipe:</string>
122+
<string name="persistent_device_owner">Persistent device owner state</string>
122123
<string name="external_storage">External storage</string>
123124
<string name="reset_protection_data">Factory reset protection</string>
124125
<string name="remove_device_owner">Remove this device owner</string>
125126
<string name="remove_device_owner_title">Remove device owner?</string>
126127
<string name="remove_device_owner_confirmation">Policies and restrictions will continue to be
127128
active and may require a factory reset to clear.</string>
128129
<string name="device_owner_removed">This app is no longer a device owner.</string>
130+
<string name="persistent_device_owner_state_hint">Test state to be restored alongside the device owner after factory reset.</string>
131+
<string name="set_persistent_device_owner_label">Set</string>
132+
<string name="clear_persistent_device_owner_label">Clear</string>
129133

130134
<!-- Strings for device reboot -->
131135
<string name="reboot">Reboot device</string>

app/src/main/res/xml/device_policy_header.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,11 @@
469469
android:title="@string/reboot"
470470
testdpc:admin="deviceOwner"
471471
testdpc:minSdkVersion="N" />
472+
<com.afwsamples.testdpc.common.preference.DpcPreference
473+
android:key="persistent_device_owner"
474+
android:title="@string/persistent_device_owner"
475+
testdpc:admin="deviceOwner"
476+
testdpc:minSdkVersion="O_MR1" />
472477
</PreferenceCategory>
473478

474479
<PreferenceCategory android:title="@string/safetynet_preference_title">

0 commit comments

Comments
 (0)