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

Commit 1ddccd07 authored by Hung-ying Tyan's avatar Hung-ying Tyan
Browse files

Fix dialog handling.

* Changes
  + VpnSettings:
    + Add reconnect dialog to showDialog() framework for handling screen
      rotation.
    + Dismiss other alert dialogs in onDestroy()
    + Remove onPrepareDialog() from VpnSettings.
    + Remove updateConnectDialog() from VpnProfileActor.
    + Add authentication error dialog.
    + Add unknown server dialog.
  + SecuritySettings:
    + Make cstor dialogs cancelable.
    + Add cancelable listener.
  Patch Set 6:
  + VpnSettings:
    + Disable preferences when connecting/disconnecting.
    + Fix state broadcast when binding a VpnService goes wrong.
parent a5cead2c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1850,6 +1850,8 @@ found in the list of installed applications.</string>
    <string name="vpn_confirm_add_profile_cancellation">Are you sure you don\'t want to create this profile?</string>
    <string name="vpn_confirm_edit_profile_cancellation">Are you sure you want to discard the changes made to this profile?</string>
    <string name="vpn_confirm_reconnect">Unable to connect to the network. Do you want to try again?</string>
    <string name="vpn_unknown_server_dialog_msg">Server name cannot be resolved. Do you want to check your server name setting?</string>
    <string name="vpn_auth_error_dialog_msg">The username or password you entered is incorrect. Do you want to try again?</string>

    <!-- VPN type selection activity title -->
    <string name="vpn_type_title">Add VPN</string>
@@ -1870,8 +1872,6 @@ found in the list of installed applications.</string>
    <!-- Preference summary text when VPN is not connected -->
    <string name="vpn_connect_hint">Connect to network</string>

    <string name="vpn_default_profile_name">nowhere</string>

    <!-- Name of a VPN profile -->
    <string name="vpn_name">VPN name</string>
    <string name="vpn_a_name">a VPN name</string>
