Merge "Extract credential storage dialogs to a new activity." into honeycomb
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5a2ecca..2e293c8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3142,5 +3142,7 @@
     <string name="enter_password">Enter password to decrypt storage</string>
     <!-- This is displayed when the password is entered incorrectly -->
     <string name="try_again">Sorry, try again</string>
+    <!-- This error message is displayed when the vpn profile is going to be saved but the vpn service is busy [CHAR LIMIT=NONE] -->
+    <string name="service_busy">Service busy, try again</string>
 
 </resources>
diff --git a/src/com/android/settings/vpn/AuthenticationActor.java b/src/com/android/settings/vpn/AuthenticationActor.java
index 0228934..f8401d6 100644
--- a/src/com/android/settings/vpn/AuthenticationActor.java
+++ b/src/com/android/settings/vpn/AuthenticationActor.java
@@ -19,16 +19,10 @@
 import com.android.settings.R;
 
 import android.app.Dialog;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.ServiceConnection;
-import android.net.vpn.IVpnService;
 import android.net.vpn.VpnManager;
 import android.net.vpn.VpnProfile;
 import android.net.vpn.VpnState;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.RemoteException;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -117,102 +111,13 @@
         return mContext;
     }
 
-    private void connect(final String username, final String password) {
-        mVpnManager.startVpnService();
-        ServiceConnection c = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className,
-                    IBinder service) {
-                try {
-                    boolean success = IVpnService.Stub.asInterface(service)
-                            .connect(mProfile, username, password);
-                    if (!success) {
-                        Log.d(TAG, "~~~~~~ connect() failed!");
-                    } 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);
-                }
-            }
-
-            public void onServiceDisconnected(ComponentName className) {
-                checkStatus();
-            }
-        };
-        if (!bindService(c)) {
-            broadcastConnectivity(VpnState.IDLE,
-                    VpnManager.VPN_ERROR_CONNECTION_FAILED);
-        }
+    private void connect(String username, String password) {
+        mVpnManager.connect(mProfile, username, password);
     }
 
     //@Override
     public void disconnect() {
-        ServiceConnection c = new ServiceConnection() {
-            public void onServiceConnected(ComponentName className,
-                    IBinder service) {
-                try {
-                    IVpnService.Stub.asInterface(service).disconnect();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "disconnect()", e);
-                    checkStatus();
-                } finally {
-                    mContext.unbindService(this);
-                }
-            }
-
-            public void onServiceDisconnected(ComponentName className) {
-                checkStatus();
-            }
-        };
-        if (!bindService(c)) {
-            checkStatus();
-        }
-    }
-
-    //@Override
-    public void checkStatus() {
-        final ConditionVariable cv = new ConditionVariable();
-        cv.close();
-        ServiceConnection c = new ServiceConnection() {
-            public synchronized void onServiceConnected(ComponentName className,
-                    IBinder service) {
-                cv.open();
-                try {
-                    IVpnService.Stub.asInterface(service).checkStatus(mProfile);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "checkStatus()", e);
-                    broadcastConnectivity(VpnState.IDLE);
-                } finally {
-                    mContext.unbindService(this);
-                }
-            }
-
-            public void onServiceDisconnected(ComponentName className) {
-                cv.open();
-                broadcastConnectivity(VpnState.IDLE);
-                mContext.unbindService(this);
-            }
-        };
-        if (bindService(c)) {
-            // wait for a second, let status propagate
-            if (!cv.block(1000)) broadcastConnectivity(VpnState.IDLE);
-        }
-    }
-
-    private boolean bindService(ServiceConnection c) {
-        return mVpnManager.bindVpnService(c);
-    }
-
-    private void broadcastConnectivity(VpnState s) {
-        mVpnManager.broadcastConnectivity(mProfile.getName(), s);
-    }
-
-    private void broadcastConnectivity(VpnState s, int errorCode) {
-        mVpnManager.broadcastConnectivity(mProfile.getName(), s, errorCode);
+        mVpnManager.disconnect();
     }
 
     private void setSavedUsername(String name) throws IOException {
diff --git a/src/com/android/settings/vpn/VpnEditor.java b/src/com/android/settings/vpn/VpnEditor.java
index 1b3bdb5..161d34b 100644
--- a/src/com/android/settings/vpn/VpnEditor.java
+++ b/src/com/android/settings/vpn/VpnEditor.java
@@ -28,6 +28,7 @@
 import android.net.vpn.L2tpIpsecPskProfile;
 import android.net.vpn.L2tpProfile;
 import android.net.vpn.PptpProfile;
+import android.net.vpn.VpnManager;
 import android.net.vpn.VpnProfile;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -37,6 +38,7 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.widget.Toast;
 
 /**
  * The activity class for editing a new or existing VPN profile.
@@ -48,6 +50,7 @@
     private static final String KEY_PROFILE = "profile";
     private static final String KEY_ORIGINAL_PROFILE_NAME = "orig_profile_name";
 
+    private VpnManager mVpnManager;
     private VpnProfileEditor mProfileEditor;
     private boolean mAddingProfile;
     private byte[] mOriginalProfileData;
@@ -63,6 +66,7 @@
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
+        mVpnManager = new VpnManager(getActivity());
 
         VpnProfile p;
         if (savedInstanceState != null) {
@@ -111,8 +115,15 @@
             case MENU_SAVE:
                 Intent resultIntent = validateAndGetResult();
                 if (resultIntent != null) {
-                    ((PreferenceActivity) getActivity()).finishPreferencePanel(
-                            this, Activity.RESULT_OK, resultIntent);
+                    PreferenceActivity activity =
+                            (PreferenceActivity) getActivity();
+                    if (!mVpnManager.isIdle()) {
+                        Toast.makeText(activity, R.string.service_busy,
+                                Toast.LENGTH_SHORT).show();
+                    } else {
+                        activity.finishPreferencePanel(this,
+                                Activity.RESULT_OK, resultIntent);
+                    }
                 }
                 return true;
 
diff --git a/src/com/android/settings/vpn/VpnProfileActor.java b/src/com/android/settings/vpn/VpnProfileActor.java
index da601f8..4c7b014 100644
--- a/src/com/android/settings/vpn/VpnProfileActor.java
+++ b/src/com/android/settings/vpn/VpnProfileActor.java
@@ -54,11 +54,4 @@
      * Tears down the connection.
      */
     void disconnect();
-
-    /**
-     * Checks the current status. The result is expected to be broadcast.
-     * Use {@link VpnManager#registerConnectivityReceiver()} to register a
-     * broadcast receiver and to receives the broadcast events.
-     */
-    void checkStatus();
 }
diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java
index 960d37e..bd1cc9e 100644
--- a/src/com/android/settings/vpn/VpnSettings.java
+++ b/src/com/android/settings/vpn/VpnSettings.java
@@ -23,12 +23,9 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
-import android.content.ServiceConnection;
-import android.net.vpn.IVpnService;
 import android.net.vpn.L2tpIpsecProfile;
 import android.net.vpn.L2tpIpsecPskProfile;
 import android.net.vpn.L2tpProfile;
@@ -37,9 +34,6 @@
 import android.net.vpn.VpnState;
 import android.net.vpn.VpnType;
 import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.IBinder;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceCategory;
@@ -137,9 +131,7 @@
 
     private int mConnectingErrorCode = NO_ERROR;
 
-    private Dialog mShowingDialog;
-
-    private StatusChecker mStatusChecker = new StatusChecker();
+    private Dialog mShowingDialog, mConnectDialog;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -190,7 +182,6 @@
         // for long-press gesture on a profile preference
         registerForContextMenu(getListView());
 
-
         retrieveVpnListFromStorage();
         restoreInstanceState(savedInstanceState);
     }
@@ -216,7 +207,13 @@
             mUnlockAction = null;
             getActivity().runOnUiThread(action);
         }
-        checkVpnConnectionStatusInBackground();
+        if (mConnectDialog == null || !mConnectDialog.isShowing()) {
+            checkVpnConnectionStatus();
+        } else {
+            // Dismiss the connect dialog in case there is another instance
+            // trying to operate a vpn connection.
+            if (!mVpnManager.isIdle()) removeConnectDialog();
+        }
     }
 
     @Override
@@ -245,7 +242,8 @@
     public Dialog onCreateDialog (int id) {
         switch (id) {
             case DIALOG_CONNECT:
-                return createConnectDialog();
+                mConnectDialog = createConnectDialog();
+                return mConnectDialog;
 
             case DIALOG_SECRET_NOT_SET:
                 return createSecretNotSetDialog();
@@ -261,11 +259,19 @@
         }
     }
 
+    private void removeConnectDialog() {
+        if (mConnectDialog != null) {
+            mConnectDialog.dismiss();
+            mConnectDialog = null;
+            checkVpnConnectionStatus();
+        }
+    }
+
     private class ConnectDialog extends AlertDialog {
         public ConnectDialog(Context context) {
             super(context);
             setTitle(String.format(getString(R.string.vpn_connect_to),
-                    mActiveProfile.getName()));
+                    mConnectingActor.getProfile().getName()));
             setButton(DialogInterface.BUTTON_POSITIVE,
                     getString(R.string.vpn_connect_button),
                     VpnSettings.this);
