diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9f99ba1..562149c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3,4 +3,6 @@
CouchDB
Stop CouchDB
Delete Databases
+CouchDB is Loading...
+Are you sure you want to delete, this will delete all of your existing data?
diff --git a/src/org/couchdb/android/CouchCtrlListener.java b/src/org/couchdb/android/CouchCtrlListener.java
index 7ef1f6b..6f1b4ce 100644
--- a/src/org/couchdb/android/CouchCtrlListener.java
+++ b/src/org/couchdb/android/CouchCtrlListener.java
@@ -28,7 +28,7 @@ public CouchCtrlListener(String couchUrl, String db, String user,
public void start() {
- Log.v(CouchFutonActivity.TAG, "Starting Listener for " + ctrl);
+ Log.v(CouchProcess.TAG, "Starting Listener for " + ctrl);
if (!running) {
try {
@@ -82,7 +82,7 @@ private void changes(int seq) throws JSONException {
+ "/_changes?include_docs=true&feed=longpoll&since="
+ Integer.toString(seq);
JSONObject json = HTTPRequest.get(url, headers()).json;
- Log.v(CouchFutonActivity.TAG, "Received Changes for " + ctrl);
+ Log.v(CouchProcess.TAG, "Received Changes for " + ctrl);
seq = json.getInt("last_seq");
JSONArray results = json.getJSONArray("results");
@@ -91,13 +91,13 @@ private void changes(int seq) throws JSONException {
handleChange(results.getJSONObject(i).getJSONObject("doc"));
}
}
- Log.v(CouchFutonActivity.TAG, "Changes listener on " + ctrl + " has stopped");
+ Log.v(CouchProcess.TAG, "Changes listener on " + ctrl + " has stopped");
running = false;
cancelled = false;
}
public void cancel() {
- Log.v(CouchFutonActivity.TAG, "Cancelling changes listener for " + ctrl);
+ Log.v(CouchProcess.TAG, "Cancelling changes listener for " + ctrl);
cancelled = true;
}
diff --git a/src/org/couchdb/android/CouchFutonActivity.java b/src/org/couchdb/android/CouchFutonActivity.java
index bcd660b..8cf89dc 100644
--- a/src/org/couchdb/android/CouchFutonActivity.java
+++ b/src/org/couchdb/android/CouchFutonActivity.java
@@ -16,7 +16,6 @@
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
-import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -28,20 +27,57 @@
public class CouchFutonActivity extends Activity {
- public final static String TAG = "CouchDB";
- public final static String FUTON = "http://127.0.0.1:5984/_utils/";
+ private CouchProcess couch = CouchProcess.getInstance();
private ProgressDialog loading;
-
private ICouchService couchService;
- public Boolean serviceStarted = false;
-
+ private WebView webView;
+
private static final int COUCH_STARTED = 1;
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ attemptLaunch();
+ }
+
+ @Override
+ public void onRestart() {
+ super.onRestart();
+ attemptLaunch();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (webView != null) {
+ webView.destroy();
+ }
+ if (couchService != null) {
+ unbindService(mConnection);
+ }
+ }
+
+ /*
+ * Checks to see if Couch is fully installed, if not prompt to complete
+ * installation otherwise start the couchdb service
+ */
+ private void attemptLaunch() {
+ if (!CouchInstaller.checkInstalled()) {
+ startActivity(new Intent(this, CouchInstallActivity.class));
+ } else if (!CouchProcess.getInstance().couchStarted) {
+ String msg = this.getString(R.string.loading_dialog);
+ loading = ProgressDialog.show(this, "", msg, true);
+ bindService(new Intent(ICouchService.class.getName()), mConnection, Context.BIND_AUTO_CREATE);
+ }
+ }
+
+ /*
+ * This holds the connection to the CouchDB Service
+ */
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
try {
- serviceStarted = true;
couchService = ICouchService.Stub.asInterface(service);
couchService.initCouchDB(mCallback);
} catch (RemoteException e) {
@@ -53,86 +89,43 @@ public void onServiceDisconnected(ComponentName className) {
couchService = null;
}
};
-
- private void setFutonView() {
-
- String user = CouchProcess.getInstance().adminUser;
- String pass = CouchProcess.getInstance().adminPass;
-
- WebView webView = new WebView(CouchFutonActivity.this);
- webView.setWebChromeClient(new WebChromeClient());
- webView.setWebViewClient(new CustomWebViewClient());
- webView.setHttpAuthUsernamePassword("127.0.0.1", "administrator", user, pass);
- webView.getSettings().setJavaScriptEnabled(true);
- webView.getSettings().setBuiltInZoomControls(true);
- webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
- setContentView(webView);
- webView.loadUrl(FUTON);
- };
-
- private class CustomWebViewClient extends WebViewClient {
+
+ /*
+ * Implement the callbacks that allow CouchDB to talk to this app
+ */
+ private ICouchClient mCallback = new ICouchClient.Stub() {
@Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- view.loadUrl(url);
- return true;
+ public void couchStarted(String host, int port) throws RemoteException {
+ mHandler.sendMessage(mHandler.obtainMessage(COUCH_STARTED));
}
@Override
- public void onReceivedHttpAuthRequest(WebView view,
- HttpAuthHandler handler, String host, String realm) {
- String[] up = view.getHttpAuthUsernamePassword(host, realm);
- handler.proceed(up[0], up[1]);
+ public void databaseCreated(String name, String user, String pass,
+ String tag) throws RemoteException {
}
- }
-
- private void showLoading() {
- loading = ProgressDialog.show(this, "", "CouchDB is Loading...", true);
- }
+ };
- private Boolean deleteDirectory(File dir) {
- if (dir.isDirectory()) {
- String[] children = dir.list();
- for (int i = 0; i < children.length; i++) {
- boolean success = deleteDirectory(new File(dir, children[i]));
- if (!success) {
- return false;
- }
+ /*
+ * Because the service communication happens in a seperate thread, we need
+ * a message handler to control the ui in this thread
+ */
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case COUCH_STARTED:
+ loading.dismiss();
+ launchFuton();
+ break;
+ default:
+ super.handleMessage(msg);
}
}
- return dir.delete();
- }
-
- private void deleteDatabases() {
- unbindService(mConnection);
- CouchProcess.getInstance().stopCouchDB();
- Log.v(TAG, "DELETING EVERYTHING");
- File couchDir = new File(Environment.getExternalStorageDirectory(),
- "couch");
- // ARG THIS IS TOTALLY SCARY AND WRONG
- deleteDirectory(couchDir);
- finish();
- }
-
- private void confirmDelete() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(
- "Are you sure you want to delete, this will delete all of your existing data?")
- .setCancelable(false)
- .setPositiveButton("Yes",
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- CouchFutonActivity.this.deleteDatabases();
- }
- })
- .setNegativeButton("No", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
- AlertDialog alert = builder.create();
- alert.show();
- }
+ };
+ /*
+ * Creates the menu items
+ */
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
@@ -140,6 +133,9 @@ public boolean onCreateOptionsMenu(Menu menu) {
return true;
};
+ /*
+ * Handles the menu item callbacks
+ */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@@ -154,61 +150,82 @@ public boolean onOptionsItemSelected(MenuItem item) {
}
}
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (couchService != null) {
- unbindService(mConnection);
- }
+ /*
+ * Confirm that the user wants to delete their databases
+ */
+ private void confirmDelete() {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage(this.getString(R.string.confirm_delete))
+ .setCancelable(false)
+ .setPositiveButton("Yes",
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ CouchFutonActivity.this.deleteDatabases();
+ }
+ })
+ .setNegativeButton("No", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ AlertDialog alert = builder.create();
+ alert.show();
}
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- boot();
+ /*
+ * Because we store the database files on the sdcard, uninstalling the application
+ * will persist the databases on reinstall, this will delete the entire
+ * couch directory on the sdcard and quit the application, the next time the
+ * user starts up again they will be prompted to reinstall couch
+ *
+ * However this is dangerous and messy and the functionality should probably
+ * be removed entirely
+ */
+ private void deleteDatabases() {
+ unbindService(mConnection);
+ CouchProcess.getInstance().stopCouchDB();
+ File couchDir = new File(Environment.getExternalStorageDirectory(), "couch");
+ deleteDirectory(couchDir);
+ finish();
}
-
- @Override
- public void onRestart() {
- super.onRestart();
- boot();
- };
-
- private void boot() {
- boolean installed = CouchInstaller.checkInstalled();
- if (!installed && !serviceStarted) {
- startActivity(new Intent(this, CouchInstallActivity.class));
- } else if (!serviceStarted) {
- showLoading();
- bindService(new Intent(ICouchService.class.getName()), mConnection,
- Context.BIND_AUTO_CREATE);
- }
+
+ private void launchFuton() {
+ webView = new WebView(CouchFutonActivity.this);
+ webView.setWebChromeClient(new WebChromeClient());
+ webView.setWebViewClient(new CustomWebViewClient());
+ webView.setHttpAuthUsernamePassword(couch.host, "administrator", couch.adminUser, couch.adminPass);
+ webView.getSettings().setJavaScriptEnabled(true);
+ webView.getSettings().setBuiltInZoomControls(true);
+ webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
+ setContentView(webView);
+ webView.loadUrl(couch.couchUrl() + "_utils/");
};
- private ICouchClient mCallback = new ICouchClient.Stub() {
- @Override
- public void couchStarted(String host, int port) throws RemoteException {
- mHandler.sendMessage(mHandler.obtainMessage(COUCH_STARTED));
+ private Boolean deleteDirectory(File dir) {
+ if (dir.isDirectory()) {
+ String[] children = dir.list();
+ for (int i = 0; i < children.length; i++) {
+ boolean success = deleteDirectory(new File(dir, children[i]));
+ if (!success) {
+ return false;
+ }
+ }
}
-
+ return dir.delete();
+ }
+
+ private class CustomWebViewClient extends WebViewClient {
@Override
- public void databaseCreated(String name, String user, String pass,
- String tag) throws RemoteException {
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ view.loadUrl(url);
+ return true;
}
- };
- private Handler mHandler = new Handler() {
@Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case COUCH_STARTED:
- loading.dismiss();
- setFutonView();
- break;
- default:
- super.handleMessage(msg);
- }
+ public void onReceivedHttpAuthRequest(WebView view,
+ HttpAuthHandler handler, String host, String realm) {
+ String[] up = view.getHttpAuthUsernamePassword(host, realm);
+ handler.proceed(up[0], up[1]);
}
- };
-
+ }
}
\ No newline at end of file
diff --git a/src/org/couchdb/android/CouchInstallActivity.java b/src/org/couchdb/android/CouchInstallActivity.java
index 656cccd..6a6e47e 100644
--- a/src/org/couchdb/android/CouchInstallActivity.java
+++ b/src/org/couchdb/android/CouchInstallActivity.java
@@ -53,7 +53,7 @@ public void onClick(DialogInterface dialog,
case CouchInstallActivity.COMPLETE:
installProgress.dismiss();
- Log.v(CouchFutonActivity.TAG, "Launching Couchdb activity");
+ Log.v(CouchProcess.TAG, "Launching Couchdb activity");
startActivity(new Intent(getApplicationContext(), CouchFutonActivity.class));
break;
}
@@ -101,7 +101,6 @@ public void run() {
class InstallError {
public String description;
-
public InstallError(String description) {
this.description = description;
}
diff --git a/src/org/couchdb/android/CouchProcess.java b/src/org/couchdb/android/CouchProcess.java
index d7fab8a..7ea90e5 100644
--- a/src/org/couchdb/android/CouchProcess.java
+++ b/src/org/couchdb/android/CouchProcess.java
@@ -23,6 +23,8 @@
public class CouchProcess {
+ public static String TAG = "CouchDB";
+
private static volatile CouchProcess INSTANCE = null;
public static synchronized CouchProcess getInstance() {
@@ -39,8 +41,8 @@ public static synchronized CouchProcess getInstance() {
public String adminPass;
// TODO: read from config file
- final String couchHost = "127.0.0.1";
- final int couchPort = 5984;
+ public final String host = "127.0.0.1";
+ public final int port = 5984;
public Integer pid;
@@ -49,7 +51,7 @@ public static synchronized CouchProcess getInstance() {
public CouchService service;
- public Boolean couchStarted;
+ public Boolean couchStarted = false;
boolean notify;
@@ -71,7 +73,7 @@ public void start(String binary, String arg1, String arg2,
new Thread(new Runnable() {
public void run() {
- Log.v(CouchFutonActivity.TAG, "PID: " + pid);
+ Log.v(TAG, "PID: " + pid);
while (fd.valid()) {
String line;
try {
@@ -79,7 +81,7 @@ public void run() {
} catch (IOException e) {
break;
}
- Log.v(CouchFutonActivity.TAG, line);
+ Log.v(TAG, line);
if (line.contains("has started on")) {
couchStarted = true;
try {
@@ -92,7 +94,7 @@ public void run() {
} catch (RemoteException e) {
e.printStackTrace();
}
- Log.v(CouchFutonActivity.TAG, "Couch has started.");
+ Log.v(TAG, "Couch has started.");
}
}
}
@@ -101,7 +103,6 @@ public void run() {
private void ensureAdmin() throws JSONException {
adminPass = readOrGeneratePass(adminUser);
- Log.v(CouchFutonActivity.TAG, "admin passsword is " + adminPass);
// TODO: only works because I cant overwrite, check if exists in future
String url = couchUrl() + "_config/admins/" + adminUser;
HTTPRequest.httpRequest("PUT", url, "\"" + adminPass + "\"",
@@ -169,8 +170,8 @@ public void stopCouchDB() {
}
- String couchUrl() {
- return "http://" + couchHost + ":" + Integer.toString(couchPort) + "/";
+ public String couchUrl() {
+ return "http://" + host + ":" + Integer.toString(port) + "/";
}
}
diff --git a/src/org/couchdb/android/CouchService.java b/src/org/couchdb/android/CouchService.java
index f5372ea..adc18e6 100644
--- a/src/org/couchdb/android/CouchService.java
+++ b/src/org/couchdb/android/CouchService.java
@@ -21,7 +21,6 @@
public class CouchService extends Service {
private NotificationManager mNM;
- private Boolean couchStarted = false;
private CouchProcess couchProcess = CouchProcess.getInstance();
@@ -44,7 +43,7 @@ public void initCouchDB(ICouchClient cb) throws RemoteException {
String packageName = packageNameFromUid(Binder.getCallingUid());
couchClients.put(packageName, cb);
- if (couchStarted) {
+ if (couchProcess.couchStarted) {
couchStarted();
}
}
@@ -172,7 +171,7 @@ void couchStarted() throws RemoteException {
for (Entry entry : couchClients.entrySet()) {
ICouchClient client = entry.getValue();
- client.couchStarted(couchProcess.couchHost, couchProcess.couchPort);
+ client.couchStarted(couchProcess.host, couchProcess.port);
couchClients.remove(entry.getKey());
}
}