Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20378768 authored by Victor Chang's avatar Victor Chang Committed by Android (Google) Code Review
Browse files

Merge "Remove VPN Overflow menu" into nyc-dev

parents 2c313f0e 6005aefd
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -132,6 +132,9 @@
            <CheckBox style="@style/vpn_value" android:id="@+id/save_login"
                    android:singleLine="false"
                    android:text="@string/vpn_save_login"/>
            <CheckBox style="@style/vpn_value" android:id="@+id/always_on_vpn"
                android:singleLine="false"
                android:text="@string/vpn_menu_lockdown"/>
        </LinearLayout>
    </LinearLayout>
</ScrollView>
+0 −4
Original line number Diff line number Diff line
@@ -20,8 +20,4 @@
        android:title="@string/vpn_create"
        android:icon="@drawable/ic_menu_add_white"
        android:showAsAction="always" />
    <item
        android:id="@+id/vpn_lockdown"
        android:title="@string/vpn_menu_lockdown"
        android:showAsAction="never" />
</menu>
+37 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.SystemProperties;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.Editable;
@@ -29,6 +30,7 @@ import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.Spinner;
import android.widget.TextView;

@@ -45,7 +47,8 @@ import java.net.InetAddress;
 * {@see AppDialog}
 */
class ConfigDialog extends AlertDialog implements TextWatcher,
        View.OnClickListener, AdapterView.OnItemSelectedListener {
        View.OnClickListener, AdapterView.OnItemSelectedListener,
        CompoundButton.OnCheckedChangeListener {
    private final KeyStore mKeyStore = KeyStore.getInstance();
    private final DialogInterface.OnClickListener mListener;
    private final VpnProfile mProfile;
@@ -72,6 +75,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
    private Spinner mIpsecServerCert;
    private CheckBox mSaveLogin;
    private CheckBox mShowOptions;
    private CheckBox mAlwaysOnVpn;

    ConfigDialog(Context context, DialogInterface.OnClickListener listener,
            VpnProfile profile, boolean editing, boolean exists) {
@@ -108,6 +112,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
        mIpsecServerCert = (Spinner) mView.findViewById(R.id.ipsec_server_cert);
        mSaveLogin = (CheckBox) mView.findViewById(R.id.save_login);
        mShowOptions = (CheckBox) mView.findViewById(R.id.show_options);
        mAlwaysOnVpn = (CheckBox) mView.findViewById(R.id.always_on_vpn);

        // Second, copy values from the profile.
        mName.setText(mProfile.name);
@@ -124,13 +129,21 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
        mL2tpSecret.setText(mProfile.l2tpSecret);
        mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
        mIpsecSecret.setText(mProfile.ipsecSecret);
        loadCertificates(mIpsecUserCert, Credentials.USER_PRIVATE_KEY,
                0, mProfile.ipsecUserCert);
        loadCertificates(mIpsecUserCert, Credentials.USER_PRIVATE_KEY, 0, mProfile.ipsecUserCert);
        loadCertificates(mIpsecCaCert, Credentials.CA_CERTIFICATE,
                R.string.vpn_no_ca_cert, mProfile.ipsecCaCert);
        loadCertificates(mIpsecServerCert, Credentials.USER_CERTIFICATE,
                R.string.vpn_no_server_cert, mProfile.ipsecServerCert);
        mSaveLogin.setChecked(mProfile.saveLogin);
        mAlwaysOnVpn.setChecked(mProfile.key.equals(VpnUtils.getLockdownVpn()));
        mAlwaysOnVpn.setOnCheckedChangeListener(this);
        // Update SaveLogin checkbox after Always-on checkbox is updated
        updateSaveLoginStatus();

        // Hide lockdown VPN on devices that require IMS authentication
        if (SystemProperties.getBoolean("persist.radio.imsregrequired", false)) {
            mAlwaysOnVpn.setVisibility(View.GONE);
        }

        // Third, add listeners to required fields.
        mName.addTextChangedListener(this);
@@ -242,6 +255,27 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
    public void onNothingSelected(AdapterView<?> parent) {
    }

    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
        if (compoundButton == mAlwaysOnVpn) {
            updateSaveLoginStatus();
        }
    }

    public boolean isVpnAlwaysOn() {
        return mAlwaysOnVpn.isChecked();
    }

    private void updateSaveLoginStatus() {
        if (mAlwaysOnVpn.isChecked()) {
            mSaveLogin.setChecked(true);
            mSaveLogin.setEnabled(false);
        } else {
            mSaveLogin.setChecked(mProfile.saveLogin);
            mSaveLogin.setEnabled(true);
        }
    }

    private void showAdvancedOptions() {
        mView.findViewById(R.id.options).setVisibility(View.VISIBLE);
        mShowOptions.setVisibility(View.GONE);
+29 −10
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.os.Bundle;
import android.os.RemoteException;
@@ -112,8 +113,10 @@ public class ConfigDialogFragment extends DialogFragment implements
            // Flush out old version of profile
            disconnect(profile);

            updateLockdownVpn(dialog.isVpnAlwaysOn(), profile);

            // If we are not editing, connect!
            if (!dialog.isEditing()) {
            if (!dialog.isEditing() && !VpnUtils.isVpnLockdown(profile.key)) {
                try {
                    connect(profile);
                } catch (RemoteException e) {
@@ -128,15 +131,7 @@ public class ConfigDialogFragment extends DialogFragment implements
            KeyStore keyStore = KeyStore.getInstance();
            keyStore.delete(Credentials.VPN + profile.key, KeyStore.UID_SELF);

            // If this was the current lockdown VPN, clear it.
            if (Arrays.equals(profile.key.getBytes(), keyStore.get(Credentials.LOCKDOWN_VPN))) {
                keyStore.delete(Credentials.LOCKDOWN_VPN);
                try {
                    mService.updateLockdownVpn();
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to clear lockdown VPN configuration");
                }
            }
            updateLockdownVpn(false, profile);
        }
        dismiss();
    }
@@ -147,6 +142,30 @@ public class ConfigDialogFragment extends DialogFragment implements
        super.onCancel(dialog);
    }

    private void updateLockdownVpn(boolean isVpnAlwaysOn, VpnProfile profile) {
        // Save lockdown vpn
        if (isVpnAlwaysOn) {
            // Show toast if vpn profile is not valid
            if (!profile.isValidLockdownProfile()) {
                Toast.makeText(getContext(), R.string.vpn_lockdown_config_error,
                        Toast.LENGTH_LONG).show();
                return;
            }

            // Update only if lockdown vpn has been changed
            if (!VpnUtils.isVpnLockdown(profile.key)) {
                final ConnectivityManager conn = ConnectivityManager.from(getActivity());
                conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
                VpnUtils.setLockdownVpn(getContext(), profile.key);
            }
        } else {
            // update only if lockdown vpn has been changed
            if (VpnUtils.isVpnLockdown(profile.key)) {
                VpnUtils.clearLockdownVpn(getContext());
            }
        }
    }

    private void connect(VpnProfile profile) throws RemoteException {
        try {
            mService.startLegacyVpn(profile);
+0 −169
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.settings.vpn2;

import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.security.Credentials;
import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.settings.R;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Dialog to configure always-on VPN.
 */
public class LockdownConfigFragment extends DialogFragment {
    private List<VpnProfile> mProfiles;
    private List<AppVpnInfo> mApps;
    private List<CharSequence> mTitles;
    private int mCurrentIndex;

    private static final String TAG_LOCKDOWN = "lockdown";
    private static final String LOG_TAG = "LockdownConfigFragment";

    private static class TitleAdapter extends ArrayAdapter<CharSequence> {
        public TitleAdapter(Context context, List<CharSequence> objects) {
            super(context, com.android.internal.R.layout.select_dialog_singlechoice_material,
                    android.R.id.text1, objects);
        }
    }

    public static void show(VpnSettings parent) {
        if (!parent.isAdded()) return;

        final LockdownConfigFragment dialog = new LockdownConfigFragment();
        dialog.show(parent.getFragmentManager(), TAG_LOCKDOWN);
    }

    private void initProfiles(KeyStore keyStore, Resources res) {
        final ConnectivityManager cm = ConnectivityManager.from(getActivity());
        final String lockdownKey = VpnUtils.getLockdownVpn();
        final String alwaysOnPackage =  cm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId());

        // Legacy VPN has a separate always-on mechanism which takes over the whole device, so
        // this option is restricted to the primary user only.
        if (UserManager.get(getContext()).isPrimaryUser()) {
            mProfiles = VpnSettings.loadVpnProfiles(keyStore, VpnProfile.TYPE_PPTP);
        } else {
            mProfiles = Collections.<VpnProfile>emptyList();
        }
        mApps = VpnSettings.getVpnApps(getActivity(), /* includeProfiles */ false);

        mTitles = new ArrayList<>(1 + mProfiles.size() + mApps.size());
        mTitles.add(res.getText(R.string.vpn_lockdown_none));
        mCurrentIndex = 0;

        // Add true lockdown VPNs to the list first.
        for (VpnProfile profile : mProfiles) {
            if (TextUtils.equals(profile.key, lockdownKey)) {
                mCurrentIndex = mTitles.size();
            }
            mTitles.add(profile.name);
        }

        // Add third-party app VPNs (VpnService) for the current profile to set as always-on.
        for (AppVpnInfo app : mApps) {
            try {
                String appName = VpnConfig.getVpnLabel(getContext(), app.packageName).toString();
                if (TextUtils.equals(app.packageName, alwaysOnPackage)) {
                    mCurrentIndex = mTitles.size();
                }
                mTitles.add(appName);
            } catch (PackageManager.NameNotFoundException pkgNotFound) {
                Log.w(LOG_TAG, "VPN package not found: '" + app.packageName + "'", pkgNotFound);
            }
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final Context context = getActivity();
        final KeyStore keyStore = KeyStore.getInstance();

        initProfiles(keyStore, context.getResources());

        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());

        builder.setTitle(R.string.vpn_menu_lockdown);

        final View view = dialogInflater.inflate(R.layout.vpn_lockdown_editor, null, false);
        final ListView listView = (ListView) view.findViewById(android.R.id.list);
        listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        listView.setAdapter(new TitleAdapter(context, mTitles));
        listView.setItemChecked(mCurrentIndex, true);
        builder.setView(view);

        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                final int newIndex = listView.getCheckedItemPosition();
                if (mCurrentIndex == newIndex) return;

                final ConnectivityManager conn = ConnectivityManager.from(getActivity());

                if (newIndex == 0) {
                    keyStore.delete(Credentials.LOCKDOWN_VPN);
                    conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
                } else if (newIndex <= mProfiles.size()) {
                    final VpnProfile profile = mProfiles.get(newIndex - 1);
                    if (!profile.isValidLockdownProfile()) {
                        Toast.makeText(context, R.string.vpn_lockdown_config_error,
                                Toast.LENGTH_LONG).show();
                        return;
                    }
                    conn.setAlwaysOnVpnPackageForUser(UserHandle.myUserId(), null);
                    keyStore.put(Credentials.LOCKDOWN_VPN, profile.key.getBytes(),
                            KeyStore.UID_SELF, /* flags */ 0);
                } else {
                    keyStore.delete(Credentials.LOCKDOWN_VPN);

                    final AppVpnInfo appVpn = mApps.get(newIndex - 1 - mProfiles.size());
                    conn.setAlwaysOnVpnPackageForUser(appVpn.userId, appVpn.packageName);
                }

                // kick profiles since we changed them
                conn.updateLockdownVpn();
            }
        });

        return builder.create();
    }
}
Loading