1 /*
2  * Copyright (C) 2015 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.android.settings.vpn2;
18 
19 import android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.app.DialogFragment;
22 import android.app.Fragment;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.pm.PackageInfo;
26 import android.net.IConnectivityManager;
27 import android.os.Bundle;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 import android.util.Log;
33 
34 import com.android.internal.net.VpnConfig;
35 import com.android.settings.R;
36 
37 /**
38  * Fragment wrapper around an {@link AppDialog}.
39  */
40 public class AppDialogFragment extends DialogFragment implements AppDialog.Listener {
41     private static final String TAG_APP_DIALOG = "vpnappdialog";
42     private static final String TAG = "AppDialogFragment";
43 
44     private static final String ARG_MANAGING = "managing";
45     private static final String ARG_LABEL = "label";
46     private static final String ARG_CONNECTED = "connected";
47     private static final String ARG_PACKAGE = "package";
48 
49     private PackageInfo mPackageInfo;
50     private Listener mListener;
51 
52     private UserManager mUserManager;
53     private final IConnectivityManager mService = IConnectivityManager.Stub.asInterface(
54             ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
55 
56     public interface Listener {
onForget()57         public void onForget();
onCancel()58         public void onCancel();
59     }
60 
show(Fragment parent, PackageInfo packageInfo, String label, boolean managing, boolean connected)61     public static void show(Fragment parent, PackageInfo packageInfo, String label,
62             boolean managing, boolean connected) {
63         show(parent, null, packageInfo, label, managing, connected);
64     }
65 
show(Fragment parent, Listener listener, PackageInfo packageInfo, String label, boolean managing, boolean connected)66     public static void show(Fragment parent, Listener listener, PackageInfo packageInfo,
67             String label, boolean managing, boolean connected) {
68         if (!parent.isAdded())
69             return;
70 
71         Bundle args = new Bundle();
72         args.putParcelable(ARG_PACKAGE, packageInfo);
73         args.putString(ARG_LABEL, label);
74         args.putBoolean(ARG_MANAGING, managing);
75         args.putBoolean(ARG_CONNECTED, connected);
76 
77         final AppDialogFragment frag = new AppDialogFragment();
78         frag.mListener = listener;
79         frag.setArguments(args);
80         frag.setTargetFragment(parent, 0);
81         frag.show(parent.getFragmentManager(), TAG_APP_DIALOG);
82     }
83 
84     @Override
onCreate(Bundle savedInstanceState)85     public void onCreate(Bundle savedInstanceState) {
86         super.onCreate(savedInstanceState);
87         mUserManager = UserManager.get(getContext());
88     }
89 
90     @Override
onCreateDialog(Bundle savedInstanceState)91     public Dialog onCreateDialog(Bundle savedInstanceState) {
92         Bundle args = getArguments();
93         final String label = args.getString(ARG_LABEL);
94         boolean managing = args.getBoolean(ARG_MANAGING);
95         boolean connected = args.getBoolean(ARG_CONNECTED);
96         mPackageInfo = (PackageInfo) args.getParcelable(ARG_PACKAGE);
97 
98         if (managing) {
99             return new AppDialog(getActivity(), this, mPackageInfo, label);
100         } else {
101             // Build an AlertDialog with an option to disconnect.
102             AlertDialog.Builder dlog = new AlertDialog.Builder(getActivity())
103                     .setTitle(label)
104                     .setMessage(getActivity().getString(R.string.vpn_disconnect_confirm))
105                     .setNegativeButton(getActivity().getString(R.string.vpn_cancel), null);
106 
107             if (connected && !isUiRestricted()) {
108                 dlog.setPositiveButton(getActivity().getString(R.string.vpn_disconnect),
109                         new DialogInterface.OnClickListener() {
110                             @Override
111                             public void onClick(DialogInterface dialog, int which) {
112                                 onDisconnect(dialog);
113                             }
114                         });
115             }
116             return dlog.create();
117         }
118     }
119 
120     @Override
onCancel(DialogInterface dialog)121     public void onCancel(DialogInterface dialog) {
122         dismiss();
123         if (mListener != null) {
124             mListener.onCancel();
125         }
126         super.onCancel(dialog);
127     }
128 
129     @Override
onForget(final DialogInterface dialog)130     public void onForget(final DialogInterface dialog) {
131         if (isUiRestricted()) {
132             return;
133         }
134         final int userId = getUserId();
135         try {
136             mService.setVpnPackageAuthorization(mPackageInfo.packageName, userId, false);
137             onDisconnect(dialog);
138         } catch (RemoteException e) {
139             Log.e(TAG, "Failed to forget authorization of " + mPackageInfo.packageName +
140                     " for user " + userId, e);
141         }
142 
143         if (mListener != null) {
144             mListener.onForget();
145         }
146     }
147 
onDisconnect(final DialogInterface dialog)148     private void onDisconnect(final DialogInterface dialog) {
149         if (isUiRestricted()) {
150             return;
151         }
152         final int userId = getUserId();
153         try {
154             if (mPackageInfo.packageName.equals(getConnectedPackage(mService, userId))) {
155                 mService.setAlwaysOnVpnPackage(userId, null, /* lockdownEnabled */ false);
156                 mService.prepareVpn(mPackageInfo.packageName, VpnConfig.LEGACY_VPN, userId);
157             }
158         } catch (RemoteException e) {
159             Log.e(TAG, "Failed to disconnect package " + mPackageInfo.packageName +
160                     " for user " + userId, e);
161         }
162     }
163 
isUiRestricted()164     private boolean isUiRestricted() {
165         final UserHandle userHandle = UserHandle.of(getUserId());
166         return mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, userHandle);
167     }
168 
getUserId()169     private int getUserId() {
170         return UserHandle.getUserId(mPackageInfo.applicationInfo.uid);
171     }
172 
getConnectedPackage(IConnectivityManager service, final int userId)173     private static String getConnectedPackage(IConnectivityManager service, final int userId)
174             throws RemoteException {
175         final VpnConfig config = service.getVpnConfig(userId);
176         return config != null ? config.user : null;
177     }
178 }
179