content: /*
  * The MIT License (MIT)
  
  * Copyright (c) 2015 Michal Tajchert
  
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
  
  package com.wm.remusic.permissions;
  
  import android.Manifest;
  import android.app.Activity;
  import android.content.Context;
  import android.content.SharedPreferences;
  import android.content.pm.PackageManager;
  import android.os.Build;
  
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.Set;
  
  /**
   * Created by Michal Tajchert on 2015-06-04.
   */
  public class Nammu {
      private static final String TAG = Nammu.class.getSimpleName();
      private static final String KEY_PREV_PERMISSIONS = "previous_permissions";
      private static final String KEY_IGNORED_PERMISSIONS = "ignored_permissions";
      private static Context context;
      private static SharedPreferences sharedPreferences;
      private static ArrayList<PermissionRequest> permissionRequests = new ArrayList<PermissionRequest>();
  
      public static void init(Context context) {
          sharedPreferences = context.getSharedPreferences("pl.tajchert.runtimepermissionhelper", Context.MODE_PRIVATE);
          Nammu.context = context;
      }
  
      /**
       * Check that all given permissions have been granted by verifying that each entry in the
       * given array is of the value {@link PackageManager#PERMISSION_GRANTED}.
       */
      public static boolean verifyPermissions(int[] grantResults) {
          for (int result : grantResults) {
              if (result != PackageManager.PERMISSION_GRANTED) {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Returns true if the Activity has access to given permissions.
       */
      public static boolean hasPermission(Activity activity, String permission) {
          return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
      }
  
      /**
       * Returns true if the Activity has access to a all given permission.
       */
      public static boolean hasPermission(Activity activity, String[] permissions) {
          for (String permission : permissions) {
              if (activity.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                  return false;
              }
          }
          return true;
      }
  
      /*
       * If we override other methods, lets do it as well, and keep name same as it is already weird enough.
       * Returns true if we should show explanation why we need this permission.
       */
      public static boolean shouldShowRequestPermissionRationale(Activity activity, String permissions) {
          return activity.shouldShowRequestPermissionRationale(permissions);
      }
  
      public static void askForPermission(Activity activity, String permission, PermissionCallback permissionCallback) {
          askForPermission(activity, new String[]{permission}, permissionCallback);
      }
  
      public static void askForPermission(Activity activity, String[] permissions, PermissionCallback permissionCallback) {
          if (permissionCallback == null) {
              return;
          }
          if (hasPermission(activity, permissions)) {
              permissionCallback.permissionGranted();
              return;
          }
          PermissionRequest permissionRequest = new PermissionRequest(new ArrayList<String>(Arrays.asList(permissions)), permissionCallback);
          permissionRequests.add(permissionRequest);
  
          activity.requestPermissions(permissions, permissionRequest.getRequestCode());
      }
  
      public static void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
          PermissionRequest requestResult = new PermissionRequest(requestCode);
          if (permissionRequests.contains(requestResult)) {
              PermissionRequest permissionRequest = permissionRequests.get(permissionRequests.indexOf(requestResult));
              if (verifyPermissions(grantResults)) {
                  //Permission has been granted
                  permissionRequest.getPermissionCallback().permissionGranted();
              } else {
                  permissionRequest.getPermissionCallback().permissionRefused();
  
              }
              permissionRequests.remove(requestResult);
          }
          refreshMonitoredList();
      }
  
  
      //Permission monitoring part below
  
      /**
       * Get list of currently granted permissions, without saving it inside Nammu
       *
       * @return currently granted permissions
       */
      public static ArrayList<String> getGrantedPermissions() {
          if (context == null) {
              throw new RuntimeException("Must call initCatchException() earlier");
          }
          ArrayList<String> permissions = new ArrayList<String>();
          ArrayList<String> permissionsGranted = new ArrayList<String>();
          //Group location
          permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
          permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
          //Group Calendar
          permissions.add(Manifest.permission.WRITE_CALENDAR);
          permissions.add(Manifest.permission.READ_CALENDAR);
          //Group Camera
          permissions.add(Manifest.permission.CAMERA);
          //Group Contacts
          permissions.add(Manifest.permission.WRITE_CONTACTS);
          permissions.add(Manifest.permission.READ_CONTACTS);
          permissions.add(Manifest.permission.GET_ACCOUNTS);
          //Group Microphone
          permissions.add(Manifest.permission.RECORD_AUDIO);
          //Group Phone
          permissions.add(Manifest.permission.CALL_PHONE);
          permissions.add(Manifest.permission.READ_PHONE_STATE);
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
              permissions.add(Manifest.permission.READ_CALL_LOG);
          }
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
              permissions.add(Manifest.permission.WRITE_CALL_LOG);
          }
          permissions.add(Manifest.permission.ADD_VOICEMAIL);
          permissions.add(Manifest.permission.USE_SIP);
          permissions.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
          //Group Body sensors
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
              permissions.add(Manifest.permission.BODY_SENSORS);
          }
          //Group SMS
          permissions.add(Manifest.permission.SEND_SMS);
          permissions.add(Manifest.permission.READ_SMS);
          permissions.add(Manifest.permission.RECEIVE_SMS);
          permissions.add(Manifest.permission.RECEIVE_WAP_PUSH);
          permissions.add(Manifest.permission.RECEIVE_MMS);
          //Group Storage
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
              permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
          }
          permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
          for (String permission : permissions) {
              if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) {
                  permissionsGranted.add(permission);
              }
          }
          return permissionsGranted;
      }
  
      /**
       * Refresh currently granted permission list, and save it for later comparing using @permissionCompare()
       */
      public static void refreshMonitoredList() {
          ArrayList<String> permissions = getGrantedPermissions();
          Set<String> set = new HashSet<String>();
          for (String perm : permissions) {
              set.add(perm);
          }
          sharedPreferences.edit().putStringSet(KEY_PREV_PERMISSIONS, set).apply();
      }
  
      /**
       * Get list of previous Permissions, from last refreshMonitoredList() call and they may be outdated,
       * use getGrantedPermissions() to get current
       */
      public static ArrayList<String> getPreviousPermissions() {
          ArrayList<String> prevPermissions = new ArrayList<String>();
          prevPermissions.addAll(sharedPreferences.getStringSet(KEY_PREV_PERMISSIONS, new HashSet<String>()));
          return prevPermissions;
      }
  
      public static ArrayList<String> getIgnoredPermissions() {
          ArrayList<String> ignoredPermissions = new ArrayList<String>();
          ignoredPermissions.addAll(sharedPreferences.getStringSet(KEY_IGNORED_PERMISSIONS, new HashSet<String>()));
          return ignoredPermissions;
      }
  
      /**
       * Lets see if we already ignore this permission
       */
      public static boolean isIgnoredPermission(String permission) {
          if (permission == null) {
              return false;
          }
          return getIgnoredPermissions().contains(permission);
      }
  
      /**
       * Use to ignore to particular Permission - even if user will deny or add it we won't receive a callback.
       *
       * @param permission Permission to ignore
       */
      public static void ignorePermission(String permission) {
          if (!isIgnoredPermission(permission)) {
              ArrayList<String> ignoredPermissions = getIgnoredPermissions();
              ignoredPermissions.add(permission);
              Set<String> set = new HashSet<String>();
              set.addAll(ignoredPermissions);
              sharedPreferences.edit().putStringSet(KEY_IGNORED_PERMISSIONS, set).apply();
          }
      }
  
      /**
       * Used to trigger comparing process - @permissionListener will be called each time Permission was revoked, or added (but only once).
       *
       * @param permissionListener Callback that handles all permission changes
       */
      public static void permissionCompare(PermissionListener permissionListener) {
          if (context == null) {
              throw new RuntimeException("Before comparing permissions you need to call Nammu.initCatchException(context)");
  
          }
          ArrayList<String> previouslyGranted = getPreviousPermissions();
          ArrayList<String> currentPermissions = getGrantedPermissions();
          ArrayList<String> ignoredPermissions = getIgnoredPermissions();
          for (String permission : ignoredPermissions) {
              if (previouslyGranted != null && !previouslyGranted.isEmpty()) {
                  if (previouslyGranted.contains(permission)) {
                      previouslyGranted.remove(permission);
                  }
              }
  
              if (currentPermissions != null && !currentPermissions.isEmpty()) {
                  if (currentPermissions.contains(permission)) {
                      currentPermissions.remove(permission);
                  }
              }
          }
          for (String permission : currentPermissions) {
              if (previouslyGranted.contains(permission)) {
                  //All is fine, was granted and still is
                  previouslyGranted.remove(permission);
              } else {
                  //We didn't have it last time
                  if (permissionListener != null) {
                      permissionListener.permissionsChanged(permission);
                      permissionListener.permissionsGranted(permission);
                  }
              }
          }
          if (previouslyGranted != null && !previouslyGranted.isEmpty()) {
              //Something was granted and removed
              for (String permission : previouslyGranted) {
                  if (permissionListener != null) {
                      permissionListener.permissionsChanged(permission);
                      permissionListener.permissionsRemoved(permission);
                  }
              }
          }
          refreshMonitoredList();
      }
  
      /**
       * Not that needed method but if we override others it is good to keep same.
       */
      public static boolean checkPermission(String permissionName) {
          if (context == null) {
              throw new RuntimeException("Before comparing permissions you need to call Nammu.initCatchException(context)");
          }
          return PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(permissionName);
      }
  }