applvsdklib/src/main/java/com/applivery/applvsdklib/domain/model/UserFeedback.java
public class UserFeedback implements FeedbackInt {

  private FeedBackType feedBackType;
  private boolean screenshotAttached = true;
  private String feedbackMessage;
  private String screen;
  private ScreenCapture screenCapture;

  @Override public void setType(FeedBackType feedBackType) {
    this.feedBackType = feedBackType;
  }

  @Override public void attachScreenshot(boolean activated) {
    this.screenshotAttached = activated;
  }

  @Override public boolean mustAttachScreenshot() {
    return screenshotAttached;
  }

  @Override public void setMessage(String feedbackMessage) {
    this.feedbackMessage = feedbackMessage;
  }

  @Override public String getMessage() {
    return feedbackMessage;
  }

  @Override public void setScreen(String screen) {
    this.screen = screen;
  }

  @Override public String getScreen() {
    return screen;
  }

  @Override public void setScreenCapture(ScreenCapture screenCapture) {
    this.screenCapture = screenCapture;
  }

  @Override public String getBase64ScreenCapture() {
    if (screenCapture!=null){
      return screenCapture.getBase64();
    }else{
      return null;
    }

  }

  @Override public FeedBackType getType() {
    return feedBackType;
  }
}
applvsdklib/src/main/java/com/applivery/applvsdklib/ui/model/ScreenCapture.java
public class ScreenCapture {

  private final Bitmap screenShot;

  public ScreenCapture(Bitmap screenShot) {
    this.screenShot = screenShot;
  }

  public Bitmap getScreenShot() {
    return screenShot;
  }

  public String getBase64() {
    return ImageUtils.getBase64(screenShot);
  }
}
applvsdklib/src/main/java/com/applivery/applvsdklib/tools/permissions/PermissionChecker.java
public interface PermissionChecker {
  void askForPermission(Permission permission, UserPermissionRequestResponseListener userResponse,
      Activity activity);

  void continuePendingPermissionsRequestsIfPossible();

  boolean isGranted(Permission permission);
}
applvsdklib/src/main/java/com/applivery/applvsdklib/domain/model/ErrorObject.java
public class ErrorObject {

  private final boolean businessError;
  private final String message;
  private final int businessCode;

  public ErrorObject(boolean businessError, String message, int businessCode) {
    this.businessError = businessError;
    this.message = message;
    this.businessCode = businessCode;
  }

  public ErrorObject() {
    businessCode = -99;
    message = "Unknown Error";
    businessError = false;
  }

  public ErrorObject(String message) {
    this.businessCode = -99;
    this.message = message;
    this.businessError = false;
  }

  public String getMessage() {
    return message;
  }

  public boolean isBusinessError() {
    return businessError;
  }

  public int getBusinessCode() {
    return businessCode;
  }

  public static final int UNAUTHORIZED_ERROR=4004;
  public static final int SUBSCRIPTION_ERROR=5004;
}
applvsdklib/src/main/java/com/applivery/applvsdklib/tools/androidimplementations/AndroidDeviceDetailsInfo.java
public class AndroidDeviceDetailsInfo implements DeviceDetailsInfo {

  private static final String ANDROID = "Android";
  private static final String TABLET = "tablet";
  private static final String MOBILE = "mobile";
  private static final String CONNECTIVITY_UNKNOWN = "unknown";
  private static final String CONNECTIVITY_WIFI = "wifi";
  private static final String CONNECTIVITY_2G = "gprs";
  private static final String CONNECTIVITY_3G = "3g";
  private static final String CONNECTIVITY_4G = "4g";
  private static final String ORIENTATION_PORTRAIT = "portrait";
  private static final String ORIENTATION_LANDSCAPE = "landscape";

  public DeviceInfo getDeviceInfo() {
    return new DeviceInfo(getDevice(), getOs());
  }

  private Device getDevice() {

    Context context = AppliverySdk.getApplicationContext();

    return new Device(getBatteryPercentage(), isBatteryCharging(), getFreeDiskPercentage(),
        getModel(), getNetworkType(context), getScreenOrientation(), getTotalRam(), getUsedRam(),
        getScreenResolution(), getDeviceType(), getVendor());
  }

  private Os getOs() {
    return new Os(getOsName(), getOsversion());
  }

