public abstract class OnAnimationEnd {
    public abstract void onEnd();
} public class Log {

    public static void i(Class clazz, String... msgs) {
        android.util.Log.i(clazz.getName(), concatenate(msgs));
    }

    public static void d(Class clazz, String... msgs) {
        android.util.Log.d(clazz.getName(), concatenate(msgs));
    }

    public static void w(Class clazz, String... msgs) {
        android.util.Log.w(clazz.getName(), concatenate(msgs));
    }

    public static void e(Class clazz, String... msgs) {
        android.util.Log.e(clazz.getName(), concatenate(msgs));
    }

    public static void e(Class clazz, String comment, Throwable throwable) {
        android.util.Log.e(clazz.getName(), comment + " error:", throwable);
    }

    public static void v(Class clazz, String... msgs) {
        android.util.Log.v(clazz.getName(), concatenate(msgs));
    }

    private static String concatenate(String[] msgs) {
        if (msgs == null) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        for (String msg : msgs) {
            sb.append(msg).append(" ");
        }
        return sb.toString();
    }

} public class Preferences {
    public static final String AUTH_TOKEN_DEFAULT_VALUE = "";
    public static final String FIREBASE_INSTANCE_ID_DEFAULT_VALUE = "";
    public static final String ACCOUNT_DEFAULT_VALUE = "";
    public static final int STATISTICS_DEFAULT_VALUE = 0;

    private static Object monitor = new Object();

    public static String getAuthToken(Context context) {
        synchronized (monitor) {
            return getSharedPreferences(context).getString(AUTH_TOKEN, AUTH_TOKEN_DEFAULT_VALUE);
        }
    }

    public static void setAuthToken(Context context, String token) {
        if (token != null) {
            synchronized (monitor) {
                getSharedPreferences(context).edit().putString(AUTH_TOKEN, token).apply();
            }
        }
    }

    public static void removeAuthToken(Context context) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().remove(AUTH_TOKEN).apply();
        }
    }


    public static String getAccount(Context context) {
        synchronized (monitor) {
            return getSharedPreferences(context).getString(ACCOUNT, ACCOUNT_DEFAULT_VALUE);
        }
    }

    public static void setAccount(Context context, String token) {
        if (token != null) {
            synchronized (monitor) {
                getSharedPreferences(context).edit().putString(ACCOUNT, token).apply();
            }
        }
    }

    public static void removeAccount(Context context) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().remove(ACCOUNT).apply();
        }
    }

    public static Location getLocation(Context context) {
        Location location = new Location(LOCATION);
        synchronized (monitor) {
            double lat = Double.valueOf(getSharedPreferences(context).getString(LATITUDE_PARAM, "0"));
            double lon = Double.valueOf(getSharedPreferences(context).getString(LONGITUDE_PARAM, "0"));
            location.setLatitude(lat);
            location.setLongitude(lon);
        }
        return location;
    }

    public static void setLocation(Context context, Location location) {
        if (location != null) {
            synchronized (monitor) {
                getSharedPreferences(context).edit().putString(LONGITUDE_PARAM, String.valueOf(location.getLongitude())).apply();
                getSharedPreferences(context).edit().putString(LATITUDE_PARAM, String.valueOf(location.getLatitude())).apply();
            }
        }
    }

    public static void removeLocation(Context context) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().remove(LONGITUDE_PARAM).apply();
            getSharedPreferences(context).edit().remove(LATITUDE_PARAM).apply();
        }
    }

    public static boolean isTrainingFragmentShown() {
        //TODO: change to return real value when Training will be Implemented.
        return true;
        //return 1 == getSharedPreferences().getInt(Constants.TRAINING_FRAGMENT_SHOWN, 0);
    }

    public static void setTrainingFragmentShown(Context context, int i) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().putInt(TRAINING_FRAGMENT_SHOWN, i).apply();
        }
    }

    public static void removeTrainingFragmentShown(Context context) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().remove(TRAINING_FRAGMENT_SHOWN).apply();
        }
    }

    public static void setBanResetAt(Context context, long resetAt) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().putLong(BAN_RESET_AT, resetAt).apply();
        }
    }

    public static long getBanResetAt(Context context) {
        synchronized (monitor) {
            return getSharedPreferences(context).getLong(BAN_RESET_AT, 0L);
        }
    }

    private static SharedPreferences getSharedPreferences(Context context) {
        synchronized (monitor) {
            return context.getSharedPreferences(PREFERENCES_FILE_NAME, Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS);
        }
    }

    public static String getFirebaseInstanceId(Context context) {
        synchronized (monitor) {
            return getSharedPreferences(context).getString(FIREBASE_INSTANCE_ID, FIREBASE_INSTANCE_ID_DEFAULT_VALUE);
        }
    }

    public static void setFirebaseInstanceId(Context context, String token) {
        if (token != null) {
            synchronized (monitor) {
                getSharedPreferences(context).edit().putString(FIREBASE_INSTANCE_ID, token).apply();
            }
        }
    }

    public static void removeFirebaseInstanceId(Context context) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().remove(FIREBASE_INSTANCE_ID).apply();
        }
    }

    public static Facing getCameraFacing(Context context) {
        synchronized (monitor) {
            Facing facing = Facing.valueOf(getSharedPreferences(context).getString(CAMERA_FACING_STRING, Facing.BACK.name()));
            return facing;
        }
    }

    public static void setCameraFacing(Context context, Facing facing) {
        synchronized (monitor) {
            if (facing != null) {
                getSharedPreferences(context).edit().putString(CAMERA_FACING_STRING, facing.name()).apply();
            }
        }
    }

    public static Grid getCameraGrid(Context context) {
        synchronized (monitor) {
            return Grid.valueOf(getSharedPreferences(context).getString(CAMERA_GRID_STRING, Grid.OFF.name()));
        }
    }

    public static void setCameraGrid(Context context, Grid cameraGrid) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().putString(CAMERA_GRID_STRING, cameraGrid.name()).apply();
        }
    }

    public static Flash getCameraFlashMode(Context context, Facing facing) {
        synchronized (monitor) {
            if (facing != null) {
                return Flash.valueOf(getSharedPreferences(context).getString(CAMERA_FLASH_MODE + facing.name(), Flash.OFF.name()));
            } else {
                return Flash.OFF;
            }
        }
    }

    public static void setCameraFlashMode(Context context, Facing facing, Flash flashMode) {
        synchronized (monitor) {
            if (flashMode != null && facing != null) {
                getSharedPreferences(context).edit().putString(CAMERA_FLASH_MODE + facing.name(), flashMode.name()).apply();
            }
        }
    }

    public static void removeCameraFlashMode(Context context, Facing facing) {
        synchronized (monitor) {
            getSharedPreferences(context).edit().remove(CAMERA_FLASH_MODE + facing.name()).apply();
        }
    }

    public static void setUserStatistics(Context context, Statistics statistics) {
        synchronized (monitor) {
            if (statistics != null) {
                getSharedPreferences(context).edit().putInt(USER_STATISTICS_LIKES, statistics.getLikes()).apply();
                getSharedPreferences(context).edit().putInt(USER_STATISTICS_DISLIKES, statistics.getDislikes()).apply();
            }
        }
    }

    public static Statistics getUserStatistics(Context context) {
        synchronized (monitor) {
            return Statistics.of(
                    getSharedPreferences(context).getInt(USER_STATISTICS_LIKES, STATISTICS_DEFAULT_VALUE),
                    getSharedPreferences(context).getInt(USER_STATISTICS_DISLIKES, STATISTICS_DEFAULT_VALUE));
        }
    }
} public class CropToSquareImageTask implements Runnable {
    private WeakReference<byte[]> data;
    private Context context;
    private boolean isFrontCamera;
    private AtomicBoolean isCanceled = new AtomicBoolean(false);

    public CropToSquareImageTask(byte[] data, boolean isFrontCamera, Context context) {
        this.data = new WeakReference<>(data);
        this.context = context;
        this.isFrontCamera = isFrontCamera;
    }

    private File saveSquareImage() {

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        if (isCanceled.get()) {
            data.clear();
            data = null;
            return null;
        }
        BitmapFactory.decodeByteArray(data.get(), 0, data.get().length, options);
        int rotateDegree = calculateImageRotation(data.get());
        if (isCanceled.get()) {
            data.clear();
            data = null;
            return null;
        }
        WeakReference<Bitmap> bitmap = decodeSquare(data, options);
        data.clear();
        data = null;
        if (isCanceled.get()) {
            bitmap.get().recycle();
            bitmap.clear();
            return null;
        }

        Bitmap resultedBitmap = rotate(bitmap, rotateDegree);

        if (isCanceled.get()) {
            if (bitmap.get()!= null) {
                bitmap.get().recycle();
            }
            bitmap.clear();
            resultedBitmap.recycle();
            return null;
        }

        File file = saveBitmap(resultedBitmap);
        if (bitmap.get()!= null) {
            bitmap.get().recycle();
        }
        bitmap.clear();
        resultedBitmap.recycle();
        return file;
    }

    private WeakReference<Bitmap> decodeSquare(WeakReference<byte[]> data, BitmapFactory.Options options) {
        int size = Math.min(options.outWidth, options.outHeight);
        //We need to crop square image from the center of the image
        int indent = (Math.max(options.outWidth, options.outHeight) - size) / 2;
        Rect rect;
        if (options.outHeight >= options.outWidth) {
            rect = new Rect(0, indent, size, size + indent);
        } else {
            rect = new Rect(indent, 0, size + indent, size);
        }

        options.inJustDecodeBounds = false;
        options.inPurgeable = true;
        options.inInputShareable = true;

        WeakReference<Bitmap> result;
        try {
            BitmapRegionDecoder regionDecoder = BitmapRegionDecoder.newInstance(data.get(), 0, data.get().length, true);
            result = new WeakReference<>(regionDecoder.decodeRegion(rect, options));
            regionDecoder.recycle();
        } catch (IOException ex) {
            Log.e(CropToSquareImageTask.class, "exception creating BitmapRegionDecoder", ex);
            throw new RuntimeException("Error creating BitmapRegionDecoder");
        }

        return result;
    }

    private Bitmap rotate(WeakReference<Bitmap> bitmap, int rotateDegree) {
        if (rotateDegree != 0 || isFrontCamera) {
            Matrix matrix = new Matrix();
            matrix.postRotate(rotateDegree);
            if (isFrontCamera) {
                matrix.postScale(-1, 1);
            }
            return Bitmap.createBitmap(bitmap.get(), 0, 0, bitmap.get().getWidth(), bitmap.get().getHeight(), matrix, true);
        } else {
            return bitmap.get();
        }
    }

    private int calculateImageRotation(byte[] data) {
        int rotation = 0;
        ExifInterface exifInterface = null;
        try {
            exifInterface = new ExifInterface(new ByteArrayInputStream(data));
        } catch (IOException e) {
            Log.e(CropToSquareImageTask.class, "Exception parsing JPEG Exif", e);
            // TODO: ripple to client
        }
        if (exifInterface != null) {
            int orientation = exifInterface.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            Log.d(CropToSquareImageTask.class, "Orientation: " + orientation);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    rotation = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    rotation = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    rotation = 270;
                    break;
                case ExifInterface.ORIENTATION_NORMAL:
                case ExifInterface.ORIENTATION_UNDEFINED:
                    rotation = 0;
                    break;
                default:
                    break;
            }
        }
        return rotation;
    }

    private File saveBitmap(Bitmap bitmap) {
        try {
            File file = FileUtil.getOutputMediaFile();
            FileOutputStream fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fos);
            fos.close();
            Log.d(CropToSquareImageTask.class, "Camera Pic Processed.");
            return file;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public void run() {
        File image = saveSquareImage();
        Intent intent = new Intent(CAMERA_BROADCAST_EVENT);
        if (image != null && !isCanceled.get()) {
            intent.putExtra(RANDO_PHOTO_PATH, image.getAbsolutePath());
            LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
        }
    }

    public void cancel() {
        Log.d(CropToSquareImageTask.class, "Cancelling...");
        isCanceled.set(true);
    }
} public class Analytics {

    private static String TAKE_RANDO = "take_rando";
    private static String UPLOAD_RANDO = "upload_rando";
    private static String SHARE_RANDO = "share_rando";
    private static String DELETE_RANDO = "delete_rando";
    private static String REPORT_RANDO = "report_rando";
    private static String TAP_STRANGER_RANDO = "tap_stranger_rando";
    private static String TAP_OWN_RANDO = "tap_own_rando";
    private static String FORCE_SYNC = "force_sync";
    private static String LOGOUT = "logout";
    private static String LOGIN_SKIP = "login_skip";
    private static String LOGIN_GOOGLE = "login_google";
    private static String LOGIN_EMAIL = "login_email";
    private static String OPEN_TAB_OWN_RANDOS = "open_tab_own_randos";
    private static String OPEN_TAB_STRANGER_RANDOS = "open_tab_stranger_randos";
    private static String OPEN_TAB_SETTINGS = "open_tab_settings";
    private static String SWITCH_CAMERA_TO_FRONT = "switch_camera_to_front";
    private static String SWITCH_CAMERA_TO_BACK = "switch_camera_to_back";
    private static String RATE_RANDO_UP = "rate_rando_up";
    private static String RATE_RANDO_NORMAL = "rate_rando_normal";
    private static String RATE_RANDO_DOWN = "rate_rando_down";

    //unwanted rando events
    private static String CLICK_UNWANTED_RANDO = "click_unwanted_rando";
    private static String DELETE_UNWANTED_RANDO_DIALOG = "delete_unwanted_rando_dialog";
    private static String CANCEL_UNWANTED_RANDO_DIALOG = "cancel_unwanted_rando_dialog";

    public static void logTakeRando(FirebaseAnalytics analytics) {
        analytics.logEvent(TAKE_RANDO, null);
    }

    public static void logUploadRando(FirebaseAnalytics analytics) {
        analytics.logEvent(UPLOAD_RANDO, null);
    }

    public static void logShareRando(FirebaseAnalytics analytics) {
        analytics.logEvent(SHARE_RANDO, null);
    }

    public static void logDeleteRando(FirebaseAnalytics analytics) {
        analytics.logEvent(DELETE_RANDO, null);
    }

    public static void logReportRando(FirebaseAnalytics analytics) {
        analytics.logEvent(REPORT_RANDO, null);
    }

    public static void logTapStrangerRando(FirebaseAnalytics analytics) {
        analytics.logEvent(TAP_STRANGER_RANDO, null);
    }

    public static void logTapOwnRando(FirebaseAnalytics analytics) {
        analytics.logEvent(TAP_OWN_RANDO, null);
    }

    public static void logForceSync(FirebaseAnalytics analytics) {
        analytics.logEvent(FORCE_SYNC, null);
    }

    public static void logLogout(FirebaseAnalytics analytics) {
        analytics.logEvent(LOGOUT, null);
    }

    public static void logLoginSkip(FirebaseAnalytics analytics) {
        analytics.logEvent(LOGIN_SKIP, null);
    }

    public static void logLoginEmail(FirebaseAnalytics analytics) {
        analytics.logEvent(LOGIN_EMAIL, null);
    }

    public static void logLoginGoogle(FirebaseAnalytics analytics) {
        analytics.logEvent(LOGIN_GOOGLE, null);
    }

    public static void logOpenTabOwnRandos(FirebaseAnalytics analytics) {
        analytics.logEvent(OPEN_TAB_OWN_RANDOS, null);
    }

    public static void logOpenTabStrangerRandos(FirebaseAnalytics analytics) {
        analytics.logEvent(OPEN_TAB_STRANGER_RANDOS, null);
    }

    public static void logOpenTabSettings(FirebaseAnalytics analytics) {
        analytics.logEvent(OPEN_TAB_SETTINGS, null);
    }

    public static void logClickUnwantedRando(FirebaseAnalytics analytics) {
        analytics.logEvent(CLICK_UNWANTED_RANDO, null);
    }

    public static void logDeleteUnwantedRandoDialog(FirebaseAnalytics analytics) {
        analytics.logEvent(DELETE_UNWANTED_RANDO_DIALOG, null);
    }

    public static void logCancelUnwantedRandoDialog(FirebaseAnalytics analytics) {
        analytics.logEvent(CANCEL_UNWANTED_RANDO_DIALOG, null);
    }

    public static void logSwitchCameraToFront(FirebaseAnalytics analytics) {
        analytics.logEvent(SWITCH_CAMERA_TO_FRONT, null);
    }

    public static void logSwitchCameraToBack(FirebaseAnalytics analytics) {
        analytics.logEvent(SWITCH_CAMERA_TO_BACK, null);
    }

    public static void logRateRandoGood(FirebaseAnalytics analytics) {
        analytics.logEvent(RATE_RANDO_UP, null);
    }

    public static void logRateRandoNormal(FirebaseAnalytics analytics) {
        analytics.logEvent(RATE_RANDO_NORMAL, null);
    }

    public static void logRateRandoBad(FirebaseAnalytics analytics) {
        analytics.logEvent(RATE_RANDO_DOWN, null);
    }

} public class LocationHelper {

    //my location manager and listener
    private LocationManager locationManager;
    private MyLocationListener locationListener;

    private Context context;

    /**
     * Constructor.
     *
     * @param context - The context of the calling activity.
     */
    public LocationHelper(Context context) {
        this.context = context;
    }

    public void updateLocationAsync() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
                ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        //setup the location manager
        locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
        //create the location listener
        locationListener = new MyLocationListener();

        //setup a callback for when the GRPS/WiFi gets a lock and we receive data
        if (locationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER)) {
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 30000, 10, locationListener);
        }
        //setup a callback for when the GPS gets a lock and we receive data
        if (locationManager.getAllProviders().contains(LocationManager.GPS_PROVIDER)) {
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 30000, 10, locationListener);
        }

        //Set timer to kill location services after timeout
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                killLocationServices();
            }
        }, Constants.LOCATION_DETECT_TIMEOUT);
    }

    /**
     * Used to receive notifications from the Location Manager when they are sent. These methods are called when
     * the Location Manager is registered with the Location Service and a state changes.
     *
     * @author Scott Helme
     */
    public class MyLocationListener implements LocationListener {

        //called when the location service reports a change in location
        public void onLocationChanged(Location location) {
            Preferences.setLocation(context, location);
            //now we have our location we can stop the service from sending updates
            //comment out this line if you want the service to continue updating the users location
            killLocationServices();
        }

        //called when the provider is disabled
        public void onProviderDisabled(String provider) {
        }

        //called when the provider is enabled
        public void onProviderEnabled(String provider) {
        }

        //called when the provider changes state
        public void onStatusChanged(String provider, int status, Bundle extras) {
        }
    }

    /**
     * Stop updates from the Location Service.
     */
    public void killLocationServices() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
                ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                ContextCompat.checkSelfPermission(context, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        if (locationManager != null && locationListener != null) {
            locationManager.removeUpdates(locationListener);
        }

    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    @SuppressWarnings("deprecation")
    public static boolean isGpsEnabled(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            String providers = Settings.Secure.getString(context.getContentResolver(),
                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
            if (TextUtils.isEmpty(providers)) {
                return false;
            }
            return (providers.contains(LocationManager.GPS_PROVIDER) || providers.contains(LocationManager.NETWORK_PROVIDER));
        } else {
            final int locationMode;
            try {
                locationMode = Settings.Secure.getInt(context.getContentResolver(),
                        Settings.Secure.LOCATION_MODE);
            } catch (Settings.SettingNotFoundException e) {
                e.printStackTrace();
                return false;
            }
            switch (locationMode) {
                case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
                case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
                case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
                    return true;
                case Settings.Secure.LOCATION_MODE_OFF:
                default:
                    return false;
            }
        }
    }
} public class PermissionUtils {

    private static final String[] allPermissions = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.GET_ACCOUNTS};

    /**
     *
     * @param activity
     * @param requestCode
     * @param permissions
     * @return true if some of requested permissions are missign
     */
    public static boolean checkAndRequestMissingPermissions(Activity activity, int requestCode, String... permissions) {

        if (permissions == null || permissions.length == 0) {
            permissions = allPermissions;
        }
        List<String> neededPermissions = new ArrayList<>();

        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                neededPermissions.add(permission);
            }
        }
        if (!neededPermissions.isEmpty()) {
            ActivityCompat.requestPermissions(activity, neededPermissions.toArray(new String[neededPermissions.size()]), requestCode);
        }
        return !neededPermissions.isEmpty();
    }
} public class CircleMaskView extends View {

    private Bitmap bitmap;


    public CircleMaskView(Context context) {
        super(context);
    }

    public CircleMaskView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CircleMaskView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    private void initMask(int height, int width) {

        Paint whiteStroke = new Paint();
        whiteStroke.setColor(Color.WHITE);
        whiteStroke.setStrokeWidth(1);

        Paint black = new Paint();
        black.setColor(Color.BLACK);

        Paint eraser = new Paint(Paint.ANTI_ALIAS_FLAG);
        eraser.setAlpha(127);
        eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

        int center = width / 2;
        int margin = getContext().getResources().getDimensionPixelSize(R.dimen.rando_padding_portrait_column_left);
        int radius = center - margin;

        bitmap = Bitmap.createBitmap(width, height,
                Bitmap.Config.ARGB_8888);
        Canvas mask = new Canvas(bitmap);

        mask.drawColor(Color.BLACK);
        mask.drawCircle(width / 2, center, radius, eraser);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = canvas.getWidth();
        int height = canvas.getHeight();
        if (bitmap == null) {
            initMask(height, width);
        }

        canvas.drawBitmap(bitmap, 0, 0, null);
    }


    public void recycle() {
        if (bitmap != null) {
            bitmap.recycle();
            bitmap = null;
        }
    }
} public class FlipImageView extends AppCompatImageView {

    private Animation[] leftToRightAnimation;

    public FlipImageView(Context context) {
        super(context);
    }

    public FlipImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FlipImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        leftToRightAnimation = AnimationFactory.flipAnimation(w, AnimationFactory.FlipDirection.LEFT_RIGHT, 150, null);
    }

    public void flipView(final int imageResource, final int backgroundResource, final OnAnimationEnd onAnimationEnd) {
        final Animation anim_out = leftToRightAnimation[0];
        final Animation anim_in = leftToRightAnimation[1];
        anim_out.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                //Do nothing
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                //Do nothing
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                setImageResource(imageResource);
                if (backgroundResource > 0) {
                    setBackgroundResource(backgroundResource);
                }
                anim_in.setAnimationListener(new Animation.AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {
                        //Do nothing
                    }

                    @Override
                    public void onAnimationRepeat(Animation animation) {
                        //Do nothing
                    }

                    @Override
                    public void onAnimationEnd(Animation animation) {
                        if (onAnimationEnd != null) {
                            onAnimationEnd.onEnd();
                        }
                    }
                });
                startAnimation(anim_in);
            }
        });
        startAnimation(anim_out);
    }

} public static final int CAMERA_ACTIVITY_CAMERA_PERMISSION_REQUIRED = 629; public static final String CAMERA_BROADCAST_EVENT = "RANDO_CAMERA_EVENT"; public static final int CAMERA_PERMISSION_REQUEST_CODE = 702; public static final int LOCATION_PERMISSION_REQUEST_CODE = 703;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.crashlytics.android.Crashlytics;
import com.github.randoapp.animation.OnAnimationEnd;
import com.github.randoapp.log.Log;
import com.github.randoapp.preferences.Preferences;
import com.github.randoapp.task.CropToSquareImageTask;
import com.github.randoapp.util.Analytics;
import com.github.randoapp.util.LocationHelper;
import com.github.randoapp.util.PermissionUtils;
import com.github.randoapp.view.CircleMaskView;
import com.github.randoapp.view.FlipImageView;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.otaliastudios.cameraview.CameraException;
import com.otaliastudios.cameraview.CameraListener;
import com.otaliastudios.cameraview.CameraOptions;
import com.otaliastudios.cameraview.CameraView;
import com.otaliastudios.cameraview.Facing;
import com.otaliastudios.cameraview.Flash;
import com.otaliastudios.cameraview.Gesture;
import com.otaliastudios.cameraview.GestureAction;
import com.otaliastudios.cameraview.Grid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import io.fabric.sdk.android.Fabric;
import static com.github.randoapp.Constants.CAMERA_ACTIVITY_CAMERA_PERMISSION_REQUIRED;
import static com.github.randoapp.Constants.CAMERA_BROADCAST_EVENT;
import static com.github.randoapp.Constants.CAMERA_PERMISSION_REQUEST_CODE;
import static com.github.randoapp.Constants.LOCATION_PERMISSION_REQUEST_CODE;
package com.github.randoapp;






