Merge branch 'master' of camlistore.org:camlistore

This commit is contained in:
Brad Fitzpatrick 2011-03-13 22:22:01 -07:00
commit 970b8e6971
2 changed files with 184 additions and 171 deletions

View File

@ -37,8 +37,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
public class BrowseActivity extends ListActivity
implements DownloadService.Listener {
public class BrowseActivity extends ListActivity {
private static final String TAG = "BrowseActivity";
private static final String BUNDLE_BLOBREF = "blobref";
@ -49,11 +48,7 @@ public class BrowseActivity extends ListActivity
private DownloadService mService = null;
private SimpleAdapter mAdapter;
private String mDirectoryBlobRef = "";
private String mDirectoryEntriesBlobRef = "";
// If true, we're showing the results of a search.
private boolean mIsSearch;
private String mBlobRef = "";
private ArrayList<HashMap<String, String>> mEntries =
new ArrayList<HashMap<String, String>>();
@ -64,9 +59,11 @@ public class BrowseActivity extends ListActivity
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "connected to service");
mService = ((DownloadService.LocalBinder) service).getService();
mService.getBlob(mDirectoryBlobRef.equals("") ? "search" : mDirectoryBlobRef,
!mDirectoryBlobRef.equals(""), // persistent
BrowseActivity.this);
if (mBlobRef.equals("")) {
mService.getBlob("search", false, mSearchResultsListener);
} else {
mService.getBlob(mBlobRef, true, mDirectoryListener);
}
}
public void onServiceDisconnected(ComponentName className) {
@ -75,6 +72,158 @@ public class BrowseActivity extends ListActivity
}
};
private final DownloadService.Listener mSearchResultsListener = new DownloadService.Listener() {
@Override
public void onBlobDownloadComplete(final String blobRef, final InputStream stream) {
try {
JSONObject object = (JSONObject) new JSONTokener(Util.slurp(stream)).nextValue();
JSONArray array = object.getJSONArray("results");
if (array == null) {
Log.e(TAG, "search results are missing results key");
return;
}
mEntries.clear();
for (int i = 0; i < array.length(); ++i) {
JSONObject jsonEntry = array.getJSONObject(i);
Log.d(TAG, "adding entry " + jsonEntry.getString("blobref"));
HashMap<String, String> entry = new HashMap<String, String>();
entry.put(KEY_TITLE, jsonEntry.getString("blobref"));
entry.put(KEY_CONTENT, jsonEntry.getString("content"));
mEntries.add(entry);
mEntriesByBlobRef.put(jsonEntry.getString("blobref"), entry);
}
mAdapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "got IO error while reading search results", e);
} catch (org.json.JSONException e) {
Log.e(TAG, "unable to parse JSON for search results", e);
}
}
@Override
public void onBlobDownloadFail(final String blobRef) {
Log.e(TAG, "download failed for search results");
}
};
private final DownloadService.Listener mDirectoryListener = new DownloadService.Listener() {
@Override
public void onBlobDownloadComplete(final String blobRef, final InputStream stream) {
try {
JSONObject object = (JSONObject) new JSONTokener(Util.slurp(stream)).nextValue();
String type = object.getString("camliType");
if (type == null || !type.equals("directory")) {
Log.e(TAG, "directory " + blobRef + " has missing or invalid type");
return;
}
String fileName = object.getString("fileName");
if (fileName == null) {
Log.e(TAG, "directory " + blobRef + " doesn't have fileName");
return;
}
setTitle(fileName + "/");
String entriesBlobRef = object.getString("entries");
if (entriesBlobRef == null) {
Log.e(TAG, "directory " + blobRef + " doesn't have entries");
return;
}
Log.d(TAG, "requesting directory entries " + entriesBlobRef);
mService.getBlob(entriesBlobRef, true, mDirectoryEntriesListener);
} catch (IOException e) {
Log.e(TAG, "got IO error while reading directory " + blobRef, e);
} catch (org.json.JSONException e) {
Log.e(TAG, "unable to parse JSON for search results", e);
}
}
@Override
public void onBlobDownloadFail(final String blobRef) {
Log.e(TAG, "download failed for directory " + blobRef);
}
};
private final DownloadService.Listener mDirectoryEntriesListener = new DownloadService.Listener() {
@Override
public void onBlobDownloadComplete(final String blobRef, final InputStream stream) {
try {
JSONObject object = (JSONObject) new JSONTokener(Util.slurp(stream)).nextValue();
String type = object.getString("camliType");
if (type == null || !type.equals("static-set")) {
Log.e(TAG, "directory list " + blobRef + " has missing or invalid camliType");
return;
}
JSONArray members = object.getJSONArray("members");
if (members == null) {
Log.e(TAG, "directory list " + blobRef + " has no members key");
return;
}
mEntries.clear();
for (int i = 0; i < members.length(); ++i) {
String entryBlobRef = members.getString(i);
mService.getBlob(entryBlobRef, true, mEntryListener);
Log.d(TAG, "adding directory entry " + entryBlobRef);
HashMap<String, String> entry = new HashMap<String, String>();
entry.put(KEY_TITLE, entryBlobRef);
entry.put(KEY_CONTENT, entryBlobRef);
mEntries.add(entry);
mEntriesByBlobRef.put(entryBlobRef, entry);
}
mAdapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "got IO error while reading directory list " + blobRef, e);
} catch (org.json.JSONException e) {
Log.e(TAG, "unable to parse JSON for directory list " + blobRef, e);
}
}
@Override
public void onBlobDownloadFail(final String blobRef) {
Log.e(TAG, "download failed for directory list " + blobRef);
}
};
private final DownloadService.Listener mEntryListener = new DownloadService.Listener() {
@Override
public void onBlobDownloadComplete(final String blobRef, final InputStream stream) {
try {
HashMap<String, String> entry = mEntriesByBlobRef.get(blobRef);
if (entry == null) {
Log.e(TAG, "got unknown entry " + blobRef);
return;
}
JSONObject object = (JSONObject) new JSONTokener(Util.slurp(stream)).nextValue();
String fileName = object.getString("fileName");
String type = object.getString("camliType");
if (fileName == null || type == null) {
Log.e(TAG, "entry " + blobRef + " is missing filename or type");
return;
}
Log.d(TAG, "updating directory entry " + blobRef + " to " + fileName);
entry.put(KEY_TITLE, fileName);
entry.put(KEY_TYPE, type);
mAdapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "got IO error while reading entry " + blobRef, e);
} catch (org.json.JSONException e) {
Log.e(TAG, "unable to parse JSON for entry " + blobRef, e);
}
}
@Override
public void onBlobDownloadFail(final String blobRef) {
Log.e(TAG, "download failed for entry " + blobRef);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
@ -82,8 +231,8 @@ public class BrowseActivity extends ListActivity
String blobRef = getIntent().getStringExtra(BUNDLE_BLOBREF);
if (blobRef != null && !blobRef.equals(""))
mDirectoryBlobRef = blobRef;
setTitle(mDirectoryBlobRef.equals("") ? getString(R.string.results) : mDirectoryBlobRef);
mBlobRef = blobRef;
setTitle(mBlobRef.equals("") ? getString(R.string.results) : mBlobRef);
Intent serviceIntent = new Intent(this, DownloadService.class);
startService(serviceIntent);
@ -112,159 +261,4 @@ public class BrowseActivity extends ListActivity
intent.putExtra(BUNDLE_BLOBREF, blob.get(KEY_CONTENT));
startActivity(intent);
}
// Implements DownloadService.Listener.
@Override
public void onBlobDownloadComplete(final String blobRef, final InputStream stream) {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
String json = Util.slurp(stream);
Log.d(TAG, "got reply: " + json);
if (blobRef.equals("search")) {
parseSearchResults(json);
} else if (blobRef.equals(mDirectoryBlobRef)) {
parseDirectory(json);
} else if (blobRef.equals(mDirectoryEntriesBlobRef)) {
parseDirectoryEntries(json);
} else if (mEntriesByBlobRef.get(blobRef) != null) {
parseEntry(blobRef, json);
}
} catch (IOException e) {
}
}
});
}
// Implements DownloadService.Listener.
@Override
public void onBlobDownloadFail(final String blobRef) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(BrowseActivity.this, "Download failed.", Toast.LENGTH_SHORT).show();
}
});
}
private boolean parseSearchResults(String json) {
try {
JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
JSONArray array = object.getJSONArray("results");
if (array == null)
return false;
mEntries.clear();
for (int i = 0; i < array.length(); ++i) {
JSONObject jsonBlob = array.getJSONObject(i);
String title = "";
JSONObject jsonAttributes = jsonBlob.getJSONObject("attr");
if (jsonAttributes != null) {
JSONArray jsonTitle = jsonAttributes.getJSONArray("title");
if (jsonTitle != null && jsonTitle.length() > 0)
title = jsonTitle.getString(0);
}
if (title.equals(""))
title = jsonBlob.getString("blobref");
Log.d(TAG, "adding entry " + title);
HashMap<String, String> entry = new HashMap<String, String>();
entry.put(KEY_TITLE, title);
entry.put(KEY_CONTENT, jsonBlob.getString("content"));
mEntries.add(entry);
mEntriesByBlobRef.put(jsonBlob.getString("blobref"), entry);
}
} catch (org.json.JSONException e) {
return false;
}
mAdapter.notifyDataSetChanged();
return true;
}
private boolean parseDirectory(String json) {
try {
JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
String type = object.getString("camliType");
if (type == null || !type.equals("directory"))
return false;
String fileName = object.getString("fileName");
if (fileName == null)
return false;
setTitle(fileName + "/");
String entriesBlobRef = object.getString("entries");
if (entriesBlobRef == null)
return false;
Log.d(TAG, "requesting directory entries " + entriesBlobRef);
mDirectoryEntriesBlobRef = entriesBlobRef;
mService.getBlob(entriesBlobRef, true, BrowseActivity.this);
} catch (org.json.JSONException e) {
return false;
}
return true;
}
private boolean parseDirectoryEntries(String json) {
try {
JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
String type = object.getString("camliType");
if (type == null || !type.equals("static-set"))
return false;
JSONArray members = object.getJSONArray("members");
if (members == null)
return false;
mEntries.clear();
for (int i = 0; i < members.length(); ++i) {
String blobRef = members.getString(i);
mService.getBlob(blobRef, true, BrowseActivity.this);
Log.d(TAG, "adding directory entry " + blobRef);
HashMap<String, String> entry = new HashMap<String, String>();
entry.put(KEY_TITLE, blobRef);
entry.put(KEY_CONTENT, blobRef);
mEntries.add(entry);
mEntriesByBlobRef.put(blobRef, entry);
}
} catch (org.json.JSONException e) {
return false;
}
mAdapter.notifyDataSetChanged();
return true;
}
private boolean parseEntry(String blobRef, String json) {
try {
HashMap<String, String> entry = mEntriesByBlobRef.get(blobRef);
if (entry == null)
return false;
JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
String fileName = object.getString("fileName");
String type = object.getString("camliType");
if (fileName == null || type == null)
return false;
Log.d(TAG, "updating directory entry " + blobRef + " to " + fileName);
entry.put(KEY_TITLE, fileName);
entry.put(KEY_TYPE, type);
} catch (org.json.JSONException e) {
return false;
}
mAdapter.notifyDataSetChanged();
return true;
}
}

