diff --git a/app/build.gradle b/app/build.gradle index 5e8bab82..2b798207 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,7 +9,7 @@ ext { // exactly 1 digit versionMinor = 0 // exactly 2 digits - versionBuild = 05 + versionBuild = 06 } android { diff --git a/app/src/main/java/com/afwsamples/testdpc/PackageMonitorReceiver.java b/app/src/main/java/com/afwsamples/testdpc/PackageMonitorReceiver.java index 991f1eda..b175056d 100644 --- a/app/src/main/java/com/afwsamples/testdpc/PackageMonitorReceiver.java +++ b/app/src/main/java/com/afwsamples/testdpc/PackageMonitorReceiver.java @@ -8,7 +8,6 @@ import android.support.v7.app.NotificationCompat; import android.support.v7.app.NotificationCompat.Builder; import android.text.TextUtils; - import com.afwsamples.testdpc.common.NotificationUtil; public class PackageMonitorReceiver extends BroadcastReceiver { @@ -37,6 +36,7 @@ public void onReceive(Context context, Intent intent) { .setContentText(notificationBody) .setStyle(new NotificationCompat.BigTextStyle().bigText(notificationBody)) .setDefaults(Notification.DEFAULT_LIGHTS) + .setOnlyAlertOnce(true) .build(); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); diff --git a/app/src/main/java/com/afwsamples/testdpc/common/Util.java b/app/src/main/java/com/afwsamples/testdpc/common/Util.java index 1a1f4da2..d4b74d25 100644 --- a/app/src/main/java/com/afwsamples/testdpc/common/Util.java +++ b/app/src/main/java/com/afwsamples/testdpc/common/Util.java @@ -30,6 +30,7 @@ import android.net.Uri; import android.os.Build; import android.os.Build.VERSION_CODES; +import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.support.annotation.RequiresApi; @@ -56,7 +57,12 @@ */ public class Util { private static final String TAG = "Util"; - private static final int DEFAULT_BUFFER_SIZE = 4096; + private static final int DEFAULT_BUFFER_SIZE = 4096; + + private static final String BROADCAST_ACTION_FRP_CONFIG_CHANGED = + "com.google.android.gms.auth.FRP_CONFIG_CHANGED"; + private static final String GMSCORE_PACKAGE = "com.google.android.gms"; + private static final String PERSISTENT_DEVICE_OWNER_STATE = "persistentDeviceOwnerState"; /** * Format a friendly datetime for the current locale according to device policy documentation. @@ -194,6 +200,42 @@ public static boolean installCaCertificate(InputStream certificateInputStream, return false; } + /** + * Returns the persistent device owner state which has been set by the device owner as an app + * restriction on GmsCore or null if there is no such restriction set. + */ + @TargetApi(VERSION_CODES.O) + public static String getPersistentDoStateFromApplicationRestriction( + DevicePolicyManager dpm, ComponentName admin) { + Bundle restrictions = dpm.getApplicationRestrictions(admin, GMSCORE_PACKAGE); + return restrictions.getString(PERSISTENT_DEVICE_OWNER_STATE); + } + + /** + * Sets the persistent device owner state by setting a special app restriction on GmsCore and + * notifies GmsCore about the change by sending a broadcast. + * + * @param state The device owner state to be preserved across factory resets. If null, the + * persistent device owner state and the corresponding restiction are cleared. + */ + @TargetApi(VERSION_CODES.O) + public static void setPersistentDoStateWithApplicationRestriction( + Context context, DevicePolicyManager dpm, ComponentName admin, String state) { + Bundle restrictions = dpm.getApplicationRestrictions(admin, GMSCORE_PACKAGE); + if (state == null) { + // Clear the restriction + restrictions.remove(PERSISTENT_DEVICE_OWNER_STATE); + } else { + // Set the restriction + restrictions.putString(PERSISTENT_DEVICE_OWNER_STATE, state); + } + dpm.setApplicationRestrictions(admin, GMSCORE_PACKAGE, restrictions); + Intent broadcastIntent = new Intent(BROADCAST_ACTION_FRP_CONFIG_CHANGED); + broadcastIntent.setPackage(GMSCORE_PACKAGE); + broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + context.sendBroadcast(broadcastIntent); + } + private static DevicePolicyManager getDevicePolicyManager(Context context) { return (DevicePolicyManager)context.getSystemService(Service.DEVICE_POLICY_SERVICE); } diff --git a/app/src/main/java/com/afwsamples/testdpc/common/preference/DpcPreferenceHelper.java b/app/src/main/java/com/afwsamples/testdpc/common/preference/DpcPreferenceHelper.java index f41a7f81..15c38869 100644 --- a/app/src/main/java/com/afwsamples/testdpc/common/preference/DpcPreferenceHelper.java +++ b/app/src/main/java/com/afwsamples/testdpc/common/preference/DpcPreferenceHelper.java @@ -93,9 +93,6 @@ public class DpcPreferenceHelper { * not yet assigned. */ private int getDeviceSdkInt() { - if (BuildCompat.isAtLeastO()) { - return Build.VERSION_CODES.O; - } return Build.VERSION.SDK_INT; } diff --git a/app/src/main/java/com/afwsamples/testdpc/policy/PersistentDeviceOwnerFragment.java b/app/src/main/java/com/afwsamples/testdpc/policy/PersistentDeviceOwnerFragment.java new file mode 100644 index 00000000..2d256379 --- /dev/null +++ b/app/src/main/java/com/afwsamples/testdpc/policy/PersistentDeviceOwnerFragment.java @@ -0,0 +1,77 @@ +package com.afwsamples.testdpc.policy; + +import android.annotation.TargetApi; +import android.app.Fragment; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; + +import com.afwsamples.testdpc.DeviceAdminReceiver; +import com.afwsamples.testdpc.R; +import com.afwsamples.testdpc.common.Util; + +/** + * Allows the user to set a test persistent device owner state. + * + *
For manual testing of forced re-enrollment. + * + *
If there is a non-empty peristent device owner state, it will survive the next factory reset,
+ * TestDPC will be re-installed automatically as device owner and the state will be passed to it
+ * during the initial device setup.
+ */
+public class PersistentDeviceOwnerFragment extends Fragment implements View.OnClickListener {
+
+ private DevicePolicyManager mDpm;
+ private ComponentName mAdminComponent;
+ private EditText mStateEdit;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getActivity().getActionBar().setTitle(R.string.persistent_device_owner);
+ mDpm = (DevicePolicyManager) getActivity().getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ mAdminComponent = DeviceAdminReceiver.getComponentName(getActivity());
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.persistent_device_owner_fragment, container, false);
+ root.findViewById(R.id.clear_persistent_device_owner_button).setOnClickListener(this);
+ root.findViewById(R.id.set_persistent_device_owner_button).setOnClickListener(this);
+ mStateEdit = (EditText) root.findViewById(R.id.persistent_device_owner_state_edit);
+ return root;
+ }
+
+ @Override
+ public void onClick(View view) {
+ String message = null;
+ switch (view.getId()) {
+ case R.id.clear_persistent_device_owner_button:
+ mStateEdit.getText().clear();
+ Util.setPersistentDoStateWithApplicationRestriction(
+ getActivity(), mDpm, mAdminComponent, null);
+ break;
+ case R.id.set_persistent_device_owner_button:
+ Util.setPersistentDoStateWithApplicationRestriction(
+ getActivity(), mDpm, mAdminComponent, mStateEdit.getText().toString());
+ break;
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ String state = Util.getPersistentDoStateFromApplicationRestriction(mDpm, mAdminComponent);
+ mStateEdit.setText(state == null ? "" : state);
+ }
+}
diff --git a/app/src/main/java/com/afwsamples/testdpc/policy/PolicyManagementFragment.java b/app/src/main/java/com/afwsamples/testdpc/policy/PolicyManagementFragment.java
index 06f88d13..b97b0e99 100644
--- a/app/src/main/java/com/afwsamples/testdpc/policy/PolicyManagementFragment.java
+++ b/app/src/main/java/com/afwsamples/testdpc/policy/PolicyManagementFragment.java
@@ -298,6 +298,7 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
private static final String UNHIDE_APPS_KEY = "unhide_apps";
private static final String UNSUSPEND_APPS_KEY = "unsuspend_apps";
private static final String WIPE_DATA_KEY = "wipe_data";
+ private static final String PERSISTENT_DEVICE_OWNER_KEY = "persistent_device_owner";
private static final String CREATE_WIFI_CONFIGURATION_KEY = "create_wifi_configuration";
private static final String CREATE_EAP_TLS_WIFI_CONFIGURATION_KEY
= "create_eap_tls_wifi_configuration";
@@ -409,6 +410,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
STAY_ON_WHILE_PLUGGED_IN);
mStayOnWhilePluggedInSwitchPreference.setOnPreferenceChangeListener(this);
findPreference(WIPE_DATA_KEY).setOnPreferenceClickListener(this);
+ findPreference(PERSISTENT_DEVICE_OWNER_KEY).setOnPreferenceClickListener(this);
findPreference(REMOVE_DEVICE_OWNER_KEY).setOnPreferenceClickListener(this);
mEnableBackupServicePreference = (SwitchPreference) findPreference(ENABLE_BACKUP_SERVICE);
mEnableBackupServicePreference.setOnPreferenceChangeListener(this);
@@ -482,6 +484,10 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
SET_AUTO_TIME_REQUIRED_KEY);
mSetAutoTimeRequiredPreference.setOnPreferenceChangeListener(this);
+ mSetDeviceOrganizationNamePreference =
+ (EditTextPreference) findPreference(SET_DEVICE_ORGANIZATION_NAME_KEY);
+ mSetDeviceOrganizationNamePreference.setOnPreferenceChangeListener(this);
+
constrainSpecialCasePreferences();
maybeDisableLockTaskPreferences();
@@ -585,6 +591,9 @@ public void onPositiveButtonClicked(String[] lockTaskArray) {
case WIPE_DATA_KEY:
showWipeDataPrompt();
return true;
+ case PERSISTENT_DEVICE_OWNER_KEY:
+ showFragment(new PersistentDeviceOwnerFragment());
+ return true;
case REMOVE_DEVICE_OWNER_KEY:
showRemoveDeviceOwnerPrompt();
return true;
diff --git a/app/src/main/java/com/afwsamples/testdpc/provision/PostProvisioningTask.java b/app/src/main/java/com/afwsamples/testdpc/provision/PostProvisioningTask.java
index 67cb0946..be4de37b 100644
--- a/app/src/main/java/com/afwsamples/testdpc/provision/PostProvisioningTask.java
+++ b/app/src/main/java/com/afwsamples/testdpc/provision/PostProvisioningTask.java
@@ -37,6 +37,7 @@
import android.util.Log;
import com.afwsamples.testdpc.AddAccountActivity;
+import com.afwsamples.testdpc.DeviceAdminReceiver;
import com.afwsamples.testdpc.EnableDeviceOwnerActivity;
import com.afwsamples.testdpc.EnableProfileActivity;
import com.afwsamples.testdpc.common.LaunchIntentUtil;
@@ -66,6 +67,8 @@ public class PostProvisioningTask {
"com.afwsamples.testdpc.SetupManagementLaunchActivity";
private static final String POST_PROV_PREFS = "post_prov_prefs";
private static final String KEY_POST_PROV_DONE = "key_post_prov_done";
+ private static final String KEY_DEVICE_OWNER_STATE =
+ "android.app.extra.PERSISTENT_DEVICE_OWNER_STATE";
private final Context mContext;
private final DevicePolicyManager mDevicePolicyManager;
@@ -98,6 +101,18 @@ public boolean performPostProvisioningOperations(Intent intent) {
maybeSetAffiliationIds(extras);
}
+ // If TestDPC asked GmsCore to store its state in the FRP area before factory reset, the
+ // state will be handed over to it during the next device setup.
+ if (BuildCompat.isAtLeastOMR1()
+ && extras != null
+ && extras.containsKey(KEY_DEVICE_OWNER_STATE)) {
+ Util.setPersistentDoStateWithApplicationRestriction(
+ mContext,
+ mDevicePolicyManager,
+ DeviceAdminReceiver.getComponentName(mContext),
+ extras.getString(KEY_DEVICE_OWNER_STATE));
+ }
+
// Hide the setup launcher when this app is the admin
mContext.getPackageManager().setComponentEnabledSetting(
new ComponentName(mContext, SETUP_MANAGEMENT_LAUNCH_ACTIVITY),
diff --git a/app/src/main/res/layout/persistent_device_owner_fragment.xml b/app/src/main/res/layout/persistent_device_owner_fragment.xml
new file mode 100644
index 00000000..92543834
--- /dev/null
+++ b/app/src/main/res/layout/persistent_device_owner_fragment.xml
@@ -0,0 +1,46 @@
+
+
+