package org.ohmage.fragments;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.BaseColumns;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.TextView;
import android.widget.Toast;
import com.commonsware.cwac.wakeful.WakefulIntentService;
import org.ohmage.AccountHelper;
import org.ohmage.R;
import org.ohmage.UserPreferencesHelper;
import org.ohmage.logprobe.Analytics;
import org.ohmage.logprobe.Log;
import org.ohmage.mobility.glue.IMobility;
import org.ohmage.mobility.glue.MobilityInterface;
import org.ohmage.probemanager.DbContract.BaseProbeColumns;
import org.ohmage.probemanager.DbContract.Probes;
import org.ohmage.service.ProbeUploadService;
import org.ohmage.ui.BaseActivity;
public class MobilityControlFragment extends Fragment implements LoaderCallbacks<Cursor> {
private static final String TAG = "MobilityFeedbackActivity";
private static final int RECENT_LOADER = 0;
private static final int ALL_LOADER = 1;
private static final int UPLOAD_LOADER = 2;
private ListView mMobilityList;
private TextView mTotalCountText;
private TextView mUploadCountText;
private TextView mLastUploadText;
private Button mUploadButton;
private RadioButton mOffRadio;
private RadioButton mInterval1Radio;
private RadioButton mInterval5Radio;
private SimpleCursorAdapter mAdapter;
private UserPreferencesHelper mPrefHelper;
private AccountHelper mAccount;
private IMobility mMobility = null;
private boolean isBound = false;
private final String emptyValue = "-";
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mPrefHelper = new UserPreferencesHelper(getActivity());
mAccount = new AccountHelper(getActivity());
setLastUploadTimestamp();
getLoaderManager().initLoader(RECENT_LOADER, null, this);
getLoaderManager().initLoader(ALL_LOADER, null, this);
getLoaderManager().initLoader(UPLOAD_LOADER, null, this);
getActivity().bindService(new Intent(IMobility.class.getName()), mConnection, Context.BIND_AUTO_CREATE);
isBound = true;
}
private void setLastUploadTimestamp() {
long lastMobilityUploadTimestamp = mPrefHelper.getLastProbeUploadTimestamp();
if (lastMobilityUploadTimestamp == 0) {
mLastUploadText.setText(emptyValue);
} else {
mLastUploadText.setText(DateFormat.format("yyyy-MM-dd kk:mm:ss", lastMobilityUploadTimestamp));
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.mobility_control_layout, container, false);
mMobilityList = (ListView) view.findViewById(R.id.mobility_list);
mTotalCountText = (TextView) view.findViewById(R.id.mobility_total);
mUploadCountText = (TextView) view.findViewById(R.id.mobility_count);
mLastUploadText = (TextView) view.findViewById(R.id.last_upload);
mUploadButton = (Button) view.findViewById(R.id.upload_button);
mOffRadio = (RadioButton) view.findViewById(R.id.radio_off);
mInterval1Radio = (RadioButton) view.findViewById(R.id.radio_1min);
mInterval5Radio = (RadioButton) view.findViewById(R.id.radio_5min);
TextView emptyView = (TextView) view.findViewById(R.id.empty);
mMobilityList.setEmptyView(emptyView);
String [] from = new String[] {MobilityInterface.KEY_MODE, MobilityInterface.KEY_TIME};
int [] to = new int[] {R.id.text1, R.id.text2};
mAdapter = new SimpleCursorAdapter(getActivity(), R.layout.mobility_list_item, null, from, to, 0);
mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
switch (view.getId()) {
case R.id.text1:
((TextView)view).setText(cursor.getString(columnIndex));
return true;
case R.id.text2:
long time = cursor.getLong(columnIndex);
((TextView)view).setText(DateFormat.format("h:mmaa", time));
return true;
}
return false;
}
});
mMobilityList.setAdapter(mAdapter);
mTotalCountText.setText(emptyValue);
mUploadCountText.setText(emptyValue);
mOffRadio.setChecked(true);
mUploadButton.setOnClickListener(mUploadListener);
return view;
}
@Override
public void onStart() {
super.onStart();
getActivity().registerReceiver(mMobilityUploadReceiver, new IntentFilter(ProbeUploadService.PROBE_UPLOAD_STARTED));
getActivity().registerReceiver(mMobilityUploadReceiver, new IntentFilter(ProbeUploadService.PROBE_UPLOAD_ERROR));
getActivity().registerReceiver(mMobilityUploadReceiver, new IntentFilter(ProbeUploadService.RESPONSE_UPLOAD_ERROR));
getActivity().registerReceiver(mMobilityUploadReceiver, new IntentFilter(ProbeUploadService.PROBE_UPLOAD_SERVICE_FINISHED));
}
@Override
public void onStop() {
super.onStop();
getActivity().unregisterReceiver(mMobilityUploadReceiver);
}
@Override
public void onDestroy() {
super.onDestroy();
if (isBound) {
getActivity().unbindService(mConnection);
}
}
private final BroadcastReceiver mMobilityUploadReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(getActivity() instanceof BaseActivity)
((BaseActivity) getActivity()).getActionBarControl().setProgressVisible(ProbeUploadService.PROBE_UPLOAD_STARTED.equals(action));
mUploadButton.setEnabled(!ProbeUploadService.PROBE_UPLOAD_STARTED.equals(action));
if (ProbeUploadService.PROBE_UPLOAD_STARTED.equals(action)) {
mUploadButton.setText("Uploading...");
} else if (ProbeUploadService.PROBE_UPLOAD_ERROR.equals(action) || ProbeUploadService.RESPONSE_UPLOAD_ERROR.equals(action)) {
String error = intent.getStringExtra(ProbeUploadService.EXTRA_PROBE_ERROR);
if(error == null)
Toast.makeText(getActivity(), R.string.mobility_network_error_message, Toast.LENGTH_SHORT).show();
else
Toast.makeText(getActivity(), getString(R.string.mobility_upload_error_message, error), Toast.LENGTH_SHORT).show();
} else if (ProbeUploadService.PROBE_UPLOAD_SERVICE_FINISHED.equals(action)) {
mUploadButton.setText("Upload Now");
setLastUploadTimestamp();
}
}
};
private final OnClickListener mUploadListener = new OnClickListener() {
@Override
public void onClick(View v) {
Analytics.widget(v);
Intent intent = new Intent(getActivity(), ProbeUploadService.class);
WakefulIntentService.sendWakefulWork(getActivity(), intent);
}
};
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mMobility = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMobility = IMobility.Stub.asInterface(service);
int interval = -1;
boolean isMobilityOn = false;
try {
isMobilityOn = mMobility.isMobilityOn();
interval = mMobility.getMobilityInterval();
} catch (RemoteException e) {
Log.e(TAG, "Unable to read mobility state", e);
}
if (! isMobilityOn) {
mOffRadio.setChecked(true);
} else if (interval == 60) {
mInterval1Radio.setChecked(true);
} else if (interval == 300) {
mInterval5Radio.setChecked(true);
}
mOffRadio.setOnClickListener(mRadioListener);
mInterval1Radio.setOnClickListener(mRadioListener);
mInterval5Radio.setOnClickListener(mRadioListener);
}
OnClickListener mRadioListener = new OnClickListener() {
@Override
public void onClick(final View v) {
Analytics.widget(v);
// do the update in an asynctask so the UI doesn't block
(new AsyncTask<Void, Void, Void>() {
@Override
protected void onPreExecute() {
mOffRadio.setEnabled(false);
mInterval1Radio.setEnabled(false);
mInterval5Radio.setEnabled(false);
};
@Override
protected Void doInBackground(Void... params) {
int newInterval = -1;
int oldInterval = -1;
switch (v.getId()) {
case R.id.radio_off:
try {
mMobility.stopMobility();
} catch (RemoteException e) {
Log.e(TAG, "Unable to stop mobility", e);
}
return null;
case R.id.radio_1min:
newInterval = 60;
break;
case R.id.radio_5min:
newInterval = 300;
break;
}
try {
oldInterval = mMobility.getMobilityInterval();
if (newInterval != oldInterval) {
mMobility.changeMobilityRate(newInterval);
}
if (! mMobility.isMobilityOn()) {
mMobility.startMobility();
}
} catch (RemoteException e) {
Log.e(TAG, "Unable to change mobility interval", e);
}
return null;
};
@Override
protected void onPostExecute(Void result) {
mOffRadio.setEnabled(true);
mInterval1Radio.setEnabled(true);
mInterval5Radio.setEnabled(true);
};
}).execute();
}
};
};
public interface MobilityQuery {
String[] PROJECTION = {
MobilityInterface.KEY_ROWID,
MobilityInterface.KEY_MODE,
MobilityInterface.KEY_TIME
};
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
long loginTimestamp = mPrefHelper.getLoginTimestamp();
String username = mAccount.getUsername();
// Filters the user by username and login time (in case they just upgraded mobility)
final String filterUser = " (" + MobilityInterface.KEY_USERNAME + "=? OR " + MobilityInterface.KEY_TIME + " > " + loginTimestamp + ") ";
final String[] filterUserParams = new String[] { username };
switch (id) {
case RECENT_LOADER:
return new CursorLoader(getActivity(), MobilityInterface.CONTENT_URI,
MobilityQuery.PROJECTION, MobilityInterface.KEY_TIME
+ " > strftime('%s','now','-20 minutes') AND " + filterUser,
filterUserParams, MobilityInterface.KEY_TIME + " DESC");
case ALL_LOADER:
return new CursorLoader(getActivity(), MobilityInterface.CONTENT_URI,
MobilityQuery.PROJECTION, filterUser, filterUserParams, null);
case UPLOAD_LOADER:
return new CursorLoader(getActivity(), Probes.CONTENT_URI,
new String[] { BaseColumns._ID }, BaseProbeColumns.USERNAME + "=?", new String[] { username }, null);
default:
return null;
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch (loader.getId()) {
case RECENT_LOADER:
mAdapter.swapCursor(data);
break;
case ALL_LOADER:
if(data != null)
mTotalCountText.setText(String.valueOf(data.getCount()));
break;
case UPLOAD_LOADER:
if(data != null)
mUploadCountText.setText(String.valueOf(data.getCount()));
break;
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
switch (loader.getId()) {
case RECENT_LOADER:
mAdapter.swapCursor(null);
break;
case ALL_LOADER:
mTotalCountText.setText(emptyValue);
break;
case UPLOAD_LOADER:
mUploadCountText.setText(emptyValue);
break;
}
}
}