Cannot get AuthToken for custom account from different app - android

I have two apps that work with a same account type. I want below page to be shown when the user opens the second app for first time and one account exists:
But nothing happens when I run this code:
final AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(account, authTokenType, null, this, null, null);
new Thread(new Runnable() {
#Override
public void run() {
try {
Bundle bnd = future.getResult();
final String authtoken = bnd.getString(AccountManager.KEY_AUTHTOKEN);
showMessage((authtoken != null) ? "SUCCESS!\ntoken: " + authtoken : "FAIL");
Log.d("udinic", "GetToken Bundle is " + bnd);
} catch (Exception e) {
e.printStackTrace();
showMessage(e.getMessage());
}
}
}).start();
The above code works correctly when I run it from the app that has the authenticator. When I run below code instead, system generates a notification that when I click on it, the above picture appears.
final AccountManagerFuture<Bundle> future = mAccountManager
.getAuthToken(account, authTokenType, null, true,
null, handler);
Clicking allow button returns the AuthToken correctly. However I want to see the grant permission page (above picture) when calling getAuthToken, not by clicking on notification. How can I do that?

I used this method instead of previous one and now I see the confirmation dialog:
accountManager.getAuthToken(account, AUTH_TOKEN_TYPE_FULL_ACCESS, null, true, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bundle = future.getResult();
String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
} catch (OperationCanceledException | IOException | AuthenticatorException e) {
}
}
}, null);
Note that the second app must have different signature. If both apps have a same signature, no confirmation is required and authToken will retrieve.

A few things to go over here. Using a Thread in Android is generally considered bad practice, per Android docs, it is recommended to use a Async task or Handler. Now for the Auth message per Android documentation the expected output is a notification.
getAuthToken(Account account, String authTokenType, Bundle options, boolean notifyAuthFailure, AccountManagerCallback<Bundle> callback, Handler handler)
Gets an auth token of the specified type for a particular account,
optionally raising a notification if the user must enter credentials.
Notice how getAuthToken has a Handler parameter? This would be the preferred method to handle the task async. The issue here is you CAN NOT have a full screen message on a handler thread, because it can't interrupt the UI thread. In your first example you actually call call mAccountManager on the UI thread, so it allows it to take over the UI and send a full screen allow or deny message, however this cannot be done with a handler, since a handler cannot use the UI thread (will throw a error at runtime).
My proposed solution? Don't use a handler if you want a full screen interruptive message, do the action on the UI thread, similar to your first code snippet.
AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(account, authTokenType, null, this, callback, null);
//USE implements and implement a listener in the class declaration and
//use 'this' in the callback param OR create a new callback method for it

Related

Quickblox manage session and recalling?