  @Override public String getOsName() {
    return ANDROID;
  }

  @Override public String getVendor() {
    return Build.MANUFACTURER;
  }

  @Override public String getModel() {
    String model = Build.MODEL;
    if (model.contains(Build.MANUFACTURER + " ")) {
      return model.replace(Build.MANUFACTURER + " ", "");
    } else {
      return model;
    }
  }

  @Override public String getDeviceType() {
    Context context = AppliverySdk.getApplicationContext();

    boolean isTablet = false;

    isTablet = (context.getResources().getConfiguration().screenLayout
        & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;

    if (isTablet) {
      return TABLET;
    } else {
      return MOBILE;
    }
  }

  @Override public String getOsversion() {
    return Build.VERSION.RELEASE;
  }

  @Override public String getDeviceId() {
    Context context = AppliverySdk.getApplicationContext();
    String secureAndroidId =
        Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
    return secureAndroidId;
  }

  @Override public int getBatteryPercentage() {
    Context context = AppliverySdk.getApplicationContext();
    Intent batteryStatus = getBatteryStatus(context);
    int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
    int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

    return  Math.round((level / (float) scale) * 100);
  }

  @Override public boolean isBatteryCharging() {
    Context context = AppliverySdk.getApplicationContext();
    boolean isBatteryCharging = false;
    Intent batteryStatus = getBatteryStatus(context);
    int plugged = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
    isBatteryCharging = plugged == BatteryManager.BATTERY_PLUGGED_AC
        || plugged == BatteryManager.BATTERY_PLUGGED_USB;

    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
      isBatteryCharging = isBatteryCharging || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS;
    }

    return isBatteryCharging;
  }

  @Override public String getNetworkConnectivity() {
    Context context = AppliverySdk.getApplicationContext();
    String connectivity = CONNECTIVITY_UNKNOWN;

    if (isConnectedWifi(context)) {
      connectivity = CONNECTIVITY_WIFI;
    } else if (isConnectedMobile(context)) {
      connectivity = getNetworkType(context);
    }

    return connectivity;
  }

  @Override public String getScreenResolution() {
    Context context = AppliverySdk.getApplicationContext();
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = windowManager.getDefaultDisplay();

    int width;
    int height;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
      Point size = new Point();
      display.getSize(size);
      width = size.x;
      height = size.y;
    } else {
      width = display.getWidth();
      height = display.getHeight();
    }

    String screenResolution = String.format(Locale.getDefault(), "%dx%d", width, height);

