Google Play Services Rock

133
Google Play Services with Xamarin Building Apps that rock

description

Google Play Services are a unified SDK that allow you to quickly and easily integrate Google features into your Android apps. Being rolled out to millions of Android devices, they provide easy access to Google services and allow you to innovate quickly. In this session, I will give you a rundown of the core services available via Google Play Services and give you an overview of the new APIs that ship as a part of Google Play Services. We will also have a look at some of the lesser known features that will enable you to build apps that truly rock.

Transcript of Google Play Services Rock

Page 1: Google Play Services Rock

Google Play Services

with Xamarin

Building Apps that rock

Page 2: Google Play Services Rock

+Peter Friese

@peterfriese

Page 3: Google Play Services Rock

What is Google Play

Services?

Page 4: Google Play Services Rock

• Set of APIs by Google

Google Play Services

Page 5: Google Play Services Rock

• Set of APIs by Google

• Available for Devices running

Gingerbread and higher

Google Play Services

Page 6: Google Play Services Rock

• Set of APIs by Google

• Available for Devices running

Gingerbread and higher

• Access the latest in Google

technology

Google Play Services

Page 7: Google Play Services Rock

• Set of APIs by Google

• Available for Devices running

Gingerbread and higher

• Access the latest in Google

technology

• Frequent updates

Google Play Services

Page 8: Google Play Services Rock

• Set of APIs by Google

• Available for Devices running

Gingerbread and higher

• Access the latest in Google

technology

• Frequent updates

• One standard way to connect

and authorise

Google Play Services

Page 9: Google Play Services Rock

Device

Google Play Services Library

Google Play Services

Drive Service

Your App

Google API Client

Maps

Google+

Wallet

Games Services

Page 10: Google Play Services Rock

How to Integrate Google

Play Services

Page 11: Google Play Services Rock

Three simple steps to success

Add Google

Play Services

to your project

Start using our

APIsProfit!

Page 12: Google Play Services Rock

it's a little

bit morecomplicated.

Actually,

Image: http://en.wikipedia.org/wiki/Turf_maze

Page 13: Google Play Services Rock

• Create new Android project

Xamarin StudioProject setup

Page 14: Google Play Services Rock

Xamarin Studio

• Create new Android project

Project setup

Page 15: Google Play Services Rock

• Create new Android project

• Download Google Play

Services

Xamarin StudioProject setup

Page 16: Google Play Services Rock

Xamarin Studio

• Create new Android project

• Download Google Play

Services

Project setup

Page 17: Google Play Services Rock

• Create new Android project

• Download Google Play

Services

• Add the NuGet component

Xamarin StudioProject setup

Page 18: Google Play Services Rock

Xamarin Studio

• Create new Android project

• Download Google Play

Services

• Add the NuGet component

Project setup

Page 19: Google Play Services Rock

• Create a new project

Google Developers ConsoleProject setup

Page 20: Google Play Services Rock

Google Developers Console

• Create a new project

Project setup

Page 21: Google Play Services Rock

• Create a new project

• Configure the Consent Screen

Google Developers ConsoleProject setup

Page 22: Google Play Services Rock

Google Developers Console

• Create a new project

• Configure the Consent Screen

Project setup

Page 23: Google Play Services Rock

• Create a new project

• Configure the Consent Screen

• Create a Client Configuration

Google Developers ConsoleProject setup

Page 24: Google Play Services Rock

Google Developers Console

• Create a new project

• Configure the Consent Screen

• Create a Client Configuration

Project setup$ keytool -list -storepass android -keystore ~/.local/share/Xamarin/Mono\ for\ Android/debug.keystore !Keystore type: JKS Keystore provider: SUN Your keystore contains 1 entry androiddebugkey, 14-May-2014, PrivateKeyEntry, Certificate fingerprint (SHA1): CA:FE:BA:BE:DE:AD:BE:EF:DE:ED:BE:AD:FE:ED:DE:AF:CA:FE:BA:BE

Page 25: Google Play Services Rock

• Create a new project

• Configure the Consent Screen

• Create a Client Configuration

Google Developers ConsoleProject setup

Page 26: Google Play Services Rock

• Create a new project

• Configure the Consent Screen

• Create a Client Configuration

• Activate APIs

Google Developers ConsoleProject setup

Page 27: Google Play Services Rock

Connecting Your App

with Google

Page 28: Google Play Services Rock

protected bool ServicesConnected(){ var resultCode = GooglePlayServicesUtil.IsGooglePlayServicesAvailable (this); if (resultCode == ConnectionResult.Success) { Log.Debug (logTag, "Google Play Services are available"); return true; } else { Log.Debug (logTag, "Connection failed. Attempting resolution."); GooglePlayServicesUtil.GetErrorDialog (resultCode, this, ConnectionFailureResolutionRequest).Show (); return false; }}

BaseActivity.cs

Checking for a compatible GMS version

Page 29: Google Play Services Rock

protected override void OnCreate (Bundle savedInstanceState){ base.OnCreate (savedInstanceState); if (googleApiClient == null) { googleApiClient = new GoogleApiClientBuilder (this) .AddApi (DriveClass.Api) .AddScope (DriveClass.ScopeFile) .AddApi(PlusClass.Api) .AddScope(PlusClass.ScopePlusLogin) .AddConnectionCallbacks (this) .AddOnConnectionFailedListener (this) .Build (); }}

BaseActivity.cs

Configuring GoogleApiClient

Page 30: Google Play Services Rock

