16
16
17
17
package com .afwsamples .testdpc .policy .networking ;
18
18
19
+ import static com .afwsamples .testdpc .common .Util .isAtLeastQ ;
20
+
19
21
import android .annotation .TargetApi ;
20
22
import android .app .admin .DevicePolicyManager ;
21
23
import android .content .ComponentName ;
27
29
import android .os .Build ;
28
30
import android .os .Bundle ;
29
31
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 ;
30
38
31
39
import com .afwsamples .testdpc .DeviceAdminReceiver ;
32
40
import com .afwsamples .testdpc .R ;
33
41
import com .afwsamples .testdpc .common .SelectAppFragment ;
34
42
35
43
import java .util .ArrayList ;
44
+ import java .util .Arrays ;
36
45
import java .util .HashSet ;
37
46
import java .util .List ;
38
47
import java .util .Set ;
48
+ import java .util .stream .Collectors ;
39
49
40
50
/**
41
51
* This fragment provides a setting for always-on VPN apps.
49
59
@ TargetApi (Build .VERSION_CODES .N )
50
60
public class AlwaysOnVpnFragment extends SelectAppFragment {
51
61
private static final String TAG = "AlwaysOnVpnFragment" ;
62
+
52
63
private DevicePolicyManager mDpm ;
53
64
65
+ private CheckBox mLockdown ;
66
+ private EditText mExemptedPackages ;
67
+
54
68
private static final Intent VPN_INTENT = new Intent (VpnService .SERVICE_INTERFACE );
69
+ private ComponentName mWho ;
55
70
56
71
@ Override
57
72
public void onCreate (Bundle savedInstanceState ) {
58
73
super .onCreate (savedInstanceState );
59
74
mDpm = (DevicePolicyManager ) getContext ().getSystemService (Context .DEVICE_POLICY_SERVICE );
75
+ mWho = DeviceAdminReceiver .getComponentName (getActivity ());
60
76
}
61
77
62
78
@ Override
@@ -65,6 +81,23 @@ public void onResume() {
65
81
getActivity ().getActionBar ().setTitle (R .string .set_always_on_vpn );
66
82
}
67
83
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
+
68
101
@ Override
69
102
protected List <String > createAppList () {
70
103
Set <String > apps = new HashSet <>();
@@ -79,16 +112,54 @@ protected List<String> createAppList() {
79
112
return new ArrayList <>(apps );
80
113
}
81
114
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
+
82
131
@ Override
83
132
protected void setSelectedPackage (String pkg ) {
84
133
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 ();
88
146
Log .e (TAG , "setAlwaysOnVpnPackage:" , e );
89
147
}
90
148
}
91
149
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
+
92
163
@ Override
93
164
protected void clearSelectedPackage () {
94
165
setSelectedPackage (null );
0 commit comments