    return screenResolution;
  }

  @Override public String getUsedRam() {
    long totalAppMemory = -1;

    Context context = AppliverySdk.getApplicationContext();
    ActivityManager activityManager = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningAppProcessInfo> runningAppProcesses =
        activityManager.getRunningAppProcesses();

    Map<Integer, String> pidMap = new TreeMap<>();
    for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses) {
      pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
    }

    Collection<Integer> processesPids = pidMap.keySet();
    for (int pid : processesPids) {
      int pids[] = new int[1];
      pids[0] = pid;
      android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
      for (android.os.Debug.MemoryInfo pidMemoryInfo : memoryInfoArray) {
        totalAppMemory += pidMemoryInfo.getTotalPss();
      }
    }

    totalAppMemory /= 1024;

    return String.valueOf(totalAppMemory);
  }

  @Override public String getTotalRam() {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN ? getTotalMemory()
        : getTotalMemoryForOlderDevices();
  }

  @Override public String getFreeDiskPercentage() {
    File rootDirectory = Environment.getRootDirectory();
    StatFs fileSystemData = new StatFs(rootDirectory.getPath());

    long blockSize;
    long totalSize;
    long availableSize;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
      blockSize = fileSystemData.getBlockSizeLong();
      totalSize = fileSystemData.getBlockCountLong() * blockSize;
      availableSize = fileSystemData.getAvailableBlocksLong() * blockSize;
    } else {
      blockSize = fileSystemData.getBlockSize();
      totalSize = fileSystemData.getBlockCount() * blockSize;
      availableSize = fileSystemData.getAvailableBlocks() * blockSize;
    }

    long freeDiskPercentage = availableSize * 100 / totalSize;
    return String.valueOf(freeDiskPercentage);
  }

  @Override public String getScreenOrientation() {
    Context context = AppliverySdk.getApplicationContext();
    String screenOrientation;

    int orientation = context.getResources().getConfiguration().orientation;
    screenOrientation = (orientation == Configuration.ORIENTATION_LANDSCAPE) ? ORIENTATION_LANDSCAPE
        : ORIENTATION_PORTRAIT;

    return screenOrientation;
  }

  private Intent getBatteryStatus(Context context) {
    return context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
  }

  private boolean isConnectedWifi(Context context) {
    NetworkInfo info = getNetworkInfo(context);
    return (info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_WIFI);
  }

  private boolean isConnectedMobile(Context context) {
    NetworkInfo info = getNetworkInfo(context);
    return (info != null
        && info.isConnected()
        && info.getType() == ConnectivityManager.TYPE_MOBILE);
  }

  private String getNetworkType(Context context) {
    TelephonyManager mTelephonyManager =
        (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    int networkType = mTelephonyManager.getNetworkType();
    switch (networkType) {
      case TelephonyManager.NETWORK_TYPE_GPRS:
      case TelephonyManager.NETWORK_TYPE_EDGE:
      case TelephonyManager.NETWORK_TYPE_CDMA:
      case TelephonyManager.NETWORK_TYPE_1xRTT:
      case TelephonyManager.NETWORK_TYPE_IDEN:
        return CONNECTIVITY_2G;
      case TelephonyManager.NETWORK_TYPE_UMTS:
      case TelephonyManager.NETWORK_TYPE_EVDO_0:
      case TelephonyManager.NETWORK_TYPE_EVDO_A:
      case TelephonyManager.NETWORK_TYPE_HSDPA:
      case TelephonyManager.NETWORK_TYPE_HSUPA:
      case TelephonyManager.NETWORK_TYPE_HSPA:
      case TelephonyManager.NETWORK_TYPE_EVDO_B:
      case TelephonyManager.NETWORK_TYPE_EHRPD:
      case TelephonyManager.NETWORK_TYPE_HSPAP:
        return CONNECTIVITY_3G;
      case TelephonyManager.NETWORK_TYPE_LTE:
        return CONNECTIVITY_4G;
      default:
        return CONNECTIVITY_UNKNOWN;
    }
  }

  private NetworkInfo getNetworkInfo(Context context) {
    ConnectivityManager cm =
        (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    return cm.getActiveNetworkInfo();
  }

  @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private String getTotalMemory() {
    Context context = AppliverySdk.getApplicationContext();
    ActivityManager activityManager =
        (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);

    long totalMemory = memoryInfo.totalMem;

    return String.valueOf((totalMemory / 1024) / 1024);
  }

  private String getTotalMemoryForOlderDevices() {
    final String fileToRead = "/proc/meminfo";
    String lineToRead = "";
    String[] arrayOfString;
    long totalMemory = 0;

    try {
      FileReader fileReader = new FileReader(fileToRead);
      BufferedReader bufferedReader = new BufferedReader(fileReader, 8192);

      lineToRead = bufferedReader.readLine();
      arrayOfString = lineToRead.split("\\s+");
      totalMemory = Integer.valueOf(arrayOfString[1]);

      bufferedReader.close();
    } catch (IOException e) {
      return String.valueOf(-1);
    }

    return String.valueOf(totalMemory / 1024);
  }
}
applvsdklib/src/main/java/com/applivery/applvsdklib/domain/download/permissions/AccessNetworkStatePermission.java
public class AccessNetworkStatePermission implements Permission {
  @Override public String getAndroidPermissionStringType() {
    return Manifest.permission.ACCESS_NETWORK_STATE;
  }

  @Override public int getPermissionSettingsDeniedFeedback() {
    return R.string.applivery_accessNetworkStatePermissionSettingsDeniedFeedback;
  }

  @Override public int getPermissionDeniedFeedback() {
    return R.string.applivery_accessNetworkStatePermissionDeniedFeedback;
  }

  @Override public int getPermissionRationaleTitle() {
    return R.string.applivery_accessNetworkStatePermissionRationaleTitle;
  }

  @Override public int getPermissionRationaleMessage() {
    return R.string.applivery_accessNetworkStatePermissionRationalMessage;
  }
}
applivery-base/src/main/java/com/applivery/base/util/AppliveryLog.java
@SuppressWarnings({"unused", "WeakerAccess"})
public class AppliveryLog {
    public static final String APPLIVERY_TAG = "AppliveryApp";

    private static int sLogLevel = Log.ERROR;

    /**
     * Get the log level to find out how much data the AppliverySDK spews into LogCat. The Default will be
     * LOG_LEVEL.ERROR so only errors show up in LogCat.
     *
     * @return the log level
     */
    public static int getLogLevel() {
        return sLogLevel;
    }

    /**
     * Set the log level to determine the amount of info the AppliverySDK spews info into LogCat.
     *
     * @param appliveryLogLevel The log level for appliverySDK logging
     */
    public static void setLogLevel(int appliveryLogLevel) {
        sLogLevel = appliveryLogLevel;
    }


    /**
     * Log a message with level VERBOSE with the default tag
     *
     * @param message the log message
     */
    public static void verbose(String message) {
        verbose(null, message);
    }

    /**
     * Log a message with level VERBOSE
     *
     * @param tag     the log tag for your message
     * @param message the log message
     */
    public static void verbose(String tag, String message) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.VERBOSE) {
            Log.v(tag, message);
        }
    }

    /**
     * Log a message with level VERBOSE with the default tag
     *
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void verbose(String message, Throwable throwable) {
        verbose(null, message, throwable);
    }

    /**
     * Log a message with level VERBOSE
     *
     * @param tag       the log tag for your message
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void verbose(String tag, String message, Throwable throwable) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.VERBOSE) {
            Log.v(tag, message, throwable);
        }
    }

    /**
     * Log a message with level DEBUG with the default tag
     *
     * @param message the log message
     */
    public static void debug(String message) {
        debug(null, message);
    }

    /**
     * Log a message with level DEBUG
     *
     * @param tag     the log tag for your message
     * @param message the log message
     */
    public static void debug(String tag, String message) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.DEBUG) {
            Log.d(tag, message);
        }
    }

    /**
     * Log a message with level DEBUG with the default tag
     *
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void debug(String message, Throwable throwable) {
        debug(null, message, throwable);
    }

    /**
     * Log a message with level DEBUG
     *
     * @param tag       the log tag for your message
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void debug(String tag, String message, Throwable throwable) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.DEBUG) {
            Log.d(tag, message, throwable);
        }
    }

    /**
     * Log a message with level INFO with the default tag
     *
     * @param message the log message
     */
    public static void info(String message) {
        info(null, message);
    }

    /**
     * Log a message with level INFO
     *
     * @param tag     the log tag for your message
     * @param message the log message
     */
    public static void info(String tag, String message) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.INFO) {
            Log.i(tag, message);
        }
    }

    /**
     * Log a message with level INFO with the default tag
     *
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void info(String message, Throwable throwable) {
        info(null, message, throwable);
    }

    /**
     * Log a message with level INFO
     *
     * @param tag       the log tag for your message
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void info(String tag, String message, Throwable throwable) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.INFO) {
            Log.i(tag, message, throwable);
        }
    }

    /**
     * Log a message with level WARN with the default tag
     *
     * @param message the log message
     */
    public static void warn(String message) {
        warn(null, message);
    }

    /**
     * Log a message with level WARN
     *
     * @param tag     the TAG
     * @param message the log message
     */
    public static void warn(String tag, String message) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.WARN) {
            Log.w(tag, message);
        }
    }

    /**
     * Log a message with level WARN with the default tag
     *
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void warn(String message, Throwable throwable) {
        warn(null, message, throwable);
    }

    /**
     * Log a message with level WARN
     *
     * @param tag       the log tag for your message
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void warn(String tag, String message, Throwable throwable) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.WARN) {
            Log.w(tag, message, throwable);
        }
    }

    /**
     * Log a message with level ERROR with the default tag
     *
     * @param message the log message
     */
    public static void error(String message) {
        error(null, message);
    }

    /**
     * Log a message with level ERROR
     *
     * @param tag     the log tag for your message
     * @param message the log message
     */
    public static void error(String tag, String message) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.ERROR) {
            Log.e(tag, message);
        }
    }

    /**
     * Log a message with level ERROR with the default tag
     *
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void error(String message, Throwable throwable) {
        error(null, message, throwable);
    }

    /**
     * Log a message with level ERROR
     *
     * @param tag       the log tag for your message
     * @param message   the log message
     * @param throwable the throwable you want to log
     */
    public static void error(String tag, String message, Throwable throwable) {
        tag = sanitizeTag(tag);
        if (sLogLevel <= Log.ERROR) {
            Log.e(tag, message, throwable);
        }
    }

    /**
     * Sanitize a TAG string
     *
     * @param tag the log tag for your message for the logging
     * @return a sanitized TAG, defaults to 'AppliveryApp' in case the log tag for your message is null, empty or longer than
     * 23 characters.
     */
    static String sanitizeTag(String tag) {
        if ((tag == null) || (tag.length() == 0) || (tag.length() > 23)) {
            tag = APPLIVERY_TAG;
        }

        return tag;
    }
}
applvsdklib/src/main/java/com/applivery/applvsdklib/tools/androidimplementations/ScreenCaptureUtils.java
public class ScreenCaptureUtils {