I am working with QuickBlox library for video chat. How can i manage it session?? because when i move to the next activity from the live chat activity i just lost the session because it says "Chat can't initialized" then i have to create the session again to do the calling. So what's the lifetime of quickblox session and how can i manage that.
I am also facing problem with recalling when stop the call or move to the next activity and try to recall i was not able to do that actually i tried different things so each time i am getting different errors. So if any one has experience with QuickBlox library need help here.
When i stop a call i call this function.
private void stopCall() {
//Toggle view show the smile view again
//ToggleSmileView();
try
{
cancelCallTimer();
if (videoChat != null) {
videoChat.stopCall();
videoChat = null;
}
if (videoChannel != null) {
videoChannel.close();
videoChannel = null;
}
sessionId = null;
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
and when i do the call i call this function
private void call() {
//toggle view
//ToggleSmileView();
// get opponent
//
VideoChatApplication app = (VideoChatApplication)getApplication();
opponent = new QBUser();
opponent.setId((app.getCurrentUser().getId() == VideoChatApplication.FIRST_USER_ID ? VideoChatApplication.SECOND_USER_ID : VideoChatApplication.FIRST_USER_ID));
// call
//
callTimer = new Timer();
callTimer.schedule(new CancelCallTimerTask(), 30 * 1000);
createSenderChannel();
initVideoChat();
if (videoChat != null)
{
videoChat.call(opponent, getCallType(), 3000);
//toggleMicrophoneMute();
}
else
{
logAndToast("Stop current chat before call");
}
}
For: Lifetime of quickblox session and how can i manage that.
To authenticate your application you have to set valid a auth_key and
generate a signature using your application auth_secret and receive a
session token which you should use to send requests to QuickBlox API
And,
Expiration time for token is 2 hours. Please, be aware about it. If
you will perform query with expired token - you will receive error
Required session does not exist.
Source: Authentication and Authorization Session Info
That part fits the Android sample code of creating the session,
QBAuth.createSession(new QBEntityCallbackImpl<QBSession>() {
#Override
public void onSuccess(QBSession session, Bundle params) {
Log.i(TAG, "session created, token = " + session.getToken());
}
#Override
public void onError(List<String> errors) {
}
});
Source: Android developers documentation
I have worked with the Android SDK, and feel it still needs some work, esp to reach a stage equivalent to the iOS SDK and REST API.
Though looking at your code, you should use getToken() before creating the new QBUser and related video chat calls, if the token has expired, just create a new one.
I have implemented similar code, not a video chat application, but in a general manner, write the functions in onSuccess() of session creation if the session needs to be recreated.
Fyi, for the multiple ones, you can try checking the error with the summary that has been given, categorized into 4; ..developers/Errors

How to stop an activity from starting while checking if a user is logged in?

I am trying to achieve the following when a user starts my app:
1- if the user is not logged in then show a login screen.
2- If the user as already created an account and there is a valid token then show start screen.
To this end I have implemented a custom Authenticator based on the tutorial found here http://www.udinic.com/.
The code works, my issue is that it shows the current activity UI briefly then switches to the add Account UI provided by my AccountAuthenticator. How can I fixed this?
This is the code:
#Override
public void onStart(){
super.onStart();
getTokenForAccountCreateIfNeeded(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mAccountManager = AccountManager.get(this);
}
/**
* Get an auth token for the account.
* If not exist - add it and then return its auth token.
* If one exist - return its auth token.
* If more than one exists - show a picker and return the select account's auth token.
* #param accountType
* #param authTokenType
*/
private void getTokenForAccountCreateIfNeeded(String accountType, String authTokenType) {
final AccountManagerFuture<Bundle> future = mAccountManager.getAuthTokenByFeatures(accountType, authTokenType, null, this, null, null,
new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
Bundle bnd = null;
try {
bnd = future.getResult();
final String authtoken = bnd.getString(AccountManager.KEY_AUTHTOKEN);
showMessage(((authtoken != null) ? "SUCCESS!\ntoken: " + authtoken : "FAIL"));
} catch (Exception e) {
e.printStackTrace();
showMessage(e.getMessage());
}
}
}
, null);
}
force my users to login at the start of the app. I have implemented a custom Authenticator based on the tutorial found here http://www.udinic.com/.
Since your authentication method is asynchronous, you can't prevent the UI from showing. I would implement a Router/Splashscreen Activity that checks the authentication status and then starts either the Login Activity or actual Activity the user sees if he's logged in. Make sure you set your Router Activity to nohistory in your manifest.
If you want to keep it in a single Activity, you should have a full-screen loading indicator in your layout that lays on top of the UI and fades out once you have figured out which layout to show.

getAuthToken y Android not calling any Callback

I've got an application in Android and I'm trying to use AccountManager to get the AuthToken and do things with Facebook or Twitter. So I've got this:
AccountManager am = AccountManager.get(this);
Account[] accounts = am.getAccountsByType("com.facebook.auth.login");
Bundle options = new Bundle();
Account myAccount=null;
for (int i=0;i<accounts.length;i++) {
if (accounts[i].type.equals("com.facebook.auth.login")) myAccount=accounts[i];
//options.putString("facebookUser", accounts[i].name);
}
am.getAuthToken(
myAccount, // Account retrieved using getAccountsByType()
"Manage your tasks", // Auth scope
options, // Authenticator-specific options
this, // Your activity
new OnTokenAcquired(), // Callback called when a token is successfully acquired
new Handler(new OnError()));
My two callbacks are onTokenAcquired:
public class OnTokenAcquired implements AccountManagerCallback<Bundle> {
#Override
public void run(AccountManagerFuture<Bundle> result) {
try {
Bundle bundle = result.getResult();
Log.e("onTokenAcquired",bundle.getString(AccountManager.KEY_AUTHTOKEN));
} catch (OperationCanceledException e) {
Log.e("onTokenAcquired","operationcanceled");
} catch (AuthenticatorException e) {
Log.e("onTokenAcquired","authenticatorexception");
} catch (IOException e) {
Log.e("onTokenAcquired","IOException");
}
}
}
and OnError:
public class OnError implements Callback {
#Override
public boolean handleMessage(Message msg) {
Log.e("onError","ERROR");
return false;
}
}
I'm following the Android Developer guide (http://developer.android.com/intl/es/training/id-auth/authenticate.html). So, I've got two options, on error or on token acquired, in each one I've got a Log.e() to read SOMETHING, but none is being writed.
Can anybody help me? If I was getting an error or the token was not being acquired at least I would have something to work on, but I just don't know what's happening.
It is not totally obvious from the documentation, but the variant of getAuthToken you are calling will never call the callback if user intervention is required. There are some workarounds here:
https://code.google.com/p/android/issues/detail?id=25473
I don't know if that is specifically the problem you're having, but it probably isn't helping.
I do not think getAuthToken is supported with the Facebook authenticator. Also the Auth scope "Manage your tasks" that you are using is the scope for "Google Tasks" and would most likely not be the correct scope to use if getAuthToken was supported.
I suggest that you use the Facebook SDK for Android instead. With this it is very easy to get the auth token. The SDK also have a fallback for users that doesn't have the official facebook installed, or a facebook account added to the phone which is very neat.
Please see also: How to retrieve an Facebook-AuthToken from the accounts saved on Android

How to revoke all Facebook permissions using Android SDK?

I'm having a problem revoking Facebook permissions using the Android SDK.
There's a case in my app where I want to revoke all permissions. According to the Facebook documentation, you can use AsyncFacebookRunner to do this, and "if you don't specify a permission then this will de-authorize the application completely."
I'm currently doing it like this:
String method = "DELETE";
Bundle params = new Bundle();
params.putString("permission", "");
mAsyncRunner.request("/me/permissions", params, method, new RequestListener()
{ ... }, null);
using the request signature like this:
void request(String graphPath, Bundle parameters, final String httpMethod,
RequestListener listener, final Object state)
The onComplete() callback function seems to come back OK, but doesn't appear to have de-authorized the access token. I'm inferring this because the next time I call facebook.authorize(), it works without pushing the user to the Facebook login page.
Any ideas what I need to change to completely de-authorize an access token? Or is there a different/better way to do this? Many thanks!
For anybody looking to do this in later versions of the SDK/Graph API - It appears the correct way to do this now is as shown here https://developers.facebook.com/docs/graph-api/reference/user/permissions/
new Request(
session,
"/me/permissions/{permission-to-revoke}",
null,
HttpMethod.DELETE,
new Request.Callback() {
public void onCompleted(Response response) {
/* handle the result */
}
}
).executeAsync();
Leaving the /{permission-to-revoke} off of the second parameter will revoke all the permissions
You can delete the entire application (not only permissions) from users Facebook account using latest SDK (mine is 4.1.1)
void deleteFacebookApplication(){
new GraphRequest(AccessToken.getCurrentAccessToken(), "/me/permissions", null, HttpMethod.DELETE, new GraphRequest.Callback() {
#Override
public void onCompleted(GraphResponse response) {
boolean isSuccess = false;
try {
isSuccess = response.getJSONObject().getBoolean("success");
} catch (JSONException e) {
e.printStackTrace();
}
if (isSuccess && response.getError()==null){
// Application deleted from Facebook account
}
}
}).executeAsync();
}
It appears from this post: Facebook deauthorize my app and others that it's not possible to deauthorize an application programmatically. Unfortunately, the call above returns successfully to onCreate() but does nothing to deauth/delete the app for the user.
Bottom line: It looks like the only way to deauth an app is for the user to do it directly in Facebook. If anyone knows differently, please say so - but otherwise, don't waste your time trying! Thanks.
I am using the code suggested in the question and it completely de-authorized my test application. Tested it several times and it worked every each one of them.
This is also the code suggested in the official facebook documentation here: https://developers.facebook.com/docs/mobile/android/build/ - Step 7

Android AccountManager API

I'm struggling to understand the Android AccountManager API. As far as I got thinks working I can use the blockingGetAuthToken method and specify whether Android should provide a notification for user to allow or deny the request. Another possibility is to use getAuthToken and check if KEY_INTENT is returned. If that's the case I could start a new Activity where the user can confirm my request.
My problem is that I would like to call one of these two methods from within a Service. Is there any chance to get a callback once the user has made a decision?
Thanks for your help
If you want a callback after the user has made a decision it's probably better to use the asynchronous version:
AccountManager mgr = AccountManager.get(getApplicationContext());
Account[] accounts = mgr.getAccountsByType("com.mydomain");
// assert that accounts is not empty
You'll want to use an AccountManagerFuture<Bundle> to hold results of the authentication token. This has to be async since the Android device may ask the user to login in the meantime:
private AccountManagerFuture<Bundle> myFuture = null;
private AccountManagerCallback<Bundle> myCallback = new AccountManagerCallback<Bundle>() {
#Override public void run(final AccountManagerFuture<Bundle> arg0) {
try {
myFuture.getResult().get(AccountManager.KEY_AUTHTOKEN); // this is your auth token
} catch (Exception e) {
// handle error
}
}
}
Now you can ask for the auth token asynchronously:
myFuture = mgr.getAuthToken(accounts[0], AUTH_TOKEN_TYPE, true, myCallback, null);

Categories

Resources