Behind the curtains: how Photos™ work

Behind the curtains: how Photos™ work

Google Photos is an amazing piece of software, and API are pretty amazing. The only problem? They are not available on Android just yet. Join us to learn how we bypassed this limitation to create a selfie box based on Kotlin, Things™, and, of course, Google Photos!

6923bdeb363961b064d2cdb6329982d6?s=128

Roberto Orgiu

October 06, 2018
Tweet

Transcript

  1. 2.

    HELLO! I am Robertoooooooo I do things Android at The

    New York Times You can find me at @_tiwiz
  2. 6.
  3. 9.

    Place your screenshot here ANDROID COMPANION APP Lets you pick

    a user, authenticate and send the token to the Android Things™ app.
  4. 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)
  5. 13.

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

    launch(UI) { val token = async { credential.token } host.showLoggedUi(token.await()) }
  6. 14.
  7. 20.
  8. 22.

    data class AlbumListResponse( val albums: Array<CompleteAlbum>, val nextPageToken: String? )

    data class AlbumResponse( val productUrl: String, val id: String, val title: String, @Json(name = "isWriteable") val writeable: Boolean )
  9. 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 } }
  10. 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() } }
  11. 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() } }
  12. 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