  private static final int COMPRESSION_BITMAP_QUALITY = 100;

  public static ScreenCapture getScreenCapture(Activity activity) {

    try {
      View v1 = activity.getWindow().getDecorView().getRootView();
      v1.setDrawingCacheEnabled(true);
      Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
      v1.setDrawingCacheEnabled(false);

      ByteArrayOutputStream out = new ByteArrayOutputStream();

      bitmap.compress(Bitmap.CompressFormat.JPEG, COMPRESSION_BITMAP_QUALITY, out);
      Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));

      return new ScreenCapture(decoded);
    } catch (Throwable e) {
      e.printStackTrace();
      return new ScreenCapture(BitmapFactory.decodeResource(null, R.drawable.applivery_icon));
    }
  }

}
applvsdklib/src/main/java/com/applivery/applvsdklib/AppliverySdk.java
public class AppliverySdk {

    // TODO This class is already using too many Static fields, consider redesign.
    // TODO Hold static reference only to AppliverySdk object and wrap smaller objects inside
    private static final String TAG = AppliverySdk.class.getCanonicalName();
    private static volatile Executor executor;
    private static volatile String appToken;
    private static volatile String fileProviderAuthority;
    private static boolean lockedApp = false;
    private static volatile boolean isDebugEnabled = BuildConfig.DEBUG;
    private static Context applicationContext;
    private static PermissionChecker permissionRequestManager;
    private static AppliveryActivityLifecycleCallbacks activityLifecycle;
    private static final Object LOCK = new Object();

