Check progress for Upload (Google GMail API for Android) - android

I'm getting frustrated trying to get information about the progress of my asynctask while inserting a mail through Gmail Api for Android.
I'm trying to use the MediaHttpUploaderProgressListener but the problem is that i just get null out of the getMediaHttpUploader() method of the insert.
I think i'm missing something big in the middle to get the expected response out of the getMediaHttpUploader...
This is my code:
private class TareaGestionEnvioMails extends AsyncTask<Void, Void, Message> {
#Override
protected Message doInBackground(Void... params) {
try {
if (mensaje != null) {
String user = "me";
Gmail.Users.Messages.Insert insert = servicioGmail.users().messages().insert(user, mensaje);
MediaHttpUploader uploader = insert.getMediaHttpUploader();
//getMediaHttpUploader returns me null value :(
uploader.setDirectUploadEnabled(false);
uploader.setChunkSize(1024*256);
uploader.setProgressListener(new FileUploadProgressListener());
mensaje = insert.execute();
}
return mensaje;
} catch (Exception e) {
mLastError = e;
cancel(true);
return null;
}
}
...
private class FileUploadProgressListener implements MediaHttpUploaderProgressListener {
public FileUploadProgressListener() {
}
#Override
public void progressChanged(MediaHttpUploader mediaHttpUploader) throws IOException {
if (mediaHttpUploader == null) return;
switch (mediaHttpUploader.getUploadState()) {
case INITIATION_STARTED:
pantallaPrincipal.onProgresoEnviarMail(0.0, "INITIATION_STARTED");
break;
case INITIATION_COMPLETE:
pantallaPrincipal.onProgresoEnviarMail(0.0, "INITIATION_COMPLETE");
break;
case MEDIA_IN_PROGRESS:
double percent = mediaHttpUploader.getProgress() * 100;
pantallaPrincipal.onProgresoEnviarMail(percent, "MEDIA_IN_PROGRESS");
break;
case MEDIA_COMPLETE:
pantallaPrincipal.onProgresoEnviarMail(100.0, "MEDIA_COMPLETE");
}
}
}
Thanks Everyone! This is my first time posting on Stackoverflow!

Solved!!!!
You have to use the three parameter version of the insert() method. I've filled the third parameter with my MimeMessage this way:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
myMimeMessage.writeTo(baos);
AbstractInputStreamContent mediaContent = new ByteArrayContent("message/rfc822", baos.toByteArray());
Gmail.Users.Messages.Insert insert = servicioGmail.users().messages().insert(user, null, mediaContent);
There are two things you have to be aware of:
1) If you keep using the "Message" and the "AbstractInputStreamContent" parameters both at the same time, you will be happy with little messages... But if you have to upload a message bigger than around 1mb, you will get a horrible 400 Bad_Request exception with a "Request too large" error. So, leave the Message parameter null.
2) Leaving the "Message" parameter null, you can't set the Label of the message... so you will have to fill it later using users().messages().modify method.
If anyone have a nicer workaround to insert a big mail and it's label at the same time, and having a feedback of the progress, please comment! Thanks!

Related

Waiting for AsyncTask postExecute to continue

