Home | History | Annotate | Download | only in vpn2
      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 java.util.Arrays;
     20 
     21 import android.app.Dialog;
     22 import android.app.DialogFragment;
     23 import android.content.Context;
     24 import android.content.DialogInterface;
     25 import android.net.ConnectivityManager;
     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.security.Credentials;
     32 import android.security.KeyStore;
     33 import android.util.Log;
     34 import android.widget.Toast;
     35 
     36 import com.android.internal.net.LegacyVpnInfo;
     37 import com.android.internal.net.VpnConfig;
     38 import com.android.internal.net.VpnProfile;
     39 import com.android.settings.R;
     40 
     41 /**
     42  * Fragment wrapper around a {@link ConfigDialog}.
     43  */
     44 public class ConfigDialogFragment extends DialogFragment implements
     45         DialogInterface.OnClickListener {
     46     private static final String TAG_CONFIG_DIALOG = "vpnconfigdialog";
     47     private static final String TAG = "ConfigDialogFragment";
     48 
     49     private static final String ARG_PROFILE = "profile";
     50     private static final String ARG_EDITING = "editing";
     51     private static final String ARG_EXISTS = "exists";
     52 
     53     private final IConnectivityManager mService = IConnectivityManager.Stub.asInterface(
     54             ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
     55 
     56     private boolean mUnlocking = false;
     57 
     58     public static void show(VpnSettings parent, VpnProfile profile, boolean edit, boolean exists) {
     59         if (!parent.isAdded()) return;
     60 
     61         Bundle args = new Bundle();
     62         args.putParcelable(ARG_PROFILE, profile);
     63         args.putBoolean(ARG_EDITING, edit);
     64         args.putBoolean(ARG_EXISTS, exists);
     65 
     66         final ConfigDialogFragment frag = new ConfigDialogFragment();
     67         frag.setArguments(args);
     68         frag.setTargetFragment(parent, 0);
     69         frag.show(parent.getFragmentManager(), TAG_CONFIG_DIALOG);
     70     }
     71 
     72     @Override
     73     public void onResume() {
     74         super.onResume();
     75 
     76         // Check KeyStore here, so others do not need to deal with it.
     77         if (!KeyStore.getInstance().isUnlocked()) {
     78             if (!mUnlocking) {
     79                 // Let us unlock KeyStore. See you later!
     80                 Credentials.getInstance().unlock(getActivity());
     81             } else {
     82                 // We already tried, but it is still not working!
     83                 dismiss();
     84             }
     85             mUnlocking = !mUnlocking;
     86             return;
     87         }
     88 
     89         // Now KeyStore is always unlocked. Reset the flag.
     90         mUnlocking = false;
     91     }
     92 
     93     @Override
     94     public Dialog onCreateDialog(Bundle savedInstanceState) {
     95         Bundle args = getArguments();
     96         VpnProfile profile = (VpnProfile) args.getParcelable(ARG_PROFILE);
     97         boolean editing = args.getBoolean(ARG_EDITING);
     98         boolean exists = args.getBoolean(ARG_EXISTS);
     99 
    100         return new ConfigDialog(getActivity(), this, profile, editing, exists);
    101     }
    102 
    103     @Override
    104     public void onClick(DialogInterface dialogInterface, int button) {
    105         ConfigDialog dialog = (ConfigDialog) getDialog();
    106         VpnProfile profile = dialog.getProfile();
    107 
    108         if (button == DialogInterface.BUTTON_POSITIVE) {
    109             // Update KeyStore entry
    110             KeyStore.getInstance().put(Credentials.VPN + profile.key, profile.encode(),
    111                     KeyStore.UID_SELF, /* flags */ 0);
    112 
    113             // Flush out old version of profile
    114             disconnect(profile);
    115 
    116             updateLockdownVpn(dialog.isVpnAlwaysOn(), profile);
    117 
    118             // If we are not editing, connect!
    119             if (!dialog.isEditing() && !VpnUtils.isVpnLockdown(profile.key)) {
    120                 try {
    121                     connect(profile);
    122                 } catch (RemoteException e) {
    123                     Log.e(TAG, "Failed to connect", e);
    124                 }
    125             }
    126         } else if (button == DialogInterface.BUTTON_NEUTRAL) {
    127             // Disable profile if connected
    128             disconnect(profile);
    129 
    130             // Delete from KeyStore
    131             KeyStore keyStore = KeyStore.getInstance();
    132             keyStore.delete(Credentials.VPN + profile.key, KeyStore.UID_SELF);
    133 
    134             updateLockdownVpn(false, profile);
    135         }
    136         dismiss();
    137     }
    138 
    139     @Override
    140     public void onCancel(DialogInterface dialog) {
    141         dismiss();
    142         super.onCancel(dialog);
    143     }
    144 
    145     private void updateLockdownVpn(boolean isVpnAlwaysOn, VpnProfile profile) {
    146         // Save lockdown vpn
    147         if (isVpnAlwaysOn) {
    148             // Show toast if vpn profile is not valid
    149             if (!profile.isValidLockdownProfile()) {
    150                 Toast.makeText(getContext(), R.string.vpn_lockdown_config_error,
    151                         Toast.LENGTH_LONG).show();
    152                 return;
    153             }
    154 
    155             final ConnectivityManager conn = ConnectivityManager.from(getActivity());
    156             conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null,
    157                     /* lockdownEnabled */ false);
    158             VpnUtils.setLockdownVpn(getContext(), profile.key);
    159         } else {
    160             // update only if lockdown vpn has been changed
    161             if (VpnUtils.isVpnLockdown(profile.key)) {
    162                 VpnUtils.clearLockdownVpn(getContext());
    163             }
    164         }
    165     }
    166 
    167     private void connect(VpnProfile profile) throws RemoteException {
    168         try {
    169             mService.startLegacyVpn(profile);
    170         } catch (IllegalStateException e) {
    171             Toast.makeText(getActivity(), R.string.vpn_no_network, Toast.LENGTH_LONG).show();
    172         }
    173     }
    174 
    175     private void disconnect(VpnProfile profile) {
    176         try {
    177             LegacyVpnInfo connected = mService.getLegacyVpnInfo(UserHandle.myUserId());
    178             if (connected != null && profile.key.equals(connected.key)) {
    179                 VpnUtils.clearLockdownVpn(getContext());
    180                 mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN,
    181                         UserHandle.myUserId());
    182             }
    183         } catch (RemoteException e) {
    184             Log.e(TAG, "Failed to disconnect", e);
    185         }
    186     }
    187 }
    188