Writing Efficient Drive Apps for Android. Claudio Cherubino / Alain Vongsouvanh Google Drive Developer Relations

Similar documents
Services. service: A background task used by an app.

Upcoming Assignments Quiz Friday? Lab 5 due today Alpha Version due Friday, February 26

1. Implementation of Inheritance with objects, methods. 2. Implementing Interface in a simple java class. 3. To create java class with polymorphism

EMBEDDED SYSTEMS PROGRAMMING Android Services

Android. Mobile operating system developed by Google A complete stack. Based on the Linux kernel Open source under the Apache 2 license

10.1 Introduction. Higher Level Processing. Word Recogniton Model. Text Output. Voice Signals. Spoken Words. Syntax, Semantics, Pragmatics

RUNTIME PERMISSIONS IN ANDROID 6.0 Lecture 10a

Mobile Application Development Android

Android/Java Lightning Tutorial JULY 30, 2018

Terms: MediaPlayer, VideoView, MediaController,

DROIDS ON FIRE. Adrián

Islamic University of Gaza. Faculty of Engineering. Computer Engineering Department. Mobile Computing ECOM Eng. Wafaa Audah.

Using Libraries, Text-to-Speech, Camera. Lecture 12

Mobile Application Development Android

Overview. Android Apps (Partner s App) Other Partner s App Platform. Samsung Health. Server SDK. Samsung Health. Samsung Health Server

ANDROID SDK. Developers Guide

Getting Started With Android Feature Flags

Learn about Android Content Providers and SQLite

Developing Android Applications

Android Help. Section 8. Eric Xiao

The Basis of Data. Steven R. Bagley

Content Provider. Introduction 01/03/2016. Session objectives. Content providers. Android programming course. Introduction. Built-in Content Provider

Workshop. 1. Create a simple Intent (Page 1 2) Launch a Camera for Photo Taking

Getting Started ArcGIS Runtime SDK for Android. Andy

Understand applications and their components. activity service broadcast receiver content provider intent AndroidManifest.xml

Introduction to Android Multimedia

Services. Marco Ronchetti Università degli Studi di Trento

Mobile and Ubiquitous Computing: Android Programming (part 4)

Solving an Android Threading Problem

Real-Time Embedded Systems

Mobile Application Development Android


Hybrid Apps Combining HTML5 + JAVASCRIPT + ANDROID

Android. Operating System and Architecture. Android. Screens. Main features

MOBILE APPLICATIONS PROGRAMMING

Overview. Lecture: Implicit Calling via Share Implicit Receiving via Share Launch Telephone Launch Settings Homework

Android Ecosystem and. Revised v4presenter. What s New

package import import import import import import import public class extends public void super new this class extends public super public void new

Automatically persisted among application sessions

Wireless Vehicle Bus Adapter (WVA) Android Library Tutorial

Diving into Android. By Jeroen Tietema. Jeroen Tietema,

Lecture 1 Introduction to Android. App Development for Mobile Devices. App Development for Mobile Devices. Announcement.

Thread. A Thread is a concurrent unit of execution. The thread has its own call stack for methods being invoked, their arguments and local variables.

Mobile Platforms and Middleware

Programming with Android: Intents. Luca Bedogni. Dipartimento di Scienze dell Informazione Università di Bologna

External Services. CSE 5236: Mobile Application Development Course Coordinator: Dr. Rajiv Ramnath Instructor: Adam C. Champion

32. And this is an example on how to retrieve the messages received through NFC.

Agenda. Overview of Xamarin and Xamarin.Android Xamarin.Android fundamentals Creating a detail screen

Embedded Systems Programming - PA8001

Android System Architecture. Android Application Fundamentals. Applications in Android. Apps in the Android OS. Program Model 8/31/2015

Distributed Systems 2011 Assignment 1

Eng. Jaffer M. El-Agha Android Programing Discussion Islamic University of Gaza. Data persistence

Introduction to Android

CS371m - Mobile Computing. Responsiveness

Multiple Activities. Many apps have multiple activities

Mobile Programming Lecture 10. ContentProviders