I am pretty new with the concept of asynctask and i have an asynctask that gets me a json from an api with parameter an then(postexecute) puts the content inside textviews to be shown(they are set visible after setting the text), the thing is i am trying to validate that the json isnt actually empty, and with my code i actually do that, but if the parameter i use is correct, the validation still detects that its empty, if i try to get it again(by pressing the button that triggers the asynctask) after 2 or three tries it will actually get it tho, i think its because i am doing it on the background, here is the asynctask
private class ConsultarDatos extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// params comes from the execute() call: params[0] is the url.
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
//working=false;
} catch (JSONException e) {
e.printStackTrace();
}
}
}
and here is what i am trying to do
btnGenerar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new ConsultarDatos().execute("https://api-adress/file.php?DNI=" + etDNI.getText().toString());
//while(working)
//{
//}
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
});
as i commented i tried to do a while that would wait until the textsviews are all set but that just crashed my app
I resolved it, just moved the the visibility set and validation to the end of the onPostExecute and just to be sure i put the toast in the exception too just so the user gets some feedback
protected void onPostExecute(String result) {
JSONArray ja = null;
try {
ja = new JSONArray(result);
txtNombre.setText(ja.getString(0) +" " + ja.getString(1));
txtCategoria.setText(ja.getString(2));
txtDNI.setText(ja.getString(3));
txtEstado.setText(ja.getString(4));
if (txtCategoria.getText()!="") {
btnGenerar.setVisibility(View.INVISIBLE);
etDNI.setVisibility(View.INVISIBLE);
txtCategoria.setVisibility(View.VISIBLE);
txtDNI.setVisibility(View.VISIBLE);
txtEstado.setVisibility(View.VISIBLE);
txtNombre.setVisibility(View.VISIBLE);
imgTarjeta.setVisibility(View.VISIBLE);
}
else
{
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"DNI Incorrecto",Toast.LENGTH_LONG).show();
}
}
Use something like https://www.getpostman.com/ to see what the result of your API call is. Right now it seems like you don't know what you're getting back, and how consistently it comes back. You need to validate that your server is sending you back valid data.
Using a json library to parse the JSON response, such as GSON or Moshi would help you out as well. Right now you're trying to get the values based on arbitrary numbers. You could be having an exception from just one field missing, but there's not enough info to tell. Gson is fairly easy to set up in my experience: https://github.com/google/gson

data not passing when running doInBackground method within for loop

I have some pics to upload to the ftp server and I am using Asynctask for it.The images need to be sent to multiple host so I am using a for loop.The data to be passed is very well being fetched by the constructor but the doInBackground method is not running which was earlier running very well without the for loop and the additional data apart from the String filePathName that I am trying to pass in now in doInBackground.please help me
class uploadTask extends AsyncTask<String, Void, String> {
public uploadTask(String filePathName,String host_2,String user_2,String pass_2)
{
filePath=filePathName;
host_1=host_2;
user_1=user_2;
pass_1=pass_2;
Toast.makeText(getBaseContext(),"FTP DATA RECEIVING:"+"HOST:"+host_2+" USERNAME:"+user_2+" PASS:"+pass_2,Toast.LENGTH_LONG).show();
//hostName=host;
}
#Override
protected String doInBackground(String... params) {
try {
Toast.makeText(getBaseContext(),"Entered Do in Background Method to upload",Toast.LENGTH_SHORT).show();
ftp_host = "ftp.photoshelter.com";//This is not the correct way. Supposed to get from Backendless table
ftp_username = "brytest";//This is not the correct way. Supposed to get from Backendless table
ftp_password = "passtest";//This is not the correct way. Supposed to get from Backendless table
Toast.makeText(getBaseContext(),"HOST:"+ftp_host+" USERNAME:"+ftp_username+" PASS:"+ftp_password,Toast.LENGTH_LONG).show();
news_agency = "news agency";
easyFTP ftp = new easyFTP();
ftp.connect(ftp_host, ftp_username, ftp_password);
status = ftp.setWorkingDirectory("mem/images"); // if User say provided any Destination then Set it , otherwise
// Upload will be stored on Default /root level on server
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageTimeStamped = ftp_username + "_" + timeStamp + ".png";
FileInputStream is = new FileInputStream(imageFileLocation);
//addPhotoGrapherInfo();
ftp.uploadFile(is, imageTimeStamped);
System.out.println("Successfull ftp upload to " + ftp_host);
Toast.makeText(getBaseContext(), "Photo uploading by ftp to " + ftp_host, Toast.LENGTH_LONG).show();
//}
//reset booleans
//cameraPicTaken = false;
//galleryImageSelected = false;
//System.out.println("reset cameraPicTaken and galleryImageSelected");
// }
return new String("Upload Successful");
}catch (Exception e){
String t="Failure : " + e.getLocalizedMessage();
return t;
}
}
}
my onClickListener with for loop
if(cameraPicTaken || galleryImageSelected) {
Toast.makeText(SubmitActivity.this,"Image Location is:"+ imageFileLocation,Toast.LENGTH_LONG).show();
//addPhotoGrapherInfo();
for(int i=0;i<Common.selectedHostArray.size();i++) {
uploadFile(imageFileLocation,Common.selectedHostArray.get(i),Common.selectedUsernameArray.get(i),Common.selectedPasswordArray.get(i));
}
cameraPicTaken = false;
galleryImageSelected = false;
}
funnction called in onClick
public void uploadFile(String filePath,String host_1,String user_1,String pass_1)
{
if(cameraPicTaken == true) {
System.out.println("camera photo start upload");
//for(int i=0;i<Common.selectedHostArray.size();i++) {
//host_1=Common.selectedHostArray.get(i);
//user_1=Common.selectedUsernameArray.get(i);
//pass_1=Common.selectedPasswordArray.get(i);
//host_1="ftp.photoshelter.com";
//user_1="brytest";
//pass_1="passtest";
Toast.makeText(getBaseContext(),"FTP DATA PASSING:"+"HOST:"+host_1+" USERNAME:"+user_1+" PASS:"+pass_1,Toast.LENGTH_LONG).show();
new uploadTask(filePath,host_1,user_1,pass_1).execute();
// }
//cameraPicTaken = false;
//galleryImageSelected = false;
System.out.println("reset cameraPicTaken and galleryImageSelected");
//cameraPicTaken = false;
}
if(galleryImageSelected == true){
System.out.println("gallery image start upload");
Toast.makeText(getBaseContext(),"FTP DATA PASSING:"+"HOST:"+host_1+" USERNAME:"+user_1+" PASS:"+pass_1,Toast.LENGTH_LONG).show();
new uploadTask(filePath,host_1,user_1,pass_1).execute();
//new uploadTask(filePat)h.execute();
//galleryImageSelected = false;
}
Toast.makeText(getBaseContext(), "Photo uploading by ftp to photoshelter.com" /*+ news_agency*/, Toast.LENGTH_LONG).show();
}
You're trying to perform a UI command on a background thread (Toast). This is causing your background tasks to fail early. Since your background tasks catch their own errors, they fail silently.
#Override
protected String doInBackground(String... params) {
try {
// you can't Toast on a background thread, this should throw an exception
Toast.makeText(getBaseContext(),"Entered Do in Background Method to upload",Toast.LENGTH_SHORT).show();
...
}catch (Exception e){
// your Toast exception is getting caught silently here
String t="Failure : " + e.getLocalizedMessage();
return t;
}
}
By the way, the try/catch on everything is not a good practice. You end up with a ton of silent failures leaving you scratching your head and asking why things aren't working.