protected override void OnCreate (Bundle savedInstanceState){ base.OnCreate (savedInstanceState); if (googleApiClient == null) { googleApiClient = new GoogleApiClientBuilder (this) .AddApi (DriveClass.Api) .AddScope (DriveClass.ScopeFile) .AddApi(PlusClass.Api) .AddScope(PlusClass.ScopePlusLogin) .AddConnectionCallbacks (this) .AddOnConnectionFailedListener (this) .Build (); }}

BaseActivity.cs

Configuring GoogleApiClient

Add multiple APIs and Scopes

Page 31: Google Play Services Rock

protected override void OnCreate (Bundle savedInstanceState){ base.OnCreate (savedInstanceState); if (googleApiClient == null) { googleApiClient = new GoogleApiClientBuilder (this) .AddApi (DriveClass.Api) .AddScope (DriveClass.ScopeFile) .AddApi(PlusClass.Api) .AddScope(PlusClass.ScopePlusLogin) .AddConnectionCallbacks (this) .AddOnConnectionFailedListener (this) .Build (); }}

BaseActivity.cs

Configuring GoogleApiClient

Set up callbacks

Page 32: Google Play Services Rock

protected override void OnStart (){ base.OnStart (); googleApiClient.Connect();} !protected override void OnStop (){ if (googleApiClient != null) { googleApiClient.Disconnect (); } base.OnStop ();}

BaseActivity.cs

Connecting GoogleApiClient

Page 33: Google Play Services Rock

BaseActivity.cs

Callbacks - The Good

