Why do I get null from retrieving the user's gmail? - android

With the following code that retrieves the user's Google account, gmail, I was wondering why I get null from devices like mine (that of course runs on my gmail), whereas it works on my mom's devices:
public class MainActivity extends AppCompatActivity {
final String TAG = "Sample2";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String test = getEmail(getApplicationContext());
Log.d(TAG, "Email is: " + test);
TextView emailTxt = (TextView)findViewById(R.id.emailTxt);
emailTxt.setText(test);
}
private String getEmail(Context context) {
AccountManager accountManager = AccountManager.get(context);
Account account = getAccount(accountManager);
if (account == null) {
return null;
} else {
return account.name;
}
}
private static Account getAccount(AccountManager accountManager) {
Account[] accounts = accountManager.getAccountsByType("com.google");
Account account;
if (accounts.length > 0) {
account = accounts[0];
} else {
account = null;
}
return account;
}
}
I also included the following permission into my Manifest file:
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
Clearly, it's because of my device... But it can't be the only device that's returning null, so I don't know if this is a good approach for a unique string token when verifying payload with in-app billing.
Oh, and here's a screenshot of what I see in my Accounts & Sync settings:
... Is there anything I'm missing here?

Based on the document Set the developer payload string. When making purchase requests, you should not use the user's email address in the payload string, since the address may change.
You should pass in a string token that helps your application to identify the user who made the purchase, so that you can later verify that this is a legitimate purchase by that user. For consumable items, you can use a randomly generated string, but for non- consumable items you should use a string that uniquely identifies the user.

https://developer.android.com/about/versions/oreo/android-8.0-changes.html
Account access and discoverability
In Android 8.0 (API level 26), apps can no longer get access to user accounts unless the authenticator owns the accounts or the user grants that access. The GET_ACCOUNTS permission is no longer sufficient. To be granted access to an account, apps should either use AccountManager.newChooseAccountIntent() or an authenticator-specific method. After getting access to accounts, an app can can call AccountManager.getAccounts() to access them.
Android 8.0 deprecates LOGIN_ACCOUNTS_CHANGED_ACTION. Apps should instead use addOnAccountsUpdatedListener() to get updates about accounts during runtime.
For information about new APIs and methods added for account access and discoverability, see Account Access and Discoverability in the New APIs section of this document
Maybe you can try this
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int PICK_ACCOUNT_REQUEST = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent googlePicker = AccountManager.newChooseAccountIntent(null, null,
new String[] { "com.google"}, true, null, null, null, null);
startActivityForResult(googlePicker, PICK_ACCOUNT_REQUEST);
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (requestCode == PICK_ACCOUNT_REQUEST && resultCode == RESULT_OK) {
String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
Log.d(TAG, "Account Name=" + accountName);
String accountType = data.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE);
Log.d(TAG, "Account type=" + accountType);
AccountManager accountManager = AccountManager.get(this);
Account[] accounts = accountManager.getAccounts();
for (Account a :
accounts) {
Log.d(TAG, "type--- " + a.type + " ---- name---- " + a.name);
}
}
}
}

Related

Getting the Gmail Id of the User In Android

I don't know it is the correct question or not.How can we get the lo-gin id of the user from which it has been lo-gin to the Google Play Store in Android.Is this possible or not.
As per my knowledge the user has to configure his gmail account in his android phone and then he gets access to Google Play.
You can fetch the account information as given below (from Jim Blackler):
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
/**
* This class uses the AccountManager to get the primary email address of the
* current user.
*/
public class UserEmailFetcher {
static String getEmail(Context context) {
AccountManager accountManager = AccountManager.get(context);
Account account = getAccount(accountManager);
if (account == null) {
return null;
} else {
return account.name;
}
}
private static Account getAccount(AccountManager accountManager) {
Account[] accounts = accountManager.getAccountsByType("com.google");
Account account;
if (accounts.length > 0) {
account = accounts[0];
} else {
account = null;
}
return account;
}
}
In Manifest
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
If you're after a method that doesn't require requesting a permission via AndroidManifest.xml you can use Google Play Services' AccountPicker.
Spawn a dialog that allows the user to pick their desired Google Account:
Intent intent = AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"}, false, null, null, null, null);
startActivityForResult(intent, SOME_REQUEST_CODE);
then handle the result in your Activity:
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
if (requestCode == SOME_REQUEST_CODE && resultCode == RESULT_OK) {
String emailAddress = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
// do something...
}
}
Remember to add compile 'com.google.android.gms:play-services-identity:8.+' to the dependencies in your build.gradle file (check here for the most recent version number to use).

