Skip to content

Commit bc74277

Browse files
committed
Update for Android 11.
1 parent 8fc45ed commit bc74277

39 files changed

+2519
-353
lines changed

app/build.gradle

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ ext {
55
// 1 or more digits
66
versionMajor = 6
77
// exactly 1 digit
8-
versionMinor = 1
8+
versionMinor = 2
99
// exactly 2 digits
1010
versionBuild = 02
1111
}
1212

1313
android {
14-
compileSdkVersion 'android-Q'
14+
compileSdkVersion 'android-R'
1515
buildToolsVersion "28.0.0"
1616

1717
defaultConfig {
@@ -49,6 +49,13 @@ android {
4949
textOutput "stdout"
5050
}
5151

52+
53+
testOptions {
54+
unitTests {
55+
includeAndroidResources = true
56+
}
57+
}
58+
5259
compileOptions {
5360
sourceCompatibility JavaVersion.VERSION_1_8
5461
targetCompatibility JavaVersion.VERSION_1_8
@@ -71,20 +78,28 @@ android {
7178
}
7279
}
7380

74-
task stripTestOnlyNormalDebug << {
75-
stripTestOnlyForBuild("normal", "debug")
81+
task stripTestOnlyNormalDebug {
82+
doLast {
83+
stripTestOnlyForBuild("normal", "debug")
84+
}
7685
}
7786

78-
task stripTestOnlyNormalRelease << {
79-
stripTestOnlyForBuild("normal", "release")
87+
task stripTestOnlyNormalRelease {
88+
doLast {
89+
stripTestOnlyForBuild("normal", "release")
90+
}
8091
}
8192

82-
task stripTestOnlyReplicaDebug << {
83-
stripTestOnlyForBuild("replica", "debug")
93+
task stripTestOnlyReplicaDebug {
94+
doLast {
95+
stripTestOnlyForBuild("replica", "debug")
96+
}
8497
}
8598

86-
task stripTestOnlyReplicaRelease << {
87-
stripTestOnlyForBuild("replica", "release")
99+
task stripTestOnlyReplicaRelease {
100+
doLast {
101+
stripTestOnlyForBuild("replica", "release")
102+
}
88103
}
89104

90105
tasks.whenTaskAdded { task ->
@@ -122,7 +137,7 @@ private void stripTestOnlyForBuild(flavor, buildType) {
122137
dependencies {
123138
def lifecycle_version = "2.0.0"
124139
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
125-
implementation 'androidx.enterprise:enterprise-feedback:1.0.0-alpha01'
140+
implementation 'androidx.enterprise:enterprise-feedback:1.0.0-alpha02'
126141
implementation 'androidx.multidex:multidex:2.0.0'
127142
implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
128143
implementation 'androidx.recyclerview:recyclerview:1.0.0'
@@ -132,6 +147,9 @@ dependencies {
132147
implementation 'org.bouncycastle:bcpkix-jdk15on:1.56'
133148
implementation 'org.bouncycastle:bcprov-jdk15on:1.56'
134149
implementation 'com.google.guava:guava:23.6-android'
135-
150+
testImplementation 'org.robolectric:robolectric:4.2'
151+
testImplementation "com.google.truth:truth:0.44"
152+
testImplementation 'junit:junit:4.5'
153+
testImplementation 'androidx.test:core:1.0.0'
136154
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
137155
}

app/src/main/AndroidManifest.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
3131
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
3232
<uses-permission android:name="android.permission.REQUEST_PASSWORD_COMPLEXITY"/>
33+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
3334

3435
<application
3536
android:allowBackup="true"
@@ -40,11 +41,16 @@
4041
<activity
4142
android:name=".PolicyManagementActivity"
4243
android:label="@string/app_name"
44+
android:exported="true"
4345
android:windowSoftInputMode="adjustPan">
4446
<intent-filter>
4547
<action android:name="android.intent.action.MAIN"/>
4648
<category android:name="android.intent.category.LAUNCHER"/>
4749
</intent-filter>
50+
<intent-filter>
51+
<action android:name="android.app.action.CHECK_POLICY_COMPLIANCE"/>
52+
<category android:name="android.intent.category.DEFAULT"/>
53+
</intent-filter>
4854
</activity>
4955

5056
<activity
@@ -99,7 +105,8 @@
99105

100106
<activity android:name=".provision.DpcLoginActivity"
101107
android:exported="true"
102-
android:permission="android.permission.BIND_DEVICE_ADMIN">
108+
android:permission="android.permission.BIND_DEVICE_ADMIN"
109+
android:theme="@style/DpcLoginTheme">
103110
<intent-filter>
104111
<action android:name="android.app.action.GET_PROVISIONING_MODE" />
105112
<category android:name="android.intent.category.DEFAULT"/>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright (C) 2016 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.afwsamples.testdpc.common;
18+
19+
import android.app.admin.DevicePolicyManager;
20+
import android.content.ComponentName;
21+
import android.content.Context;
22+
import android.content.pm.PackageInfo;
23+
import android.content.pm.PackageManager;
24+
import android.content.pm.PackageManager.NameNotFoundException;
25+
import android.content.pm.PermissionInfo;
26+
import android.os.Build.VERSION_CODES;
27+
import android.util.Log;
28+
import androidx.annotation.RequiresApi;
29+
import java.util.Arrays;
30+
import java.util.List;
31+
32+
/**
33+
* Checks that the requested permissions are present, and grants any dangerous
34+
* permissions required.
35+
*/
36+
public class PermissionsHelper {
37+
38+
public static String TAG = "PermissionsHelper";
39+
40+
/**
41+
* Ensures that the passed in permissions are defined in manifest and attempts to grant a
42+
* permission automatically if it is considered dangerous.
43+
*/
44+
@RequiresApi(VERSION_CODES.M)
45+
public static boolean ensureRequiredPermissions(String[] requiredPermissions, ComponentName admin,
46+
Context context) {
47+
PackageInfo packageInfo;
48+
try {
49+
packageInfo =
50+
context
51+
.getPackageManager()
52+
.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
53+
} catch (NameNotFoundException e) {
54+
Log.e(TAG, "Could not find own package.", e);
55+
return false;
56+
}
57+
List<String> manifestPermissions = Arrays.asList(packageInfo.requestedPermissions);
58+
for (String expectedPermission : requiredPermissions) {
59+
if (!manifestPermissions.contains(expectedPermission)) {
60+
Log.e(TAG, "Missing required permission from manifest: " + expectedPermission);
61+
return false;
62+
}
63+
if (!maybeGrantDangerousPermission(expectedPermission, admin, context)){
64+
return false;
65+
}
66+
}
67+
return true;
68+
}
69+
70+
/**
71+
* Attempts to grant a permission automatically if it is considered dangerous - this only happens
72+
* for PO/DO devices.
73+
*/
74+
@RequiresApi(VERSION_CODES.M)
75+
private static boolean maybeGrantDangerousPermission(String permission, ComponentName admin,
76+
Context context) {
77+
if (!isPermissionDangerous(permission, context)) {
78+
return true;
79+
}
80+
if (!ProvisioningStateUtil.isManagedByTestDPC(context)) {
81+
return false;
82+
}
83+
if (hasPermissionGranted(admin, context, permission)) {
84+
return true;
85+
}
86+
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context
87+
.getSystemService(Context.DEVICE_POLICY_SERVICE);
88+
return devicePolicyManager.setPermissionGrantState(
89+
admin,
90+
context.getPackageName(),
91+
permission,
92+
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
93+
}
94+
95+
96+
// Min API version required for DevicePolicyManager.getPermissionGrantState
97+
@RequiresApi(VERSION_CODES.M)
98+
private static boolean hasPermissionGranted(
99+
ComponentName componentName, Context context, String permission) {
100+
DevicePolicyManager devicePolicyManager = context.getSystemService(DevicePolicyManager.class);
101+
return devicePolicyManager
102+
.getPermissionGrantState(componentName, context.getPackageName(), permission)
103+
== DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
104+
}
105+
106+
private static boolean isPermissionDangerous(String permission, Context context) {
107+
PermissionInfo permissionInfo;
108+
try {
109+
permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0);
110+
} catch (NameNotFoundException e) {
111+
Log.e(TAG, "Failed to look up permission.", e);
112+
return false;
113+
}
114+
return permissionInfo != null
115+
&& (permissionInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
116+
== PermissionInfo.PROTECTION_DANGEROUS;
117+
}
118+
}

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,11 @@ public class Util {
5757
private static final String GMSCORE_PACKAGE = "com.google.android.gms";
5858
private static final String PERSISTENT_DEVICE_OWNER_STATE = "persistentDeviceOwnerState";
5959

60-
// TODO:(133143789): Remove when we no longer need to support pre-release Q
61-
private static final boolean IS_RUNNING_Q =
62-
VERSION.CODENAME.length() == 1 && VERSION.CODENAME.charAt(0) == 'Q';
60+
// TODO: Update to S when VERSION_CODES.R becomes available.
61+
public static final int R_VERSION_CODE = 30;
62+
63+
private static final boolean IS_RUNNING_R =
64+
VERSION.CODENAME.length() == 1 && VERSION.CODENAME.charAt(0) == 'R';
6365

6466
public static final int Q_VERSION_CODE = 29;
6567

@@ -69,7 +71,8 @@ public class Util {
6971
* <p>This will be set to the version SDK, or {@link VERSION_CODES.CUR_DEVELOPMENT} if the SDK
7072
* int is not yet assigned.
7173
**/
72-
public static final int SDK_INT = IS_RUNNING_Q ? Q_VERSION_CODE : VERSION.SDK_INT;
74+
public static final int SDK_INT =
75+
IS_RUNNING_R ? VERSION_CODES.CUR_DEVELOPMENT : VERSION.SDK_INT;
7376

7477
/**
7578
* Format a friendly datetime for the current locale according to device policy documentation.

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

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import android.view.View;
3030
import android.widget.TextView;
3131
import com.afwsamples.testdpc.R;
32+
import com.afwsamples.testdpc.common.ReflectionUtil;
33+
import com.afwsamples.testdpc.common.ReflectionUtil.ReflectionIsTemporaryException;
3234
import com.afwsamples.testdpc.common.Util;
3335
import java.lang.annotation.Retention;
3436
import java.lang.annotation.RetentionPolicy;
@@ -47,15 +49,18 @@
4749
*/
4850
public class DpcPreferenceHelper {
4951
@Retention(RetentionPolicy.SOURCE)
50-
@IntDef(flag = true, value = {ADMIN_NONE, ADMIN_DEVICE_OWNER, ADMIN_PROFILE_OWNER})
52+
@IntDef(flag = true, value = {ADMIN_NONE, ADMIN_DEVICE_OWNER, ADMIN_BYOD_PROFILE_OWNER,
53+
ADMIN_ORG_OWNED_PROFILE_OWNER})
5154
public @interface AdminKind {}
5255
public static final int ADMIN_NONE = 0x1;
5356
public static final int ADMIN_DEVICE_OWNER = 0x2;
54-
public static final int ADMIN_PROFILE_OWNER = 0x4;
55-
public static final int ADMIN_ANY = ADMIN_NONE | ADMIN_DEVICE_OWNER | ADMIN_PROFILE_OWNER;
57+
public static final int ADMIN_BYOD_PROFILE_OWNER = 0x4;
58+
public static final int ADMIN_ORG_OWNED_PROFILE_OWNER = 0x8;
59+
public static final int ADMIN_PROFILE_OWNER =
60+
ADMIN_BYOD_PROFILE_OWNER | ADMIN_ORG_OWNED_PROFILE_OWNER;
61+
public static final int ADMIN_ANY =
62+
ADMIN_NONE | ADMIN_DEVICE_OWNER | ADMIN_PROFILE_OWNER | ADMIN_ORG_OWNED_PROFILE_OWNER;
5663
public static final int ADMIN_NOT_NONE = ADMIN_ANY & ~ADMIN_NONE;
57-
public static final int ADMIN_NOT_DEVICE_OWNER = ADMIN_ANY & ~ADMIN_DEVICE_OWNER;
58-
public static final int ADMIN_NOT_PROFILE_OWNER = ADMIN_ANY & ~ADMIN_PROFILE_OWNER;
5964
public static final @AdminKind int ADMIN_DEFAULT = ADMIN_NOT_NONE;
6065
public static final int NO_CUSTOM_CONSTRIANT = 0;
6166

@@ -253,19 +258,27 @@ private int getCurrentAdmin() {
253258
return ADMIN_DEVICE_OWNER;
254259
}
255260
if (dpm.isProfileOwnerApp(packageName)) {
256-
return ADMIN_PROFILE_OWNER;
261+
Boolean orgOwned = Util.SDK_INT >= VERSION_CODES.R &&
262+
dpm.isOrganizationOwnedDeviceWithManagedProfile();
263+
if (orgOwned) {
264+
return ADMIN_ORG_OWNED_PROFILE_OWNER;
265+
} else {
266+
return ADMIN_PROFILE_OWNER;
267+
}
257268
}
258269
return ADMIN_NONE;
259270
}
260271

261272
private List<String> getCurrentDelegations() {
262273
if (Util.SDK_INT < VERSION_CODES.O) {
263-
return Collections.EMPTY_LIST;
274+
return Collections.emptyList();
264275
}
276+
265277
final DevicePolicyManager dpm =
266278
(DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
267279
final String packageName = mContext.getPackageName();
268-
return dpm.getDelegatedScopes(null, packageName);
280+
return dpm.getDelegatedScopes(null, packageName);
281+
269282
}
270283

271284
private int getCurrentUser() {
@@ -302,7 +315,12 @@ private String getAdminConstraintSummary() {
302315
if (isEnabledForAdmin(ADMIN_DEVICE_OWNER)) {
303316
admins.add(mContext.getString(R.string.device_owner));
304317
}
305-
if (isEnabledForAdmin(ADMIN_PROFILE_OWNER)) {
318+
// Only add the org-owned profile message if the constraint is specific to org-owned profile
319+
// and not all profile types, to reduce verbosity of the message.
320+
if (isEnabledForAdmin(ADMIN_ORG_OWNED_PROFILE_OWNER) &&
321+
!isEnabledForAdmin(ADMIN_PROFILE_OWNER)) {
322+
admins.add(mContext.getString(R.string.org_owned_profile_owner));
323+
} else if (isEnabledForAdmin(ADMIN_PROFILE_OWNER)) {
306324
admins.add(mContext.getString(R.string.profile_owner));
307325
}
308326
if (!TextUtils.isEmpty(mDelegationConstraint)) {

0 commit comments

Comments
 (0)