Skip to content

Commit e2d3ec4

Browse files
author
Rubin Xu
committed
Delegation-aware TestDPC
Mark some of the preferences available when TestDPC is not a DO/PO, but has the appropriate delegation capabilities. Fix calls to DPM so TestDPC can call these APIs as a delegated app (passing null as admin argument). Also make the delegation fragment show the current delegations TestDPC has if it's no DO/PO. To use this functionality, you should install the TestDPC-replica app alongside the normal TestDPC as DO/PO, grant delegation to TestDPC-replica, and use it to test the delegated functonalities. Bug: 112982695 Test: manual Change-Id: I630f532320f3ea37e37a3b3011a01e9611ca8f37
1 parent fb58cd9 commit e2d3ec4

File tree

13 files changed

+174
-46
lines changed

13 files changed

+174
-46
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ protected SpinnerAdapter createSpinnerAdapter() {
4646
managedAppList);
4747
}
4848

49+
/**
50+
* Additionally filter apps returned in the list, return {@code true} to keep the app in the
51+
* list, {@code false} to exclude it.
52+
*/
53+
protected boolean filterApp(ApplicationInfo info) {
54+
return true;
55+
}
56+
4957
private List<ApplicationInfo> getInstalledOrLaunchableApps() {
5058
List<ApplicationInfo> installedApps = mPackageManager.getInstalledApplications(
5159
0 /* Default flags */);
@@ -54,7 +62,9 @@ private List<ApplicationInfo> getInstalledOrLaunchableApps() {
5462
if (mPackageManager.getLaunchIntentForPackage(applicationInfo.packageName) != null
5563
|| (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
5664
|| WHITELISTED_APPS.contains(applicationInfo.packageName)) {
57-
filteredAppList.add(applicationInfo);
65+
if (filterApp(applicationInfo)) {
66+
filteredAppList.add(applicationInfo);
67+
}
5868
}
5969
}
6070
return filteredAppList;

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,13 @@ private static DevicePolicyManager getDevicePolicyManager(Context context) {
259259
return (DevicePolicyManager)context.getSystemService(Service.DEVICE_POLICY_SERVICE);
260260
}
261261

262+
public static boolean hasDelegation(Context context, String delegation) {
263+
if (Build.VERSION.SDK_INT < VERSION_CODES.O) {
264+
return false;
265+
}
266+
DevicePolicyManager dpm = context.getSystemService(DevicePolicyManager.class);
267+
return dpm.getDelegatedScopes(null, context.getPackageName()).contains(delegation);
268+
}
269+
270+
262271
}

app/src/main/java/com/afwsamples/testdpc/common/preference/DpcPreferenceHelper.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.lang.annotation.Retention;
3636
import java.lang.annotation.RetentionPolicy;
3737
import java.util.ArrayList;
38+
import java.util.Collections;
3839
import java.util.List;
3940

4041
/**
@@ -84,6 +85,7 @@ public class DpcPreferenceHelper {
8485
private int mMinSdkVersion;
8586
private @AdminKind int mAdminConstraint;
8687
private @UserKind int mUserConstraint;
88+
private String mDelegationConstraint;
8789

8890
/**
8991
* Update this method as {@link Build.VERSION_CODES} and Android releases are updated.
@@ -118,7 +120,7 @@ public DpcPreferenceHelper(Context context, Preference preference, AttributeSet
118120
mAdminConstraint = a.getInt(R.styleable.DpcPreference_admin, ADMIN_DEFAULT);
119121
// noinspection ResourceType
120122
mUserConstraint = a.getInt(R.styleable.DpcPreference_user, USER_DEFAULT);
121-
123+
mDelegationConstraint = a.getString(R.styleable.DpcPreference_delegation);
122124
a.recycle();
123125
}
124126

@@ -223,7 +225,7 @@ private CharSequence findConstraintViolation() {
223225
return mContext.getString(R.string.requires_android_api_level, mMinSdkVersion);
224226
}
225227

226-
if (!isEnabledForAdmin(getCurrentAdmin())) {
228+
if (!isSufficientlyPrivileged(getCurrentAdmin(), getCurrentDelegations())) {
227229
return getAdminConstraintSummary();
228230
}
229231

@@ -254,23 +256,40 @@ private int getCurrentAdmin() {
254256
return ADMIN_NONE;
255257
}
256258

259+
private List<String> getCurrentDelegations() {
260+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
261+
return Collections.EMPTY_LIST;
262+
}
263+
final DevicePolicyManager dpm =
264+
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
265+
final String packageName = mContext.getPackageName();
266+
return dpm.getDelegatedScopes(null, packageName);
267+
}
268+
257269
private int getCurrentUser() {
258270
if (Util.isPrimaryUser(mContext)) {
259271
return USER_PRIMARY_USER;
260272
}
261273

262274
if (Util.isManagedProfileOwner(mContext)) {
263-
264275
return USER_MANAGED_PROFILE;
265276
}
266277

267278
return USER_SECONDARY_USER;
268279
}
269280

281+
private boolean isSufficientlyPrivileged(@AdminKind int admin, List<String> delegations) {
282+
return isEnabledForAdmin(admin) || hasDelegation(delegations);
283+
}
284+
270285
private boolean isEnabledForAdmin(@AdminKind int admin) {
271286
return (mAdminConstraint & admin) == admin;
272287
}
273288

289+
private boolean hasDelegation(List<String> delegations) {
290+
return delegations.contains(mDelegationConstraint);
291+
}
292+
274293
private boolean isEnabledForUser(@UserKind int user) {
275294
return (mUserConstraint & user) == user;
276295
}
@@ -284,7 +303,9 @@ private String getAdminConstraintSummary() {
284303
if (isEnabledForAdmin(ADMIN_PROFILE_OWNER)) {
285304
admins.add(mContext.getString(R.string.profile_owner));
286305
}
287-
306+
if (!TextUtils.isEmpty(mDelegationConstraint)) {
307+
admins.add(mDelegationConstraint);
308+
}
288309
return joinRequirementList(admins);
289310
}
290311

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,11 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
427427

428428
@Override
429429
public void onCreate(Bundle savedInstanceState) {
430-
mAdminComponentName = DeviceAdminReceiver.getComponentName(getActivity());
430+
if (isDelegatedApp()) {
431+
mAdminComponentName = null;
432+
} else {
433+
mAdminComponentName = DeviceAdminReceiver.getComponentName(getActivity());
434+
}
431435
mDevicePolicyManager = (DevicePolicyManager) getActivity().getSystemService(
432436
Context.DEVICE_POLICY_SERVICE);
433437
mUserManager = (UserManager) getActivity().getSystemService(Context.USER_SERVICE);
@@ -667,6 +671,14 @@ private void maybeDisableLockTaskPreferences() {
667671
}
668672
}
669673

674+
private boolean isDelegatedApp() {
675+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
676+
return false;
677+
}
678+
DevicePolicyManager dpm = getActivity().getSystemService(DevicePolicyManager.class);
679+
return !dpm.getDelegatedScopes(null, getActivity().getPackageName()).isEmpty();
680+
}
681+
670682
@Override
671683
public boolean isAvailable(Context context) {
672684
return true;
@@ -1287,7 +1299,7 @@ private void generateKeyPair(final String alias, boolean isUserSelectable,
12871299
boolean useStrongBox) {
12881300
new GenerateKeyAndCertificateTask(
12891301
alias, isUserSelectable, attestationChallenge, idAttestationFlags,
1290-
useStrongBox, getActivity()).execute();
1302+
useStrongBox, getActivity(), mAdminComponentName).execute();
12911303
}
12921304

12931305
/**
@@ -1952,6 +1964,8 @@ private void loadAppStatus() {
19521964
appStatusStringId = R.string.this_is_a_profile_owner;
19531965
} else if (mDevicePolicyManager.isDeviceOwnerApp(mPackageName)) {
19541966
appStatusStringId = R.string.this_is_a_device_owner;
1967+
} else if (isDelegatedApp()) {
1968+
appStatusStringId = R.string.this_is_a_delegated_app;
19551969
} else {
19561970
appStatusStringId = R.string.this_is_not_an_admin;
19571971
}
@@ -2521,7 +2535,7 @@ private void showBlockUninstallationPrompt() {
25212535

25222536
final BlockUninstallationInfoArrayAdapter blockUninstallationInfoArrayAdapter
25232537
= new BlockUninstallationInfoArrayAdapter(getActivity(), R.id.pkg_name,
2524-
resolveInfoList);
2538+
resolveInfoList, mAdminComponentName);
25252539
ListView listview = new ListView(getActivity());
25262540
listview.setAdapter(blockUninstallationInfoArrayAdapter);
25272541
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {

app/src/main/java/com/afwsamples/testdpc/policy/blockuninstallation/BlockUninstallationInfoArrayAdapter.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.afwsamples.testdpc.policy.blockuninstallation;
1818

19+
import android.content.ComponentName;
1920
import android.content.Context;
2021
import android.content.pm.ApplicationInfo;
2122
import android.content.pm.PackageManager;
@@ -37,16 +38,18 @@
3738
*/
3839
public class BlockUninstallationInfoArrayAdapter extends ToggleComponentsArrayAdapter {
3940

41+
private final ComponentName mAdminComponent;
42+
4043
public BlockUninstallationInfoArrayAdapter(Context context, int resource,
41-
List<ResolveInfo> resolveInfoList) {
44+
List<ResolveInfo> resolveInfoList, ComponentName admin) {
4245
super(context, resource, resolveInfoList);
46+
mAdminComponent = admin;
4347
setIsComponentEnabledList(createIsComponentEnabledList());
4448
}
4549

4650
@Override
4751
public boolean isComponentEnabled(ResolveInfo resolveInfo) {
48-
return mDevicePolicyManager.isUninstallBlocked(
49-
DeviceAdminReceiver.getComponentName(getContext()),
52+
return mDevicePolicyManager.isUninstallBlocked(mAdminComponent,
5053
resolveInfo.resolvePackageName);
5154
}
5255

@@ -59,8 +62,7 @@ public View getView(final int position, View convertView, ViewGroup parent) {
5962
public void onClick(View v) {
6063
boolean isBlocked = ((CheckBox) v).isChecked();
6164
mIsComponentCheckedList.set(position, isBlocked);
62-
mDevicePolicyManager.setUninstallBlocked(
63-
DeviceAdminReceiver.getComponentName(getContext()),
65+
mDevicePolicyManager.setUninstallBlocked(mAdminComponent,
6466
getItem(position).resolvePackageName, isBlocked);
6567
}
6668
}

app/src/main/java/com/afwsamples/testdpc/policy/keymanagement/GenerateKeyAndCertificateTask.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,15 @@ public GenerateKeyAndCertificateTask(
6868
byte[] attestationChallenge,
6969
int idAttestationFlags,
7070
boolean useStrongBox,
71-
Activity activity) {
71+
Activity activity,
72+
ComponentName admin) {
7273
mAlias = alias;
7374
mIsUserSelectable = isUserSelectable;
7475
mAttestationChallenge = attestationChallenge;
7576
mIdAttestationFlags = idAttestationFlags;
7677
mUseStrongBox = useStrongBox;
7778
mActivity = activity;
78-
mAdminComponentName = DeviceAdminReceiver.getComponentName(activity);
79+
mAdminComponentName = admin;
7980
mDevicePolicyManager =
8081
(DevicePolicyManager) activity.getSystemService(Context.DEVICE_POLICY_SERVICE);
8182
}

app/src/main/java/com/afwsamples/testdpc/profilepolicy/apprestrictions/ManageAppRestrictionsFragment.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.annotation.TargetApi;
2020
import android.app.Activity;
2121
import android.app.admin.DevicePolicyManager;
22+
import android.content.ComponentName;
2223
import android.content.Context;
2324
import android.content.Intent;
2425
import android.content.RestrictionEntry;
@@ -39,6 +40,7 @@
3940
import com.afwsamples.testdpc.common.EditDeleteArrayAdapter;
4041
import com.afwsamples.testdpc.common.ManageAppFragment;
4142
import com.afwsamples.testdpc.common.RestrictionManagerCompat;
43+
import com.afwsamples.testdpc.common.Util;
4244
import com.afwsamples.testdpc.common.keyvaluepair.KeyValuePairDialogFragment;
4345

4446
import java.util.ArrayList;
@@ -60,6 +62,7 @@ public class ManageAppRestrictionsFragment extends ManageAppFragment
6062
private RestrictionsManager mRestrictionsManager;
6163
private EditDeleteArrayAdapter<RestrictionEntry> mAppRestrictionsArrayAdapter;
6264
private RestrictionEntry mEditingRestrictionEntry;
65+
private ComponentName mAdminComponent;
6366

6467
private static final int RESULT_CODE_EDIT_DIALOG = 1;
6568

@@ -86,6 +89,11 @@ public void onCreate(Bundle savedInstanceState) {
8689
Context.DEVICE_POLICY_SERVICE);
8790
mRestrictionsManager = (RestrictionsManager) getActivity().getSystemService(
8891
Context.RESTRICTIONS_SERVICE);
92+
if (Util.hasDelegation(getActivity(), DevicePolicyManager.DELEGATION_APP_RESTRICTIONS)) {
93+
mAdminComponent = null;
94+
} else {
95+
mAdminComponent = DeviceAdminReceiver.getComponentName(getActivity());
96+
}
8997
}
9098

9199
@Override
@@ -320,7 +328,7 @@ protected void onSpinnerItemSelected(ApplicationInfo appInfo) {
320328
String pkgName = appInfo.packageName;
321329
if (!TextUtils.isEmpty(pkgName)) {
322330
Bundle bundle = mDevicePolicyManager.getApplicationRestrictions(
323-
DeviceAdminReceiver.getComponentName(getActivity()), pkgName);
331+
mAdminComponent, pkgName);
324332
loadAppRestrictionsList(convertBundleToRestrictions(bundle));
325333
mLastRestrictionEntries = new ArrayList<>(mRestrictionEntries);
326334
}
@@ -368,7 +376,7 @@ protected void saveConfig() {
368376
String pkgName =
369377
((ApplicationInfo) mManagedAppsSpinner.getSelectedItem()).packageName;
370378
mDevicePolicyManager.setApplicationRestrictions(
371-
DeviceAdminReceiver.getComponentName(getActivity()), pkgName,
379+
mAdminComponent, pkgName,
372380
RestrictionManagerCompat.convertRestrictionsToBundle(mRestrictionEntries));
373381
mLastRestrictionEntries = new ArrayList<>(mRestrictionEntries);
374382
showToast(getString(R.string.set_app_restrictions_success, pkgName));

app/src/main/java/com/afwsamples/testdpc/profilepolicy/delegation/DelegationFragment.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,17 @@ public class DelegationFragment extends ManageAppFragment {
5151
* Model for representing the scopes delegated to the selected app.
5252
*/
5353
List<DelegationScope> mDelegations = DelegationScope.defaultDelegationScopes();
54+
private String mPackageName;
55+
private boolean mIsDeviceOrProfileOwner;
5456

5557
@Override
5658
public void onCreate(Bundle savedInstanceState) {
5759
super.onCreate(savedInstanceState);
5860
mDpm = (DevicePolicyManager) getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
61+
mPackageName = getActivity().getPackageName();
62+
final boolean isDeviceOwner = mDpm.isDeviceOwnerApp(mPackageName);
63+
final boolean isProfileOwner = mDpm.isProfileOwnerApp(mPackageName);
64+
mIsDeviceOrProfileOwner = isDeviceOwner || isProfileOwner;
5965

6066
getActivity().getActionBar().setTitle(R.string.generic_delegation);
6167
}
@@ -66,17 +72,33 @@ public View onCreateView(LayoutInflater layoutInflater, ViewGroup container,
6672
View view = super.onCreateView(layoutInflater, container, savedInstanceState);
6773
view.findViewById(R.id.add_new_row).setVisibility(View.GONE);
6874
view.findViewById(R.id.reset_app).setVisibility(View.GONE);
75+
76+
if (!mIsDeviceOrProfileOwner) {
77+
// Non-PO/DO app cannot make changes to delegations.
78+
view.findViewById(R.id.save_app).setVisibility(View.GONE);
79+
}
6980
return view;
7081
}
7182

83+
@Override
84+
protected boolean filterApp(ApplicationInfo info) {
85+
if (mIsDeviceOrProfileOwner) {
86+
return super.filterApp(info);
87+
} else {
88+
// Non-PO/DO app can only view its own delegations
89+
return info.packageName.equals(mPackageName);
90+
}
91+
}
92+
7293
/**
7394
* Query the DevicePolicyManager for the delegation scopes granted to pkgName.
7495
*/
7596
@TargetApi(Build.VERSION_CODES.O)
7697
private void readScopesFromDpm(String pkgName) {
7798
// Get the scopes delegated to pkgName.
78-
List<String> scopes = mDpm.getDelegatedScopes(
79-
DeviceAdminReceiver.getComponentName(getActivity()), pkgName);
99+
List<String> scopes = mDpm.getDelegatedScopes(mIsDeviceOrProfileOwner
100+
? DeviceAdminReceiver.getComponentName(getActivity())
101+
: null, pkgName);
80102
Log.i(TAG, pkgName + " | " + Arrays.toString(scopes.toArray()));
81103

82104
// Update our model.
@@ -121,6 +143,12 @@ protected void onSpinnerItemSelected(ApplicationInfo info) {
121143
@Override
122144
@TargetApi(Build.VERSION_CODES.O)
123145
protected void saveConfig() {
146+
if (!mIsDeviceOrProfileOwner) {
147+
Toast.makeText(getActivity(), getString(R.string.delegation_error),
148+
Toast.LENGTH_SHORT).show();
149+
Log.i(TAG, "Only PO/DO can modify delegations");
150+
return;
151+
}
124152
// Get selected package name.
125153
final ApplicationInfo info = (ApplicationInfo) mManagedAppsSpinner.getSelectedItem();
126154
final String pkgName = info.packageName;

app/src/main/java/com/afwsamples/testdpc/profilepolicy/permission/AppPermissionsArrayAdapter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ public class AppPermissionsArrayAdapter
4545
private final DevicePolicyManager mDpm;
4646
private final ComponentName mAdminComponentName;
4747

48-
public AppPermissionsArrayAdapter(Context context, int resource,
49-
List<AppPermission> objects) {
48+
public AppPermissionsArrayAdapter(Context context, int resource, List<AppPermission> objects,
49+
ComponentName admin) {
5050
super(context, resource, objects);
5151
mDpm = (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
52-
mAdminComponentName = DeviceAdminReceiver.getComponentName(context);
52+
mAdminComponentName = admin;
5353
}
5454

5555
@Override

0 commit comments

Comments
 (0)