In Android Oreo, AccountManager.getAccountsByType("com.google"); returns null.
Its, working fine in below Android 8 versions.
Below is my code:
private static Account getAccount(AccountManager accManager) {
Account[] accounts = accManager.getAccountsByType("com.google");
Account account;
if (accounts.length > 0) {
account = accounts[0];
} else {
account = null;
}
return account;
}
Thanks in advance.
As per Android's update, from Oreo onwards we can not use AccountManager.getAccountsByType to get the list of google accounts configured on user's device, as they have updated the Google SignIn features. The new feature will prompt the user to select the account and that account will be only visible to our app.
See the documentation: https://developer.android.com/about/versions/oreo/android-8.0-changes#aaad
If you still want to continue with the old approach of showing all the account's to users, you need to get an extra consent from user by doing below procedures.
You can use GoogleAuthUtil.requestGoogleAccountsAccess to get the list of Google accounts.
A sample code is given below:
new Thread(() -> {
try {
GoogleAuthUtil.requestGoogleAccountsAccess(getApplicationContext());
} catch (Exception e) {
if (e instanceof UserRecoverableAuthException) {
startActivityForResult(((UserRecoverableAuthException) e).getIntent(),
REQ_CODE_PERMISSION_GET_GOOGLE_ACCOUNTS);
} else {
Log.e("SignIn", "Exception in getting google accounts" + e);
}
}
}).start();
This will create an activity to prompt user to accept the consent to allow Google Play Service to access the list of google accounts configured on the device.
You can then override onActivityResult() function on your activity to continue after.
Then you can use AccountManager.getAccountsByType to get the list of google accounts as you done before.
Happy Coding!
Related
I'm working on an app for android phones to be used by multiple users, where they can log in with google or microsoft accounts, to connect the app info to microsoft teams and/or sharepoint if desired.
I'm coding on Android Studio, using MSAL supporting multiple accounts.
Underneath is a method I have to remove accounts from the current PublicClientApplication.MultipleAccountPublicClientApplication. It also returns the result for each removal, if they were removed or not, in a list of booleans.
When testing, all the accounts are removed successfully, but when signing in again and the microsoft sign in intent is opened, the accounts can just be clicked to sign in without password. Signing out seems kind of pointless because of this, since one can just select their user and be logged in again right away. Is it possible to require or force the Microsoft intent to log in with password?
public CompletableFuture<List<Boolean>> signOutAll() {
List<Boolean> removedList = new ArrayList<>();
CompletableFuture<List<Boolean>> future = new CompletableFuture();
for (IAccount account : accountList) {
mPCA.removeAccount(account,
new IMultipleAccountPublicClientApplication.RemoveAccountCallback() {
#Override
public void onRemoved() {
removedList.add(true);
if (accountList.size() == removedList.size()) {
future.complete(removedList);
}
}
#Override
public void onError(#NonNull MsalException exception) {
removedList.add(false);
if (accountList.size() == removedList.size()) {
future.complete(removedList);
}
}
});
}
return future;
}
--
Thank you,
Didrik
This is happening because MSAL automatically refreshes your token after expiration. When user opens your app it checks if that token is already present and valid. So you can remove the token from the Android KeyStore in onStop().
So yes you also need to remove the cache as well to remove the account from the cache, find the account that need to be removed and then call PublicClientApplication.removeAccount()
Set<IAccount> accounts = pca.getAccounts().join();
IAccount accountToBeRemoved = accounts.stream().filter(
x -> x.username().equalsIgnoreCase(
UPN_OF_USER_TO_BE_REMOVED)).findFirst().orElse(null);
pca.removeAccount(accountToBeRemoved).join();
Read more here.
On Android we basically don't have any control on the cookies because they are shared with external Chrome app and because of that it is not accessible. If you want the user to enter the password again then you should do this: AcquireTokenInteractive(scopes).WithPrompt(Prompt.ForceLogin);
When my app starts, I'd like to ask my users either to create an Account or to choose from existing ones. I've implemented an Authenticator (extended AccountAuthenticatorActivity, AbstractAccountAuthenticator, made a Service) It seems to be working, I can create new Accounts from Settings/Accounts.
When I start an AccountPicker, I get a list of already created Accounts. When I click Add acccount it shows up my Account creation Activity. But when I'm done with account creation, finishing that Activity, and going back to the AccountPicker I dont see a new option of the newly created Account. Although if I restart the app, the recently created Account is in the list.
How I start the AccountPicker:
Intent intent = accountManager.newChooseAccountIntent(null, null, new String[]{"test_namespace"}, null, null, null, null);
startActivityForResult(intent, TEST_CODE);
My questions:
Is it supposed to work like this?
Can I reload the content of the AccountPicker after I created a new
Account?
Can I just simply return an Intent with the newly created Account when I
return from my Account creation Activity?
In my authenticator activity, after the user authenticates on the server I check the existing accounts and explicitly add the account if it's not there:
boolean accountRegistered = false;
Account account = new Account(username, AccountAuthenticator.ACCOUNT_TYPE_MYAPP);
AccountManager acctMgr = AccountManager.get(this);
Account[] accounts = acctMgr.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE_MYAPP);
for (Account acct : accounts) {
if (acct.equals(account)) {
accountRegistered = true;
break;
}
}
if (accountRegistered) {
acctMgr.setPassword(account, password);
} else {
acctMgr.addAccountExplicitly(account, password, null);
}
After I do this, I see the account in the account picker.
I can't guarantee this is 100% correct; with the undocumented authentication classes, we're all flying blind.
need a little help. Im making an android app and integrated Soomla for a simple "No ads" purchase inside my app. Ive a purchase button which should do the actual purchase via google.
What occurs is a popup from google : "Error
authentication needed, You have to login in your google account" .
I think its a small problem, but i dont get what. I am logged in in my google account. Store in Soomla is running ( at least it says so). ive enable test purchase.Im using my phone for the purchase ofc. What i am missing?
public class NoADsButton : MonoBehaviour {
private static bool storeInitialized = false; // prevent store to be initialized twice
void Start () {
if(storeInitialized) return;
SoomlaHighway.Initialize();
StoreEvents.OnSoomlaStoreInitialized += onSoomlaStoreInitialized;
SoomlaStore.Initialize(new SoomlaAssets());
}
public void onSoomlaStoreInitialized() {
storeInitialized = true;
}
public void OnMouseDown(){
StoreInventory.BuyItem("no_ads");
}
And the item ive done as its shown in the soomla example:
public const string NO_ADDS_PRODUCT_ID = "no_ads";
public static VirtualGood NO_ADS_LTVG = new LifetimeVG(
"No Ads", // name
"No More Ads!", // description
"no_ads", // item id
new PurchaseWithMarket(NO_ADDS_PRODUCT_ID, 0.99)); // the way this virtual good is purchased
}
This usually happens when the process of publishing the app for testing wasn't done properly. Try going carefully over Google's instructions, make sure you didn't miss anything. http://developer.android.com/google/play/billing/billing_testing.html#billing-testing-test
I'm using the google play services authentication example here
How do I reset the GoogleAuthUtil so it will ask for permission again?
It asks for permission by throwing the userRecoverableException which is fed to a dialog. But it only asks for permission one time. I need to test asking for permission again.
I've tried to uninstall the sample app and re-install the sample app and this didn't work it doesn't ask for permission seems it already knows the app.
protected String fetchToken() throws IOException {
try {
return GoogleAuthUtil.getToken(mActivity, mEmail, mScope);
} catch (UserRecoverableAuthException userRecoverableException) {
// GooglePlayServices.apk is either old, disabled, or not
// present, which is
// recoverable, so we need to show the user some UI through the
// activity.
MyGooglePlay.handleException(userRecoverableException);
} catch (GoogleAuthException fatalException) {
onError("Unrecoverable error " + fatalException.getMessage(),
fatalException);
}
return null;
}
/**
* This method is a hook for background threads and async tasks that need to provide the
* user a response UI when an exception occurs.
*/
public void handleException(final Exception e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (e instanceof GooglePlayServicesAvailabilityException) {
// The Google Play services APK is old, disabled, or not present.
// Show a dialog created by Google Play services that allows
// the user to update the APK
int statusCode = ((GooglePlayServicesAvailabilityException)e)
.getConnectionStatusCode();
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(statusCode,
HelloActivity.this,
REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR);
dialog.show();
} else if (e instanceof UserRecoverableAuthException) {
// Unable to authenticate, such as when the user has not yet granted
// the app access to the account, but the user can fix this.
// Forward the user to an activity in Google Play services.
Intent intent = ((UserRecoverableAuthException)e).getIntent();
startActivityForResult(intent,
REQUEST_CODE_RECOVER_FROM_PLAY_SERVICES_ERROR);
}
}
});
}
You can use the Google Settings app to de-authorize connected applications, by following these steps:
Launch the Google Settings app
Choose the Connected apps option (at the top)
A list of connected apps is displayed; find the app you want to de-authorize and select it. Sorry there is no screenshot as I'm not able to remove personal info from it ATM - but it should be quite straightforward what to do here :)
Finally, click the Disconnect button (at the bottom) on the details page of the app
Note that it might take a moment before the app is de-authorized.
You can also call GoogleAuthUtil.invalidateToken or GoogleAuthUtil.clearToken, that should make it ask the permission again.
If you're a user, like what free3dom answered, you can go to Google Settings app to revoke the access.
If you want to revoke the access programmatically, you can call Google's revoke token API: https://developers.google.com/identity/protocols/OAuth2WebServer#tokenrevoke. Basically, you should first get a valid token with a set of scopes by calling GoogleAuthUtil.getToken(), and then revoke the token. After the token is revoked, you should see the permission dialog again.
Does anyone manage to get Google Drive Notepad sample for Android to work? I followed the instructions as given in Google's developer page but I could not get the notification to start the Google Play Service dialog for authorization.
The app starts as expected and when the method
credential.getToken();
is called, a UserRecoverableAuthException exception is raised. I expect that an authorization dialog will be shown, but nothing happens. I bring down the list of notification from the status bar, tap on the notification created by this app, and again nothing happens.
When I tap on the "Recent Apps" button, I could see "Google Play services" in the list, but it has empty (blank and black) content. Tapping it does nothing, except I was brought back to my home screen.
Any idea on this?
I tried the other sample app, "Quick Start Drive" and this one worked as expected. An authorization dialog was presented as I expected.
Further information, target device is Nexus 7 running OS 4.2.2.
Many thanks.
I had the same problem and I solved it with :
credential.setSelectedAccountName(accountName);
AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
Account[] accounts = accountManager.getAccountsByType("com.google");
Account account = null;
for(Account a : accounts){
if(a.name.equals(accountName)){
account = a;
break;
}
}
if(account != null){
String AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/drive";
accountManager.getAuthToken(account, AUTH_TOKEN_TYPE, null, true, null, null);
service = getDriveService(credential);
}
To authorize Google Drive API, you have to catch the UserRecoverableException and trigger the intent to have an authorization dialog.
try{
....
} catch (UserRecoverableAuthIOException e) {
Intent intent = e.getIntent();
startActivityForResult(intent, REQUEST_AUTHORIZATION_FOLDER);
}
Gabriele Mariotti, your solution seems better but can't work in that case. Indeed, the class is not an activity and the startActivityForResult method can't be called.