Android Programming Lecture 8: Activities, Odds & Ends, Two New Views 9/28/2011

Mobile Computing. Introduction to Android

User Interface Design & Development

API Guide for Gesture Recognition Engine. Version 2.0

Mobile Programming Practice Background processing AsynTask Service Broadcast receiver Lab #5

Login with Amazon. Getting Started Guide for Android apps

UNDERSTANDING ACTIVITIES

Android App Development

CMSC436: Fall 2013 Week 3 Lab

Change in Orientation. Marco Ronchetti Università degli Studi di Trento

Android Services & Local IPC: Overview of Programming Bound Services

Embedded Systems Programming - PA8001

Software Practice 3 Today s lecture Today s Task

Our First Android Application

Application Fundamentals

Android Application Development using Kotlin

EMBEDDED SYSTEMS PROGRAMMING Application Basics

9.0 Help for Community Managers About Jive for Google Docs...4. System Requirements & Best Practices... 5

Android Programming Lecture 7 9/23/2011

Understanding Application

In-app Billing Version 3

Zephyr Cloud for HipChat

Android Services & Local IPC: The Command Processor Pattern (Part 1)

COMP4521 EMBEDDED SYSTEMS SOFTWARE

Spring Lecture 5 Lecturer: Omid Jafarinezhad

Android Tutorial: Part 3

Android permissions Defining and using permissions Component permissions and related APIs

Native Android Development Practices

Applied Cognitive Computing Fall 2016 Android Application + IBM Bluemix (Cloudant NoSQL DB)

SMAATSDK. NFC MODULE ON ANDROID REQUIREMENTS AND DOCUMENTATION RELEASE v1.0

Lecture 2 Android SDK

ATC Android Application Development

Android writing files to the external storage device

Introduction to Android

ContentProvider & ContentResolver ContentResolver methods CursorLoader Implementing ContentProviders

Mobile and Ubiquitous Computing: Android Programming (part 3)

Table of Content. CLOUDCHERRY Android SDK Manual

CSCU9YH: Development with Android

ReportPlus Embedded Web SDK Guide

Programming with Android: Activities and Intents. Dipartimento di Informatica Scienza e Ingegneria Università di Bologna

This tutorial is meant for software developers who want to learn how to lose less time on API integrations!

Introduction to Android Development

CS371m - Mobile Computing. Persistence

Distributed Systems Assignment 1

Transcription:

Writing Efficient Drive Apps for Android Claudio Cherubino / Alain Vongsouvanh Google Drive Developer Relations

Raise your hand if you use Google Drive source: "put your hands up!" (CC-BY)

Raise the other hand if you use Android source: Eloïse L, "Untitled" (CC-BY)

Google Drive Access everywhere Store files in a safe place Go beyond storage. Collaborate.

Google Drive in your browser

Google Drive on your desktop

Google Drive on Android

Drive SDK opportunity ++ Extensive Reach Put your app in front of millions of users with billions of files Effortless Integration Get the best of Google Drive's sharing capabilities, storage capacity and user identity management so you can focus on your app Drive Apps Open files and docs with your app directly from Drive. Full integration - search, sharing and revisions

Android Notepad Simple notepad application Uses SQLite to store notes on the device The app you write right after Hello World! Perfect starting point for our app

Integrate Notepad with Google Drive Perform Authorization Unblock the UI thread Write a Drive Sync Adapter Interact with the Drive app for Android Optimize Efficiency

Integrate Notepad with Google Drive Perform Authorization Unblock the UI thread Write a Drive Sync Adapter Interact with the Drive app for Android Optimize Efficiency

Authorization in Android: Getting an account import com.google.android.gms.common.accountpicker; //... class MyActivity extends Activity { private static final int CHOOSE_ACCOUNT = 0; //... private void chooseaccount(account savedaccount) { startactivityforresult(accountpicker.newchooseaccountintent(savedaccount, null, new String[]() {"com.google", false, null, null, null, null), CHOOSE_ACCOUNT); //... JAVA