public class BaseDemoActivity : Activity, IGoogleApiClientConnectionCallbacks{ public virtual void OnConnected (Bundle connectionHint) { Log.Debug (logTag, "Google API client connected.”); // let the good stuff happen here } public void OnConnectionSuspended (int cause) { Log.Debug (logTag, "Google API client connection suspended."); // deactivate UI components, etc. }}

Page 34: Google Play Services Rock

BaseActivity.cs

Callbacks - The Bad

public class BaseDemoActivity : Activity, IGoogleApiClientOnConnectionFailedListener{ public void OnConnectionFailed (ConnectionResult result) { if (result.HasResolution) { try { result.StartResolutionForResult (this, RequestCodeResolution); } catch (IntentSender.SendIntentException ex) { Log.Error (logTag, "Exception while starting resolution activity", ex); } } else { GooglePlayServicesUtil.GetErrorDialog (result.ErrorCode, this, 0).Show (); return; } }}

Page 35: Google Play Services Rock

BaseActivity.cs

Callbacks - The Bad

public class BaseDemoActivity : Activity, IGoogleApiClientOnConnectionFailedListener{ public void OnConnectionFailed (ConnectionResult result) { if (result.HasResolution) { try { result.StartResolutionForResult (this, RequestCodeResolution); } catch (IntentSender.SendIntentException ex) { Log.Error (logTag, "Exception while starting resolution activity", ex); } } else { GooglePlayServicesUtil.GetErrorDialog (result.ErrorCode, this, 0).Show (); return; } }}

Try to resolve this error by asking for the user’s consent

Page 36: Google Play Services Rock

A Closer Look at Some

of the Services

Page 37: Google Play Services Rock

?

Page 38: Google Play Services Rock

Google Drive

Record demos

Reading / writing files

App folders

Page 39: Google Play Services Rock

• Cloud storage powered by

Google’s infrastructure

Google Drive

Page 40: Google Play Services Rock

• Cloud storage powered by

Google’s infrastructure

• 15 GB for free, upgrades at

competitive prices

Google Drive

Page 41: Google Play Services Rock

• Cloud storage powered by

Google’s infrastructure

• 15 GB for free, upgrades at

competitive prices

• Automatic synchronisation

Google Drive

Page 42: Google Play Services Rock

• Cloud storage powered by

Google’s infrastructure

• 15 GB for free, upgrades at

competitive prices

• Automatic synchronisation

• Android, iOS, Mac, Windows,

Web

Google Drive

Page 43: Google Play Services Rock

• Cloud storage powered by

Google’s infrastructure

• 15 GB for free, upgrades at

competitive prices

• Automatic synchronisation

• Android, iOS, Mac, Windows,

Web

• UI controls (create / pick files)

Google Drive

Page 44: Google Play Services Rock

protected override void OnCreate (Bundle savedInstanceState){ base.OnCreate (savedInstanceState); if (googleApiClient == null) { googleApiClient = new GoogleApiClientBuilder (this) .AddApi (DriveClass.Api) .AddScope (DriveClass.ScopeFile) .AddConnectionCallbacks (this) .AddOnConnectionFailedListener (this) .Build (); }}

BaseActivity.cs

Google Drive - Connecting

Page 45: Google Play Services Rock

protected override void OnCreate (Bundle savedInstanceState){ base.OnCreate (savedInstanceState); if (googleApiClient == null) { googleApiClient = new GoogleApiClientBuilder (this) .AddApi (DriveClass.Api) .AddScope (DriveClass.ScopeFile) .AddConnectionCallbacks (this) .AddOnConnectionFailedListener (this) .Build (); }}

BaseActivity.cs

Configuring GoogleApiClient

Supported scopes:

• DriveClass.ScopeFile (drive.file)

• DriveClass.ScopeAppFolder (drive.appfolder)

More about scopes: https://developers.google.com/drive/web/scopes

Page 46: Google Play Services Rock

Google DriveList Files

Page 47: Google Play Services Rock

public class ListFilesActivity : BaseDemoActivity, IResultCallback{ private bool hasMore; private string nextPageToken; private ListView listView; protected ResultsAdapter resultsAdapter;

protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); SetContentView (Resource.Layout.ListFiles); hasMore = true; listView = (ListView) FindViewById (Resource.Id.ListViewResults); resultsAdapter = new ResultsAdapter (this); listView.Adapter = resultsAdapter; listView.Scroll += (object sender, AbsListView.ScrollEventArgs e) => { if (nextPageToken != null && e.FirstVisibleItem + e.VisibleItemCount + 5 < e.TotalItemCount) {

ListFilesActivity.cs

Called for paging list of files.

Page 48: Google Play Services Rock

public class ListFilesActivity : BaseDemoActivity, IResultCallback{ private bool hasMore; private string nextPageToken; private ListView listView; protected ResultsAdapter resultsAdapter;

protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); SetContentView (Resource.Layout.ListFiles); hasMore = true; listView = (ListView) FindViewById (Resource.Id.ListViewResults); resultsAdapter = new ResultsAdapter (this); listView.Adapter = resultsAdapter; listView.Scroll += (object sender, AbsListView.ScrollEventArgs e) => { if (nextPageToken != null && e.FirstVisibleItem + e.VisibleItemCount + 5 < e.TotalItemCount) { RetrieveNextPage(); } } ; }

protected override void OnStop() {

ListFilesActivity.cs

General view setup

Page 49: Google Play Services Rock

base.OnCreate (bundle); SetContentView (Resource.Layout.ListFiles); hasMore = true; listView = (ListView) FindViewById (Resource.Id.ListViewResults); resultsAdapter = new ResultsAdapter (this); listView.Adapter = resultsAdapter; listView.Scroll += (object sender, AbsListView.ScrollEventArgs e) => { if (nextPageToken != null && e.FirstVisibleItem + e.VisibleItemCount + 5 < e.TotalItemCount) { RetrieveNextPage(); } } ; }

protected override void OnStop() { base.OnStop(); resultsAdapter.Clear(); } public override void OnConnected (Bundle connectionHint) { base.OnConnected (connectionHint); RetrieveNextPage(); }

ListFilesActivity.cs

Fetch next page when scrolling

Page 50: Google Play Services Rock

listView.Scroll += (object sender, AbsListView.ScrollEventArgs e) => { if (nextPageToken != null && e.FirstVisibleItem + e.VisibleItemCount + 5 < e.TotalItemCount) { RetrieveNextPage(); } } ; }

protected override void OnStop() { base.OnStop(); resultsAdapter.Clear(); } public override void OnConnected (Bundle connectionHint) { base.OnConnected (connectionHint); RetrieveNextPage(); } private void RetrieveNextPage () { if (!hasMore) { return; } var query = new QueryClass.Builder () .SetPageToken (nextPageToken)

ListFilesActivity.cs

Clear adapter on stop.

Page 51: Google Play Services Rock

}

protected override void OnStop() { base.OnStop(); resultsAdapter.Clear(); } public override void OnConnected (Bundle connectionHint) { base.OnConnected (connectionHint); RetrieveNextPage(); } private void RetrieveNextPage () { if (!hasMore) { return; } var query = new QueryClass.Builder () .SetPageToken (nextPageToken) .Build (); DriveClass.DriveApi.Query (GoogleApiClient, query).SetResultCallback (this); } public void OnResult (Java.Lang.Object result) {

ListFilesActivity.cs

Fetch data as soon as we’re connected

Page 52: Google Play Services Rock

} public override void OnConnected (Bundle connectionHint) { base.OnConnected (connectionHint); RetrieveNextPage(); } private void RetrieveNextPage () { if (!hasMore) { return; } var query = new QueryClass.Builder () .SetPageToken (nextPageToken) .Build (); DriveClass.DriveApi.Query (GoogleApiClient, query).SetResultCallback (this); } public void OnResult (Java.Lang.Object result) { var metadataBufferResult = result.JavaCast<IDriveApiMetadataBufferResult> (); if (metadataBufferResult != null) { if (!metadataBufferResult.Status.IsSuccess) { ShowMessage ("Problems while retrieving files."); }

ListFilesActivity.cs

Use token to keep track of position

Page 53: Google Play Services Rock

return; } var query = new QueryClass.Builder () .SetPageToken (nextPageToken) .Build (); DriveClass.DriveApi.Query (GoogleApiClient, query).SetResultCallback (this); } public void OnResult (Java.Lang.Object result) { var metadataBufferResult = result.JavaCast<IDriveApiMetadataBufferResult> (); if (metadataBufferResult != null) { if (!metadataBufferResult.Status.IsSuccess) { ShowMessage ("Problems while retrieving files."); } resultsAdapter.Append (metadataBufferResult.MetadataBuffer); nextPageToken = metadataBufferResult.MetadataBuffer.NextPageToken; hasMore = nextPageToken != null; } }}

ListFilesActivity.cs

Fetch results from metadata buffer

Page 54: Google Play Services Rock

Google DrivePick Files & Folders

Page 55: Google Play Services Rock

public override void OnConnected (Bundle connectionHint){ base.OnConnected (connectionHint); var intentSender = DriveClass.DriveApi .NewOpenFileActivityBuilder () .SetMimeType (new string[]{ "text/plain", "text/html" } ) .Build (GoogleApiClient); try { StartIntentSenderForResult (intentSender, RequestCodeOpener, null, 0, 0, 0); } catch (IntentSender.SendIntentException ex) { Log.Warn (logTag, "Unable to send intent", ex); }}protected override void OnActivityResult (int requestCode, Result resultCode, Intent data){ base.OnActivityResult (requestCode, resultCode, data);

PickFileWithOpenerActivity.cs

Page 56: Google Play Services Rock

public override void OnConnected (Bundle connectionHint){ base.OnConnected (connectionHint); var intentSender = DriveClass.DriveApi .NewOpenFileActivityBuilder () .SetMimeType (new string[]{ "text/plain", "text/html" } ) .Build (GoogleApiClient); try { StartIntentSenderForResult (intentSender, RequestCodeOpener, null, 0, 0, 0); } catch (IntentSender.SendIntentException ex) { Log.Warn (logTag, "Unable to send intent", ex); }}protected override void OnActivityResult (int requestCode, Result resultCode, Intent data){ base.OnActivityResult (requestCode, resultCode, data);

PickFileWithOpenerActivity.cs

Create new file picker

Page 57: Google Play Services Rock

public override void OnConnected (Bundle connectionHint){ base.OnConnected (connectionHint); var intentSender = DriveClass.DriveApi .NewOpenFileActivityBuilder () .SetMimeType (new string[]{ "text/plain", "text/html" } ) .Build (GoogleApiClient); try { StartIntentSenderForResult (intentSender, RequestCodeOpener, null, 0, 0, 0); } catch (IntentSender.SendIntentException ex) { Log.Warn (logTag, "Unable to send intent", ex); }}protected override void OnActivityResult (int requestCode, Result resultCode, Intent data){ base.OnActivityResult (requestCode, resultCode, data);

PickFileWithOpenerActivity.cs

Mime types to show in picker

Page 58: Google Play Services Rock

public override void OnConnected (Bundle connectionHint){ base.OnConnected (connectionHint); var intentSender = DriveClass.DriveApi .NewOpenFileActivityBuilder () .SetMimeType (new string[]{ "text/plain", "text/html" } ) .Build (GoogleApiClient); try { StartIntentSenderForResult (intentSender, RequestCodeOpener, null, 0, 0, 0); } catch (IntentSender.SendIntentException ex) { Log.Warn (logTag, "Unable to send intent", ex); }}protected override void OnActivityResult (int requestCode, Result resultCode, Intent data){ base.OnActivityResult (requestCode, resultCode, data);

PickFileWithOpenerActivity.cs

Start picker intent

Page 59: Google Play Services Rock

.Build (GoogleApiClient); try { StartIntentSenderForResult (intentSender, RequestCodeOpener, null, 0, 0, 0); } catch (IntentSender.SendIntentException ex) { Log.Warn (logTag, "Unable to send intent", ex); }}protected override void OnActivityResult (int requestCode, Result resultCode, Intent data){ base.OnActivityResult (requestCode, resultCode, data); if (requestCode == RequestCodeOpener) { if (resultCode == Result.Ok) { var driveId = data.GetParcelableExtra (OpenFileActivityBuilder.ExtraResponseDriveId); ShowMessage ("Selected folder with ID: " + driveId); } Finish (); } else { base.OnActivityResult (requestCode, resultCode, data); }}

PickFileWithOpenerActivity.cs

Page 60: Google Play Services Rock

.Build (GoogleApiClient); try { StartIntentSenderForResult (intentSender, RequestCodeOpener, null, 0, 0, 0); } catch (IntentSender.SendIntentException ex) { Log.Warn (logTag, "Unable to send intent", ex); }}protected override void OnActivityResult (int requestCode, Result resultCode, Intent data){ base.OnActivityResult (requestCode, resultCode, data); if (requestCode == RequestCodeOpener) { if (resultCode == Result.Ok) { var driveId = data.GetParcelableExtra (OpenFileActivityBuilder.ExtraResponseDriveId); ShowMessage ("Selected folder with ID: " + driveId); } Finish (); } else { base.OnActivityResult (requestCode, resultCode, data); }}

PickFileWithOpenerActivity.cs

Returning from picker?

Page 61: Google Play Services Rock

.Build (GoogleApiClient); try { StartIntentSenderForResult (intentSender, RequestCodeOpener, null, 0, 0, 0); } catch (IntentSender.SendIntentException ex) { Log.Warn (logTag, "Unable to send intent", ex); }}protected override void OnActivityResult (int requestCode, Result resultCode, Intent data){ base.OnActivityResult (requestCode, resultCode, data); if (requestCode == RequestCodeOpener) { if (resultCode == Result.Ok) { var driveId = data.GetParcelableExtra (OpenFileActivityBuilder.ExtraResponseDriveId); ShowMessage ("Selected folder with ID: " + driveId); } Finish (); } else { base.OnActivityResult (requestCode, resultCode, data); }}

PickFileWithOpenerActivity.cs

Get metadata from extras

Page 62: Google Play Services Rock

Activity Recogniton

Image by Martijn van Dalen

https://www.flickr.com/photos/martijnvandalen/4591360652

Page 63: Google Play Services Rock

Activity RecognitionDemo

Page 64: Google Play Services Rock

protected override void OnCreate (Bundle savedInstanceState){ base.OnCreate (savedInstanceState); if (googleApiClient == null) { googleApiClient = new GoogleApiClientBuilder (this) .AddApi (ActivityRecognition.Api) .AddConnectionCallbacks (this) .AddOnConnectionFailedListener (this) .Build (); }}

BaseActivity.cs

Activity Recognition - Connecting

Page 65: Google Play Services Rock

protected override void OnCreate (Bundle savedInstanceState){ base.OnCreate (savedInstanceState); if (googleApiClient == null) { googleApiClient = new GoogleApiClientBuilder (this) .AddApi (ActivityRecognition.Api) .AddConnectionCallbacks (this) .AddOnConnectionFailedListener (this) .Build (); }}

BaseActivity.cs

Activity Recognition - Connecting

Page 66: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="ActivityRecognitionDemos.ActivityRecognitionDemos"> <uses-sdk /> <application android:label="ActivityRecognitionDemos"> </application> <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" /></manifest>

AndroidManifest.xml

Activity Recognition - Permissions

Page 67: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="ActivityRecognitionDemos.ActivityRecognitionDemos"> <uses-sdk /> <application android:label="ActivityRecognitionDemos"> </application> <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" /></manifest>

AndroidManifest.xml

Activity Recognition - Permissions

Page 68: Google Play Services Rock

public override void OnConnected (Bundle connectionHint){ var intent = new Intent (this, typeof(ActivityRecognitionIntentService)); activityRecognitionPendingIntent = PendingIntent.GetService ( this, 0, intent, PendingIntentFlags.UpdateCurrent); ActivityRecognition.ActivityRecognitionApi.RequestActivityUpdates (GoogleApiClient, DetectionInterval, activityRecognitionPendingIntent);}

MainActivity.cs

Starting Activity Recognition

Page 69: Google Play Services Rock

public override void OnConnected (Bundle connectionHint){ var intent = new Intent (this, typeof(ActivityRecognitionIntentService)); activityRecognitionPendingIntent = PendingIntent.GetService ( this, 0, intent, PendingIntentFlags.UpdateCurrent); ActivityRecognition.ActivityRecognitionApi.RequestActivityUpdates (GoogleApiClient, DetectionInterval, activityRecognitionPendingIntent);}

MainActivity.cs

Starting Activity Recognition

Page 70: Google Play Services Rock

public override void OnConnected (Bundle connectionHint){ var intent = new Intent (this, typeof(ActivityRecognitionIntentService)); activityRecognitionPendingIntent = PendingIntent.GetService ( this, 0, intent, PendingIntentFlags.UpdateCurrent); ActivityRecognition.ActivityRecognitionApi.RequestActivityUpdates (GoogleApiClient, DetectionInterval, activityRecognitionPendingIntent);}

MainActivity.cs

Starting Activity Recognition

Page 71: Google Play Services Rock

[Service][IntentFilter(new String[]{"ActivityRecognitionIntentService"})]public class ActivityRecognitionIntentService : IntentService{ protected override void OnHandleIntent (Android.Content.Intent intent) { if (ActivityRecognitionResult.HasResult (intent)) { var result = ActivityRecognitionResult.ExtractResult (intent); var mostProbableActivity = result.MostProbableActivity; var confidence = mostProbableActivity.Confidence; var activityType = mostProbableActivity.Type; var name = GetActivityName (activityType); } } ! protected string GetActivityName(int activityType) { switch (activityType) { } } }

ActivityRecognitionIntentService.cs

Receiving Activity Updates

Page 72: Google Play Services Rock

[Service][IntentFilter(new String[]{"ActivityRecognitionIntentService"})]public class ActivityRecognitionIntentService : IntentService{ protected override void OnHandleIntent (Android.Content.Intent intent) { if (ActivityRecognitionResult.HasResult (intent)) { var result = ActivityRecognitionResult.ExtractResult (intent); var mostProbableActivity = result.MostProbableActivity; var confidence = mostProbableActivity.Confidence; var activityType = mostProbableActivity.Type; var name = GetActivityName (activityType); } } ! protected string GetActivityName(int activityType) { switch (activityType) { } } }

ActivityRecognitionIntentService.cs

Receiving Activity Updates

Page 73: Google Play Services Rock

[Service][IntentFilter(new String[]{"ActivityRecognitionIntentService"})]public class ActivityRecognitionIntentService : IntentService{ protected override void OnHandleIntent (Android.Content.Intent intent) { if (ActivityRecognitionResult.HasResult (intent)) { var result = ActivityRecognitionResult.ExtractResult (intent); var mostProbableActivity = result.MostProbableActivity; var confidence = mostProbableActivity.Confidence; var activityType = mostProbableActivity.Type; var name = GetActivityName (activityType); } } ! protected string GetActivityName(int activityType) { switch (activityType) { } } }

ActivityRecognitionIntentService.cs

Receiving Activity Updates

Page 74: Google Play Services Rock

[Service][IntentFilter(new String[]{"ActivityRecognitionIntentService"})]public class ActivityRecognitionIntentService : IntentService{ protected override void OnHandleIntent (Android.Content.Intent intent) { if (ActivityRecognitionResult.HasResult (intent)) { var result = ActivityRecognitionResult.ExtractResult (intent); var mostProbableActivity = result.MostProbableActivity; var confidence = mostProbableActivity.Confidence; var activityType = mostProbableActivity.Type; var name = GetActivityName (activityType); } } ! protected string GetActivityName(int activityType) { switch (activityType) { } } }

ActivityRecognitionIntentService.cs

Receiving Activity Updates

Page 75: Google Play Services Rock

[Service][IntentFilter(new String[]{"ActivityRecognitionIntentService"})]public class ActivityRecognitionIntentService : IntentService{ protected override void OnHandleIntent (Android.Content.Intent intent) { if (ActivityRecognitionResult.HasResult (intent)) { var result = ActivityRecognitionResult.ExtractResult (intent); var mostProbableActivity = result.MostProbableActivity; var confidence = mostProbableActivity.Confidence; var activityType = mostProbableActivity.Type; var name = GetActivityName (activityType); } } ! protected string GetActivityName(int activityType) { switch (activityType) { } } }

ActivityRecognitionIntentService.cs

Receiving Activity Updates

Page 76: Google Play Services Rock

Maps

Image: Wikipedia

http://bit.ly/10L5SC1

Page 77: Google Play Services Rock

• Obtaining a Maps Key

Google Developers ConsoleMaps Setup

Page 78: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android=“http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName=“1.0" package="com.google.xamarin.sample.GoogleMapsAndroidDemos">

<uses-sdk /> <application android:label="GoogleMapsAndroidDemos"> <meta-data android:name=“com.google.android.maps.v2.API_KEY" android:value="AAzaXXXv3LKXXX0yJb-dXX0xxxWo0XxX_XXXxAg" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission

AndroidManifest.xml

Maps Key and Permissions

Page 79: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android=“http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName=“1.0" package="com.google.xamarin.sample.GoogleMapsAndroidDemos">

<uses-sdk /> <application android:label="GoogleMapsAndroidDemos"> <meta-data android:name=“com.google.android.maps.v2.API_KEY" android:value="AAzaXXXv3LKXXX0yJb-dXX0xxxWo0XxX_XXXxAg" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission

AndroidManifest.xml

Maps Key and Permissions

Maps API Key

Page 80: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android=“http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName=“1.0" package="com.google.xamarin.sample.GoogleMapsAndroidDemos">

<uses-sdk /> <application android:label="GoogleMapsAndroidDemos"> <meta-data android:name=“com.google.android.maps.v2.API_KEY" android:value="AAzaXXXv3LKXXX0yJb-dXX0xxxWo0XxX_XXXxAg" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission

AndroidManifest.xml

Maps Key and Permissions

GMS Version

Page 81: Google Play Services Rock

android:versionName=“1.0" package="com.google.xamarin.sample.GoogleMapsAndroidDemos">

<uses-sdk /> <application android:label="GoogleMapsAndroidDemos"> <meta-data android:name=“com.google.android.maps.v2.API_KEY" android:value="AAzaXXXv3LKXXX0yJb-dXX0xxxWo0XxX_XXXxAg" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /></manifest>

Maps Key and Permissions

AndroidManifest.xml

Page 82: Google Play Services Rock

MapsStreet View

Page 83: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/StreetViewActivity" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.StreetViewPanoramaFragment" /></FrameLayout>

StreetViewActivity.axml

Layout

Page 84: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/StreetViewActivity" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.StreetViewPanoramaFragment" /></FrameLayout>

StreetViewActivity.axml

Layout

Page 85: Google Play Services Rock

protected override void OnCreate (Bundle bundle){ base.OnCreate (bundle); SetContentView (Resource.Layout.StreetViewActivity);

svp = (FragmentManager.FindFragmentById<StreetViewPanoramaFragment> (Resource.Id.StreetViewActivity)).StreetViewPanorama; svp.SetPosition (new LatLng(51.493896, -0.146866));}

StreetViewActivity.cs

StreetView - Set Position

Page 86: Google Play Services Rock

protected override void OnCreate (Bundle bundle){ base.OnCreate (bundle); SetContentView (Resource.Layout.StreetViewActivity);

svp = (FragmentManager.FindFragmentById<StreetViewPanoramaFragment> (Resource.Id.StreetViewActivity)).StreetViewPanorama; svp.SetPosition (new LatLng(51.493896, -0.146866));}

StreetViewActivity.cs

StreetView - Set Position

Page 87: Google Play Services Rock

protected override void OnCreate (Bundle bundle){ base.OnCreate (bundle); SetContentView (Resource.Layout.StreetViewActivity);

svp = (FragmentManager.FindFragmentById<StreetViewPanoramaFragment> (Resource.Id.StreetViewActivity)).StreetViewPanorama; svp.SetPosition (new LatLng(51.493896, -0.146866));}

StreetViewActivity.cs

StreetView - Set Position

Page 88: Google Play Services Rock

protected void walkToOffice() { long duration = 500; float tilt = 0; var camera = new StreetViewPanoramaCamera.Builder () .Zoom (svp.PanoramaCamera.Zoom) .Bearing (svp.PanoramaCamera.Bearing) .Tilt (tilt) .Build (); svp.AnimateTo (camera, duration); svp.SetPosition (new LatLng(51.493896, -0.146866));}

StreetViewActivity.cs

StreetView - Move Camera

Page 89: Google Play Services Rock

protected void walkToOffice() { long duration = 500; float tilt = 0; var camera = new StreetViewPanoramaCamera.Builder () .Zoom (svp.PanoramaCamera.Zoom) .Bearing (svp.PanoramaCamera.Bearing) .Tilt (tilt) .Build (); svp.AnimateTo (camera, duration); svp.SetPosition (new LatLng(51.493896, -0.146866));}

StreetViewActivity.cs

StreetView - Move Camera

Page 90: Google Play Services Rock

protected void walkToOffice() { long duration = 500; float tilt = 0; var camera = new StreetViewPanoramaCamera.Builder () .Zoom (svp.PanoramaCamera.Zoom) .Bearing (svp.PanoramaCamera.Bearing) .Tilt (tilt) .Build (); svp.AnimateTo (camera, duration); svp.SetPosition (new LatLng(51.493896, -0.146866));}

StreetViewActivity.cs

StreetView - Move Camera

Customizing user-controlled functionality:

• PanningGesturesEnabled

• UserNavigationEnabled

• ZoomGesturesEnabled

• StreetNamesEnabled

Page 91: Google Play Services Rock

MapsIndoor Maps

Page 92: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/IndoorMaps" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" /></FrameLayout>

StreetViewActivity.axml

Layout

Page 93: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <fragment android:id="@+id/IndoorMaps" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" /></FrameLayout>

StreetViewActivity.axml

Layout

Page 94: Google Play Services Rock

protected override void OnCreate (Bundle bundle){ base.OnCreate (bundle); SetContentView (Resource.Layout.IndoorMapsActivity);

if (map == null) { map = (FragmentManager.FindFragmentById<MapFragment> (Resource.Id.IndoorMaps)).Map; if (map != null) { var camera = CameraUpdateFactory.NewLatLngZoom ( new LatLng(51.493896, -0.146866), 18); map.MoveCamera (camera); } }}

IndoorMapsViewActivity.cs

Indoor Maps

Page 95: Google Play Services Rock

protected override void OnCreate (Bundle bundle){ base.OnCreate (bundle); SetContentView (Resource.Layout.IndoorMapsActivity);

if (map == null) { map = (FragmentManager.FindFragmentById<MapFragment> (Resource.Id.IndoorMaps)).Map; if (map != null) { var camera = CameraUpdateFactory.NewLatLngZoom ( new LatLng(51.493896, -0.146866), 18); map.MoveCamera (camera); } }}

IndoorMapsViewActivity.cs

Indoor Maps

Page 96: Google Play Services Rock

protected override void OnCreate (Bundle bundle){ base.OnCreate (bundle); SetContentView (Resource.Layout.IndoorMapsActivity);

if (map == null) { map = (FragmentManager.FindFragmentById<MapFragment> (Resource.Id.IndoorMaps)).Map; if (map != null) { var camera = CameraUpdateFactory.NewLatLngZoom ( new LatLng(51.493896, -0.146866), 18); map.MoveCamera (camera); } }}

IndoorMapsViewActivity.cs

Indoor Maps

Page 97: Google Play Services Rock

Google+

Page 98: Google Play Services Rock

• Powerful identity provider

Google+

Page 99: Google Play Services Rock

• Powerful identity provider

• Over the Air Installs (OTA)

Google+

Page 100: Google Play Services Rock

• Powerful identity provider

• Over the Air Installs (OTA)

• Drive engagement via

interactive posts

Google+

Page 101: Google Play Services Rock
Page 102: Google Play Services Rock
Page 103: Google Play Services Rock
Page 104: Google Play Services Rock
Page 105: Google Play Services Rock
Page 106: Google Play Services Rock
Page 107: Google Play Services Rock

No tap required, log-in will happen automatically!

Page 108: Google Play Services Rock
Page 109: Google Play Services Rock
Page 110: Google Play Services Rock

• Use Google+ Sign-in button

Google+ OTA

Page 111: Google Play Services Rock

• Use Google+ Sign-in button

• Set App package name on the

button

Google+ OTA

Page 112: Google Play Services Rock

• Use Google+ Sign-in button

• Set App package name on the

button

• Use the same scopes on web

and in the app

Google+ OTA

Page 113: Google Play Services Rock

• Use Google+ Sign-in button

• Set App package name on the

button

• Use the same scopes on web

and in the app

• Configure consent screen

Google+ OTA

Page 114: Google Play Services Rock

• Use Google+ Sign-in button

• Set App package name on the

button

• Use the same scopes on web

and in the app

• Configure consent screen

• Meet quality thresholds

Google+ OTA

Page 115: Google Play Services Rock

Google+Interactive Posts

Page 116: Google Play Services Rock

Google+Interactive Posts

Page 117: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android=“http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.google.xamarin.GooglePlusAndroidDemos"> <uses-sdk /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <application android:label="GooglePlusAndroidDemos"> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" /></manifest>

AndroidManifest.xml

Permissions

Page 118: Google Play Services Rock

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android=“http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.google.xamarin.GooglePlusAndroidDemos"> <uses-sdk /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <application android:label="GooglePlusAndroidDemos"> </application> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.USE_CREDENTIALS" /></manifest>

AndroidManifest.xml

Permissions

Page 119: Google Play Services Rock

const int RequestCodeInterActivePost = 1;

var callToActionUrl = Android.Net.Uri.Parse ( GetString (Resource.String.plus_example_deep_link_url) + action);var callToActionDeepLinkId = GetString (Resource.String.plus_example_deep_link_id) + action;var intent = new PlusShare.Builder (this) .AddCallToAction ( LabelViewItem, callToActionUrl, callToActionDeepLinkId) .SetContentUrl (Android.Net.Uri.Parse ( GetString (Resource.String.plus_example_deep_link_url))) .SetContentDeepLinkId ( GetString (Resource.String.plus_example_deep_link_id), null, null, null) .SetText (sendEditText.Text.ToString ()) .Intent;

MainActivity.cs

Create Interactive Posts

Page 120: Google Play Services Rock

const int RequestCodeInterActivePost = 1;

var callToActionUrl = Android.Net.Uri.Parse ( GetString (Resource.String.plus_example_deep_link_url) + action);var callToActionDeepLinkId = GetString (Resource.String.plus_example_deep_link_id) + action;var intent = new PlusShare.Builder (this) .AddCallToAction ( LabelViewItem, callToActionUrl, callToActionDeepLinkId) .SetContentUrl (Android.Net.Uri.Parse ( GetString (Resource.String.plus_example_deep_link_url))) .SetContentDeepLinkId ( GetString (Resource.String.plus_example_deep_link_id), null, null, null) .SetText (sendEditText.Text.ToString ()) .Intent;

MainActivity.cs

Create Interactive Posts

Page 121: Google Play Services Rock

const int RequestCodeInterActivePost = 1;

var callToActionUrl = Android.Net.Uri.Parse ( GetString (Resource.String.plus_example_deep_link_url) + action);var callToActionDeepLinkId = GetString (Resource.String.plus_example_deep_link_id) + action;var intent = new PlusShare.Builder (this) .AddCallToAction ( LabelViewItem, callToActionUrl, callToActionDeepLinkId) .SetContentUrl (Android.Net.Uri.Parse ( GetString (Resource.String.plus_example_deep_link_url))) .SetContentDeepLinkId ( GetString (Resource.String.plus_example_deep_link_id), null, null, null) .SetText (sendEditText.Text.ToString ()) .Intent; !StartActivityForResult(intent, RequestCodeInterActivePost);

MainActivity.cs

Create Interactive Posts

Page 122: Google Play Services Rock

var callToActionDeepLinkId = GetString (Resource.String.plus_example_deep_link_id) + action;var intent = new PlusShare.Builder (this) .AddCallToAction ( LabelViewItem, callToActionUrl, callToActionDeepLinkId) .SetContentUrl (Android.Net.Uri.Parse ( GetString (Resource.String.plus_example_deep_link_url))) .SetContentDeepLinkId ( GetString (Resource.String.plus_example_deep_link_id), null, null, null) .SetText (sendEditText.Text.ToString ()) .Intent; !StartActivityForResult(intent, RequestCodeInterActivePost);

MainActivity.cs

Create Interactive Posts

Page 123: Google Play Services Rock

[Activity (Label = "ParseDeepLinkActivity")] [IntentFilter (new[]{"com.google.android.apps.plus.VIEW_DEEP_LINK"}, DataScheme="vnd.google.deeplink", Categories=new[]{Intent.CategoryDefault, Intent.CategoryBrowsable} )]public class ParseDeepLinkActivity : BaseActivity{ const string logTag = "ParseDeepLinkActivity"; protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); var deepLinkId = PlusShare.GetDeepLinkId (Intent); var target = ProcessDeepLinkId (deepLinkId); if (target != null) { StartActivity (target); } }

ParseDeepLinkActivity.cs

Parse Deep Links

Page 124: Google Play Services Rock

[Activity (Label = "ParseDeepLinkActivity")] [IntentFilter (new[]{"com.google.android.apps.plus.VIEW_DEEP_LINK"}, DataScheme="vnd.google.deeplink", Categories=new[]{Intent.CategoryDefault, Intent.CategoryBrowsable} )]public class ParseDeepLinkActivity : BaseActivity{ const string logTag = "ParseDeepLinkActivity"; protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); var deepLinkId = PlusShare.GetDeepLinkId (Intent); var target = ProcessDeepLinkId (deepLinkId); if (target != null) { StartActivity (target); } }

ParseDeepLinkActivity.cs

Parse Deep Links

Page 125: Google Play Services Rock

[Activity (Label = "ParseDeepLinkActivity")] [IntentFilter (new[]{"com.google.android.apps.plus.VIEW_DEEP_LINK"}, DataScheme="vnd.google.deeplink", Categories=new[]{Intent.CategoryDefault, Intent.CategoryBrowsable} )]public class ParseDeepLinkActivity : BaseActivity{ const string logTag = "ParseDeepLinkActivity"; protected override void OnCreate (Bundle bundle) { base.OnCreate (bundle); var deepLinkId = PlusShare.GetDeepLinkId (Intent); var target = ProcessDeepLinkId (deepLinkId); if (target != null) { StartActivity (target); } } protected Intent ProcessDeepLinkId(string deepLinkId) { Intent route = null; var uri = Android.Net.Uri.Parse (deepLinkId);

Parse Deep Links

ParseDeepLinkActivity.cs

Page 126: Google Play Services Rock

base.OnCreate (bundle); var deepLinkId = PlusShare.GetDeepLinkId (Intent); var target = ProcessDeepLinkId (deepLinkId); if (target != null) { StartActivity (target); } } protected Intent ProcessDeepLinkId(string deepLinkId) { Intent route = null; var uri = Android.Net.Uri.Parse (deepLinkId); if (uri.Path.StartsWith (GetString (Resource.String.plus_example_deep_link_id))) { Toast.MakeText (this, string.Format (“Deep link was { 0}", uri.Path.ToString ()), ToastLength.Long) .Show (); } else { Log.Debug (TAG, "We cannot handle this"); } return route; }}

ParseDeepLinkActivity.cs

Parse Deep Links

Page 127: Google Play Services Rock

Recap

Page 128: Google Play Services Rock

?

Page 129: Google Play Services Rock

Google Play Services https://developer.android.com/google/play-services/

Page 130: Google Play Services Rock

Q & A

Page 131: Google Play Services Rock

What’s next?Material Android Design from Concept to Implementation (I + II) Thursday, 1 pm (Franklin Salon)

C# is in My Ears and in My Eyes Thursday, 4:15 pm (Linnaeus Salon)

youtube.com/GoogleDevelopers

Page 132: Google Play Services Rock

+PeterFriese

@

Thank you!

#Xamarin+Google

Page 133: Google Play Services Rock