    private static Boolean sdkInitialized = false;
    private static Boolean checkForUpdatesBackground = BuildConfig.CHECK_FOR_UPDATES_BACKGROUND;
    private static Boolean isUpdating = false;

    public static synchronized void sdkInitialize(Application app, String appToken) {
        init(app, appToken);
    }

    @TargetApi(14)
    private static void init(Application app, String appToken) {
        if (!sdkInitialized) {
            sdkInitialized = true;
            initializeAppliveryConstants(app, appToken);
            app.registerActivityLifecycleCallbacks(new AppliveryLifecycleCallbacks());
            registerActivityLifecyleCallbacks(app);
            obtainAppConfig(false);
        }
    }

    /**
     * @return true if success false otherwise
     */
    @TargetApi(14)
    private static boolean registerActivityLifecyleCallbacks(Application app) {
        try {
            app.registerActivityLifecycleCallbacks(activityLifecycle);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static synchronized void isUpdating(Boolean updating) {
        isUpdating = updating;
    }

    public static synchronized Boolean isUpdating() {
        return isUpdating;
    }

    private static void initializeAppliveryConstants(Application app, String appToken) {

        //region validate some requirements
        Context applicationContext = Validate.notNull(app, "Application").getApplicationContext();
        Validate.notNull(applicationContext, "applicationContext");
        Validate.hasInternetPermissions(applicationContext, false);
        //endregion

        AppliverySdk.appToken = appToken;
        AppliveryDataManager.INSTANCE.setAppToken(appToken);

        AppliverySdk.fileProviderAuthority = composeFileProviderAuthority(app);

        AppliverySdk.applicationContext = applicationContext;

        AppliverySdk.activityLifecycle = new AppliveryActivityLifecycleCallbacks(applicationContext);
        AppliverySdk.permissionRequestManager =
                new AndroidPermissionCheckerImpl(AppliverySdk.activityLifecycle);
    }

    private static void obtainAppConfig(boolean checkForUpdates) {
        if (isInitialized()) {
            AppConfigUseCase appConfigUseCase = AppConfigUseCase.Companion.getInstance();
            appConfigUseCase.getAppConfig(checkForUpdates, null);
        }
    }

    private static String composeFileProviderAuthority(Application application) {
        return application.getPackageName() + ".provider";
    }

    @Nullable
    public static Context getApplicationContext() {
        return applicationContext;
    }

    @Nullable
    public static PermissionChecker getPermissionRequestManager() {
        return permissionRequestManager;
    }

    public static Activity getCurrentActivity() throws NotForegroundActivityAvailable {
        Activity activity = activityLifecycle.getCurrentActivity();
        if (activity != null) {
            return activity;
        } else {
            throw new NotForegroundActivityAvailable("There is not any available ActivityContext");
        }
    }

    public static boolean isContextAvailable() {
        return (activityLifecycle.getCurrentActivity() != null);
    }

    @SuppressLint("SourceLockedOrientationActivity")
    public static void lockRotationToPortrait() {
        Activity activity = activityLifecycle.getCurrentActivity();
        if (activity != null) {
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }
    }

    public static void unlockRotation() {
        Activity activity = activityLifecycle.getCurrentActivity();
        if (activity != null) {
            activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
        }
    }

    public static synchronized boolean isInitialized() {
        return sdkInitialized;
    }

    public static void obtainAppConfigForCheckUpdates() {
        if (isInitialized()) {
            obtainAppConfig(true);
        }
    }

    public static void update() {
        if (isInitialized()) {
            DownloadBuildUseCase downloadBuildUseCase = DownloadBuildUseCase.Companion.getInstance();
            downloadBuildUseCase.downloadLastBuild();
        }
    }

    public static void updateAppConfig() {
        obtainAppConfig(false);
    }

    public static void continuePendingPermissionsRequestsIfPossible() {
        if (isInitialized()) {
            permissionRequestManager.continuePendingPermissionsRequestsIfPossible();
        }
    }

    public static Boolean getCheckForUpdatesBackground() {
        return checkForUpdatesBackground;
    }

    public static void setCheckForUpdatesBackground(Boolean checkForUpdatesBackground) {
        if (isInitialized()) {
            AppliverySdk.checkForUpdatesBackground = checkForUpdatesBackground;
        }
    }

    public static FeedbackView requestForUserFeedBack() {
        obtainAppConfig(false);
        FeedbackView feedbackView = null;
        if (!lockedApp) {
            feedbackView = UserFeedbackView.getInstance();
            if (feedbackView.isNotShowing()) {
                try {
                    feedbackView.lockRotationOnParentScreen(getCurrentActivity());
                    feedbackView.show();
                } catch (NotForegroundActivityAvailable exception) {
                }
            }
        }

        return feedbackView;
    }

    public static void requestForUserFeedBackWith(ScreenCapture screenCapture) {
        if (lockedApp) {
            return;
        }

        FeedbackView feedbackView = requestForUserFeedBack();
        if (feedbackView != null) {
            feedbackView.setScreenCapture(screenCapture);
        }
    }

    static void disableShakeFeedback() {
        if (isInitialized()) {
            SensorEventsController sensorController =
                    SensorEventsController.getInstance(applicationContext);
            sensorController.disableSensor(Sensor.TYPE_ACCELEROMETER);
        }
    }

    static void enableShakeFeedback() {
        if (isInitialized()) {
            SensorEventsController sensorController =
                    SensorEventsController.getInstance(applicationContext);
            sensorController.enableSensor(Sensor.TYPE_ACCELEROMETER);
        }
    }

    static void disableScreenshotFeedback() {
        if (isInitialized()) {
            ScreenshotObserver screenshotObserver = ScreenshotObserver.getInstance(applicationContext);
            screenshotObserver.stopObserving();
            screenshotObserver.disableScreenshotObserver();
        }
    }

    static void enableScreenshotFeedback() {
        if (isInitialized()) {
            ScreenshotObserver screenshotObserver = ScreenshotObserver.getInstance(applicationContext);
            screenshotObserver.enableScreenshotObserver();

            if (activityLifecycle.isActivityContextAvailable()) {
                screenshotObserver.startObserving();
            }
        }
    }

    static void bindUser(@NonNull String email, @Nullable String firstName, @Nullable String lastName,
                         @Nullable Collection<String> tags, final @Nullable BindUserCallback callback) {

        BindUserInteractor bindUserInteractor = Injection.INSTANCE.provideBindUserInteractor();
        UserData userData = new UserData(email, firstName, lastName, tags, "", "");
        bindUserInteractor.bindUser(userData, new Function0<Unit>() {
            @Override
            public Unit invoke() {
                if (callback != null) {
                    callback.onSuccess();
                }
                return null;
            }
        }, new Function1<ErrorObject, Unit>() {
            @Override
            public Unit invoke(ErrorObject errorObject) {
                if (callback != null) {
                    callback.onError(errorObject.getMessage());
                }
                return null;
            }
        });
    }

    static void unbindUser() {
        UnBindUserInteractor unBindUserInteractor = Injection.INSTANCE.provideUnBindUserInteractor();
        unBindUserInteractor.unBindUser(new Function0<Unit>() {
            @Override
            public Unit invoke() {
                return null;
            }
        }, new Function1<ErrorObject, Unit>() {
            @Override
            public Unit invoke(ErrorObject errorObject) {
                return null;
            }
        });
    }

    static void isUpToDate(IsUpToDateCallback isUpToDateCallback) {
        if (isInitialized()) {
            AppConfigUseCase appConfigUseCase = AppConfigUseCase.Companion.getInstance();
            appConfigUseCase.getAppConfig(false, isUpToDateCallback);
        }
    }

    static void getUser(final @NonNull GetUserCallback callback) {

        GetUserProfileInteractor getUserProfileInteractor = Injection.INSTANCE.provideGetUserProfileInteractor();
        getUserProfileInteractor.getUser(
                new Function1<UserProfile, Unit>() {
                    @Override
                    public Unit invoke(UserProfile userProfile) {
                        callback.onSuccess(userProfile);
                        return null;
                    }
                }, new Function1<ErrorObject, Unit>() {
                    @Override
                    public Unit invoke(ErrorObject errorObject) {
                        callback.onError(errorObject.getMessage());
                        return null;
                    }
                }
        );
    }


    public static class Logger {

        private static volatile boolean debug = isDebugEnabled;

        public static void log(String text) {
            if (debug) {
                if (text == null) {
                    text = "Empty message";
                }
                Log.d(TAG, text);
            }
        }

        public static void loge(String text) {
            if (debug) {
                if (text == null) {
                    text = "Empty message";
                }
                Log.e(TAG, text);
            }
        }
    }
}
applvsdklib/src/main/java/com/applivery/applvsdklib/tools/permissions/UserPermissionRequestResponseListener.java
public interface UserPermissionRequestResponseListener {
  void onPermissionAllowed(boolean permissionAllowed);
}
applvsdklib/src/main/java/com/applivery/applvsdklib/domain/model/FeedBackType.java
public enum FeedBackType implements StringValueEnum{
  FEEDBACK("feedback"),
  BUG("bug");

  private final String type;

  FeedBackType(final String type) {
    this.type = type;
  }

  public String getStringValue() {
    return type;
  }
}


Question: import android.graphics.Bitmap;
import android.text.TextUtils;
import com.applivery.applvsdklib.AppliverySdk;
import com.applivery.applvsdklib.domain.download.permissions.AccessNetworkStatePermission;
import com.applivery.applvsdklib.domain.login.GetUserProfileInteractor;
import com.applivery.applvsdklib.domain.model.ErrorObject;
import com.applivery.applvsdklib.domain.model.FeedBackType;
import com.applivery.applvsdklib.domain.model.UserFeedback;
import com.applivery.applvsdklib.features.feedback.FeedbackUseCase;
import com.applivery.applvsdklib.tools.androidimplementations.AndroidDeviceDetailsInfo;
import com.applivery.applvsdklib.tools.androidimplementations.ScreenCaptureUtils;
import com.applivery.applvsdklib.tools.permissions.PermissionChecker;
import com.applivery.applvsdklib.tools.permissions.UserPermissionRequestResponseListener;
import com.applivery.applvsdklib.ui.model.ScreenCapture;
import com.applivery.applvsdklib.ui.views.ShowErrorAlert;
import com.applivery.base.AppliveryDataManager;
import com.applivery.base.domain.PreferencesManager;
import com.applivery.base.domain.SessionManager;
import com.applivery.base.domain.model.AppData;
import com.applivery.base.domain.model.DeviceInfo;
import com.applivery.base.domain.model.Feedback;
import com.applivery.base.domain.model.PackageInfo;
import com.applivery.base.util.AndroidCurrentAppInfo;
import com.applivery.base.util.AppliveryLog;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
    }

