/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.gnd.system;

import android.Manifest.permission;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import com.google.android.gnd.system.ActivityStreams.ActivityResult;
import io.reactivex.Completable;
import io.reactivex.Observable;
import javax.inject.Inject;
import javax.inject.Singleton;
import timber.log.Timber;

/** Manages permissions needed for using camera and related flows to/from Activity. */
@Singleton
public class CameraManager {

  private static final int CAPTURE_PHOTO_REQUEST_CODE = CameraManager.class.hashCode() & 0xffff;
  private final PermissionsManager permissionsManager;
  private final ActivityStreams activityStreams;

  @Inject
  public CameraManager(PermissionsManager permissionsManager, ActivityStreams activityStreams) {
    this.permissionsManager = permissionsManager;
    this.activityStreams = activityStreams;
  }

  /**
   * Requests for capturing a photo from camera, if necessary permissions are granted. Otherwise,
   * requests for the permissions and then sends out the request.
   */
  public Completable launchPhotoCapture() {
    return permissionsManager
        .obtainPermission(permission.WRITE_EXTERNAL_STORAGE)
        .andThen(permissionsManager.obtainPermission(permission.CAMERA))
        .andThen(sendCapturePhotoIntent());
  }

  /** Enqueue an intent for capturing a photo from camera. */
  private Completable sendCapturePhotoIntent() {
    return Completable.fromAction(
        () ->
            activityStreams.withActivity(
                activity -> {
                  Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                  activity.startActivityForResult(cameraIntent, CAPTURE_PHOTO_REQUEST_CODE);
                  Timber.d("capture photo intent sent");
                }));
  }

  /** Observe for the result of request code {@link CameraManager#CAPTURE_PHOTO_REQUEST_CODE}. */
  public Observable<Bitmap> capturePhotoResult() {
    return activityStreams
        .getNextActivityResult(CAPTURE_PHOTO_REQUEST_CODE)
        .flatMap(this::onCapturePhotoResult);
  }

  /** Fetch bitmap from the result, if present. */
  // TODO: Investigate if returning a Maybe is better or not?
  private Observable<Bitmap> onCapturePhotoResult(ActivityResult result) {
    return Observable.create(
        em -> {
          if (!result.isOk()) {
            return;
          }
          Intent data = result.getData();
          if (data == null) {
            return;
          }
          Bundle extras = data.getExtras();
          if (extras == null) {
            return;
          }
          em.onNext((Bitmap) extras.get("data"));
        });
  }
}

@@ -790,16 +790,117 @@
 aStore;%0A
+import com.google.android.gnd.rx.annotations.Cold;%0Aimport com.google.android.gnd.rx.annotations.Hot;%0A
 import c
@@ -960,16 +960,16 @@
 Result;%0A
-
 import i
@@ -1239,16 +1239,81 @@
 ager %7B%0A%0A
+  /** Used to identify requests coming from this application. */%0A
   privat
@@ -1401,16 +1401,17 @@
 0xffff;%0A
+%0A
   privat
@@ -1722,178 +1722,103 @@
  /**
-%0A   * Requests for capturing a photo from camera, if necessary permissions are granted. Otherwise,%0A   * requests for the permissions and then sends out the request.%0A   */
+ Launches the system's photo capture flow, first obtaining permissions if necessary. */%0A  @Cold
 %0A  p
@@ -2120,24 +2120,20 @@
 hoto
- from camera. */
+. */%0A  @Cold
 %0A  p
@@ -2570,19 +2570,13 @@
 /** 
-Observe for
+Emits
  the
@@ -2590,73 +2590,44 @@
  of 
-request code %7B@link CameraManager#CAPTURE_PHOTO_REQUEST_CODE%7D. */
+the photo capture request. */%0A  @Hot
 %0A  p
@@ -2821,13 +2821,20 @@
 /** 
-Fetch
+Extracts the
  bit
@@ -2856,86 +2856,57 @@
 sult
-, if present. */%0A  // TODO: Investigate
+ returned by the activity,
  if 
+p
 re
-turning a Maybe is better or not?
+sent. */%0A  @Cold
 %0A  p
@@ -2973,24 +2973,88 @@
 t result) %7B%0A
+    // TODO: Investigate if returning a Maybe is better or not?%0A
     return O
@@ -3115,24 +3115,67 @@
 t.isOk()) %7B%0A
+            // TODO(#726): Call onError()?%0A
             
@@ -3258,32 +3258,75 @@
 data == null) %7B%0A
+            // TODO(#726): Call onError()?%0A
             retu
@@ -3381,24 +3381,24 @@
 etExtras();%0A
-
           if
@@ -3409,32 +3409,75 @@
 tras == null) %7B%0A
+            // TODO(#726): Call onError()?%0A
             retu

Add annotations and Javadoc to CameraManager