Authorization in Android: Getting an account import com.google.android.gms.common.accountpicker; //... class MyActivity extends Activity { private static final int CHOOSE_ACCOUNT = 0; //... protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == CHOOSE_ACCOUNT && resultcode == RESULT_OK && data!= null) { String accountname = data.getstringextra(accountmanager.key_account_name); // TODO: Do something with the account. //... JAVA

Authorization in Android: Getting an account import com.google.android.gms.common.accountpicker; //... class MyActivity extends Activity { private static final int CHOOSE_ACCOUNT = 0; //... protected void onactivityresult(int requestcode, int resultcode, Intent data) { if (requestcode == CHOOSE_ACCOUNT && resultcode == RESULT_OK && data!= null) { String accountname = data.getstringextra(accountmanager.key_account_name); // TODO: Do something with the account. //... JAVA

Authorization in Android: Getting an account

Authorization in Android: Getting an access token // Must run outside of the UI thread. private String getaccesstoken(context context, Account account) { try { return GoogleAuthUtil.getToken(context, account.name, "oauth2:" + DriveScopes.DRIVE_FILE); catch (UserRecoverableAuthException e) { // Start the Approval Screen Intent, if not run from an Activity, add the Intent.FLAG_ACTIVITY_NEW_TASK flag. context.startactivityforresult(e.getintent()); return null; JAVA

Authorization in Android: Getting an access token // Must run outside of the UI thread. private String getaccesstoken(context context, Account account) { try { return GoogleAuthUtil.getToken(context, account.name, "oauth2:" + DriveScopes.DRIVE_FILE); catch (UserRecoverableAuthException e) { // Start the Approval Screen Intent. context.startactivity(e.getintent()); return null; JAVA

Authorization in Android: Getting an access token

