/*
 * Copyright 2018 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.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.android.gnd.rx.RxCompletable;
import io.reactivex.Completable;
import javax.inject.Inject;
import javax.inject.Singleton;
import timber.log.Timber;

@Singleton
public class PermissionsManager {
  private static final int PERMISSIONS_REQUEST_CODE = PermissionsManager.class.hashCode() & 0xffff;

  private final Context context;
  private final ActivityStreams activityStreams;

  @Inject
  public PermissionsManager(Application app, ActivityStreams activityStreams) {
    context = app.getApplicationContext();
    this.activityStreams = activityStreams;
  }

  public Completable obtainPermission(String permission) {
    return RxCompletable.completeIf(() -> requestPermission(permission))
        .ambWith(getPermissionsResult(permission));
  }

  private boolean requestPermission(String permission) {
    if (isGranted(permission)) {
      Timber.d("%s already granted", permission);
      return true;
    } else {
      Timber.d("Requesting %s", permission);
      activityStreams.withActivity(
          activity ->
              ActivityCompat.requestPermissions(
                  activity, new String[]{permission}, PERMISSIONS_REQUEST_CODE));
      return false;
    }
  }

  private boolean isGranted(String permission) {
    return ContextCompat.checkSelfPermission(context, permission)
        == PackageManager.PERMISSION_GRANTED;
  }

  private Completable getPermissionsResult(String permission) {
    return activityStreams
        .getNextRequestPermissionsResult(PERMISSIONS_REQUEST_CODE)
        .flatMapCompletable(
            r ->
                RxCompletable.completeOrError(
                    () -> r.isGranted(permission), PermissionDeniedException.class));
  }

  public static class PermissionDeniedException extends Exception {}
}

@@ -864,24 +864,75 @@
 ompletable;%0A
+import com.google.android.gnd.rx.annotations.Cold;%0A
 import io.re
@@ -1038,16 +1038,82 @@
 imber;%0A%0A
+/** Provides access to obtain and check the app's permissions. */%0A
 @Singlet
@@ -1427,16 +1427,21 @@
 ) %7B%0A    
+this.
 context 
@@ -1516,24 +1516,261 @@
 reams;%0A  %7D%0A%0A
+  /**%0A   * Asynchronously requests the app be granted the specified permission. If the permission has%0A   * already been granted, completes immediately, otherwise completes once the next permissions%0A   * result is received.%0A   */%0A  @Cold%0A
   public Com
@@ -1942,24 +1942,181 @@
 ion));%0A  %7D%0A%0A
+  /**%0A   * Sends the system request that the app be granted the specified permission. Returns %7B@code true%7D%0A   * if the permission was already granted.%0A   */%0A
   private bo
@@ -2467,16 +2467,17 @@
 String%5B%5D
+ 
 %7Bpermiss
@@ -2537,24 +2537,109 @@
 %0A    %7D%0A  %7D%0A%0A
+  /** Returns %7B@code true%7D iff the app has been granted the specified permission. */%0A
   private bo
@@ -2792,16 +2792,231 @@
 D;%0A  %7D%0A%0A
+  /**%0A   * Returns a %7B@link Completable%7D that completes once the specified permission is granted or%0A   * terminates with error %7B@link PermissionDeniedException%7D if the requested permission was denied.%0A   */%0A  @Cold%0A
   privat
@@ -3349,16 +3349,225 @@
 );%0A  %7D%0A%0A
+  /**%0A   * Indicates a request to grant the app permissions was denied. More specifically, it indicates%0A   * the requested permission was not in the list of granted permissions in the system's response.%0A   */%0A
   public

Add Javadoc and Rx annotations to PermissionsManager