Unlocks app even after payment decline

I develop an app with in app version 2 and publish it on developers Google now some one download the app and try to purchase it. On purchasing a message showed to him that "Your card is decline" now even after this message app got "unlock" . Now this is a very difficult situation that payment is not made while app got unlock. Is this issue with in app billing method(logic) in my app or its with Google.
If its in my app then is there any method which check that the person card is a "declined card" so in this method i can restrict my app not to unlock the app.
Any app will be appreciated.
I have this code in my BillingReceviver:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Consts.ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
String signedData = intent.getStringExtra(Consts.INAPP_SIGNED_DATA);
String signature = intent.getStringExtra(Consts.INAPP_SIGNATURE);
purchaseStateChanged(context, signedData, signature);
} else if (Consts.ACTION_NOTIFY.equals(action)) {
String notifyId = intent.getStringExtra(Consts.NOTIFICATION_ID);
if (Consts.DEBUG) {
Log.i(TAG, "notifyId: " + notifyId);
}
notify(context, notifyId);
} else if (Consts.ACTION_RESPONSE_CODE.equals(action)) {
long requestId = intent.getLongExtra(Consts.INAPP_REQUEST_ID, -1);
int responseCodeIndex = intent.getIntExtra(Consts.INAPP_RESPONSE_CODE,
ResponseCode.RESULT_ERROR.ordinal());
checkResponseCode(context, requestId, responseCodeIndex);
} else {
Log.w(TAG, "unexpected action: " + action);
}
}
After making ACTION_PURCHASE_STATE_CHANGED matches the action the my purchsedstatechanged calls in file BillingService
private void purchaseStateChanged(int startId, String signedData, String signature) {
ArrayList<Security.VerifiedPurchase> purchases;
DatabaseHandler db=new DatabaseHandler(this);
purchases = Security.verifyPurchase(signedData, signature);
if (purchases == null) {
return;
}
ArrayList<String> notifyList = new ArrayList<String>();
for (VerifiedPurchase vp : purchases) {
if (vp.notificationId != null) {
notifyList.add(vp.notificationId);
}
ResponseHandler.purchaseResponse(this, vp.purchaseState, vp.productId,
vp.orderId, vp.purchaseTime, vp.developerPayload);
db.addUser("com.example.app", "111", "1222");
Log.i("Usgdgfer",""+db.isUserPresent("com.example.app"));
}
if (!notifyList.isEmpty()) {
String[] notifyIds = notifyList.toArray(new String[notifyList.size()]);
confirmNotifications(startId, notifyIds);
}
}
Usually, the card has to be mapped to the Google Wallet account before the purchase is made. If the card is invalid, it will show an error while you map the card to your Google account.
Seems strange that the card is being validated during purchase. Even then, if the payment is not made properly , you should get an error response
BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3;
Check if you handle these errors properly after you receive them in the IabResult. Make sure you unlock your app only when you receive a proper response.

How to remove account in AccountManager in Android

