Java tutorial
/** * @author MindSpiker * Encapsulates posting a tweet using twitter4j into a library that allows for * simple posting of tweet text with an image. * * Originally inspired by http://blog.blundell-apps.com/sending-a-tweet/ by Blundell. * This code Uses the the unmodified Twitter4J Library found at http://twitter4j.org by Yusuke Yamamoto * * * To use: * -Project setup: * -Create a twitter app on https://dev.twitter.com/apps/ to get: * -CONSUMER_KEY a public key(string) used to authenticate your app with Twitter.com * -CONSUMER_SECRET a private key(string) used to authenticate your app with Twitter.com * You don't need any thing else so authorization url etc are not important for this process * -Put twitter4j-core-3.0.2.jar and MSTwitter.jar files in your project's libs directory: * -You can download twitter4j from from http://twitter4j.org * -Register the jars in your project build path: Project->Properties->Java Build Path->Libraries->Add Jar * ->select the jar files you just added to your project's libs directory. * -Make AndroidManifest.xml modifications * -Add <uses-permission android:name="android.permission.INTERNET" /> inside manifest section (<manifest>here</manifest>) * -Add <uses-permission android:name="com.mindspiker.mstwitter.MSTwitterService" /> inside manifest section * -Add <uses-permission android:name="android.permission.BROADCAST_STICKY" /> inside manifest section * -Add <activity android:name="com.mindspiker.mstwitter.MSTwitterAuthorizer" /> inside application section. * -Add <service android:name="com.mindspiker.mstwitter.MSTwitterService" /> inside application section. * * -Code to add to you calling activity * -Define a module MSTwitter variable. * -In onCreate() allocate a module level MSTwitter variable * ex: mMTwitter = new MSTWitter(args);] * -Add code to catch response from MSTwitterAuthorizer in your activity's onActivityResult() ex: * @Override * protected void onActivityResult(int requestCode, int resultCode, Intent data){ * mMSTwitter.onCallingActivityResult(requestCode, resultCode, data); * } * -Call startTweet(String text, String imagePath) on your MSTwitter object instance. * if you image is held in memory and not saved to disk call MSTwitter.putBitmapInDiskCache() * to save to a temporary file on disk. * -(Optional) Add a MSTwitterResultReceiver to catch MSTwitter events which are * fired at various stages of the process. * MSTwitterResultReceiver events: * -MSTWEET_STATUS_AUTHORIZING the app is not authorized and the authorization process is * starting. * -MSTWEET_STATUS_STARTING the app is authorized and sending the tweet text and image is * starting. * -MSTWEET_STATUS_FINSIHED_SUCCCESS the tweet is done and was successful. * -MSTWEET_STATUS_FINSIHED_FAILED the tweet is done and failed to complete. * * * Notes: * -If your project compiles but crashes when any twwiter4j object is instantiated a possible * cause may be trying to add the jars as external jars instead of the suggested method above. * If your libraries directory already exists but is called 'lib', change the name to 'libs'. * Sounds crazy I know, but works in some situations. * -To prevent large images from being passed around between intents images should be * cached to disk and retrieved when used. Only the file name is passed between intents. * -To perform tasks on a separate thread that passes information to and from activities, * which could be destroyed at any time (phone call, screen orientation change, etc.), * a method using intent services to perform the work and sticky broadcasts to pass the * data was employed. For more on this method and why it was used check out: * http://stackoverflow.com/questions/1111980/how-to-handle-screen-orientation-change-when-progress-dialog-and-background-thre/8074278#8074278 * * * Copyright 2013 MindSpiker.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.djbrick.twitter_photo_uploader; import java.io.File; import java.io.FileOutputStream; import java.util.UUID; import twitter4j.TwitterFactory; import twitter4j.TwitterException; import twitter4j.auth.AccessToken; import twitter4j.auth.RequestToken; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; /** * Encapsulates posting a tweet using twitter4j. * @author MindSpiker */ public class MSTwitter { protected static final String INTENT_BROADCAST_MSTWITTER = "com.mindspiker.MSTwitter.broadcast"; /** used to detect twitter result in onActivityResult from MSTwitterAuthorizer */ private static final int REQUEST_TWITTER_AUTH = 544; /** used in log statements */ protected static final String TAG = "MSTwitter"; /** File name of preferences file used to store authentication details */ protected static final String PERF_FILENAME = "MSPerfsFile"; /** Name to store the users access token */ protected static final String PREF_ACCESS_TOKEN = "accessToken"; /** Name to store the users access token secret */ protected static final String PREF_ACCESS_TOKEN_SECRET = "accessTokenSecret"; /** String with last unknown error that resulted from a twitter operation **/ protected static final String PREF_LAST_TWITTER_ERROR = "lastTwitterError"; /** The URL that Twitter will redirect to after a user log's in - this will be picked up by the custom webView */ protected static final String CALLBACK_URL = "com-mindspiker-mstwitter"; /** Tweet Life Cycle events are returned to calling activity via MSTwitterResultReceiver */ /** Tweet life cycle event status: Means app is being authorized */ public static final int MSTWEET_STATUS_AUTHORIZING = 1; /** Tweet life cycle event status: Means app is authorized and tweet is being uploaded */ public static final int MSTWEET_STATUS_STARTING = 2; /** Tweet life cycle event status: Means tweet uploaded successfully */ public static final int MSTWEET_STATUS_FINSIHED_SUCCCESS = 3; /** Tweet life cycle event status: Means tweet unsuccessful */ public static final int MSTWEET_STATUS_FINSIHED_FAILED = 4; /** Consumer Key String from http://dev.twitter.com/apps/ only one per app */ protected static String smConsumerKey; /** Consumer Secret String from http://dev.twitter.com/apps/ only one per app */ protected static String smConsumerSecret; /** Request token signifies the unique ID of the request you are sending to twitter */ protected static RequestToken smReqToken; /** * Sticky broadcasts persist and any prior broadcast will trigger in the * broadcast receiver as soon as it is registered. * To clear any prior broadcast this code sends a blank broadcast to clear * the last sticky broadcast. * This broadcast has no extras it will be ignored in the broadcast receiver */ private static void clearPriorBroadcast(Context context) { Intent broadcastIntent = new Intent(); broadcastIntent.setAction(MSTwitter.INTENT_BROADCAST_MSTWITTER); context.sendStickyBroadcast(broadcastIntent); } /** * Get the access token stored in the shared preferences file * @param context A contect that has access to the shared file * @return */ protected static AccessToken getAccessToken(Context context) { // Create shared preference object to remember if the user has already given us permission SharedPreferences prefs = context.getSharedPreferences(PERF_FILENAME, Context.MODE_PRIVATE); // do we already have an access credentials saved from a previous tweet? if (prefs.contains(PREF_ACCESS_TOKEN) && prefs.contains(PREF_ACCESS_TOKEN_SECRET)) { // set access token using saved token and secret values String token = prefs.getString(PREF_ACCESS_TOKEN, null); String secret = prefs.getString(PREF_ACCESS_TOKEN_SECRET, null); return new AccessToken(token, secret); } else { return null; } } /** * @param context * @return true if this app is authorized to post tweets */ public static boolean authorized(Context context) { AccessToken token = getAccessToken(context); if (token == null) { return false; } else { return true; } } /** * @category Helpers * Write bitmap associated with a url to disk cache * @param context - Context used to get the app cache directory * @param image - Bitmap of file to save * @return String - file path of image saved */ public static String putBitmapInDiskCache(Context context, Bitmap image) { // Create a path pointing to the system-recommended cache dir for the app String filename = "testrgfg.png"; File cacheFile = new File(context.getCacheDir(), filename); try { // Create a file at the file path, and open it for writing obtaining the output stream cacheFile.createNewFile(); FileOutputStream fos = new FileOutputStream(cacheFile); // Write the bitmap to the output stream (and thus the file) // in PNG format (lossless compression) image.compress(CompressFormat.PNG, 1, fos); // Flush and close the output stream fos.flush(); fos.close(); return cacheFile.getPath(); } catch (Exception e) { // Log anything that might go wrong with IO to file Log.e(TAG, "Error when saving image to cache. ", e); return null; } } /** * @category Helpers * @param context - Context used to get the app cache directory * @param filename - filename of the file to open * @return Bitmap - object of the opened file. */ public static Bitmap getBitmap(Context context, String filePath) { File file = new File(filePath); if (file.exists()) { Bitmap outBitmap = BitmapFactory.decodeFile(filePath); return outBitmap; } else { return null; } } /** * Used to receive messages from MSTwitter during the tweet process */ public interface MSTwitterResultReceiver { public void onRecieve(int tweetLifeCycleEvent, String tweetMessage); } /** * Receives boradcast events from MSTwitterService */ protected class MSTwitterSerciceBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle extras = intent.getExtras(); processRecievedEvent(extras); } } //*******************Error handling ************************ /** result codes sent between intents */ protected static final int MST_RESULT_USER_CANCELED = 0, // default MST_RESULT_SUCCESSFUL = 1, MST_RESULT_NOT_AUTHORIZED = 401, MST_RESULT_DUPLICATE_STATUS = 403, MST_RESULT_RATE_LIMITED = 420, MST_RESULT_SERVERS_OVERLOADED = 503, MST_RESULT_TWITTER_NOT_AVALIABLE = 4, MST_RESULT_ACCESS_TOKEN_EXISTS = 5, MST_RESULT_BAD_RESPONSE_FROM_TWITTER = 6, MST_RESULT_NO_PASSED_URL = 7, MST_RESULT_NO_PASSED_OAUTH = 8, MST_RESULT_INVALID_CREDENTIALS = 9, MST_RESULT_ILLEGAL_STATE_TOKEN_ALREADY_AVALIABLE = 10, MST_RESULT_ILLEGAL_STATE_SETOAUTHCONSUMER = 11, MST_RESULT_NO_DATA_TO_SEND = 12, MST_RESULT_UNKNOWN_ERROR = 13; /** * Returns a result text from a result code. * @param resultCode * @return String containing result text. */ protected static String getResultDescription(int resultCode, Context context) { switch (resultCode) { case MST_RESULT_USER_CANCELED: return "Canceled by user or OS."; case MST_RESULT_SUCCESSFUL: return "Success."; case MST_RESULT_NOT_AUTHORIZED: return "Denied by Twitter.com: Unauthorized. 401"; case MST_RESULT_DUPLICATE_STATUS: return "Denied by Twitter.com: duplicate status or update limits. 403"; case MST_RESULT_RATE_LIMITED: return "Denied by Twitter.com: rate limited. Enhance your calm. 420"; case MST_RESULT_SERVERS_OVERLOADED: return "Denied by Twitter.com: Servers overloaded. 503"; case MST_RESULT_TWITTER_NOT_AVALIABLE: return "Twitter service or network is unavailable."; case MST_RESULT_ACCESS_TOKEN_EXISTS: return "Access token is already available."; case MST_RESULT_BAD_RESPONSE_FROM_TWITTER: return "Response from Twitter.com is wrong uri format."; case MST_RESULT_NO_PASSED_URL: return "Twitter authorization url not found."; case MST_RESULT_NO_PASSED_OAUTH: return "Twitter oauth verifier url not found."; case MST_RESULT_INVALID_CREDENTIALS: return "Invalid app credentials: Consumer Key, Consumer Secret, or both."; case MST_RESULT_ILLEGAL_STATE_TOKEN_ALREADY_AVALIABLE: return "Illegal state exception getting request token. Twitter access token already available."; case MST_RESULT_NO_DATA_TO_SEND: return "No data to send."; case MST_RESULT_ILLEGAL_STATE_SETOAUTHCONSUMER: return "Illegal state when setting consumer key and secret. OAuth consumer has already been set, or the instance is using basic authorization."; case MST_RESULT_UNKNOWN_ERROR: default: String lastErrorS = getLastTwitterError(context); if (lastErrorS == null) { return "Unknown error code: " + resultCode; } else { return lastErrorS; } } } /** * Get the last twitter error stored in the shared preferences file * @param context A context that has access to the shared file * @return String in perfs file or null */ protected static String getLastTwitterError(Context context) { // Create shared preference object to remember if the user has already given us permission SharedPreferences prefs = context.getSharedPreferences(PERF_FILENAME, Context.MODE_PRIVATE); // do we already have an access credentials saved from a previous tweet? if (prefs.contains(PREF_LAST_TWITTER_ERROR)) { // set access token using saved token and secret values return prefs.getString(PREF_LAST_TWITTER_ERROR, null); } else { return null; } } /** * Parse result code and message to get twitter error number * @return int with MST_RESULT code. */ protected static int getTwitterErrorNum(TwitterException e, Context context) { int errNum = e.getErrorCode(); String errMsg = e.getMessage(); if (errNum != -1) { // get error code from message sent back from twitter String errNumS = e.getMessage().substring(0, 3); Log.d(MSTwitter.TAG, "errNumS=" + errNumS); try { errNum = Integer.parseInt(errNumS); } catch (NumberFormatException nfe) { errNum = -1; } } int outInt = -1; switch (errNum) { case 401: case 403: case 420: case 503: outInt = errNum; break; default: // first see if it is from bad creditentials if (errMsg.equals("Received authentication challenge is null")) { outInt = MST_RESULT_INVALID_CREDENTIALS; } else { // Create shared preference object to remember this error message. SharedPreferences refs = context.getSharedPreferences(MSTwitter.PERF_FILENAME, Context.MODE_PRIVATE); Editor editor = refs.edit(); editor.putString(MSTwitter.PREF_LAST_TWITTER_ERROR, errMsg + "[code:" + e.getErrorCode() + "]"); editor.commit(); outInt = MST_RESULT_UNKNOWN_ERROR; } } Log.e(MSTwitter.TAG, "Tweeter Error: " + e.getMessage()); return outInt; } ////////////////////////non static class starts here ///////////////////////////// private MSTwitterResultReceiver mResultReceiver; private Activity mCallingActivity; private boolean mDoingATweet; private String mText; private String mImagePath; /** * Constructor. Should be placed in onCreate of calling activity. Is OK if this object gets destroyed * and recreated during a tweet. In other words there is no need to pass it around in the * savedInstanceState bundle. * @param activity Calling activity used to perform QUI thread activities, required will throw err if null. * @param consumerKey Required String value provided by https://dev.twitter.com/apps/ * @param consumerSecret Required String value provided by https://dev.twitter.com/apps/ * @param resultReceiver For receiving a result message when task is finished. Can be null if you don't want to receive events. * @throws IllegalArgumentException */ public MSTwitter(Activity activity, String consumerKey, String consumerSecret, MSTwitterResultReceiver resultReceiver) throws IllegalArgumentException { if (activity == null) { IllegalArgumentException e = new IllegalArgumentException("Context required. Cannot be null."); throw e; } if (consumerKey == null) { IllegalArgumentException e = new IllegalArgumentException("Consumer Key required. Cannot be null."); throw e; } if (consumerSecret == null) { IllegalArgumentException e = new IllegalArgumentException("Consumer Secret required. Cannot be null."); throw e; } // save passed in vars to module level vars mCallingActivity = activity; smConsumerKey = consumerKey; smConsumerSecret = consumerSecret; mResultReceiver = resultReceiver; // setup a broadcast receiver to receive update events from the twitter upload process clearPriorBroadcast(mCallingActivity); IntentFilter filter = new IntentFilter(); filter.addAction(MSTwitter.INTENT_BROADCAST_MSTWITTER); mCallingActivity.registerReceiver(new MSTwitterSerciceBroadcastReceiver(), filter); // init object module variables; mDoingATweet = false; mText = null; mImagePath = null; } /** * Kicks off a tweet by first trying to get authorized then sending the tweet itself * If not authorized will first call a service to get the oAuthAccesstoken from twitter.com * then will display the twitter.com authorization page on the gui thread, finally will * communicate back to twitter.com to create the authorization token completing the * authorization process. Whew! * If is authorized or after authorization then will call a service to send the tweet. * Authorized or not a result event will fire when the process is finished * in the resultReceiver passed in on MSTwitter object creation unless it is null. * @param text Text to tweet * @param imagePath File path to an image to attach to the tweet. */ public void startTweet(String text, String imagePath) { // only do one tweet at time. if (mDoingATweet) { return; } mDoingATweet = true; // check if there is not data to send if (text == null && imagePath == null) { // send message back to receiver if (mResultReceiver != null) { mResultReceiver.onRecieve(MSTWEET_STATUS_FINSIHED_FAILED, "No data to send."); } } mText = text; mImagePath = imagePath; // first see if we are authorized to send if (MSTwitter.authorized(mCallingActivity)) { // this event will terminate in UploadBroadcastReceiver below kickOffTweet(); } else { startAuthorization(); } } /** * Starts tweet by starting MSTwitterService which sends data to twitter.com. * Then displays a user message indicating the tweet has started. * When MSTwitterService is finished a broadcast event is sent and caught in * MSTwitterSerciceBroadcastReceiver(). */ private void kickOffTweet() { // send message back to receiver if (mResultReceiver != null) { mResultReceiver.onRecieve(MSTWEET_STATUS_STARTING, ""); } Intent svc = new Intent(mCallingActivity, MSTwitterService.class); svc.putExtra(MSTwitterService.MST_KEY_SERVICE_TASK, MSTwitterService.MST_SERVICE_TASK_SENDTWEET); svc.putExtra(MSTwitterService.MST_KEY_TWEET_TEXT, mText); svc.putExtra(MSTwitterService.MST_KEY_TWEET_IMAGE_PATH, mImagePath); mCallingActivity.startService(svc); } /** * Authorization takes place in three parts: * Part 1 starts a MSTwitterService to get the RequestToken from twitter.com. * when finished a broadcast event is sent and caught in MSTwitterSerciceBroadcastReceiver(). * The RequestToken is then used to make an authorization url that is * sent to the second Part * Part 2 opens a new activity (MSTwitterAuthorizer) on the calling activity's gui * thread that displays a full screen webView with the URL obtained in part one. * After this webview is closed an event will get caught in onActivityResult() of * the calling activity which needs to call onCallingActivityResult() so MSTwitter * can catch this event. * Part 3 starts MSTWitterSercice again with parameters instructing it to communicate * with twitter.com to get the access token and access secret strings which are then * saved to disk using SharedPreferences interface. When finished a broadcast event * is sent and caught in MSTwitterSerciceBroadcastReceiver(). * At this point the app is authorized and the tweet is started in kickOffTweet() */ private void startAuthorization() { // send message back to receiver if (mResultReceiver != null) { mResultReceiver.onRecieve(MSTWEET_STATUS_AUTHORIZING, ""); } // start part 1, get the authorization url Intent svc = new Intent(mCallingActivity, MSTwitterService.class); svc.putExtra(MSTwitterService.MST_KEY_SERVICE_TASK, MSTwitterService.MST_SERVICE_TASK_GET_AUTH_URL); svc.putExtra(MSTwitterService.MST_KEY_TWEET_TEXT, mText); svc.putExtra(MSTwitterService.MST_KEY_TWEET_IMAGE_PATH, mImagePath); mCallingActivity.startService(svc); } /** * Routes events received broadcast by MSTwitterSercvice object * @param extras */ private void processRecievedEvent(Bundle extras) { if (extras == null) { return; } // exit if no service task if (!extras.containsKey(MSTwitterService.MST_KEY_SERVICE_TASK)) { return; } parseTweetTextAndPath(extras); int task = extras.getInt(MSTwitterService.MST_KEY_SERVICE_TASK); switch (task) { case MSTwitterService.MST_SERVICE_TASK_GET_AUTH_URL: processGetAuthURLResult(extras); break; case MSTwitterService.MST_SERVICE_TASK_MAKE_TOKEN: processMakeTokenResult(extras); break; case MSTwitterService.MST_SERVICE_TASK_SENDTWEET: processSendTweetResult(extras); break; } } /** * Used to parse the tweet text and image path which get passed to and from each task * @param extras */ private void parseTweetTextAndPath(Bundle extras) { mText = null; if (extras.containsKey(MSTwitterService.MST_KEY_TWEET_TEXT)) { mText = extras.getString(MSTwitterService.MST_KEY_TWEET_TEXT); } mImagePath = null; if (extras.containsKey(MSTwitterService.MST_KEY_TWEET_IMAGE_PATH)) { mImagePath = extras.getString(MSTwitterService.MST_KEY_TWEET_IMAGE_PATH); } } /** * End of Part 1 in the authorization process (see startAuthorization() comment.) * Starts Part 2, displaying twitter.com authorization web page. * @param extras Bundle containing the authorization URL */ private void processGetAuthURLResult(Bundle extras) { if (extras.containsKey(MSTwitterService.MST_KEY_AUTHURL_RESULT)) { int authResult = extras.getInt(MSTwitterService.MST_KEY_AUTHURL_RESULT); // see if auth was successful if (authResult == MST_RESULT_SUCCESSFUL) { // worked so get the url if (extras.containsKey(MSTwitterService.MST_KEY_AUTHURL_RESULT_URL)) { String url = extras.getString(MSTwitterService.MST_KEY_AUTHURL_RESULT_URL); // start the authorizer activity (Part 2 of authorization) Intent intent = new Intent(mCallingActivity, MSTwitterAuthorizer.class); intent.putExtra(MSTwitterAuthorizer.MST_KEY_AUTH_URL, url); intent.putExtra(MSTwitterService.MST_KEY_TWEET_TEXT, mText); intent.putExtra(MSTwitterService.MST_KEY_TWEET_IMAGE_PATH, mImagePath); mCallingActivity.startActivityForResult(intent, REQUEST_TWITTER_AUTH); } else { // should never happen finishTweet(false, "No url returned from auth token."); } } else { String resultDesc = getResultDescription(authResult, mCallingActivity); finishTweet(false, resultDesc); } } } /** * End of part 2 in the authorization process (see startAuthorization() comment.) * Needs to be called from the calling activity's onActivityResult() function * for authorization to complete. * @param requestCode * @param resultCode * @param data */ public void onCallingActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_TWITTER_AUTH) { if (resultCode == MST_RESULT_SUCCESSFUL) { processAuthorizerResponse(data); } else { // something went wrong, finish the tweet attempt String resultDesc = getResultDescription(resultCode, mCallingActivity); finishTweet(false, resultDesc); } } } /** * End of part 2 in the authorization process (see startAuthorization() comment.) * Start part 3 of the authorization process, get the access token. * @param data Intent containing the oauth verifier string */ private void processAuthorizerResponse(Intent data) { // get the oAuth string used to make the access token parts Bundle extras = data.getExtras(); String oAuthVerifier = extras.getString(MSTwitterAuthorizer.MST_KEY_AUTH_OAUTH_VERIFIER); parseTweetTextAndPath(extras); if (oAuthVerifier != null) { // part 3 make the authorization token Intent svc = new Intent(mCallingActivity, MSTwitterService.class); svc.putExtra(MSTwitterService.MST_KEY_SERVICE_TASK, MSTwitterService.MST_SERVICE_TASK_MAKE_TOKEN); svc.putExtra(MSTwitterService.MST_KEY_AUTH_OAUTH_VERIFIER, oAuthVerifier); svc.putExtra(MSTwitterService.MST_KEY_TWEET_TEXT, mText); svc.putExtra(MSTwitterService.MST_KEY_TWEET_IMAGE_PATH, mImagePath); mCallingActivity.startService(svc); } else { finishTweet(false, "No oauth token returned from Twitter authorizer"); } } /** * End of part 3 in the authorization process (see startAuthorization() comment.) * If authorized then kick off the tweet. * @param extras */ private void processMakeTokenResult(Bundle extras) { if (extras.containsKey(MSTwitterService.MST_KEY_MAKE_TOKEN_RESULT)) { int makeTokenResult = extras.getInt(MSTwitterService.MST_KEY_MAKE_TOKEN_RESULT); // see if auth was successful if (makeTokenResult == MST_RESULT_SUCCESSFUL) { // worked so now we can start the tweet kickOffTweet(); } else { String resultDesc = getResultDescription(makeTokenResult, mCallingActivity); finishTweet(false, resultDesc); } } } /** * Process result of sending tweet by assembling data and calling finishTweet() * @param extras Bundle containing tweet result and error description */ private void processSendTweetResult(Bundle extras) { boolean tweetResult = false; String tweetResultDesc = ""; // first check to see if we got a result if (extras.containsKey(MSTwitterService.MST_KEY_SENDTWEET_RESULT)) { // get the data int tweetResultCode = extras.getInt(MSTwitterService.MST_KEY_SENDTWEET_RESULT); if (tweetResultCode == MST_RESULT_SUCCESSFUL) { tweetResult = true; } else { tweetResultDesc = getResultDescription(tweetResultCode, mCallingActivity); } } finishTweet(tweetResult, tweetResultDesc); } public static void clearCredentials(Context context) { SharedPreferences prefs = context.getSharedPreferences(PERF_FILENAME, Context.MODE_PRIVATE); final Editor edit = prefs.edit(); edit.remove(PREF_ACCESS_TOKEN); edit.remove(PREF_ACCESS_TOKEN_SECRET); edit.commit(); } /** * Called when tweet if finished. Sends result to receiver if one is available * @param tweetResult True if tweet was successful * @param tweetResultDesc Description of what went wrong if tweet was unsuccessful */ private void finishTweet(boolean tweetResult, String tweetResultDesc) { int tweetLifeCycleEvent = MSTWEET_STATUS_FINSIHED_SUCCCESS; // start with optimism if (!tweetResult) { tweetLifeCycleEvent = MSTWEET_STATUS_FINSIHED_FAILED; } // send back to receiver if (mResultReceiver != null) { mResultReceiver.onRecieve(tweetLifeCycleEvent, tweetResultDesc); } // indicate that tweet is finished. mDoingATweet = false; } }