Skip to content

Commit c6026e1

Browse files
author
Pavel Grafov
committed
Support lockdown whitelisting in TestDPC.
Test: manual Bug: 77468593 Change-Id: Ic3634b0fd9bedb29a74b5e93b405b8abc69f34a4
1 parent db12e19 commit c6026e1

File tree

5 files changed

+141
-7
lines changed

5 files changed

+141
-7
lines changed

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ public View onCreateView(LayoutInflater layoutInflater, ViewGroup container,
6565
Bundle savedInstanceState) {
6666
View view = layoutInflater.inflate(R.layout.select_app, null);
6767

68-
mCurrentSelectedPackage = (EditText) view.findViewById(R.id.selected_package_current);
69-
mNewSelectedPackage = (EditText) view.findViewById(R.id.selected_package_new);
70-
mAppListView = (ListView) view.findViewById(R.id.select_app_list);
68+
mCurrentSelectedPackage = view.findViewById(R.id.selected_package_current);
69+
mNewSelectedPackage = view.findViewById(R.id.selected_package_new);
70+
mAppListView = view.findViewById(R.id.select_app_list);
7171
AppInfoArrayAdapter appInfoArrayAdapter = new AppInfoArrayAdapter(getActivity(),
7272
R.id.pkg_name, mAppPackages, true);
7373
mAppListView.setAdapter(appInfoArrayAdapter);
@@ -93,6 +93,10 @@ protected List<String> createAppList() {
9393
return appList;
9494
}
9595

96+
protected ViewGroup getExtensionLayout(View rootView) {
97+
return rootView.findViewById(R.id.extension);
98+
}
99+
96100
@Override
97101
public void onClick(View v) {
98102
switch (v.getId()) {
@@ -108,7 +112,7 @@ public void onClick(View v) {
108112
}
109113
}
110114

111-
private void reloadSelectedPackage() {
115+
protected void reloadSelectedPackage() {
112116
String selectedPackage = getSelectedPackage();
113117
if (selectedPackage == null) {
114118
mCurrentSelectedPackage.setText("");

app/src/main/java/com/afwsamples/testdpc/policy/networking/AlwaysOnVpnFragment.java

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

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

19+
import static com.afwsamples.testdpc.common.Util.isAtLeastQ;
20+
1921
import android.annotation.TargetApi;
2022
import android.app.admin.DevicePolicyManager;
2123
import android.content.ComponentName;
@@ -27,15 +29,23 @@
2729
import android.os.Build;
2830
import android.os.Bundle;
2931
import android.util.Log;
32+
import android.view.LayoutInflater;
33+
import android.view.View;
34+
import android.view.ViewGroup;
35+
import android.widget.CheckBox;
36+
import android.widget.EditText;
37+
import android.widget.Toast;
3038

3139
import com.afwsamples.testdpc.DeviceAdminReceiver;
3240
import com.afwsamples.testdpc.R;
3341
import com.afwsamples.testdpc.common.SelectAppFragment;
3442

3543
import java.util.ArrayList;
44+
import java.util.Arrays;
3645
import java.util.HashSet;
3746
import java.util.List;
3847
import java.util.Set;
48+
import java.util.stream.Collectors;
3949

4050
/**
4151
* This fragment provides a setting for always-on VPN apps.
@@ -49,14 +59,20 @@
4959
@TargetApi(Build.VERSION_CODES.N)
5060
public class AlwaysOnVpnFragment extends SelectAppFragment {
5161
private static final String TAG = "AlwaysOnVpnFragment";
62+
5263
private DevicePolicyManager mDpm;
5364

65+
private CheckBox mLockdown;
66+
private EditText mExemptedPackages;
67+
5468
private static final Intent VPN_INTENT = new Intent(VpnService.SERVICE_INTERFACE);
69+
private ComponentName mWho;
5570

5671
@Override
5772
public void onCreate(Bundle savedInstanceState) {
5873
super.onCreate(savedInstanceState);
5974
mDpm = (DevicePolicyManager) getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
75+
mWho = DeviceAdminReceiver.getComponentName(getActivity());
6076
}
6177

6278
@Override
@@ -65,6 +81,23 @@ public void onResume() {
6581
getActivity().getActionBar().setTitle(R.string.set_always_on_vpn);
6682
}
6783

84+
@Override
85+
public View onCreateView(LayoutInflater layoutInflater, ViewGroup container,
86+
Bundle savedInstanceState) {
87+
final View view = super.onCreateView(layoutInflater, container, savedInstanceState);
88+
89+
if (isAtLeastQ()) {
90+
final ViewGroup extension = getExtensionLayout(view);
91+
extension.setVisibility(View.VISIBLE);
92+
layoutInflater.inflate(R.layout.lockdown_settings, extension);
93+
mLockdown = view.findViewById(R.id.enable_lockdown);
94+
mExemptedPackages = view.findViewById(R.id.exempted_packages);
95+
mLockdown.setOnCheckedChangeListener(
96+
(unused, checked) -> mExemptedPackages.setEnabled(checked));
97+
}
98+
return view;
99+
}
100+
68101
@Override
69102
protected List<String> createAppList() {
70103
Set<String> apps = new HashSet<>();
@@ -79,16 +112,54 @@ protected List<String> createAppList() {
79112
return new ArrayList<>(apps);
80113
}
81114

115+
@Override
116+
protected void reloadSelectedPackage() {
117+
super.reloadSelectedPackage();
118+
if (isAtLeastQ()) {
119+
updateLockdown();
120+
}
121+
}
122+
123+
@TargetApi(Build.VERSION_CODES.Q)
124+
private void updateLockdown() {
125+
mLockdown.setChecked(mDpm.isAlwaysOnVpnLockdownEnabled(mWho));
126+
final List<String> exemptedPackages = mDpm.getAlwaysOnVpnLockdownWhitelist(mWho);
127+
mExemptedPackages.setText(
128+
exemptedPackages != null ? String.join(",", exemptedPackages) : "");
129+
}
130+
82131
@Override
83132
protected void setSelectedPackage(String pkg) {
84133
try {
85-
final ComponentName who = DeviceAdminReceiver.getComponentName(getActivity());
86-
mDpm.setAlwaysOnVpnPackage(who, pkg, /* lockdownEnabled */ true);
87-
} catch (PackageManager.NameNotFoundException | UnsupportedOperationException e) {
134+
if (isAtLeastQ()) {
135+
setAlwaysOnVpnPackageQPlus(pkg);
136+
} else {
137+
mDpm.setAlwaysOnVpnPackage(mWho, pkg, /* lockdownEnabled */ true);
138+
}
139+
} catch (PackageManager.NameNotFoundException e) {
140+
final String text = "Package not found: " + e.getMessage();
141+
Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
142+
Log.e(TAG, "setAlwaysOnVpnPackage:", e);
143+
} catch (UnsupportedOperationException e) {
144+
Toast.makeText(getActivity(), "App doesn't support always-on VPN", Toast.LENGTH_SHORT)
145+
.show();
88146
Log.e(TAG, "setAlwaysOnVpnPackage:", e);
89147
}
90148
}
91149

150+
@TargetApi(Build.VERSION_CODES.Q)
151+
private void setAlwaysOnVpnPackageQPlus(String pkg)
152+
throws PackageManager.NameNotFoundException {
153+
final boolean lockdown = mLockdown.isChecked();
154+
final List<String> packages = lockdown ?
155+
Arrays.stream(mExemptedPackages.getText().toString().split(","))
156+
.map(String::trim)
157+
.filter(s -> !s.isEmpty())
158+
.collect(Collectors.toList())
159+
: null;
160+
mDpm.setAlwaysOnVpnPackage(mWho, pkg, lockdown, packages);
161+
}
162+
92163
@Override
93164
protected void clearSelectedPackage() {
94165
setSelectedPackage(null);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2019 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+
18+
<LinearLayout
19+
xmlns:android="http://schemas.android.com/apk/res/android"
20+
android:layout_width="match_parent"
21+
android:layout_height="wrap_content"
22+
android:orientation="vertical">
23+
24+
<CheckBox
25+
android:id="@+id/enable_lockdown"
26+
android:layout_width="match_parent"
27+
android:layout_height="wrap_content"
28+
android:text="@string/vpn_lockdown"/>
29+
30+
<LinearLayout
31+
android:layout_width="match_parent"
32+
android:layout_height="wrap_content"
33+
android:orientation="horizontal">
34+
35+
<TextView
36+
android:layout_width="wrap_content"
37+
android:layout_height="wrap_content"
38+
android:text="@string/vpn_exempted_packages"/>
39+
40+
<EditText
41+
android:id="@+id/exempted_packages"
42+
android:layout_width="fill_parent"
43+
android:layout_height="wrap_content"/>
44+
45+
</LinearLayout>
46+
47+
</LinearLayout>

app/src/main/res/layout/select_app.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ limitations under the License.
4848
android:layout_weight="1">
4949
</ListView>
5050

51+
<!-- For extension by subclasses of SelectAppFragment -->
52+
<FrameLayout
53+
android:id="@+id/extension"
54+
android:layout_width="match_parent"
55+
android:layout_height="wrap_content"
56+
android:orientation="vertical">
57+
</FrameLayout>
58+
5159
<EditText
5260
android:id="@+id/selected_package_new"
5361
android:layout_width="fill_parent"
@@ -69,4 +77,5 @@ limitations under the License.
6977
android:layout_height="50dip"
7078
android:text="@string/selected_package_clear" />
7179
</LinearLayout>
80+
7281
</LinearLayout>

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,4 +1091,7 @@
10911091
<string name="dpc_policy_compliance_title">Dpc policy compliance</string>
10921092
<string name="dpc_policy_compliance_explanation">TestDPC setup is completed.</string>
10931093

1094+
<string name="vpn_exempted_packages">Exempted packages</string>
1095+
<string name="vpn_lockdown">Lockdown</string>
1096+
10941097
</resources>

0 commit comments

Comments
 (0)