    public void bugButtonPressed() {
        userFeedback.setType(FeedBackType.BUG);
        feedbackView.setBugButtonSelected();
    }

    public void screenshotSwitchPressed(boolean activated) {
        userFeedback.attachScreenshot(activated);

        if (activated) {
            feedbackView.showFeedbackImage();
        } else {
            feedbackView.hideFeedbackImage();
        }
    }

    public ScreenCapture getScreenCapture() {

        if (screenCapture == null) {
            ScreenCapture screenCapture =
                    ScreenCaptureUtils.getScreenCapture(AppliverySdk.getCurrentActivity());
            this.screenCapture = screenCapture;
        }

        return screenCapture;
    }

    public void setScreenCapture(ScreenCapture screenCapture) {
        this.screenCapture = screenCapture;
    }

    public void updateScreenCaptureWith(Bitmap screenshot) {
        if (screenshot == null) {
            AppliverySdk.Logger.log("Cannot update ScreenCapture with a null bitmap.");
            return;
        }

        screenCapture = new ScreenCapture(screenshot);
        feedbackView.showFeedbackImage();
        feedbackView.checkScreenshotSwitch(true);
    }

    public void sendFeedbackInfo(String feedbackMessage, String screen) {
        if (permissionRequestExecutor == null) {
            AppliverySdk.Logger.log(
                    "PermissionRequestExecutor must be initialized before accessing network state");
            return;
        }

        userFeedback.setMessage(feedbackMessage);
        userFeedback.setScreen(screen);

        if (userFeedback.mustAttachScreenshot()) {
            userFeedback.setScreenCapture(screenCapture);
        } else {
            userFeedback.setScreenCapture(null);
        }

        if (!permissionRequestExecutor.isGranted(accessNetworkStatePermission)) {
            askForPermission();
        } else {
            if (needLogin()) {
                feedbackView.requestLogin();
            } else {
                sendFeedback();
            }
        }
    }