Authorization in Android: Additional Information If you want to know more about Authorization in Android, please attend the "Building Android Applications that Use Web APIs" session (http://goo.gl/rsdh2) Register your Android app on the APIs Console Full implementation of the GoogleAuthUtil.getToken call in an AsyncTask Catch errors from AccountPicker and the Authorization Grant Screen Catch expired or invalid tokens

Integrate Notepad with Google Drive Perform Authorization Unblock the UI thread Write a Drive Sync Adapter Interact with the Drive app for Android Optimize Efficiency

From synchronous... source: Alessandro Bonvini, "14,23: In fila per un gelato" (CC-BY)

...to asynchronous source: William Warby, "Heat 1 of the Womens 100m Hurdles Semi-Final" (CC-BY)

Unblock the UI thread If the UI thread freezes the user is presented with the "application not responding" (ANR) dialog Always run long-running operations in worker threads Provide a Handler for child threads to post back to upon completion Fortunately, SyncAdapters do all the heavy lifting!

Integrate Notepad with Google Drive Perform Authorization Unblock the UI thread Write a Drive Sync Adapter Interact with the Drive app for Android Optimize Performance

Drive sync adapter 3 components are involved: 1. Data is stored in the local database by a ContentProvider 2. A SyncAdapter Service runs in the background and periodically synchronizes data with the cloud 3. An AbstractThreadedSyncAdapter implementation contains the sync logic You may optionally add a settings page to allow users to configure the sync frequency

Drive sync adapter: DriveSyncService public class DriveSyncService extends Service { @Override public void oncreate() { // Instantiate a new static DriveSyncAdapter. @Override public IBinder onbind(intent intent) { // Return the DriveSyncAdapter instance's Sync Adapter Binder. Java

Drive sync adapter: DriveSyncService Java //... private static final Object ssyncadapterlock = new Object(); private static DriveSyncAdapter ssyncadapter = null; @Override public void oncreate() { synchronized (ssyncadapterlock) { if (ssyncadapter == null) { ssyncadapter = new DriveSyncAdapter(getApplicationContext(), true); //...

Drive sync adapter: DriveSyncService Java //... private static DriveSyncAdapter ssyncadapter = null; @Override public IBinder onbind(intent intent) { return ssyncadapter.getsyncadapterbinder(); //...

Drive sync adapter: Service manifest XML <service android:name="drivesyncservice"> <intent-filter> <action android:name="android.content.syncadapter" /> </intent-filter> <meta-data android:name="android.content.syncadapter" android:resource="@xml/syncadapter" /> </service>

Drive sync adapter: XML resource XML <?xml version="1.0" encoding="utf-8"?> <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" android:contentauthority="com.google.provider.notepad" android:accounttype="com.google" android:uservisible="true" android:supportsuploading="true" />

Drive sync adapter: DriveSyncAdapter public class DriveSyncAdapter extends AbstractThreadedSyncAdapter { public DriveSyncAdapter(Context context, boolean autoinitialize) { super(context, autoinitialize); @Override public void onperformsync(account account, Bundle bundle, String authority, ContentProviderClient provider, SyncResult syncresult) { // Perform sync logic. Java

Drive sync adapter: Enable it! private static final String AUTHORITY = "com.google.provider.notepad"; private void setsyncfrequency(account account, long syncfrequency) { ContentResolver.setSyncAutomatically(account, AUTHORITY, true); ContentResolver.addPeriodicSync(account, AUTHORITY, new Bundle(), syncfrequency); JAVA

Drive sync adapter

Let's talk to Drive! Retrieve files from the user's Google Drive Create new local file Sync local files with remote changes Handle deleted files

Retrieve files from Drive private void storealldrivefiles(drive service) { Files.List request = service.files().list().setq("mimetype=text/plain"); do { FileList files = request.execute(); for (File file : files.getitems()) { String fileid = file.getid(); String title = file.gettitle(); InputStream content = service.getrequestfactory().buildgetrequest(file.getdownloadurl()).execute().getcontent(); insertdrivefile(fileid, title, content); request.setpagetoken(files.getnextpagetoken()); while (request.getpagetoken()!= null && request.getpagetoken().length() > 0); JAVA

Retrieve files from Drive private void storealldrivefiles(drive service) { Files.List request = service.files().list().setq("mimetype=text/plain"); do { FileList files = request.execute(); for (File file : files.getitems()) { String fileid = file.getid(); String title = file.gettitle(); InputStream content = service.getrequestfactory().buildgetrequest(file.getdownloadurl()).execute().getcontent(); insertdrivefile(fileid, title, content); request.setpagetoken(files.getnextpagetoken()); while (request.getpagetoken()!= null && request.getpagetoken().length() > 0); JAVA

Retrieve files from Drive private void storealldrivefiles(drive service) { Files.List request = service.files().list().setq("mimetype=text/plain"); do { FileList files = request.execute(); for (File file : files.getitems()) { String fileid = file.getid() String title = file.gettitle(); InputStream content = service.getrequestfactory().buildgetrequest(file.getdownloadurl()).execute().getcontent(); insertdrivefile(fileid, title, content); request.setpagetoken(files.getnextpagetoken()); while (request.getpagetoken()!= null && request.getpagetoken().length() > 0); JAVA

Save files to Drive private void insertlocalfile(drive service, ContentClientProvider provider, Cursor cursor, Uri noteuri) { File newfile = new File(); newfile.settitle(cursor.getstring(column_index_title)); newfile.setmimetype("text/plain"); String content = cursor.getstring(column_index_note); File insertedfile = service.files().insert( newfile, ByteArrayContent.fromString("text/plain", content)).execute(); ContentValues values = new ContentValues(); values.put(column_name_drive_id, insertedfile.getid()); values.put(column_name_modification_date, insertedfile.getmodifiedbymedate().getvalue(); values.put(column_name_created_date, insertedfile.getcreateddate().getvalue()); provider.update(noteuri, values, null, null); JAVA

Save files to Drive private void insertlocalfile(drive service, ContentClientProvider provider, Cursor cursor, Uri noteuri) { File newfile = new File(); newfile.settitle(cursor.getstring(column_index_title)); newfile.setmimetype("text/plain"); String content = cursor.getstring(column_index_note); File insertedfile = service.files().insert( newfile, ByteArrayContent.fromString("text/plain", content)).execute(); ContentValues values = new ContentValues(); values.put(column_name_drive_id, insertedfile.getid()); values.put(column_name_modification_date, insertedfile.getmodifiedbymedate().getvalue(); values.put(column_name_created_date, insertedfile.getcreateddate().getvalue()); provider.update(noteuri, values, null, null); JAVA

Save files to Drive private void insertlocalfile(drive service, ContentClientProvider provider, Cursor cursor, Uri noteuri) { File newfile = new File(); newfile.settitle(cursor.getstring(column_index_title)); newfile.setmimetype("text/plain"); String content = cursor.getstring(column_index_note); File insertedfile = service.files().insert( newfile, ByteArrayContent.fromString("text/plain", content)).execute(); ContentValues values = new ContentValues(); values.put(column_name_drive_id, insertedfile.getid()); values.put(column_name_modification_date, insertedfile.getmodifiedbymedate().getvalue(); values.put(column_name_created_date, insertedfile.getcreateddate().getvalue()); provider.update(noteuri, values, null, null); JAVA

Save files to Drive

Integrate Notepad with Google Drive Perform Authorization Unblock the UI thread Write a Drive Sync Adapter Interact with the Drive app for Android Optimize Efficiency

Receiving intents from the Drive app Export an Activity that supports an intent with the following info: action: drive.intent.action.drive_open path: content://com.google.android.drive/open/resourceid type: MIME type of the file Declare your API Project ID in the Activity's metadata List supported MIME types in the intent-filter element The intent will not include the body of the document nor the user account Retrieve the file from the Drive API using the resourceid provided by the intent in the path

Receiving intents from the Drive app <manifest > <uses-permission android:name="android.permission.get_accounts" /> <application > <activity android:name="driveactivity" android:label="@string/cloud_paint" android:icon="@drawable/app_icon" android:exported="true"> <meta-data android:name="com.google.android.apps.drive.app_id" android:value="id=1234567890" /> <intent-filter> <action android:name="com.google.android.apps.drive.drive_open" /> <data android:mimetype="text/plain" /> <data android:mimetype="text/html" /> </intent-filter> </activity> </application> </manifest> XML

Receiving intents from the Drive app @Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); final Intent intent = getintent(); final String action = intent.getaction(); if ("drive.intent.action.drive_open".equals(action)) { String fileid = intent.getstringextra("resourceid"); // Prompt the user to choose the account to use and process the file using the Drive API. else { // Other action. JAVA

Receiving intents from the Drive app @Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); final Intent intent = getintent(); final String action = intent.getaction(); if ("drive.intent.action.drive_open".equals(action)) { String fileid = intent.getstringextra("resourceid"); // Prompt the user to choose the account to use and process the file using the Drive API. else { // Other action. JAVA

Receiving intents from the Drive app @Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); final Intent intent = getintent(); final String action = intent.getaction(); if ("drive.intent.action.drive_open".equals(action)) { String fileid = intent.getstringextra("resourceid"); // Prompt the user to choose the account to use and process the file using the Drive API. else { // Other action. JAVA

Receiving intents from the Drive app @Override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); final Intent intent = getintent(); final String action = intent.getaction(); if ("drive.intent.action.drive_open".equals(action)) { String fileid = intent.getstringextra("resourceid"); // Prompt the user to choose the account to use and process the file using the Drive API. else { // Other action. JAVA

Receiving intents from the Drive app

Integrate Notepad with Google Drive Perform Authorization Unblock the UI thread Write a Drive Sync Adapter Interact with the Drive app for Android Optimize Efficiency

Every byte is sacred Drive files can be up to 10GB Even with the fastest available 4G, it takes 20+ hours to download a 10GB file! Only download files from Drive when it is absolutely necessary Use the local database as cache When the user requests a file send a request to get its metadata compare the md5checksum field in the metadata with the one in the local database (if present) return the local copy if they match or download the document from Drive when they don't source: http://www.theverge.com/2012/4/18/2956899/4g-3g-speed-test-att-verizon-tmobile-sprint-fastest-carrier

Using Drive file metadata private void pushchangetodrive(drive service, Cursor localfile, File drivefile) { String localnote = localfile.getstring(column_index_note); File updatedfile = null; drivefile.settitle(localfile.getstring(column_index_title)); if (md5checksum(localnote).equals(drivefile.getmd5checksum())) { updatedfile = service.files().update(drivefile.getid(), drivefile).execute(); // Only update the metadata. else { // Update both content and metadata. ByteArrayContent content = ByteArrayContent.fromString("text/plain", localnote); updatedfile = service.files().update(drivefile.getid(), drivefile, content).execute(); // Update local files metadata. JAVA

Using Drive file metadata private void pushchangetodrive(drive service, Cursor localfile, File drivefile) { String localnote = localfile.getstring(column_index_note); File updatedfile = null; drivefile.settitle(localfile.getstring(column_index_title)); if (md5checksum(localnote).equals(drivefile.getmd5checksum())) { updatedfile = service.files().update(drivefile.getid(), drivefile).execute(); // Only update the metadata. else { // Update both content and metadata. ByteArrayContent content = ByteArrayContent.fromString("text/plain", localnote); updatedfile = service.files().update(drivefile.getid(), drivefile, content).execute(); // Update local files metadata. JAVA

Using Drive file metadata private void pushchangetodrive(drive service, Cursor localfile, File drivefile) { String localnote = localfile.getstring(column_index_note); File updatedfile = null; drivefile.settitle(localfile.getstring(column_index_title)); if (md5checksum(localnote).equals(drivefile.getmd5checksum())) { updatedfile = service.files().update(drivefile.getid(), drivefile).execute(); // Only update the metadata. else { // Update both content and metadata. ByteArrayContent content = ByteArrayContent.fromString("text/plain", localnote); updatedfile = service.files().update(drivefile.getid(), drivefile, content).execute(); // Update local files metadata. JAVA

Using Drive file metadata private void pushchangetodrive(drive service, Cursor localfile, File drivefile) { String localnote = localfile.getstring(column_index_note); File updatedfile = null; drivefile.settitle(localfile.getstring(column_index_title)); if (md5checksum(localnote).equals(drivefile.getmd5checksum())) { updatedfile = service.files().update(drivefile.getid(), drivefile).execute(); // Only update the metadata. else { // Update both content and metadata. ByteArrayContent content = ByteArrayContent.fromString("text/plain", localnote); updatedfile = service.files().update(drivefile.getid(), drivefile, content).execute(); // Update local files metadata. JAVA

Detecting changes to files Collection GET On Client File Modified File PUT File File Deleted DELETE File New Stuff New Stuff POST Changes Feed

Detecting changes to files Changes.List request = service.changes().list().setstartchangeid(new BigInteger(Long.toString(startChangeId))); do { ChangeList changes = request.execute(); for (Change change : changes.getitems()) { if (change.getdeleted()) { // File with ID "change.getfileid()" has been deleted. else { File changedfile = change.getfile(); // Do something with the updated metadata. request.setpagetoken(changes.getnextpagetoken()); while (request.getpagetoken()!= null && request.getpagetoken().length() > 0); JAVA

Detecting changes to files Changes.List request = service.changes().list().setstartchangeid(new BigInteger(Long.toString(startChangeId))); do { ChangeList changes = request.execute(); for (Change change : changes.getitems()) { if (change.getdeleted()) { // File with ID "change.getfileid()" has been deleted. else { File changedfile = change.getfile(); // Do something with the updated metadata. request.setpagetoken(changes.getnextpagetoken()); while (request.getpagetoken()!= null && request.getpagetoken().length() > 0); JAVA

Detecting changes to files Changes.List request = service.changes().list().setstartchangeid(new BigInteger(Long.toString(startChangeId))); do { ChangeList changes = request.execute(); for (Change change : changes.getitems()) { if (change.getdeleted()) { // File with ID "change.getfileid()" has been deleted. else { File changedfile = change.getfile(); // Do something with the updated metadata. request.setpagetoken(changes.getnextpagetoken()); while (request.getpagetoken()!= null && request.getpagetoken().length() > 0); JAVA

Live demo

<Thank You!> https://developers.google.com/drive/ ccherubino@google.com alainv@google.com http://plus.claudiocherubino.it http://plus.vongsouvanh.com #ccherubino