I am trying to remove a custom account in AccountManager.
This is my code :
final Handler handler = new Handler ();
AccountManagerCallback<Boolean> callback = new AccountManagerCallback<Boolean>()
{
#Override
public void run(AccountManagerFuture<Boolean> arg0)
{
String test = "test";
}
};
AccountManagerFuture<Boolean> bool = am.removeAccount(account, callback, handler);
Permissions I'm using :
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"></uses-permission>
<uses-permission android:name="android.permission.GET_ACCOUNTS"></uses-permission>
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"></uses-permission>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"></uses-permission>
The account is never removed and the callback never called, any idea ? No trace in logs
Try this it will work
// Global Variables
public static final String AUTHORITY = "com.example.package";
public static final String ACCOUNT_TYPE = "com.example.package";
public static final String ACCOUNT = "my_custom_account_name";
// Account Manager definition
AccountManager accountManager = (AccountManager) this.getSystemService(ACCOUNT_SERVICE);
// loop through all accounts to remove them
Account[] accounts = accountManager.getAccounts();
for (int index = 0; index < accounts.length; index++) {
if (accounts[index].type.intern() == AUTHORITY)
accountManager.removeAccount(accounts[index], null, null);
}
requires
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
You need to override the following method in the Authenticator class from AbstractAccountAuthenticator.
public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) {
Bundle result = new Bundle();
boolean allowed = true; // or whatever logic you want here
result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, allowed);
return result;
}
Had the same problem
if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP_MR1) {
accountManager.removeAccount(account, {}, AContext.app.mainHandler)
} else {
accountManager.removeAccountExplicitly(account)
}
For API 22 and higher works perfectly, but on API 19 didn't work at all.
Finally found the problem in my implementation of AbstractAccountAuthenticator:
override fun getAccountRemovalAllowed(response: AccountAuthenticatorResponse?, account: Account?): Bundle {
AccountHelper.removeAccount()
return super.getAccountRemovalAllowed(response, account)
}
It became to work after deleting "AccountHelper.removeAccount()"
I don't know - maybe it'll help
You have to call 2 below methods before removeAccount method and the system will allow you to remove the account in account manager.
clearPassword
invalidateAuthToken
Based on the description on the removeAccount method:
"The authenticator may have its own policies preventing account deletion, in which case the account will not be deleted."
Have fun.
This Code works like a charm to me.
You will need the WRITE_SYNC_SETTINGS,also need to add android.permission.MANAGE_ACCOUNTS works for me with same code pattern. permission. So if you use AccountManager and Account correctly you will manage to remove the account successfully.
I had some issues using the account manager in the Android Simulator, so try to test on a real device...
AccountManager accMgr = AccountManager.get(this);
final Account account = new Account(username, accountType);
removeCaxtonAccount(accMgr, account);
public void removeCaxtonAccount(AccountManager accMgr, Account account){
accMgr.removeAccount(account, null,null);
}
Here is my solution. The previous solutions I found don't explicitly wait for the removal of accounts to finish so they randomly fail.
final AccountManager accountManager = AccountManager.get(getContext());
final String accountType = AuthenticatorService.ACCOUNT_TYPE;
final Account[] availableAccounts = accountManager.getAccountsByType(accountType);
for (final Account availableAccount : availableAccounts) {
final AccountManagerFuture<Boolean> booleanAccountManagerFuture = accountManager.removeAccount(availableAccount, null, null);
assertTrue("Impossible to delete existing account for this application", booleanAccountManagerFuture.getResult(1, TimeUnit.SECONDS));
}
Note: You still need the permissions mentioned before.
I my case for api before 22 adding Authenticator class helped. Just inspire yourself from this source https://www.programcreek.com/java-api-examples/?code=MLNO/airgram/airgram-master/TMessagesProj/src/main/java/ir/hamzad/telegram/ContactsController.java#
for api 22+ this works without Authenticator:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
Timber.e(String.valueOf(accountManager.removeAccountExplicitly(account)));
}

On the Kindle Fire, is it possible to get a user's email address?