+16 −11
Original line number Diff line number Diff line
@@ -442,8 +442,9 @@ public class SecuritySettings extends PreferenceActivity implements
        }
    }

    private class CstorHelper implements
            DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
    private class CstorHelper implements DialogInterface.OnClickListener,
            DialogInterface.OnDismissListener,
            DialogInterface.OnCancelListener {
        private Keystore mKeystore = Keystore.getInstance();
        private View mView;
        private int mDialogId;
@@ -523,14 +524,18 @@ public class SecuritySettings extends PreferenceActivity implements
                    .show();
        }

        public void onClick(DialogInterface dialog, int which) {
            if (which == DialogInterface.BUTTON_NEGATIVE) {
        public void onCancel(DialogInterface dialog) {
            if (mCstorAddCredentialHelper != null) {
                // release the object here so that it doesn't get triggerred in
                // onDismiss()
                mCstorAddCredentialHelper = null;
                finish();
            }
        }

        public void onClick(DialogInterface dialog, int which) {
            if (which == DialogInterface.BUTTON_NEGATIVE) {
                onCancel(dialog);
                return;
            }

@@ -797,7 +802,7 @@ public class SecuritySettings extends PreferenceActivity implements
                    .setTitle(R.string.cstor_access_dialog_title)
                    .setPositiveButton(android.R.string.ok, this)
                    .setNegativeButton(android.R.string.cancel, this)
                    .setCancelable(false)
                    .setOnCancelListener(this)
                    .create();
            d.setOnDismissListener(this);
            return d;
@@ -837,7 +842,7 @@ public class SecuritySettings extends PreferenceActivity implements
                    .setTitle(R.string.cstor_set_passwd_dialog_title)
                    .setPositiveButton(android.R.string.ok, this)
                    .setNegativeButton(android.R.string.cancel, this)
                    .setCancelable(false)
                    .setOnCancelListener(this)
                    .create();
            d.setOnDismissListener(this);
            return d;
@@ -872,7 +877,7 @@ public class SecuritySettings extends PreferenceActivity implements
                    .setTitle(R.string.cstor_name_credential_dialog_title)
                    .setPositiveButton(android.R.string.ok, this)
                    .setNegativeButton(android.R.string.cancel, this)
                    .setCancelable(false)
                    .setOnCancelListener(this)
                    .create();
            d.setOnDismissListener(this);
            return d;
+30 −30
Original line number Diff line number Diff line
@@ -99,14 +99,18 @@ public class AuthenticationActor implements VpnProfileActor {

    //@Override
    public View createConnectView() {
        return View.inflate(mContext, R.layout.vpn_connect_dialog_view, null);
    }
        View v = View.inflate(mContext, R.layout.vpn_connect_dialog_view, null);
        TextView usernameView = (TextView) v.findViewById(R.id.username_value);
        TextView passwordView = (TextView) v.findViewById(R.id.password_value);
        CheckBox saveUsername = (CheckBox) v.findViewById(R.id.save_username);

    //@Override
    public void updateConnectView(Dialog d) {
        String username = mProfile.getSavedUsername();
        if (username == null) username = "";
        updateConnectView(d, username, "", !TextUtils.isEmpty(username));
        if (!TextUtils.isEmpty(username)) {
            usernameView.setText(username);
            saveUsername.setChecked(true);
            passwordView.requestFocus();
        }
        return v;
    }

    protected Context getContext() {
@@ -118,22 +122,20 @@ public class AuthenticationActor implements VpnProfileActor {
        ServiceConnection c = new ServiceConnection() {
            public void onServiceConnected(ComponentName className,
                    IBinder service) {
                boolean success = false;
                try {
                    success = IVpnService.Stub.asInterface(service)
                    boolean success = IVpnService.Stub.asInterface(service)
                            .connect(mProfile, username, password);
                } catch (Throwable e) {
                    Log.e(TAG, "connect()", e);
                    checkStatus();
                } finally {
                    mContext.unbindService(this);

                    if (!success) {
                        Log.d(TAG, "~~~~~~ connect() failed!");
                        broadcastConnectivity(VpnState.IDLE);
                    } else {
                        Log.d(TAG, "~~~~~~ connect() succeeded!");
                    }
                } catch (Throwable e) {
                    Log.e(TAG, "connect()", e);
                    broadcastConnectivity(VpnState.IDLE,
                            VpnManager.VPN_ERROR_CONNECTION_FAILED);
                } finally {
                    mContext.unbindService(this);
                }
            }

@@ -141,7 +143,10 @@ public class AuthenticationActor implements VpnProfileActor {
                checkStatus();
            }
        };
        if (!bindService(c)) broadcastConnectivity(VpnState.IDLE);
        if (!bindService(c)) {
            broadcastConnectivity(VpnState.IDLE,
                    VpnManager.VPN_ERROR_CONNECTION_FAILED);
        }
    }

    //@Override
@@ -156,7 +161,6 @@ public class AuthenticationActor implements VpnProfileActor {
                    checkStatus();
                } finally {
                    mContext.unbindService(this);
                    broadcastConnectivity(VpnState.IDLE);
                }
            }

@@ -164,7 +168,9 @@ public class AuthenticationActor implements VpnProfileActor {
                checkStatus();
            }
        };
        bindService(c);
        if (!bindService(c)) {
            checkStatus();
        }
    }

    //@Override
@@ -174,8 +180,9 @@ public class AuthenticationActor implements VpnProfileActor {
                    IBinder service) {
                try {
                    IVpnService.Stub.asInterface(service).checkStatus(mProfile);
                } catch (Throwable e) {
                } catch (RemoteException e) {
                    Log.e(TAG, "checkStatus()", e);
                    broadcastConnectivity(VpnState.IDLE);
                } finally {
                    notify();
                }
@@ -196,21 +203,14 @@ public class AuthenticationActor implements VpnProfileActor {
        return mVpnManager.bindVpnService(c);
    }

    private void updateConnectView(Dialog d, String username,
            String password, boolean toSaveUsername) {
        TextView usernameView = (TextView) d.findViewById(R.id.username_value);
        TextView passwordView = (TextView) d.findViewById(R.id.password_value);
        CheckBox saveUsername = (CheckBox) d.findViewById(R.id.save_username);
        usernameView.setText(username);
        passwordView.setText(password);
        saveUsername.setChecked(toSaveUsername);
        if (toSaveUsername) passwordView.requestFocus();
    }

    private void broadcastConnectivity(VpnState s) {
        mVpnManager.broadcastConnectivity(mProfile.getName(), s);
    }

    private void broadcastConnectivity(VpnState s, int errorCode) {
        mVpnManager.broadcastConnectivity(mProfile.getName(), s, errorCode);
    }

    private void wait(Object o, int ms) {
        synchronized (o) {
            try {
+0 −6
Original line number Diff line number Diff line
@@ -37,12 +37,6 @@ public interface VpnProfileActor {
     */
    View createConnectView();

    /**
     * Updates the view in the connect dialog.
     * @param dialog the recycled connect dialog.
     */
    void updateConnectView(Dialog dialog);

    /**
     * Validates the inputs in the dialog.
     * @param dialog the connect dialog
+118 −62
Original line number Diff line number Diff line
@@ -99,7 +99,12 @@ public class VpnSettings extends PreferenceActivity implements
    private static final int CONNECT_BUTTON = DialogInterface.BUTTON1;
    private static final int OK_BUTTON = DialogInterface.BUTTON1;

    private static final int DIALOG_CONNECT = 0;
    private static final int DIALOG_CONNECT = 1;
    private static final int DIALOG_RECONNECT = 2;
    private static final int DIALOG_AUTH_ERROR = 3;
    private static final int DIALOG_UNKNOWN_SERVER = 4;

    private static final int NO_ERROR = 0;

    private PreferenceScreen mAddVpn;
    private PreferenceCategory mVpnListContainer;
@@ -115,7 +120,6 @@ public class VpnSettings extends PreferenceActivity implements

    // actor engaged in connecting
    private VpnProfileActor mConnectingActor;
    private boolean mStateSaved = false;

    // states saved for unlocking keystore
    private Runnable mUnlockAction;
@@ -125,7 +129,9 @@ public class VpnSettings extends PreferenceActivity implements
    private ConnectivityReceiver mConnectivityReceiver =
            new ConnectivityReceiver();

    private boolean mConnectingError;
    private int mConnectingErrorCode = NO_ERROR;

    private Dialog mShowingDialog;

    private StatusChecker mStatusChecker = new StatusChecker();

@@ -156,11 +162,10 @@ public class VpnSettings extends PreferenceActivity implements
        String profileName = (savedInstanceState == null)
                ? null
                : savedInstanceState.getString(STATE_ACTIVE_ACTOR);
        mStateSaved = !TextUtils.isEmpty(profileName);
        retrieveVpnListFromStorage();
        if (mStateSaved) {
            mConnectingActor =
                    getActor(mVpnPreferenceMap.get(profileName).mProfile);
        if (!TextUtils.isEmpty(profileName)) {
            mActiveProfile = mVpnPreferenceMap.get(profileName).mProfile;
            mConnectingActor = getActor(mActiveProfile);
        } else {
            checkVpnConnectionStatusInBackground();
        }
@@ -188,6 +193,7 @@ public class VpnSettings extends PreferenceActivity implements
    protected synchronized void onSaveInstanceState(Bundle outState) {
        if (mConnectingActor == null) return;

        Log.d(TAG, "   ~~~~~    save connecting actor");
        outState.putString(STATE_ACTIVE_ACTOR,
                mConnectingActor.getProfile().getName());
    }
@@ -197,6 +203,9 @@ public class VpnSettings extends PreferenceActivity implements
        super.onDestroy();
        unregisterForContextMenu(getListView());
        mVpnManager.unregisterConnectivityReceiver(mConnectivityReceiver);
        if ((mShowingDialog != null) && mShowingDialog.isShowing()) {
            mShowingDialog.dismiss();
        }
    }

    @Override
@@ -205,39 +214,76 @@ public class VpnSettings extends PreferenceActivity implements
            case DIALOG_CONNECT:
                return createConnectDialog();

            case DIALOG_RECONNECT:
                return createReconnectDialogBuilder().create();

            case DIALOG_AUTH_ERROR:
                return createAuthErrorDialog();

            case DIALOG_UNKNOWN_SERVER:
                return createUnknownServerDialog();

            default:
                return null;
                return super.onCreateDialog(id);
        }
    }

    private Dialog createConnectDialog() {
        if (mConnectingActor == null) {
            Log.e(TAG, "no connecting actor to create the dialog");
            return null;
        }
        String name = (mConnectingActor == null)
                ? getString(R.string.vpn_default_profile_name)
                : mConnectingActor.getProfile().getName();
        Dialog d = new AlertDialog.Builder(this)
        return new AlertDialog.Builder(this)
                .setView(mConnectingActor.createConnectView())
                .setTitle(String.format(getString(R.string.vpn_connect_to),
                        name))
                        mConnectingActor.getProfile().getName()))
                .setPositiveButton(getString(R.string.vpn_connect_button),
                        this)
                .setNegativeButton(getString(android.R.string.cancel),
                        this)
                .create();
        return d;
    }

    @Override
    protected void onPrepareDialog (int id, Dialog dialog) {
        if (mStateSaved) {
            mStateSaved = false;
            super.onPrepareDialog(id, dialog);
        } else if (mConnectingActor != null) {
            mConnectingActor.updateConnectView(dialog);
    private AlertDialog.Builder createReconnectDialogBuilder() {
        return new AlertDialog.Builder(this)
                .setTitle(android.R.string.dialog_alert_title)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .setMessage(R.string.vpn_confirm_reconnect)
                .setPositiveButton(R.string.vpn_yes_button,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int w) {
                                connectOrDisconnect(mConnectingActor.getProfile());
                            }
                        })
                .setNegativeButton(R.string.vpn_no_button,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int w) {
                                onIdle();
                            }
                        })
                .setOnCancelListener(new DialogInterface.OnCancelListener() {
                            public void onCancel(DialogInterface dialog) {
                                onIdle();
                            }
                        });
    }

    private Dialog createAuthErrorDialog() {
        return createReconnectDialogBuilder()
                .setMessage(R.string.vpn_auth_error_dialog_msg)
                .create();
    }

    private Dialog createUnknownServerDialog() {
        return createReconnectDialogBuilder()
                .setMessage(R.string.vpn_unknown_server_dialog_msg)
                .setPositiveButton(R.string.vpn_yes_button,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int w) {
                                VpnProfile p = mConnectingActor.getProfile();
                                onIdle();
                                mIndexOfEditedProfile =
                                        mVpnProfileList.indexOf(p);
                                startVpnEditor(p);
                            }
                        })
                .create();
    }

    @Override
@@ -252,8 +298,8 @@ public class VpnSettings extends PreferenceActivity implements
            menu.setHeaderTitle(p.getName());

            boolean isIdle = (state == VpnState.IDLE);
            boolean isNotConnect =
                    (isIdle || (state == VpnState.DISCONNECTING));
            boolean isNotConnect = (isIdle || (state == VpnState.DISCONNECTING)
                    || (state == VpnState.CANCELLED));
            menu.add(0, CONTEXT_MENU_CONNECT_ID, 0, R.string.vpn_menu_connect)
                    .setEnabled(isIdle && (mActiveProfile == null));
            menu.add(0, CONTEXT_MENU_DISCONNECT_ID, 0,
@@ -363,17 +409,18 @@ public class VpnSettings extends PreferenceActivity implements
    // Called when the buttons on the connect dialog are clicked.
    //@Override
    public synchronized void onClick(DialogInterface dialog, int which) {
        dismissDialog(DIALOG_CONNECT);
        if (which == CONNECT_BUTTON) {
            Dialog d = (Dialog) dialog;
            String error = mConnectingActor.validateInputs(d);
            if (error == null) {
                changeState(mConnectingActor.getProfile(), VpnState.CONNECTING);
                mConnectingActor.connect(d);
                removeDialog(DIALOG_CONNECT);
                return;
            } else {
                dismissDialog(DIALOG_CONNECT);
                // show error dialog
                new AlertDialog.Builder(this)
                mShowingDialog = new AlertDialog.Builder(this)
                        .setTitle(android.R.string.dialog_alert_title)
                        .setIcon(android.R.drawable.ic_dialog_alert)
                        .setMessage(String.format(getString(
@@ -385,8 +432,11 @@ public class VpnSettings extends PreferenceActivity implements
                                        showDialog(DIALOG_CONNECT);
                                    }
                                })
                        .show();
                        .create();
                mShowingDialog.show();
            }
        } else {
            removeDialog(DIALOG_CONNECT);
        }
    }

@@ -428,13 +478,14 @@ public class VpnSettings extends PreferenceActivity implements
                        }
                    }
                };
        new AlertDialog.Builder(this)
        mShowingDialog = new AlertDialog.Builder(this)
                .setTitle(android.R.string.dialog_alert_title)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .setMessage(R.string.vpn_confirm_profile_deletion)
                .setPositiveButton(android.R.string.ok, onClickListener)
                .setNegativeButton(R.string.vpn_no_button, onClickListener)
                .show();
                .create();
        mShowingDialog.show();
    }

    // Randomly generates an ID for the profile.
@@ -583,8 +634,8 @@ public class VpnSettings extends PreferenceActivity implements
        }

        mConnectingActor = getActor(p);
        mActiveProfile = p;
        if (mConnectingActor.isConnectDialogNeeded()) {
            removeDialog(DIALOG_CONNECT);
            showDialog(DIALOG_CONNECT);
        } else {
            changeState(p, VpnState.CONNECTING);
@@ -605,8 +656,6 @@ public class VpnSettings extends PreferenceActivity implements
                break;

            case CONNECTED:
                mConnectingError = false;
                // pass through
            case DISCONNECTING:
                changeState(p, VpnState.DISCONNECTING);
                getActor(p).disconnect();
@@ -625,16 +674,13 @@ public class VpnSettings extends PreferenceActivity implements
        switch (state) {
        case CONNECTED:
            mConnectingActor = null;
            // pass through
        case CONNECTING:
            mActiveProfile = p;
            disableProfilePreferencesIfOneActive();
            break;

        case CONNECTING:
        case DISCONNECTING:
            if (oldState == VpnState.CONNECTING) {
                mConnectingError = true;
            }
            disableProfilePreferencesIfOneActive();
            break;

        case CANCELLED:
@@ -642,31 +688,34 @@ public class VpnSettings extends PreferenceActivity implements
            break;

        case IDLE:
            assert(mActiveProfile != p);
            mActiveProfile = null;
            mConnectingActor = null;
            enableProfilePreferences();
            assert(mActiveProfile == p);

            switch (mConnectingErrorCode) {
                case NO_ERROR:
                    onIdle();
                    break;

            if (oldState == VpnState.CONNECTING) mConnectingError = true;
            if (mConnectingError) showReconnectDialog(p);
                case VpnManager.VPN_ERROR_AUTH:
                    showDialog(DIALOG_AUTH_ERROR);
                    break;

                case VpnManager.VPN_ERROR_UNKNOWN_SERVER:
                    showDialog(DIALOG_UNKNOWN_SERVER);
                    break;

                default:
                    showDialog(DIALOG_RECONNECT);
                    break;
            }
            mConnectingErrorCode = NO_ERROR;
            break;
        }

    private void showReconnectDialog(final VpnProfile p) {
        new AlertDialog.Builder(this)
                .setTitle(android.R.string.dialog_alert_title)
                .setIcon(android.R.drawable.ic_dialog_alert)
                .setMessage(R.string.vpn_confirm_reconnect)
                .setPositiveButton(R.string.vpn_yes_button,
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int w) {
                                dialog.dismiss();
                                connectOrDisconnect(p);
    }
                        })
                .setNegativeButton(R.string.vpn_no_button, null)
                .show();

    private void onIdle() {
        mActiveProfile = null;
        mConnectingActor = null;
        enableProfilePreferences();
    }

    private void disableProfilePreferencesIfOneActive() {
@@ -674,6 +723,7 @@ public class VpnSettings extends PreferenceActivity implements

        for (VpnProfile p : mVpnProfileList) {
            switch (p.getState()) {
                case CONNECTING:
                case DISCONNECTING:
                case IDLE:
                    mVpnPreferenceMap.get(p.getName()).setEnabled(false);
@@ -856,14 +906,20 @@ public class VpnSettings extends PreferenceActivity implements

            VpnState s = (VpnState) intent.getSerializableExtra(
                    VpnManager.BROADCAST_CONNECTION_STATE);

            if (s == null) {
                Log.e(TAG, "received null connectivity state");
                return;
            }

            mConnectingErrorCode = intent.getIntExtra(
                    VpnManager.BROADCAST_ERROR_CODE, NO_ERROR);

            VpnPreference pref = mVpnPreferenceMap.get(profileName);
            if (pref != null) {
                Log.d(TAG, "received connectivity: " + profileName
                        + ": connected? " + s);
                        + ": connected? " + s
                        + "   err=" + mConnectingErrorCode);
                changeState(pref.mProfile, s);
            } else {
                Log.e(TAG, "received connectivity: " + profileName