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.
Related
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);
}
}
}
}
I am working in an application where I am fetch all the application installed my device using this code :
final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory("com.myapp.MY_CATEGORY");
final List<ResolveInfo> pkgAppsList =getPackageManager().queryIntentActivities( mainIntent, 0);
Now I want to categories the apps differently According to their Categories. Please Suggest me.
To know the category of an application you need to get the data from google play. you can check android-market-api. it is a third party api. according to their info
You can browse market with any carrier or locale you want.
Search for apps using keywords or package name.
Retrieve an app info using an app ID.
Retrieve comments using an app ID.
Get PNG screenshots and icon
So you better check if you can parse the category info using this api.
I realized an AsyncTask to collect categories for some apps, using these libraries:
android-market-api-0.6
com.google.protobuf 2.4.1
you can find them on this link:
https://code.google.com/archive/p/android-market-api/downloads
http://mvnrepository.com/artifact/com.google.protobuf/protobuf-java
Here's the code in doInBackground() Method:
final ArrayList<MarketApplication> results = new ArrayList<>();
AccountManager am = AccountManager.get(MainActivity.this.getBaseContext());
Account[] accounts = am.getAccountsByType("com.google");
if (accounts.length > 0) {
try {
AccountManagerFuture<Bundle> accountManagerFuture =
am.getAuthToken(accounts[0], "android", null, MainActivity.this, null,
null);
Bundle authTokenBundle = accountManagerFuture.getResult();
String authToken =
authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN).toString();
MarketSession session = new MarketSession();
session.setAuthSubToken(authToken);
Market.AppsRequest appsRequest = Market.AppsRequest.newBuilder()
.setQuery(params[0])
.setStartIndex(0).setEntriesCount(10)
.setWithExtendedInfo(true)
.build();
session.append(appsRequest, new MarketSession.Callback<Market.AppsResponse>() {
public void onResult(Market.ResponseContext context, Market.AppsResponse
response) {
for (int i = 0; i < response.getEntriesCount(); i++) {
MarketApplication marketApplication = new MarketApplication();
Market.App app = response.getApp(i);
marketApplication.setName(app.getTitle());
Market.App.ExtendedInfo extendedInfo = app.getExtendedInfo();
marketApplication.setCategory(extendedInfo.getCategory());
results.add(marketApplication);
}
}
});
session.flush();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
return results;
Category information, got from ExtendedInfo, and name of application are added to a custom class MarketApplication. params[0] is a query String, like app name of interest.
There is a wiki page that helps developer to make a specific query:
https://code.google.com/archive/p/android-market-api/wikis/HowToSearchApps.wiki
take notice that this service requires to add these permissions in the Android manifest:
<uses-permission android:name="android.permission.GET_ACCOUNTS"></uses-permission>
<uses-permission android:name="android.permission.USE_CREDENTIALS"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
Well i need to authorize Google Calendar's access for a user, first google Id works fine when i use
blockingGetAuthToken
and it gets a token, i usually log on this token.
So when i tried to use other accounts i got a null token.
I searched a lot and found out that using getAuthToken is preferred as it uses a context from the activity calling it.. then i converted the whole process to use it
private static final String AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/calendar";
public static String authorize(AndroidtestActivity parent, Account account) {
AccountManager accountManager = AccountManager.get(parent);
Bundle options= new Bundle();
Log.d("MyAPP", "Get Authorization");
try {
AccountManagerFuture<Bundle> acc=accountManager.getAuthToken ( account, AUTH_TOKEN_TYPE, options, true, null, null);
Bundle authTokenBundle = acc.getResult();
String authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString();
Log.d("MyAPP","Token= "+authToken);
return authToken;
} catch (Exception ex) {
Logger.getLogger(GoogleAuthorize.class.getName()).log(Level.SEVERE,
null, ex);
}
return null;
}
}
but still no accounts could get a valid token, they all get a null one
then i saw this answer https://stackoverflow.com/a/2021337/1280902 and followed using invalidateAuthToken
private static final String AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/calendar";
public static String authorize(AndroidtestActivity parent, Account account) {
AccountManager accountManager = AccountManager.get(parent);
Bundle options= new Bundle();
Log.d("MyAPP", "Get Authorization");
try {
AccountManagerFuture<Bundle> acc=accountManager.getAuthToken ( account, AUTH_TOKEN_TYPE, options, true, null, null);
Bundle authTokenBundle = acc.getResult();
String authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString();
accountManager.invalidateAuthToken("com.google",authToken);
acc=accountManager.getAuthToken ( account, AUTH_TOKEN_TYPE, options, true, null, null);
authTokenBundle = acc.getResult();
authToken = authTokenBundle.get(AccountManager.KEY_AUTHTOKEN).toString();
Log.d("MyAPP","Token= "+authToken);
return authToken;
} catch (Exception ex) {
Logger.getLogger(GoogleAuthorize.class.getName()).log(Level.SEVERE,
null, ex);
}
return null;
}
}
but i had the same problem on every account i use, even the one that used to work at the beginning with blockingGetAuthToken
So am i missing something?
Ok it works fine when i use
getAuthToken (Account account, String authTokenType, Bundle options, Activity activity, AccountManagerCallback<Bundle> callback, Handler handler)
The activity parameter solved the problem..
I am trying to follow the lesson on developer.android.com and I am getting stuck on the
am.getAuthToken(
myAccount_, AUTH_TOKEN_TYPE,options,this,new OnTokenAcquired(),new Handler(new OnError()));
I don't get what to put in for the myAccount_; Is it accounts that is linked to the account array? Account[] accounts = accountManager.getAccountsByType("com.google");
The token part on class OnTokenAcquired is also gennerating an error saying it isn't a var, should I just make it a global var even though it is suposse to be a constant in the AccountManager.KEY_AUTHTOKEN?
This is the other link for the Authentication lesson and I am getting an error with DIALOG_ACCOUNTS, showDialog(DIALOG_ACCOUNTS) and manager.getAuthToken(account, AUTH_TOKEN_TYPE, null, activity, new AccountManagerCallback<Bundle>() in that tutorioul. I haven't gone much further in it because of the errors I am currently getting.
I don't get why these errors are happening? I assume it is just me not putting in the right vars though.
Any suggestions?
Here is the code I have copied.
public class AccountManagerActivity extends Activity {
AccountManager accountManager = AccountManager.get(this);
Account[] accounts = accountManager.getAccountsByType("com.google");
String AUTH_TOKEN_TYPE = "Manage your tasks";
String your_api_key;
String your_client_id;
String your_client_secret;
String token;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
URL url = new URL("https://www.googleapis.com/tasks/v1/users/#me/lists?key=" + your_api_key);
URLConnection conn = (HttpURLConnection) url.openConnection();
conn.addRequestProperty("client_id", your_client_id);
conn.addRequestProperty("client_secret", your_client_secret);
conn.setRequestProperty("Authorization", "OAuth " + token);
AccountManager am = AccountManager.get(this);
Bundle options = new Bundle();
am.invalidateAuthToken(token, AUTH_TOKEN_TYPE);
am.getAuthToken(
/*Error here*/ myAccount_, // Account retrieved using getAccountsByType()
AUTH_TOKEN_TYPE, // Auth scope
options, // Authenticator-specific options
this, // Your activity
new OnTokenAcquired(), // Callback called when a token is successfully acquired
new Handler(new OnError())); // Callback called if an error occurs
}
}
And then the OnTokenAcquired class
public class OnTokenAcquired implements AccountManagerCallback<Bundle> {
public void run(AccountManagerFuture<Bundle> result) {
// TODO Auto-generated method stub
// Get the result of the operation from the AccountManagerFuture.
Bundle bundle = result.getResult();
// The token is a named value in the bundle. The name of the value
// is stored in the constant AccountManager.KEY_AUTHTOKEN.
/*Error here*/ Token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
Intent launch = (Intent) result./*Error here*/get(AccountManager.KEY_INTENT);
if (launch != null) {
/*Error here*/ startActivityForResult(launch, 0);
return;
}
}
}
am.invalidateAuthToken(token, AUTH_TOKEN_TYPE);
should be
am.invalidateAuthToken(AUTH_TOKEN_TYPE, token);
I am working on an Android Honeycomb (v3.0) application that has a requirement of communicating with the Google Calendar API. I would like to allow my application to access a particular Google account's Calendar data in order to read and create events.
Unfortunately, I ran into a problem with authorization using OAuth2. Here's what I have so far:
1) The Google account whose calendar I would like to access is registered within the Android device I am working with.
2) I enabled the Calendar API within the Google APIs Console on the account.
3) I am able to access this account using the following code:
AccountManager accountManager = AccountManager.get(this.getBaseContext());
Account[] accounts = accountManager.getAccountsByType("com.google");
Account acc = accounts[0]; // The device only has one account on it
4) I would now like to obtain an AuthToken for use when communicating with the calendar. I followed this tutorial, but converted everything to work with Google Calendar instead of Google Tasks. I successfully retrieve an authToken from the AccountManager with the account I would like to use by using getAuthToken with AUTH_TOKEN_TYPE == "oauth2:https://www.googleapis.com/auth/calendar".
5) Here's where the problems begin. I am now at this point:
AccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(tokens[0]); // this is the correct token
HttpTransport transport = AndroidHttp.newCompatibleTransport();
Calendar service = Calendar.builder(transport, new JacksonFactory())
.setApplicationName("My Application's Name")
.setHttpRequestInitializer(accessProtectedResource)
.build();
service.setKey("myCalendarSimpleAPIAccessKey"); // This is deprecated???
Events events = service.events().list("primary").execute(); // Causes an exception!
6) Here's the exception returned by the last line:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "usageLimits",
"message" : "Daily Limit Exceeded. Please sign up",
"reason" : "dailyLimitExceededUnreg",
"extendedHelp" : "https://code.google.com/apis/console"
} ],
"message" : "Daily Limit Exceeded. Please sign up"
}
7) According to this Google API Video (wait a minute or so to get to the applicable content), a reason for this exception may be the fact that I did not enable the API access within the Google APIs Console for the account. However, if you look at 2), you can see that I did do so.
8) To me, it seems that the problem is that I was unable to set the Simple API Access Key correctly, because the Calendar.setKey method is deprecated. Within the Google Tasks tutorial that I previously linked, the key is set using Tasks.accessKey = "key". I'm not sure how to get this working with the Calendar API, though. I have tried multiple Google accounts, which all came up with the exception from 5).
9) I would like to point out that the traditional method of using OAuth2 did work for me. Here's the code I used for that:
HttpTransport TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
String SCOPE = "https://www.googleapis.com/auth/calendar";
String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";
String CLIENT_ID = "myClientID";
String CLIENT_SECRET = "myClientSecret";
String authorizeUrl = new GoogleAuthorizationRequestUrl(CLIENT_ID, CALLBACK_URL, SCOPE).build();
String authorizationCode = "???"; // At this point, I have to manually go to the authorizeUrl and grab the authorization code from there to paste it in here while in debug mode
GoogleAuthorizationCodeGrant authRequest = new GoogleAuthorizationCodeGrant(TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authorizationCode, CALLBACK_URL);
authRequest.useBasicAuthorization = false;
AccessTokenResponse authResponse = authRequest.execute();
String accessToken = authResponse.accessToken; // gets the correct token
GoogleAccessProtectedResource access = new GoogleAccessProtectedResource(accessToken, TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, authResponse.refreshToken);
HttpRequestFactory rf = TRANSPORT.createRequestFactory(access);
AccessProtectedResource accessProtectedResource = new GoogleAccessProtectedResource(accessToken);
HttpTransport transport = AndroidHttp.newCompatibleTransport();
Calendar service = Calendar.builder(transport, new JacksonFactory())
.setApplicationName("My Application's Name")
.setHttpRequestInitializer(accessProtectedResource)
.build();
Events events = service.events().list("primary").execute(); // this works!
10) Finally, my question: I would like to use the account from the AccountManager on the device itself in order to retrieve a working OAuth2 token for use with the Google Calendar API. The second method is not useful for me, because the user will have to manually go to their web browser and get the authorization code, which is not user friendly. Anyone have any ideas? Apologies for the long post, and thanks!
Try adding a JsonHttpRequestInitializer to the builder and setting your key there:
Calendar service = Calendar.builder(transport, new JacksonFactory())
.setApplicationName("My Application's Name")
.setHttpRequestInitializer(accessProtectedResource)
.setJsonHttpRequestInitializer(new JsonHttpRequestInitializer() {
public void initialize(JsonHttpRequest request) {
CalendarRequest calRequest = (CalendarRequest) request;
calRequest.setKey("myCalendarSimpleAPIAccessKey");
}
}).build();
To answer no 10 : I've basically had to do what you had to do working with the TaskSample and then use the Android GData Calendar Sample available here : http://code.google.com/p/google-api-java-client/source/browse/calendar-android-sample/src/main/java/com/google/api/client/sample/calendar/android/CalendarSample.java?repo=samples
to get the AuthToken from the AccountManager itself:
accountManager = new GoogleAccountManager(this);
settings = this.getSharedPreferences(PREF, 0);
gotAccount();
private void gotAccount() {
Account account = accountManager.getAccountByName(accountName);
if (account != null) {
if (settings.getString(PREF_AUTH_TOKEN, null) == null) {
accountManager.manager.getAuthToken(account, AUTH_TOKEN_TYPE,
true, new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
try {
Bundle bundle = future.getResult();
if (bundle
.containsKey(AccountManager.KEY_INTENT)) {
Intent intent = bundle
.getParcelable(AccountManager.KEY_INTENT);
int flags = intent.getFlags();
flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
intent.setFlags(flags);
startActivityForResult(intent,
REQUEST_AUTHENTICATE);
} else if (bundle
.containsKey(AccountManager.KEY_AUTHTOKEN)) {
setAuthToken(bundle
.getString(AccountManager.KEY_AUTHTOKEN));
// executeRefreshCalendars();
}
} catch (Exception e) {
handleException(e);
}
}
}, null);
} else {
// executeRefreshCalendars();
}
return;
}
chooseAccount();
}
private void chooseAccount() {
accountManager.manager.getAuthTokenByFeatures(
GoogleAccountManager.ACCOUNT_TYPE, AUTH_TOKEN_TYPE, null,
ExportClockOption.this, null, null,
new AccountManagerCallback<Bundle>() {
#Override
public void run(AccountManagerFuture<Bundle> future) {
Bundle bundle;
try {
bundle = future.getResult();
setAccountName(bundle
.getString(AccountManager.KEY_ACCOUNT_NAME));
setAuthToken(bundle
.getString(AccountManager.KEY_AUTHTOKEN));
// executeRefreshCalendars();
} catch (OperationCanceledException e) {
// user canceled
} catch (AuthenticatorException e) {
handleException(e);
} catch (IOException e) {
handleException(e);
}
}
}, null);
}
void setAuthToken(String authToken) {
SharedPreferences.Editor editor = settings.edit();
editor.putString(PREF_AUTH_TOKEN, authToken);
editor.commit();
createCalendarService(authToken);
try {
Events events = service.events().list("primary").execute();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void createCalendarService(String authToken) {
accessProtectedResource = new GoogleAccessProtectedResource(authToken);
Log.i(TAG, "accessProtectedResource.getAccessToken() = "
+ accessProtectedResource.getAccessToken());
JacksonFactory jsonFactory = new JacksonFactory();
service = com.google.api.services.calendar.Calendar
.builder(transport, jsonFactory)
.setApplicationName("Time Journal")
.setJsonHttpRequestInitializer(
new JsonHttpRequestInitializer() {
#Override
public void initialize(JsonHttpRequest request) {
CalendarRequest calendarRequest = (CalendarRequest) request;
calendarRequest
.setKey("<YOUR SIMPLE API KEY>");
}
}).setHttpRequestInitializer(accessProtectedResource)
.build();
}