public class CameraActivity16 extends Activity {

    private BroadcastReceiver receiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            progressBar.setVisibility(View.GONE);
            Bundle extra = intent.getExtras();
            if (extra != null) {
                String photoPath = (String) extra.get(Constants.RANDO_PHOTO_PATH);
                if (photoPath != null && !photoPath.isEmpty()) {

                    Intent activityIntent = new Intent(CameraActivity16.this, ImageReviewUploadActivity.class);
                    activityIntent.putExtra(Constants.FILEPATH, photoPath);
                    activityIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
                    startActivity(activityIntent);

                    finish();
                    return;
                } else {
                    Toast.makeText(CameraActivity16.this, getResources().getText(R.string.image_crop_failed),
                            Toast.LENGTH_LONG).show();
                }
            }
        }
    };

    private CameraActivity16.UnexpectedTerminationHelper mUnexpectedTerminationHelper = new CameraActivity16.UnexpectedTerminationHelper();

    private boolean isReturningFromCameraPermissionRequest = false;
    private boolean isReturningFromLocationPermissionRequest = false;

    private CameraView cameraView;
    private ImageView captureButton;
    private FlipImageView cameraSwitchButton;
    private ImageView flashButton;
    private FlipImageView gridButton;
    private LinearLayout progressBar;
    private Handler mBackgroundHandler;
    private FirebaseAnalytics mFirebaseAnalytics;
    private CircleMaskView circleMaskView;