@@ -506,11 +512,11 @@
             String error = mConnectingActor.validateInputs(d);
             if (error == null) {
                 mConnectingActor.connect(d);
-                removeDialog(DIALOG_CONNECT);
+                removeConnectDialog();
                 return;
             } else {
                 // dismissDialog(DIALOG_CONNECT);
-                removeDialog(DIALOG_CONNECT);
+                removeConnectDialog();
 
                 final Activity activity = getActivity();
                 // show error dialog
@@ -530,8 +536,7 @@
                 mShowingDialog.show();
             }
         } else {
-            removeDialog(DIALOG_CONNECT);
-            changeState(mActiveProfile, VpnState.IDLE);
+            removeConnectDialog();
         }
     }
 
@@ -620,14 +625,10 @@
         saveProfileToStorage(p);
 
         mVpnProfileList.add(p);
-        addPreferenceFor(p);
+        addPreferenceFor(p, true);
         disableProfilePreferencesIfOneActive();
     }
 
-    private VpnPreference addPreferenceFor(VpnProfile p) {
-        return addPreferenceFor(p, true);
-    }
-
     // Adds a preference in mVpnListContainer
     private VpnPreference addPreferenceFor(
             VpnProfile p, boolean addToContainer) {
@@ -886,18 +887,23 @@
                 return p1.getName().compareTo(p2.getName());
             }
         });
+        // Delay adding preferences to mVpnListContainer until states are
+        // obtained so that the user won't see initial state transition.
         for (VpnProfile p : mVpnProfileList) {
             Preference pref = addPreferenceFor(p, false);
         }
         disableProfilePreferencesIfOneActive();
     }
 
-    private void checkVpnConnectionStatusInBackground() {
-        new Thread(new Runnable() {
-            public void run() {
-                mStatusChecker.check(mVpnProfileList);
-            }
-        }).start();
+    private void checkVpnConnectionStatus() {
+        for (VpnProfile p : mVpnProfileList) {
+            changeState(p, mVpnManager.getState(p));
+        }
+        // make preferences appear
+        for (VpnProfile p : mVpnProfileList) {
+            VpnPreference pref = mVpnPreferenceMap.get(p.getName());
+            mVpnListContainer.addPreference(pref);
+        }
     }
 
     // A sanity check. Returns true if the profile directory name and profile ID
@@ -1074,61 +1080,4 @@
             }
         }
     }
-
-    // managing status check in a background thread
-    private class StatusChecker {
-        synchronized void check(final List<VpnProfile> list) {
-            final ConditionVariable cv = new ConditionVariable();
-            cv.close();
-            mVpnManager.startVpnService();
-            ServiceConnection c = new ServiceConnection() {
-                public synchronized void onServiceConnected(
-                        ComponentName className, IBinder binder) {
-                    cv.open();
-
-                    IVpnService service = IVpnService.Stub.asInterface(binder);
-                    for (VpnProfile p : list) {
-                        try {
-                            service.checkStatus(p);
-                        } catch (Throwable e) {
-                            Log.e(TAG, " --- checkStatus(): " + p.getName(), e);
-                            changeState(p, VpnState.IDLE);
-                        }
-                    }
-                    if (getActivity() == null) return;
-                    getActivity().unbindService(this);
-                    showPreferences();
-                }
-
-                public void onServiceDisconnected(ComponentName className) {
-                    cv.open();
-
-                    setDefaultState(list);
-                    if (getActivity() == null) return;
-                    getActivity().unbindService(this);
-                    showPreferences();
-                }
-            };
-            if (mVpnManager.bindVpnService(c)) {
-                if (!cv.block(1000)) {
-                    Log.d(TAG, "checkStatus() bindService failed");
-                    setDefaultState(list);
-                }
-            } else {
-                setDefaultState(list);
-            }
-        }
-
-        private void showPreferences() {
-            for (VpnProfile p : mVpnProfileList) {
-                VpnPreference pref = mVpnPreferenceMap.get(p.getName());
-                mVpnListContainer.addPreference(pref);
-            }
-        }
-
-        private void setDefaultState(List<VpnProfile> list) {
-            for (VpnProfile p : list) changeState(p, VpnState.IDLE);
-            showPreferences();
-        }
-    }
 }