/** * Copyright 2010 Mark Wyszomierski */ package com.joelapenna.foursquared; import com.joelapenna.foursquare.Foursquare; import com.joelapenna.foursquare.error.FoursquareException; import com.joelapenna.foursquare.types.CheckinResult; import com.joelapenna.foursquared.location.LocationUtils; import com.joelapenna.foursquared.util.NotificationsUtil; import com.joelapenna.foursquared.util.RemoteResourceManager; import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.DialogInterface.OnCancelListener; import android.location.Location; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.Window; /** * Can be called to execute a checkin. Should be presented with the transparent * dialog theme to appear only as a progress bar. When execution is complete, a * successful checkin will show an instance of CheckinResultDialog to handle * rendering the CheckinResult response object. A failed checkin will show a * toast with the error message. Ideally we could launch another activity for * rendering the result, but passing the CheckinResult between activities using * the extras data will have to be done when we have more time. * * For the location paramters of the checkin method, this activity will grab the * global last-known best location. * * The activity will setResult(RESULT_OK) if the checkin worked, and will * setResult(RESULT_CANCELED) if it did not work. * * @date March 2, 2010 * @author Mark Wyszomierski (markww@gmail.com). */ public class CheckinExecuteActivity extends Activity { public static final String TAG = "CheckinExecuteActivity"; public static final boolean DEBUG = FoursquaredSettings.DEBUG; public static final String INTENT_EXTRA_VENUE_ID = Foursquared.PACKAGE_NAME + ".CheckinExecuteActivity.INTENT_EXTRA_VENUE_ID"; public static final String INTENT_EXTRA_SHOUT = Foursquared.PACKAGE_NAME + ".CheckinExecuteActivity.INTENT_EXTRA_SHOUT"; public static final String INTENT_EXTRA_TELL_FRIENDS = Foursquared.PACKAGE_NAME + ".CheckinExecuteActivity.INTENT_EXTRA_TELL_FRIENDS"; public static final String INTENT_EXTRA_TELL_FOLLOWERS = Foursquared.PACKAGE_NAME + ".CheckinExecuteActivity.INTENT_EXTRA_TELL_FOLLOWERS"; public static final String INTENT_EXTRA_TELL_TWITTER = Foursquared.PACKAGE_NAME + ".CheckinExecuteActivity.INTENT_EXTRA_TELL_TWITTER"; public static final String INTENT_EXTRA_TELL_FACEBOOK = Foursquared.PACKAGE_NAME + ".CheckinExecuteActivity.INTENT_EXTRA_TELL_FACEBOOK"; private static final int DIALOG_CHECKIN_RESULT = 1; private StateHolder mStateHolder; private ProgressDialog mDlgProgress; private BroadcastReceiver mLoggedOutReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "onReceive: " + intent); finish(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (DEBUG) Log.d(TAG, "onCreate()"); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.checkin_execute_activity); registerReceiver(mLoggedOutReceiver, new IntentFilter(Foursquared.INTENT_ACTION_LOGGED_OUT)); // We start the checkin immediately on creation. Object retained = getLastNonConfigurationInstance(); if (retained != null && retained instanceof StateHolder) { mStateHolder = (StateHolder) retained; mStateHolder.setActivity(this); } else { mStateHolder = new StateHolder(); String venueId = null; if (getIntent().getExtras().containsKey(INTENT_EXTRA_VENUE_ID)) { venueId = getIntent().getExtras().getString(INTENT_EXTRA_VENUE_ID); } else { Log.e(TAG, "CheckinExecuteActivity requires intent extra 'INTENT_EXTRA_VENUE_ID'."); finish(); return; } Foursquared foursquared = (Foursquared) getApplication(); Location location = foursquared.getLastKnownLocation(); mStateHolder.startTask( CheckinExecuteActivity.this, venueId, location, getIntent().getExtras().getString(INTENT_EXTRA_SHOUT), getIntent().getExtras().getBoolean(INTENT_EXTRA_TELL_FRIENDS, false), getIntent().getExtras().getBoolean(INTENT_EXTRA_TELL_FOLLOWERS, false), getIntent().getExtras().getBoolean(INTENT_EXTRA_TELL_TWITTER, false), getIntent().getExtras().getBoolean(INTENT_EXTRA_TELL_FACEBOOK, false) ); } } @Override public Object onRetainNonConfigurationInstance() { mStateHolder.setActivity(null); return mStateHolder; } @Override public void onResume() { super.onResume(); if (mStateHolder.getIsRunning()) { startProgressBar(getResources().getString(R.string.checkin_action_label), getResources().getString(R.string.checkin_execute_activity_progress_bar_message)); } } @Override public void onPause() { super.onPause(); stopProgressBar(); if (isFinishing()) { mStateHolder.cancelTasks(); } } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mLoggedOutReceiver); } private void startProgressBar(String title, String message) { if (mDlgProgress == null) { mDlgProgress = ProgressDialog.show(this, title, message); } mDlgProgress.show(); } private void stopProgressBar() { if (mDlgProgress != null) { mDlgProgress.dismiss(); mDlgProgress = null; } } @Override protected Dialog onCreateDialog(int id) { switch (id) { case DIALOG_CHECKIN_RESULT: // When the user cancels the dialog (by hitting the 'back' key), we // finish this activity. We don't listen to onDismiss() for this // action, because a device rotation will fire onDismiss(), and our // dialog would not be re-displayed after the rotation is complete. CheckinResultDialog dlg = new CheckinResultDialog( this, mStateHolder.getCheckinResult(), ((Foursquared)getApplication())); dlg.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { removeDialog(DIALOG_CHECKIN_RESULT); setResult(Activity.RESULT_OK); finish(); } }); return dlg; } return null; } private void onCheckinComplete(CheckinResult result, Exception ex) { mStateHolder.setIsRunning(false); stopProgressBar(); if (result != null) { mStateHolder.setCheckinResult(result); showDialog(DIALOG_CHECKIN_RESULT); } else { NotificationsUtil.ToastReasonForFailure(this, ex); setResult(Activity.RESULT_CANCELED); finish(); } } private static class CheckinTask extends AsyncTask<Void, Void, CheckinResult> { private CheckinExecuteActivity mActivity; private String mVenueId; private Location mLocation; private String mShout; private boolean mTellFriends; private boolean mTellFollowers; private boolean mTellTwitter; private boolean mTellFacebook; private Exception mReason; public CheckinTask(CheckinExecuteActivity activity, String venueId, Location location, String shout, boolean tellFriends, boolean tellFollowers, boolean tellTwitter, boolean tellFacebook) { mActivity = activity; mVenueId = venueId; mLocation = location; mShout = shout; mTellFriends = tellFriends; mTellFollowers = tellFollowers; mTellTwitter = tellTwitter; mTellFacebook = tellFacebook; } public void setActivity(CheckinExecuteActivity activity) { mActivity = activity; } @Override protected void onPreExecute() { mActivity.startProgressBar(mActivity.getResources().getString( R.string.checkin_action_label), mActivity.getResources().getString( R.string.checkin_execute_activity_progress_bar_message)); } @Override protected CheckinResult doInBackground(Void... params) { try { Foursquared foursquared = (Foursquared) mActivity.getApplication(); Foursquare foursquare = foursquared.getFoursquare(); CheckinResult result = foursquare.checkin( mVenueId, null, // passing in the real venue name causes a 400 response from the server. LocationUtils.createFoursquareLocation(mLocation), mShout, !mTellFriends, // (isPrivate) mTellFollowers, mTellTwitter, mTellFacebook); // Here we should really be downloading the mayor's photo serially, so that this // work is done in the background while the progress bar is already spinning. // When the checkin result dialog pops up, the photo would already be loaded. // We can at least start the request if necessary here in the background thread. if (result != null && result.getMayor() != null && result.getMayor().getUser() != null) { if (result.getMayor() != null && result.getMayor().getUser() != null) { Uri photoUri = Uri.parse(result.getMayor().getUser().getPhoto()); RemoteResourceManager rrm = foursquared.getRemoteResourceManager(); if (rrm.exists(photoUri) == false) { rrm.request(photoUri); } } } return result; } catch (Exception e) { if (DEBUG) Log.d(TAG, "CheckinTask: Exception checking in.", e); mReason = e; } return null; } @Override protected void onPostExecute(CheckinResult result) { if (DEBUG) Log.d(TAG, "CheckinTask: onPostExecute()"); if (mActivity != null) { mActivity.onCheckinComplete(result, mReason); } } @Override protected void onCancelled() { if (mActivity != null) { mActivity.onCheckinComplete(null, new FoursquareException( "Check-in cancelled.")); } } } private static class StateHolder { private CheckinTask mTask; private CheckinResult mCheckinResult; private boolean mIsRunning; public StateHolder() { mCheckinResult = null; mIsRunning = false; } public void startTask(CheckinExecuteActivity activity, String venueId, Location location, String shout, boolean tellFriends, boolean tellFollowers, boolean tellTwitter, boolean tellFacebook) { mIsRunning = true; mTask = new CheckinTask( activity, venueId, location, shout, tellFriends, tellFollowers, tellTwitter, tellFacebook); mTask.execute(); } public void setActivity(CheckinExecuteActivity activity) { if (mTask != null) { mTask.setActivity(activity); } } public boolean getIsRunning() { return mIsRunning; } public void setIsRunning(boolean isRunning) { mIsRunning = isRunning; } public CheckinResult getCheckinResult() { return mCheckinResult; } public void setCheckinResult(CheckinResult result) { mCheckinResult = result; } public void cancelTasks() { if (mTask != null && mIsRunning) { mTask.setActivity(null); mTask.cancel(true); } } } }