This question discusses it for android devices in general, but if you try to run this code on a Kindle Fire, all you get is the user's name. Is there any way to get the email address? We were hoping to pop-up a dialog with the email address already pre-filled so they wouldn't have to type it if it were correct, but it seems like the only solution is to have them re-type it.
edit: Here's the code that other threads have suggested (that doesn't work on the Kindle Fire):
Account[] accounts = AccountManager.get(this).getAccounts();
for (Account account : accounts) {
// TODO: Check possibleEmail against an email regex or treat
// account.name as an email address only for certain account.type values.
String possibleEmail = account.name;
// possibleEmail is a list of account names, hopefully including the #gmail.com address.
}
On the Kindle Fire, is it possible to get a user's email address?
Sorry, But You totally wrong.
I used to link to Google Login Dialog which show all user existed on Kindle Fire.
Please follow this code :
public class AuthAcount {
private Context context;
private AccountManager mAccountManager;
public AuthAcount(Context context) {
setContext(context);
}
public Account[] getAccount() {
mAccountManager = AccountManager.get(context);
Account[] accounts = mAccountManager
.getAccountsByType(GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
return accounts;
}
public Context getContext() {
return context;
}
public void setContext(Context context) {
this.context = context;
}
}
P/s : To use GoogleAuthUtil class, might be you need google-oauth-client-1.15.0-rc.jar (Please use the lastest version).
On the Fire devices that I have available to me, this is what I did:
final static String TYPE_GOOGLE = "com.google";
final static String TYPE_AMAZON = "com.amazon";
final static String AMAZON_EMAIL = "com.amazon.pim";
public static String getAccountName(final Context context) {
boolean amazon = TextUtils.equals(Build.MANUFACTURER, "Amazon");
String type = amazon ? TYPE_AMAZON : TYPE_GOOGLE;
String email = null;
try {
Account acc[] = AccountManager.get(context).getAccountsByType(type);
if (acc.length > 0) {
email = acc[0].name;
for (int i = 0; i < acc.length; i++) {
Account account = acc[i];
if (amazon) {
// there are a lot of flags, just skip them
if (!TextUtils.equals(account.type, TYPE_AMAZON)) {
// is it an email account?
if (account.type.startsWith(AMAZON_EMAIL)) {
email = account.name;
}
}
}
}
} else {
acc = AccountManager.get(context).getAccounts();
if (acc.length > 0) {
// just return the first one...
email = acc[0].name;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return email;
}
This will also work with Google Play devices.

Android Google Api for SpreadSheet

I'm trying to figure out how to use Google Api for accessing/editing Google SpreadSheet.
I want to have a connection always with the same spreadsheet from many devices. I got examples using the AccountManager, but i should not use the user account. There is any good turorial?
Right now i've got the following..is that right?
AccountManager accountManager = AccountManager.get(this);
ArrayList googleAccounts = new ArrayList();
// Just for the example, I am using the first google account returned.
Account account = new Account("email#gmail.com", "com.google");
// "wise" = Google Spreadheets
AccountManagerFuture<Bundle> amf = accountManager.getAuthToken(account, "wise", null, this, null, null);
try {
Bundle authTokenBundle = amf.getResult();
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
// do something with the token
//InputStream response = sgc.getFeedAsStream(feedUrl, authToken, null, "2.1");
}
catch (Exception e) {
// TODO: handle exception
}
Required permissions:
<uses-permission android:name="android.permission.ACCOUNT_MANAGER"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
Choose needed outh token type from the table:
http://code.google.com/intl/ja/apis/spreadsheets/faq_gdata.html#Authentication
Spreadsheets Data API wise
Code sample:
public class OuthTokenActivity extends Activity {
String tag = "DEBUG";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AccountManager mAccountManager = AccountManager.get(this);
for (Account account : mAccountManager.getAccountsByType("com.google")) {
mAccountManager.getAuthToken(account, "wise", savedInstanceState,
this, resultCallback, null);
}
}
AccountManagerCallback<Bundle> resultCallback = new AccountManagerCallback<Bundle>() {
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle result = future.getResult();
String token = (String) result.get(AccountManager.KEY_AUTHTOKEN);
String name = (String) result.get(AccountManager.KEY_ACCOUNT_NAME);
Log.d(tag, String.format("name: %s, token: %s", name, token));
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
There is an API released now, available for java script, which could be run in your app. And they show how to integrate this into an Android app in a video here.

Categories

Resources