unity (c#) in facebook, how to post to friends wall? how to get FBResult values?

I succeed login and post my wall.
FB.API("me/photos", Facebook.HttpMethod.POST, Callback, wwwForm);// it works well.
FB.Feed("", "link", "link_name", ~~bulabula~~ );// it works well, too!
//////////////AND PLEASE SEE NEXT CODE. THIS IS PROBLEM.///////////////////
private string FriendSelectorTitle = "Share it with your friends!";
private string FriendSelectorMessage = "invite";
private string FriendSelectorFilters = "[\"all\"]";
private string FriendSelectorData = "{data}";
private string FriendSelectorExcludeIds = "";
private string FriendSelectorMax = "5";
private void CallAppRequestAsFriendSelector()
{
// If there's a Max Recipients specified, include it
int? maxRecipients = null;
if (FriendSelectorMax != "")
{
try
{
maxRecipients = Int32.Parse(FriendSelectorMax);
}
catch (Exception e)
{
//status = e.Message;
Debug.Log(e.Message);
}
}
// include the exclude ids
string[] excludeIds = (FriendSelectorExcludeIds == "") ? null : FriendSelectorExcludeIds.Split(',');
List<object> FriendSelectorFiltersArr = null;
if (!String.IsNullOrEmpty(FriendSelectorFilters))
{
try
{
FriendSelectorFiltersArr = Facebook.MiniJSON.Json.Deserialize(FriendSelectorFilters) as List<object>;
}
catch
{
throw new Exception("JSON Parse error");
}
}
FB.AppRequest(
FriendSelectorMessage,
null,
FriendSelectorFiltersArr,
excludeIds,
maxRecipients,
FriendSelectorData,
FriendSelectorTitle,
Callback
);
}
void Callback(FBResult result)
{
Debug.Log(result.Text);
}
/////////////////////////////////////////////////
it look like works well.
first, pop up friends selector dialog,
and I clicked some friends, and click 'done' button.
it will call 'Callback' Funtion, and
debug.log(FBResult.text); show follow like this.
{"request":"8939391818800568","to":["2446462595631736"],["189238719238719238"]}
but now, I don't know how to use these values. T_T
I think FB.feed(); is well done. So,
I try to
for( int i=0; i<usernum; i++ )
{
FB.feed( "id[user_index]" , bula~bula );
}
but failed.
becuase, fbresult.text is not string!!?
I try to split this string(fbresult.text), to get "to":["userid1 number"], ["userid2 number"]
but I failed and disappointed.
please someone help me.
Anybody who has a good idea???
I really want to send my message(pic or message) to friend's facebook wall.
You canĀ“t post to the wall of a friend anymore, since a very long time. In most (all?) cases this would be considered as spam, so they remove that possibility.
You can use the Send Dialog to send something to a friend, for example.

Android Google+ integration - repeated UserRecoverableAuthException

We have contacted Google about this and we are on chat
The issue seems to be fixed for devices except Samsung phones.
I'm adding a Google+ sign in option to an app per the official instructions. Once the user has selected their account I would like my server to retrieve their Google+ profile info and update their profile on our site to match.
The first part - having the user select a Google account locally - seems to work just fine. When I try to request a token for the selected account, the Google auth dialog displays with the appropriate parameters; however, when I authorize the app using that dialog and re-request the token, GoogleAuthUtil.getToken(...) again throws a UserRecoverableAuthException (NeedPermission, not GooglePlayServicesAvailabilityException) and I get the same dialog asking me to approve!
This behavior is present on a Samsung S3 running Android 4.1.1 (with 3 Google accounts) and an Acer A100 running 4.0.3. It is NOT present on an HTC Glacier running 2.3.4. Instead, the HTC Glacier gives me a valid auth code. All devices have the latest iteration of Google Play Services installed and are using different Google+ accounts.
Anyone seen this before? Where can I start with debugging?
Here's the complete code - is anything obviously awry?
public class MyGooglePlusClient {
private static final String LOG_TAG = "GPlus";
private static final String SCOPES_LOGIN = Scopes.PLUS_LOGIN + " " + Scopes.PLUS_PROFILE;
private static final String ACTIVITIES_LOGIN = "http://schemas.google.com/AddActivity";
private static MyGooglePlusClient myGPlus = null;
private BaseActivity mRequestingActivity = null;
private String mSelectedAccount = null;
/**
* Get the GPlus singleton
* #return GPlus
*/
public synchronized static MyGooglePlusClient getInstance() {
if (myGPlus == null)
myGPlus = new MyGooglePlusClient();
return myGPlus;
}
public boolean login(BaseActivity requester) {
Log.w(LOG_TAG, "Starting login...");
if (mRequestingActivity != null) {
Log.w(LOG_TAG, "Login attempt already in progress.");
return false; // Cannot launch a new request; already in progress
}
mRequestingActivity = requester;
if (mSelectedAccount == null) {
Intent intent = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, false,
null, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE, null, null);
mRequestingActivity.startActivityForResult(intent, BaseActivity.REQUEST_GPLUS_SELECT);
}
return true;
}
public void loginCallback(String accountName) {
mSelectedAccount = accountName;
authorizeCallback();
}
public void logout() {
Log.w(LOG_TAG, "Logging out...");
mSelectedAccount = null;
}
public void authorizeCallback() {
Log.w(LOG_TAG, "User authorized");
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String token = null;
try {
Bundle b = new Bundle();
b.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES, ACTIVITIES_LOGIN);
token = GoogleAuthUtil.getToken(mRequestingActivity,
mSelectedAccount,
"oauth2:server:client_id:"+Constants.GOOGLE_PLUS_SERVER_OAUTH_CLIENT
+":api_scope:" + SCOPES_LOGIN,
b);
} catch (IOException transientEx) {
// Network or server error, try later
Log.w(LOG_TAG, transientEx.toString());
onCompletedLoginAttempt(false);
} catch (GooglePlayServicesAvailabilityException e) {
Log.w(LOG_TAG, "Google Play services not available.");
Intent recover = e.getIntent();
mRequestingActivity.startActivityForResult(recover, BaseActivity.REQUEST_GPLUS_AUTHORIZE);
} catch (UserRecoverableAuthException e) {
// Recover (with e.getIntent())
Log.w(LOG_TAG, "User must approve "+e.toString());
Intent recover = e.getIntent();
mRequestingActivity.startActivityForResult(recover, BaseActivity.REQUEST_GPLUS_AUTHORIZE);
} catch (GoogleAuthException authEx) {
// The call is not ever expected to succeed
Log.w(LOG_TAG, authEx.toString());
onCompletedLoginAttempt(false);
}
Log.w(LOG_TAG, "Finished with task; token is "+token);
if (token != null) {
authorizeCallback(token);
}
return token;
}
};
task.execute();
}
public void authorizeCallback(String token) {
Log.w(LOG_TAG, "Token obtained: "+token);
// <snipped - do some more stuff involving connecting to the server and resetting the state locally>
}
public void onCompletedLoginAttempt(boolean success) {
Log.w(LOG_TAG, "Login attempt "+(success ? "succeeded" : "failed"));
mRequestingActivity.hideProgressDialog();
mRequestingActivity = null;
}
}
I've had this issue for a while and came up with a proper solution.
String token = GoogleAuthUtil.getToken(this, accountName, scopeString, appActivities);
This line will either return the one time token or will trigger the UserRecoverableAuthException.
On the Google Plus Sign In guide, it says to open the proper recovery activity.
startActivityForResult(e.getIntent(), RECOVERABLE_REQUEST_CODE);
When the activity returns with the result, it will come back with few extras in the intent and that is where the new token resides :
#Override
protected void onActivityResult(int requestCode, int responseCode, Intent intent) {
if (requestCode == RECOVERABLE_REQUEST_CODE && responseCode == RESULT_OK) {
Bundle extra = intent.getExtras();
String oneTimeToken = extra.getString("authtoken");
}
}
With the new oneTimeToken given from the extra, you can submit to the server to connect properly.
I hope this helps!
Its too late to reply but it may help to people having same concern in future.
They have mentioned in the tutorial that it will always throw UserRecoverableAuthException
when you invoke GoogleAuthUtil.getToken() for the first time. Second time it will succeed.
catch (UserRecoverableAuthException e) {
// Requesting an authorization code will always throw
// UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
// because the user must consent to offline access to their data. After
// consent is granted control is returned to your activity in onActivityResult
// and the second call to GoogleAuthUtil.getToken will succeed.
startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
return;
}
i used below code to get access code from google.
execute this new GetAuthTokenFromGoogle().execute(); once from public void onConnected(Bundle connectionHint) and once from protected void onActivityResult(int requestCode, int responseCode, Intent intent)
private class GetAuthTokenFromGoogle extends AsyncTask<Void, Integer, Void>{
#Override
protected void onPreExecute()
{
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
accessCode = GoogleAuthUtil.getToken(mContext, Plus.AccountApi.getAccountName(mGoogleApiClient), SCOPE);
new ValidateTokenWithPhoneOmega().execute();
Log.d("Token -- ", accessCode);
} catch (IOException transientEx) {
// network or server error, the call is expected to succeed if you try again later.
// Don't attempt to call again immediately - the request is likely to
// fail, you'll hit quotas or back-off.
return null;
} catch (UserRecoverableAuthException e) {
// Recover
startActivityForResult(e.getIntent(), RC_ACCESS_CODE);
e.printStackTrace();
} catch (GoogleAuthException authEx) {
// Failure. The call is not expected to ever succeed so it should not be
// retried.
authEx.printStackTrace();
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
}
}
I have got around this issue by using a web based login. I open a url like this
String url = "https://accounts.google.com/o/oauth2/auth?scope=" + Scopes.PLUS_LOGIN + "&client_id=" + webLoginClientId + "&response_type=code&access_type=offline&approval_prompt=force&redirect_uri=" + redirect;
The redirect url then handles the response and returns to my app.
In terms of my findings on using the Google Play Services, I've found:
HTC One is 3.1.59 (736673-30) - not working
Galaxy Note is 3.1.59 (736673-36) - not working
Nexus S is 3.1.59 (736673-34) - works
And I'd like to be involved in the chat that is occurring, however I don't have a high enough reputation to do so.
I've experienced the same issue recently - it appears to be device-specific (I had it happen every time on one S3, but on another S3 running the same OS it didn't happen, even with the same account). My hunch is that it's a bug in a client app, either the G+ app or the Google Play Services app. I managed to solve the issue on one of my devices by factory resetting it (a Motorola Defy), then reinstalling the Google Play Services app, but that's a completely useless solution to tell to users.
Edit (6th Aug 2013): This seems to have been fixed for me without any changes to my code.
The first potential issue I can see is that you are calling GoogleAuthUtil.getToken() after you get the onConnected() callback. This is a problem because requesting an authorization code for your server using GoogleAuthUtil.getToken() will always show a consent screen to your users. So you should only get an authorization code for new users and, to avoid showing new users two consent screens, you must fetch an authorization code and exchange it on your server before resolving any connection failures from PlusClient.
Secondly, make sure you actually need both a PlusClient and an authorization code for your servers. You only need to get a PlusClient and an authorization code if you are intending to make calls to the Google APIs from both the Android client and your server. As explained in this answer.
These issues would only result in two consent dialogs being displayed (which is clearly not an endless loop) - are you seeing more than two consent dialogs?
I had a similar problem where an apparent auth loop kept creating {read: spamming} these "Signing In..." and Permission request dialogs while also giving out the discussed exception repeatedly.
The problem appears in some slightly-modified example code that I (and other like me, I suspect) "cargo-culted" from AndroidHive. The solution that worked for me was ensuring that only one background token-retrieval task runs at the background at any given time.
To make my code easier to follow, here's the auth flow in my app (that is almost identical to the example code on AndoidHive): Activity -> onConnected(...) -> getProfileInformation() -> getOneTimeToken().
Here's where getOneTimeToken() is called:
private void getProfileInformation() {
try {
if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null) {
Person currentPerson = Plus.PeopleApi
.getCurrentPerson(mGoogleApiClient);
String personName = currentPerson.getDisplayName();
String personPhotoUrl = currentPerson.getImage().getUrl();
String personGooglePlusProfile = currentPerson.getUrl();
String email = Plus.AccountApi.getAccountName(mGoogleApiClient);
getOneTimeToken(); // <-------
...
Here's my getOneTimeToken():
private void getOneTimeToken(){
if (task==null){
task = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
LogHelper.log('d',LOGTAG, "Executing background task....");
Bundle appActivities = new Bundle();
appActivities.putString(
GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES,
ACTIVITIES_LOGIN);
String scopes = "oauth2:server" +
":client_id:" + SERVER_CLIENT_ID +
":api_scope:" + SCOPES_LOGIN;
String token = null;
try {
token = GoogleAuthUtil.getToken(
ActivityPlus.this,
Plus.AccountApi.getAccountName(mGoogleApiClient),
scopes,
appActivities
);
} catch (IOException transientEx) {
/* Original comment removed*/
LogHelper.log('e',LOGTAG, transientEx.toString());
} catch (UserRecoverableAuthException e) {
/* Original comment removed*/
LogHelper.log('e',LOGTAG, e.toString());
startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST);
} catch (GoogleAuthException authEx) {
/* Original comment removed*/
LogHelper.log('e',LOGTAG, authEx.toString());
} catch (IllegalStateException stateEx){
LogHelper.log('e',LOGTAG, stateEx.toString());
}
LogHelper.log('d',LOGTAG, "Background task finishing....");
return token;
}
#Override
protected void onPostExecute(String token) {
LogHelper.log('i',LOGTAG, "Access token retrieved: " + token);
}
};
}
LogHelper.log('d',LOGTAG, "Task setup successful.");
if(task.getStatus() != AsyncTask.Status.RUNNING){
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); //double safety!
} else
LogHelper.log('d',LOGTAG,
"Attempted to restart task while it is running!");
}
Please note that I have a {probably redundant} double-safety against the task executing multiple times:
if(task .getStatus() != AsyncTask.Status.RUNNING){...} - ensures that the task isn't running before attempting to execute it.
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);- makes sure that copies of this task are "synchronized" (i.e. a queue is in place such that only one task of this type can executed at a given time).
P.S.
Minor clarification: LogHelper.log('e',...) is equivalent to Log.e(...) etc.
you should startactiviy in UI thread
try {
....
} catch (IOException transientEx) {
....
} catch (final UserRecoverableAuthException e) {
....
runOnUiThread(new Runnable() {
public void run() {
startActivityForResult(e1.getIntent(), AUTH_CODE_REQUEST);
}
});
}
Had the same bug with infinite loop of permission request. For me it was because time on my phone was shifted. When I check detect time automatically this bug disappeared. Hope this helps!