    public void onEmailEntered(String email) {
        this.email = !TextUtils.isEmpty(email) ? email : null;
        feedbackView.onEmailError(false);
    }

    private Boolean needLogin() {
        AppData appConfig = AppliveryDataManager.INSTANCE.getAppData();
        if (appConfig != null) {
            boolean isAuthUpdate = appConfig.component5().getForceAuth();
            return isAuthUpdate && !sessionManager.hasSession();
        } else {
            AppliveryLog.error("Null app config at send feedback");
            return true;
        }
    }

    private void onSuccess() {
        screenCapture = null;
        feedbackView.cleanScreenData();
        feedbackView.dismissFeedBack();
    }

    private void onError(ErrorObject error) {
        ShowErrorAlert showErrorAlert = new ShowErrorAlert();
        showErrorAlert.showError(error);
    }

    public void feedbackImagePressed() {
        feedbackView.showScheenShotPreview();
    }

    public void okScreenShotPressed() {
        feedbackView.retrieveEditedScreenshot();
        feedbackView.hideScheenShotPreview();
    }

    private void askForPermission() {
        permissionRequestExecutor.askForPermission(accessNetworkStatePermission,
                new UserPermissionRequestResponseListener() {
                    @Override
                    public void onPermissionAllowed(boolean permissionAllowed) {
                        if (permissionAllowed) {
                            sendFeedback();
                        }
                    }
                }, AppliverySdk.getCurrentActivity());
    }

    private void sendFeedback() {
        PackageInfo packageInfo = AndroidCurrentAppInfo.Companion.getPackageInfo();
Answer:         AndroidDeviceDetailsInfo androidDeviceDetailsInfo = new AndroidDeviceDetailsInfo();