How to share a document using google-api-java-client on Android? - android

I want to create an Android client app for Google Documents List API, taking into account that it might be replaced by the Google Drive API in the near future. Therefore, I implemented authentication using google-api-java-client, which would presumably ease a transition to the new API if needed.
Now I'm trying to extend the DocsClient.java class, found in the shared-sample-docs project provided by Google, in order to be able to share documents with user contacts.
I found no better information on this matter than the following introduction written by #yanivinbar: http://javadoc.google-api-java-client.googlecode.com/hg/1.4.1-beta/com/google/api/client/googleapis/xml/atom/package-summary.html
From the Google Documents List API docs, I figured out ACL is used to give other users access to a specific document. However, it's not clear to me which methods I should implement to achive this or other common API related transactions.

You are right, you need to add ACL entry for your document entry. You can have method as below :
public void shareFile(DocumentListEntry documentListEntry,
AclScope.Type type, String value, String role)
throws MalformedURLException, IOException, ServiceException {
// Instantiate a AclEntry object to update sharing permissions.
AclEntry acl = new AclEntry();
// Set the ACL scope.
acl.setScope(new AclScope(type, value));
// Set the ACL role.
acl.setRole(new AclRole(role));
// Insert the new role into the ACL feed.
service.insert(new URL(documentListEntry.getAclFeedLink().getHref()), acl);
}
Here service is an object of com.google.gdata.client.docs.DocsService . Also you can specify different sharing types and roles on your documents.
Possible calls for above method can be
shareFile(entryObj,AclScope.Type.USER,"your email id",AclRole.OWNER);
shareFile(entryObj,AclScope.Type.DOMAIN,"domain name",AclRole.READER);

Related

People API of google versus contacts API

While trying to fetch contacts using google account of user , I am facing some issues after using people API.It only returns few email addresses out of all listed ones.Access token and all scopes have been set correctly.
Code for following :
People peopleService = new People.Builder(httpTransport, jsonFactory, credential)
.build();
ListConnectionsResponse response = peopleService.people().connections().list("people/me")
.setPageSize(500).setSortOrder("FIRST_NAME_ASCENDING")
.setAccessToken(tokenResponse.getAccessToken())
.setAlt("json")
.setRequestMaskIncludeField("person.names,person.emailAddresses,person.phoneNumbers")
. execute();
connections = response.getConnections();
Instead of this if I use contact API of google then I am getting more no of email addresses than people.Code for contact API :
URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/default/full");
ContactFeed resultFeed = myService.getFeed(feedUrl, ContactFeed.class);
// Print the results
System.out.println(resultFeed.getTitle().getPlainText());
for (ContactEntry entry : resultFeed.getEntries()) {
....
.....
.......
}
I want to know if there is any difference between both of them and which one i have to use for better results or am I missing something. please suggest. Thanks..!!
People API is more up-to-date. Reading through Google's blog announcement, People API simplifies what needed to be separate calls to Google+ API and Contacts API. Now you only need to use one.
"The new People API uses the newest protocols and technologies and
will eventually replace the Contacts API which uses the GData
protocol"
When getting the user's list of connections, be sure to specify the correct scopes when using it.
https://www.googleapis.com/auth/contacts - Requests that your app be given read and write access to the contacts in the authenticated user’s Google Contacts.
https://www.googleapis.com/auth/contacts.readonly - Requests that your app be given read access to the contacts in the authenticated user’s Google Contacts.
Check this link for similarities and differences between People API and Contacts API.
I'm not sure if there is any issues with the java code, but if you look at the request that is sent out it should be like this:
URL:https://content-people.googleapis.com/v1/people/me/connections?pageSize=300&requestMask.includeField=person.names%2Cperson.email_addresses&sortOrder=FIRST_NAME_ASCENDING&key=
I was able to get all the contacts with the correct email and name. If you google "manage google contacts" you will see a list of contacts. From there take that number, and just print out the connection count which should match. You just need to make sure the pageSize is big enough or you have to handle paging to get all the contacts.
Also i realized that the requestMask.includeField is really sensitive to what parameters and spaces you put. "person.name,person.email_addresses" worked and "person.name, person.email_addresses" did not.
With the older contact api, you can query the q parameter which I don't think the people api provides this ability. I think the ability to filter your search by key words is important to reduce the request size.

Google Cloud Endpoint + Restful + CRUD