How to update tweets using Twitter 4J?

I am using Twitter4J (2.1.0) to try to update tweets. I can't figure out what is wrong with my code.
In particular my problems are:
(a) Not all tweets post successfully. I often get the error code of -1. According to a google group post...
You get code -1 when the internal http component fails to connect to
or read from the API. You may also get code -1 when the API is
unreachable from the JVM due to the DNS related issues.
Strangely I seemed to be getting this pretty much every second post. To deal with this whenever I received the -1 error code I would try to update again. While I realise this is not a very good solution. this fixed the probem 95% of the time
(b) I get a duplication errors (error code 403) whenever the new tweet matches any old tweet
Error code 403 occurs even if the duplicate is now outdated (eg. post "Hello there", post a variety of status updates, then post "Hello there" again throws a TwitterException with error code 403)
My current code...
My code is in an AsyncTask which is in turn in a Service (rather than activity). I have included the Asynctask code and another method below....
class SendTwitAsyncTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
String tokenTwit = params[0];
String tokenSecretTwit = params[1];
String strMessageBody = params[2];
AccessToken aToken = new AccessToken(tokenTwit, tokenSecretTwit);
// initialize Twitter4J
Twitter twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);
twitter.setOAuthAccessToken(aToken);
// create a tweet
// strMessageBody varies
String tweet = strMessageBody;
boolean bool = twitter.isOAuthEnabled();
if (twitter.isOAuthEnabled()) {
GeoLocation geolocation = new GeoLocation(-33.91, 151.25);
try {
twitter.updateStatus(tweet, geolocation);
showNotification("Twitter One" , TWIT_SUCCESS);
} catch (TwitterException te) {
if (te.getStatusCode() == -1) {
//try again
try {
twitter.updateStatus(tweet, geolocation);
showNotification("Twitter Two ", TWIT_SUCCESS);
}
catch (TwitterException tetwo) {
describeTwitException(tetwo.getStatusCode());
}
} //end if
//else exception other than -1
else {
describeTwitException(te.getStatusCode());
} //end else
}// end outer catch
} //end if
else {
showNotification("Unable to authenticate" , TWIT_FAIL);
}//
return null;
}
} //end class SendTwitAsyncTask
public void describeTwitException(int twitExceptionCode) {
switch (twitExceptionCode) {
case (-1):
showNotification("Twitter (unable to connect)", TWIT_FAIL);
break;
case(403):
showNotification("Twitter (duplicate tweet)", TWIT_FAIL);
break;
default:
showNotification("Twitter", TWIT_FAIL);
} //end switch
} //end describeTwitException method
The twitter API will reject any tweet that matches a tweet that you've already made. I don't think the old tweet ever 'expires.'

Categories

Resources