package org.ohmage.fragments;
import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.view.Gravity;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import org.ohmage.R;
import org.ohmage.activity.SubActionClickListener;
import org.ohmage.activity.UploadQueueActivity;
import org.ohmage.adapters.ResponseListCursorAdapter;
import org.ohmage.adapters.UploadingResponseListCursorAdapter;
import org.ohmage.db.DbContract.Campaigns;
import org.ohmage.db.DbContract.Responses;
import org.ohmage.db.DbContract.Surveys;
import org.ohmage.db.DbHelper.Tables;
import org.ohmage.db.DbProvider;
import org.ohmage.db.Models.Response;
import org.ohmage.db.utils.SelectionBuilder;
import org.ohmage.logprobe.Analytics;
import org.ohmage.logprobe.Log;
public class ResponseListFragment extends FilterableListFragment implements SubActionClickListener {
private static final String TAG = "ResponseListFragment";
private ResponseListCursorAdapter mAdapter;
private OnResponseActionListener mListener;
public interface OnResponseActionListener {
public void onResponseActionView(Uri responseUri);
public void onResponseActionUpload(Uri responseUri);
public void onResponseActionError(Uri responseUri, int status);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Set the empty text
setEmptyText(getActivity().getString(R.string.response_list_empty));
// style the empty text, too
TextView emptyView = (TextView)getListView().getEmptyView();
emptyView.setGravity(Gravity.LEFT);
emptyView.setPadding(25, 25, 25, 0);
// We have no menu items to show in action bar.
setHasOptionsMenu(false);
// Create an empty adapter we will use to display the loaded data.
mAdapter = createAdapter();
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
getLoaderManager().initLoader(0, null, this);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnResponseActionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnResponseActionListener");
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Cursor cursor = (Cursor) getListAdapter().getItem(position);
String uuid = cursor.getString(cursor.getColumnIndex(Responses.RESPONSE_UUID));
Analytics.widget(v, null, uuid);
// startActivity(new Intent(Intent.ACTION_VIEW, DbContract.Response.getResponseByID(id)));
mListener.onResponseActionView(Responses.buildResponseUri(id));
}
@Override
public void onSubActionClicked(Uri uri) {
Cursor cursor = null;
try {
cursor = getActivity().getContentResolver().query(uri, new String [] {Tables.RESPONSES + "." + Responses.RESPONSE_STATUS}, null, null, null);
if (cursor.getCount() == 1) {
cursor.moveToFirst();
int status = cursor.getInt(cursor.getColumnIndexOrThrow(Responses.RESPONSE_STATUS));
switch (status) {
case Response.STATUS_STANDBY:
mListener.onResponseActionUpload(uri);
break;
case Response.STATUS_UPLOADED:
case Response.STATUS_DOWNLOADED:
break;
case Response.STATUS_QUEUED:
case Response.STATUS_UPLOADING:
break;
case Response.STATUS_WAITING_FOR_LOCATION:
case Response.STATUS_ERROR_AUTHENTICATION:
case Response.STATUS_ERROR_CAMPAIGN_NO_EXIST:
case Response.STATUS_ERROR_CAMPAIGN_OUT_OF_DATE:
case Response.STATUS_ERROR_CAMPAIGN_STOPPED:
case Response.STATUS_ERROR_INVALID_USER_ROLE:
case Response.STATUS_ERROR_HTTP:
case Response.STATUS_ERROR_OTHER:
mListener.onResponseActionError(uri, status);
break;
default:
//campaign is in some unknown state!
break;
}
} else {
Log.e(TAG, "onSubActionClicked: more than one response read from content provider!");
}
}
finally {
if (cursor != null)
cursor.close();
}
}
public interface ResponseQuery {
String[] PROJECTION = {
Tables.RESPONSES + "." + Responses._ID,
Campaigns.CAMPAIGN_NAME,
Surveys.SURVEY_TITLE,
Responses.RESPONSE_TIME,
Tables.RESPONSES + "." + Responses.RESPONSE_STATUS,
Responses.RESPONSE_UUID
};
}
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
SelectionBuilder selection = new SelectionBuilder();
// Set the campaign filter selection
if(getCampaignUrn() != null)
selection.where(DbProvider.Qualified.RESPONSES_CAMPAIGN_URN + "=?", getCampaignUrn());
// Set the survey filter selection
if(getSurveyId() != null)
selection.where(DbProvider.Qualified.RESPONSES_SURVEY_ID + "=?", getSurveyId());
// Set the date filter selection
if(!ignoreTimeBounds()) {
selection.where(Responses.RESPONSE_TIME + " >= " + getStartBounds());
selection.where(Responses.RESPONSE_TIME + " <= " + getEndBounds());
}
return new CursorLoader(getActivity(), Responses.CONTENT_URI, ResponseQuery.PROJECTION, selection.getSelection(), selection.getSelectionArgs(), Responses.RESPONSE_TIME + " DESC");
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
/**
* Extending fragments can override this method to change the list adapter used. For example, the {@link UploadQueueActivity}
* uses this fragment with the {@link UploadingResponseListCursorAdapter} so it can have the uploading action for the responses
* @return the adapter used in this fragment
*/
protected ResponseListCursorAdapter createAdapter() {
return new ResponseListCursorAdapter(getActivity(), null, 0);
}
/**
* @return true if there should be no time filtering for this type of response fragment
*/
protected boolean ignoreTimeBounds() {
return false;
}
}