I'm using Google App Engine and Google Cloud Endpoints to communicate between my Android app (frontend) and the webservice (backend) that runs in the cloud. But I wonder about the URL's used for GET and POST.
Imagine you have a list of notes on the server each with a caption and an id. According to CRUD (create, updated, delete), the HTTP/HTTPS calls should look like that:
Get all notes:
GET http://domain.eu/notes
Get a specific note by it's id (let's say 123):
GET http://domain.eu/notes/id
and so on. But Google uses a different pattern. For instance if you use the API explorer you get calls like this:
GET https://domain/_ah/api/notesEndpoint/v1/notesdata
Question: Is there a general way to get a call for listing all notes? According to the annotations in the source code it should be somewhat like /notes or /notes.listNodes I simply don't understand how Google constructs the URL's
Google Cloud Endpoints use the API-Explorer system.
/_ah/api is defined for the API Explorer, you can't change it.
notesEndpoint is the name of your Api, and v1 the version you define.
notesdata is the name of the method. You can override the path by annotation.
Example, to access to the notes through
domain/_ah/api/notesEndpoint/v1/notes
You have to make this method :
#ApiMethod(
name = "notes.listNodes",
path = "notes",
httpMethod = HttpMethod.GET
)
public List<Foo> notesdata() {
return myList;
}
(a link to the documentation : DOC)
For information, with this system, you can explore your API with this URL :
GET http://domain.eu/_ah/api/explorer

Protecting my Google App Engine API Endpoints

I have been doing a lot of research recently on securing my app engine. Currently, I've been reading through the question below and the links in that question:
How do I restrict Google App Engine Endpoints API access to only my Android applications?
However, it doesn't answer my problem. My question is similar to the question above, restricting access to my endpoint API to only my app. The guy seemed to have got it working when he inputs a correct email into the credentials.
My question is if I can achieve the same results without having to input any credentials. I want it so that only my app can use my endpoint API so to prevent other apps from abusing it and using up my quota. I already got a client id for my android application, and have placed it within my #API annotation. To test if it worked, I made a random value for the client id in the #API notation of another api class. However, my app was still able to use methods from both class. Any help?
-Edit-
From reading from the docs and researching further, the endpoint way of authorizing apps is by authenticating the user and for my API to check if user is null. My question is that in the process of authenticating the user, is Google somehow able to read my app's SHA1 fingerprint and authorize it to its list of client ids? If so, how can I replicate this process in my endpoint so that I check the SHA1 fingerprint of the app making the request and compare it to a set value? I don't understand the mechanics behind the endpoints very well, so correct me if I am understanding this wrong.
If the android app has access, then the user has access. A motivated party has many options for inspecting your protocol, including putting the device behind transparent proxy or simply running the app through a debugger. I do suggest running your app through ProGuard before publishing, as this will make the process [a bit] more difficult.
Ultimately, you'll need to make your appengine API robust against untrusted parties. This is simply the state of the web.
How you can protect your endpoint API is described here: http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html
The secret is that you request a token from Google Play using the following scope: audience:server:client_id:9414861317621.apps.googleusercontent.com where 9414861317621.apps.googleusercontent.com is your ClientId.
Google Play will look up the id at your endpoints app and return a Google-signed JSON Web Token if it finds the id. Then you pass that id in with your request. Above article says you should pass it in with the body. I would possibly rather add another parameter for that because otherwise you can't pass your own entities anymore. Anyway, your server backend receives the token, and you ask Google as described if it is authentic, before you process the API request.
If you pass in the token using an extra parameter, you can catch it on the server side by adding HttpServletRequest to your endpoint signature and then using request.getHeader("Yourname") to read it out. Make sure you never add the parameter as a URL parameter as it may be logged somewhere.
public void endpointmethod(
// ... your own parameters here
final HttpServletRequest request
) throws ServiceException, OAuthRequestException {
request.getHeader("YourHeaderName") // read your header here, authenticate it with Google and raise OAuthRequestException if it can't be validated
On the Android side you can pass in your token when you build the endpoint api, like this, so you don't have to do it with each and every request:
Yourapiname.Builder builder = new Yourapiname.Builder(AndroidHttp.newCompatibleTransport(), getJsonFactory(), new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
httpRequest.setHeader(...);
}})
Hope this helps you make your endpoints API secure. It should.

Authenticate my "app" to Google Cloud Endpoints not a "user"