View File

@ -20,6 +20,7 @@ import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
@ -44,6 +45,7 @@ public class DownloadService extends Service {
private static final String USERNAME = "TODO-DUMMY-USER";
private final IBinder mBinder = new LocalBinder();
private final Handler mHandler = new Handler();
// Effectively-final objects initialized in onCreate().
private SharedPreferences mSharedPrefs;
@ -120,7 +122,7 @@ public class DownloadService extends Service {
Log.e(TAG,
"got status code " + response.getStatusLine().getStatusCode() +
"while downloading " + mBlobRef);
mListener.onBlobDownloadFail(mBlobRef);
handleFailure();
return;
}
@ -147,11 +149,11 @@ public class DownloadService extends Service {
} catch (ClientProtocolException e) {
Log.e(TAG, "protocol error while downloading " + mBlobRef, e);
mListener.onBlobDownloadFail(mBlobRef);
handleFailure();
return;
} catch (IOException e) {
Log.e(TAG, "IO error while downloading " + mBlobRef, e);
mListener.onBlobDownloadFail(mBlobRef);
handleFailure();
return;
} finally {
if (outputStream != null) {
@ -159,7 +161,24 @@ public class DownloadService extends Service {
}
}
mListener.onBlobDownloadComplete(mBlobRef, resultStream);
// FIXME: In the case of BrowseActivity asking for a schema blob, we should probably
// just return an in-memory copy and write to disk in the background.
final InputStream finalResultStream = resultStream;
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onBlobDownloadComplete(mBlobRef, finalResultStream);
}
});
}
private void handleFailure() {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onBlobDownloadFail(mBlobRef);
}
});
}
}
}