Behind the curtains: how Photos™ work

Behind the curtains: how Photos™ work

Daniele Bonaldo (@danybony_) and I will explore the inner works of Google Photos and how we integrated it with Android Things and get to create a smart photo boot project

6923bdeb363961b064d2cdb6329982d6?s=128

Roberto Orgiu

October 27, 2018
Tweet

Transcript

  1. Behind the curtains: HOW PHOTOS™ WORKS

  2. HELLO! I am Robertoooooooo I do things Android at The

    New York Times You can find me at @_tiwiz
  3. Daniele Bonaldo @danybony_ danybony danielebonaldo.com

  4. We ♡ github.com/danybony/do-it-yourselfie

  5. THE FLOW®

  6. None
  7. LOGIN • No touchscreen • No users • No screen

  8. COMPANION APP Not such a great idea, right?

  9. Place your screenshot here ANDROID COMPANION APP Lets you pick

    a user, authenticate and send the token to the Android Things™ app.
  10. private val oAuthSecret = "S3cR3t11!" private val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)

    .requestEmail() .requestScopes(Scope(PHOTOS_SHARING_SCOPE), Scope(PHOTOS_READ_APPEND_SCOPE)) .requestIdToken(oAuthSecret) .build() private val client = GoogleSignIn.getClient(host, gso)
  11. host.startActivityForResult( client.signInIntent, AUTHENTICATION_CODE )

  12. val task = GoogleSignIn.getSignedInAccountFromIntent(intent) val account = task.getResult(ApiException::class.java) dispatchToken(account)

  13. val credential = GoogleAccountCredential.usingOAuth2(host, scopes).apply { selectedAccount = account.account }

    launch(UI) { val token = async { credential.token } host.showLoggedUi(token.await()) }
  14. None
  15. NEARBY API

  16. class TokenMessageReceiver : MessageListener() { override fun onFound(message: Message) {

    onTokenReceived(String(message.content)) } }
  17. fun onActivityStart() { Nearby.getMessagesClient(activity) .subscribe(tokenMessageReceiver) } fun onActivityStop() { Nearby.getMessagesClient(activity)

    .unsubscribe(tokenMessageReceiver) }
  18. val message = Message(token.toByteArray())

  19. Nearby.getMessagesClient(activity) .publish(message) Nearby.getMessagesClient(activity) .unpublish(message)

  20. None
  21. @GET("albums") fun fetchAlbums(@Header("Authorization") token: String, @Query("pageToken") nextPageToken: String? = null

    ): Deferred<AlbumListResponse>
  22. data class AlbumListResponse( val albums: Array<AlbumResponse>, val nextPageToken: String? )

    data class AlbumResponse( val productUrl: String, val id: String, val title: String, @Json(name = "isWriteable") val writeable: Boolean )
  23. internal fun fetchAlbums(): Deferred<ArrayList<CompleteAlbum>> { return async { val albums

    = arrayListOf<CompleteAlbum>() var nextPageToken: String? = null do { val page = apiService .fetchAlbums(tokenBearer, nextPageToken).await() nextPageToken = nextPageToken .replaceWith(page.nextPageToken) albums.addAll(page.albums) } while (nextPageToken != null && nextPageToken.isNotEmpty()) return@async albums } }
  24. fun String?.replaceWith(nextPageToken: String?): String? = if (this != nextPageToken) {

    nextPageToken } else { null }
  25. internal fun uploadImage(albumId: String, fileName: String, bytes: ByteArray): Deferred<ImageUploadResult> {

    return async { val token = uploadApiService .uploadMedia(tokenBearer, fileName, bytes).await() apiService .createMediaLink(tokenBearer, token.asImageUploadRequestWith(albumId, fileName) ).await() } }
  26. fun uploadMedia(token: String, fileName: String, bytes: ByteArray): Deferred<String> { val

    requestBody = RequestBody.create(MediaType.parse(OCTET_TYPE), bytes) return async { val request = Request.Builder() .url(endpoint) .addHeader(AUTHORIZATION, token) .addHeader(UPLOAD_FILENAME, fileName) .post(requestBody) .build() client.newCall(request).execute().body().string() } }
  27. @POST("./mediaItems:batchCreate") fun createMediaLink( @Header("Authorization") token: String, @Body request: ImageUploadRequest ):

    Deferred<ImageUploadResult>
  28. An album only shows in Photos™ when it has at

    least one picture. Cannot delete a picture. You can only interact with albums you created. LESSONS LEARNED
  29. AVAILABLE NOW API EXAMPLES LIBRARIES

  30. AVAILABLE NOW API EXAMPLES LIBRARIES developers.google.com/photos

  31. AVAILABLE NOW API EXAMPLES LIBRARIES bit.ly/photos-java-client

  32. AVAILABLE NOW API EXAMPLES LIBRARIES github.com/google/java-photoslibrary

  33. THANKS! Questions time! You can find us at @_tiwiz and

    @danybony_