What I'm trying to do is to authenticate my Android app to the Google Cloud Endpoint.
Basically the endpoints should only allow my Android app to access the methods and nothing else.
I have done these things -
Create a client id using my SHA1 value in Eclipse in the Google Cloud Console.
Create a web client id in the Google Cloud Console for my endpoint project.
Add both these client id's in the "#Api" mentioned on each endpoint.
Add an extra "user" parameter in the endpoint methods.
Regenerate and deploy the backend to the cloud.
But when I'm running this the "user" is always coming as "null". I'm at my wits end trying to find a proper working method for doing all this.
I've searched many forums but no proper answers anywhere.
Here's another similar post Restrict access to google cloud endpoints to Android app
This is the reference I'm using -
https://developers.google.com/appengine/docs/java/endpoints/auth
Has anyone here done this before? My main goal is to not allow unauthenticated apps and outside world to access the endpoints, for obvious security reasons. I don't want to use end-user based authentication since I want to keep my app very simple.
It sounds like it's working as intended. You control which client apps can call your endpoint methods via the client IDs as you have already done. The User parameter is coming in as null precisely because you aren't doing end-user authentication. The User parameter represents an actual real user (Google Account). So if you don't need end-user authenticated methods, you can just simply not define the User parameter, or else ignore the null value. You said your problem is that the User parameter is set null. What are you expecting it to be in this scenario?
You need to call authenticate on the client, then possibly the library you're using will 'inject' the user information.
Here's what worked for me :
Let's say you have the keys below :
static final String WEB_CLIENT_ID = "somekeyfor webclientid.apps.googleusercontent.com";
static final String ANDROID_CLIENT_ID = "somekeyfor androidclientid.apps.googleusercontent.com";
static final String ANDROID_AUDIENCE = WEB_CLIENT_ID;
Your Api anotation should look like this :
#Api(
name = "yourapiname",
clientIds = {CloudEndpoint.WEB_CLIENT_ID,CloudEndpoint.ANDROID_CLIENT_ID},
audiences = {CloudEndpoint.ANDROID_AUDIENCE},
version = "v1",
namespace = #ApiNamespace(
ownerDomain = "myapp.app.com",
ownerName = "myapp.app.com",
packagePath = ""
)
)
In the annotation below, notice how your audience is the variable --> ANDROID_AUDIENCE which is equal to WEB_CLIENT_ID.
Now in your app side, when you create the googleAccountCredential object, you should pass in the Web Client Id like this :
mAccountCredentials = GoogleAccountCredential.usingAudience(getApplicationContext(),"server:client_id:" + "yourwebclientID");
Note that even if this is properly done, your user object in the endpoint might still coming out as Null if the account name you pass in mAccountCredentials.setSelectedAccountName("accontname") does not exist in the device. Therefore make sure the account name you pass does exist in the Android device by going to --> (Settings/Accounts)

How to use a server to store/receive data?

I am wondering what is required to setup a server so that you can store data on it, and then have an application send requests to it to store and receive data. More specifically, I am working on an Android application where a user will generate data and then that should be stored on a server so other users can access it. But I do not know how setting up a server to be capable of this works. I have worked on Android applications in the past that sends requests (put, post, get, etc) to a server, but that back end was already set up for me. Any info or resources about setting this up would be great.
There are many, many different ways to accomplish this.
Since you're already working with a Google technology, Android - you could start by creating a Google App Engine project. Following the tutorials you can get started setting up a simple back end solution that will store data for you and you can make requests to it for that data.
Another advantage to this for you is that you don't have to learn how to install software on a server and all the dependencies that arise from that, etc. Simply set up a new account and push-button deploy through Eclipse or command line.
And since you've used Java in Android, you can use JAva for Google App Engine (GAE) too!
Getting started: http://code.google.com/appengine/docs/java/gettingstarted/introduction.html
You can try ready to use BAAS/PAAS services to store your data, e.g. QuickBlox for Android http://quickblox.com/developers/Android, where you can manipulate with your data with few strings
QBLocation location = new QBLocation();
location.setLatitude(35.0);
location.setLongitude(53.0);
location.setStatus("I'm at this place");
String someImportantString = "Dr. Henry Walton Indiana Jones";
QBLocations.createLocation(location, new QBCallbackImpl() {
#Override
public void onComplete(Result result, Object context) {
// retrieve context object inside callback
String passedContextObject = (String) context;
System.out.println(passedContextObject);
// do stuff with result
}
}, someImportantString);
All logic of data exchange with server is encapsulated in framework.

Categories

Resources