public enum UIShield {
    LED_SHIELD((byte) 0x02, R.string.led_shield_name, 0xff03d203, R.drawable.shields_list_led_symbol, false, LedShield.class, LedFragment.class),
    NOTIFICATION_SHIELD((byte) 0x06, R.string.notifications_shield_name, 0xffd4d903, R.drawable.shields_list_notifications_symbol, false, NotificationShield.class, NotificationFragment.class),
    SEVENSEGMENT_SHIELD((byte) 0x07, R.string.seven_segment_shield_name, 0xffe28203, R.drawable.shields_list_seven_segment_symbol, false, SevenSegmentShield.class, SevenSegmentFragment.class),
    BUZZER_SHIELD((byte) 0x08, R.string.buzzer_shield_name, 0xffe93f03, R.drawable.shields_list_buzzer_symbol, false, SpeakerShield.class, BuzzerFragment.class),
    MIC_SHIELD((byte) 0x18, R.string.mic_shield_name, 0xff0362c0, R.drawable.shields_list_mic_symbol, false, MicShield.class, MicFragment.class, 1),
    KEYPAD_SHIELD((byte) 0x09, R.string.keypad_shield_name, 0xff03c0ae, R.drawable.shields_list_keypad_symbol, false, KeypadShield.class, KeypadFragment.class),
    SLIDER_SHIELD((byte) 0x01, R.string.slider_shield_name, 0xffc0034c, R.drawable.shields_list_slider_symbol, false, SliderShield.class, SliderFragment.class),
    LCD_SHIELD((byte) 0x17, R.string.lcd_shield_name, 0xff99bd03, R.drawable.shields_list_lcd_symbol, false, LcdShield.class, LcdFragment.class, true),
    MAGNETOMETER_SHIELD((byte) 0x0A, R.string.magnetometer_shield_name, 0xff40039f, R.drawable.shields_list_magnetometer_symbol, false, MagnetometerShield.class, MagnetometerFragment.class, 1),
    PUSHBUTTON_SHIELD((byte) 0x03, R.string.push_button_shield_name, 0xffb97547, R.drawable.shields_list_push_button_symbol, false, PushButtonShield.class, PushButtonFragment.class),
    TOGGLEBUTTON_SHIELD((byte) 0x04, R.string.toggle_button_shield_name, 0xffc0039d, R.drawable.shields_list_push_button_symbol, false, ToggleButtonShield.class, ToggleButtonFragment.class),
    ACCELEROMETER_SHIELD((byte) 0x0B, R.string.accelerometer_shield_name, 0xff266a5d, R.drawable.shields_list_accelerometer_symbol, false, AccelerometerShield.class, AccelerometerFragment.class, 1),
    FACEBOOK_SHIELD((byte) 0x19, R.string.facebook_shield_name, 0xff039dc0, R.drawable.shields_list_facebook_symbol, false, FacebookShield.class, FacebookFragment.class, 1),
    TWITTER_SHIELD((byte) 0x1A, R.string.twitter_shield_name, 0xffa14c4c, R.drawable.shields_list_twitter_symbol, false, TwitterShield.class, TwitterFragment.class, 1),
    GAMEDPAD_SHIELD((byte) 0x0C, R.string.game_pad_shield_name, 0xff658f08, R.drawable.shields_list_gamepad_symbol, false, GamepadShield.class, GamepadFragment.class),
    FOURSQUARE_SHIELD((byte) 0x1B, R.string.foursquare_shield_name, 0xff061179, R.drawable.shields_list_foursquare_symbol, false, FoursquareShield.class, FoursquareFragment.class),
    GPS_SHIELD((byte) 0x1C, R.string.gps_shield_name, 0xffa10b07, R.drawable.shields_list_gps_symbol, false, GpsShield.class, GpsFragment.class, 1),
    SMS_SHIELD((byte) 0x0D, R.string.sms_shield_name, 0xffdb7f40, R.drawable.shields_list_sms_symbol, false, SmsShield.class, SmsFragment.class, 1),
    MUSICPLAYER_SHIELD((byte) 0x1D, R.string.music_player_shield_name, 0xffb950e9, R.drawable.shields_list_musicplayer_symbol, false, MusicShield.class, MusicPlayerFragment.class, 1),
    GYROSCOPE_SHIELD((byte) 0x0E, R.string.gyroscope_shield_name, 0xff4c84e9, R.drawable.shields_list_gyroscope_symbol, false, GyroscopeShield.class, GyroscopeFragment.class, 1),
    SKYPE_SHIELD((byte) 0x1F, R.string.skype_shield_name, 0xff08c473, R.drawable.shields_list_skype_symbol, false, SkypeShield.class, SkypeFragment.class),
    PROXIMITY_SHIELD((byte) 0x13, R.string.proximity_shield_name, 0xff543c8d, R.drawable.shields_list_proximity_symbol, false, ProximityShield.class, ProximityFragment.class, 1),
    GRAVITY_SHIELD((byte) 0x14, R.string.gravity_shield_name, 0xffd95342, R.drawable.shields_list_gravity_symbol, false, GravityShield.class, GravityFragment.class, 1),
    ORIENTATION_SHIELD((byte) 0x0F, R.string.orientation_shield_name, 0xff58844f, R.drawable.shields_list_orientation_symbol, false, OrientationShield.class, OrientationFragment.class, 1),
    LIGHT_SHIELD((byte) 0x10, R.string.light_shield_name, 0xff8b268d, R.drawable.shields_list_light_sensor_symbol, false, LightShield.class, LightFragment.class, 1),
    PRESSURE_SHIELD((byte) 0x11, R.string.pressure_shield_name, 0xff67584d, R.drawable.shields_list_pressure_symbol, false, PressureShield.class, PressureFragment.class, 1),
    TEMPERATURE_SHIELD((byte) 0x12, R.string.temperature_shield_name, 0xff999f45, R.drawable.shields_list_temperature_symbol, false, TemperatureShield.class, TemperatureFragment.class, 1),
    CAMERA_SHIELD((byte) 0x15, R.string.camera_shield_name, 0xff6d0347, R.drawable.shields_list_camera_symbol, false, CameraShield.class, CameraFragment.class, 1),
    PHONE_SHIELD((byte) 0x20, R.string.phone_shield_name, 0xffe9bd03, R.drawable.shields_list_phone_symbol, false, PhoneShield.class, PhoneFragment.class, 1),
    EMAIL_SHIELD((byte) 0x1E, R.string.email_shield_name, 0xff114540, R.drawable.shields_list_email_symbol, false, EmailShield.class, EmailFragment.class, 1),
    CLOCK_SHIELD((byte) 0x21, R.string.clock_shield_name, 0xffc45527, R.drawable.shields_list_clock_symbol, false, ClockShield.class, ClockFragment.class),
    KEYBOARD_SHIELD((byte) 0x22, R.string.keyboard_shield_name, 0xffde1f26, R.drawable.shields_list_keyboard_symbol, false, KeyboardShield.class, KeyboardFragment.class),
    TEXT_TO_SPEECH_SHIELD((byte) 0x23, R.string.text_to_speech_shield_name, 0xffde1f26, R.drawable.shields_list_tts_symbol, false, TextToSpeechShield.class, TextToSpeechFragment.class),
    SPEECH_RECOGNIZER_SHIELD((byte) 0x24, R.string.voice_recognizer_shield_name, 0xffde1f26, R.drawable.shields_list_voice_recognition_symbol, false, SpeechRecognitionShield.class, SpeechRecognitionFragment.class, 1),
    DATA_LOGGER((byte) 0x25, R.string.data_logger_shield_name, 0xffde1f26, R.drawable.shields_list_data_logger_symbol, false, DataLoggerShield.class, DataLoggerFragment.class, 1),
    TERMINAL_SHIELD((byte) 0x26, R.string.terminal_shield_name, 0xffde1f26, R.drawable.shields_list_terminal_symbol, false, TerminalShield.class, TerminalFragment.class),
    TASKER_SHIELD((byte) 0x0, R.string.tasker_shield_name, 0xff0b4c8d, R.drawable.shields_list_flashlight_symbol, false, TaskerShield.class, EmptyShieldFragment.class, false),
    PATTERN_SHIELD((byte) 0x27, R.string.pattern_shield_name, 0xffde1f26, R.drawable.shields_list_pattern_symbol, false, PatternShield.class, PatternFragment.class),
    INTERNET_SHIELD((byte) 0x29, R.string.internet_shield_name, 0xffde1f26, R.drawable.shields_list_internet_symbol, false, InternetShield.class, InternetFragment.class, 1),
    NFC_SHIELD((byte) 0x16, R.string.nfc_shield_name, 0xff03d203, R.drawable.shields_list_nfc_symbol, false, NfcShield.class, NfcFragment.class, 1),
    GLCD_SHIELD((byte) 0x28, R.string.glcd_shield_name, 0xff03d203, R.drawable.shields_list_glcd_symbol, false, GlcdShield.class, GlcdFragment.class),
    COLOR_DETECTION_SHIELD((byte) 0x05, R.string.color_detector_shield_name, 0xffde1f26, R.drawable.shields_list_color_detector_symbol, false, ColorDetectionShield.class, ColorDetectionFragment.class, 1),
    VIBRATION_SHIELD((byte) 0x2A, R.string.vibration_shield_name, 0xffde1f26, R.drawable.shields_list_vibration_symbol, false, VibrationShield.class, VibrationFragment.class, 1),
    FACE_DETECTION((byte) 0x2D, R.string.face_detection_shield_name, 0xff0b4c8d, R.drawable.shields_list_face_detection_symbol, false, FaceDetectionShield.class, FaceDetectionFragment.class, 1);
    public static int[] colors = new int[]{0xff03d203, 0xffd4d903,
            0xffe28203, 0xffe93f03, 0xff0362c0, 0xff03c0ae, 0xffc0034c,
            0xff99bd03, 0xff40039f, 0xffb97547, 0xffc0039d, 0xff266a5d,
            0xff039dc0, 0xffa14c4c, 0xff658f08, 0xff061179, 0xffa10b07,
            0xffdb7f40, 0xffb950e9, 0xff4c84e9, 0xff0b4c8d, 0xff08c473,
            0xff543c8d, 0xffd95342, 0xff58844f, 0xff8b268d, 0xff67584d,
            0xff999f45, 0xff6d0347, 0xffe9bd03, 0xff127303, 0xff08bbb2,
            0xff5a0303, 0xff988564, 0xff114540, 0xffc45527, 0xffde1f26,
            0xff142218, 0xffc9a302, 0xffa57378, 0xff3354af, 0xff282742,
            0xff381616, 0xff0b4c8d};
    public static UIShield shieldsActivitySelection;
    public static boolean isConnected = false;
    private byte id;
    private int shieldNameStringResource;
    private int itemBackgroundColor;
    private int symbolId;
    private boolean mainActivitySelection;
    private boolean isReleasable = true;
    private int isInvalidatable = 0;
    private Class<? extends ControllerParent<?>> shieldType;
    private Class<? extends ShieldFragmentParent<?>> shieldFragment;
    private int position = 0;

    UIShield(byte id, int shieldNameStringResource, int mainImageStripId, int symbolId,
             boolean mainActivitySelection,
             Class<? extends ControllerParent<?>> shieldType, Class<? extends ShieldFragmentParent<?>> shieldFragment) {
        this.id = id;
        this.shieldNameStringResource = shieldNameStringResource;
        this.itemBackgroundColor = mainImageStripId;
        this.symbolId = symbolId;
        this.mainActivitySelection = mainActivitySelection;
        this.shieldType = shieldType;
        this.shieldFragment = shieldFragment;
    }

    UIShield(byte id, int shieldNameStringResource, int mainImageStripId, int symbolId,
             boolean mainActivitySelection,
             Class<? extends ControllerParent<?>> shieldType, Class<? extends ShieldFragmentParent<?>> shieldFragment, int isInvalidatable) {
        this.id = id;
        this.shieldNameStringResource = shieldNameStringResource;
        this.itemBackgroundColor = mainImageStripId;
        this.symbolId = symbolId;
        this.mainActivitySelection = mainActivitySelection;
        this.shieldType = shieldType;
        this.shieldFragment = shieldFragment;
        this.isInvalidatable = isInvalidatable;
    }

    UIShield(byte id, int shieldNameStringResource, int mainImageStripId, int symbolId,
             boolean mainActivitySelection,
             Class<? extends ControllerParent<?>> shieldType, Class<? extends ShieldFragmentParent<?>> shieldFragment,
             boolean isReleasable) {
        this.id = id;
        this.shieldNameStringResource = shieldNameStringResource;
        this.itemBackgroundColor = mainImageStripId;
        this.symbolId = symbolId;
        this.mainActivitySelection = mainActivitySelection;
        this.shieldType = shieldType;
        this.shieldFragment = shieldFragment;
        this.isReleasable = isReleasable;
    }

    public static UIShield getShieldsActivitySelection() {
        return shieldsActivitySelection;
    }

    public static void setConnected(boolean isConnected) {
        UIShield.isConnected = isConnected;
    }

    public static synchronized List<UIShield> valuesFiltered() {
        UIShield[] vals = values();
        List<UIShield> valsFiltered = new ArrayList<UIShield>();
        for (int i = 0; i < vals.length; i++) {
            UIShield cur = vals[i];
            if (cur.isReleasable) {
                cur.position = valsFiltered.size();
                valsFiltered.add(cur);
            }
        }
        Collections.sort(valsFiltered, new Comparator<UIShield>() {

            @Override
            public int compare(UIShield lhs, UIShield rhs) {
                return lhs.getName().compareToIgnoreCase(rhs.getName());
            }
        });
        vals = null;
        final ArrayList<UIShield> ret = new ArrayList<UIShield>();
        for (UIShield uiShield : valsFiltered) {
            uiShield.itemBackgroundColor = colors[ret.size()];
            ret.add(uiShield);
        }
        valsFiltered.clear();
        valsFiltered = null;
        return ret;
    }

    public String getName() {
        return OneSheeldApplication.getContext().getString(shieldNameStringResource);
    }

    public byte getId() {
        return id;
    }

    public int getItemBackgroundColor() {
        return itemBackgroundColor;
    }

    public int getSymbolId() {
        return symbolId;
    }

    public boolean isMainActivitySelection() {
        return mainActivitySelection;
    }

    public int getIsInvalidatable() {
        return isInvalidatable;
    }

    public int getPosition() {
        return position;
    }

    public Class<? extends ControllerParent<?>> getShieldType() {
        return shieldType;
    }

    public Class<? extends ShieldFragmentParent<?>> getShieldFragment() {
        return shieldFragment;
    }

    public boolean isReleasable() {
        return isReleasable;
    }
} public class CameraShield extends ControllerParent<CameraShield> {
    public static final int CRASHED = 3;
    public final static int UNBIND_CAMERA_CAPTURE = 4, BIND_CAMERA_CAPTURE = 5, NEXT_CAPTURE = 14, SET_LAST_IMAGE_BUTTON = 17;
    private static final byte CAPTURE_METHOD_ID = (byte) 0x01;
    private static final byte FLASH_METHOD_ID = (byte) 0x02;
    private static final byte QUALITY_METHOD_ID = (byte) 0x04;
    private static final byte FRONT_CAPTURE = (byte) 0x03;
    private static String FLASH_MODE;
    private static int QUALITY_MODE = 0;
    private static String lastImageAbsoultePath = null;
    public Queue<CameraShield.CameraCapture> capturesQueue = new ConcurrentLinkedQueue<>();
    public boolean isBackPreview = true;
    CameraCapture capture;
    int numberOfFrames = 0;
    Handler UIHandler;
    private Messenger cameraBinder;
    private boolean isCameraBound;
    private boolean isCameraCapturing = false;
    private CameraEventHandler eventHandler;
    private boolean hasFrontCamera = false;
    private boolean isChangingPreview = false;
    private Messenger mMessenger = new Messenger(new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == CRASHED) {
                cameraBinder = null;
                isCameraBound = false;
                if (capturesQueue == null)
                    capturesQueue = new ConcurrentLinkedQueue<>();
                bindService();
            } else if (msg.what == NEXT_CAPTURE) {
                if (msg.getData().getBoolean("takenSuccessfuly")) {
                    if (capturesQueue != null && !capturesQueue.isEmpty())
                        capturesQueue.poll();
                }
                isCameraCapturing = false;
                checkQueue();
            } else if (msg.what == CameraHeadService.SET_CAMERA_PREVIEW_TYPE) {
                isBackPreview = msg.getData().getBoolean("isBack");
                if (eventHandler != null)
                    eventHandler.setOnCameraPreviewTypeChanged(isBackPreview);
                isChangingPreview = false;
            } else if (msg.what == SET_LAST_IMAGE_BUTTON) {
                lastImageAbsoultePath = msg.getData().getString("absolutePath");
                CameraUtils.setLastCapturedImagePathFromOneSheeldFolder(lastImageAbsoultePath, activity);
                Log.d("LastImage", lastImageAbsoultePath);
                File img = new File(lastImageAbsoultePath);
                if (img.exists() && eventHandler != null) {
                    eventHandler.updatePreviewButton(lastImageAbsoultePath);
                }
                img = null;
            }
            super.handleMessage(msg);
        }


    });
    private ServiceConnection cameraServiceConnector = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            isCameraCapturing = false;
            notifyHardwareOfShieldSelection();
            cameraBinder = new Messenger(service);
            Message msg = Message.obtain(null, BIND_CAMERA_CAPTURE);
            msg.replyTo = mMessenger;
            try {
                cameraBinder.send(msg);
            } catch (RemoteException e) {
            }
            isCameraBound = true;
            checkQueue();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            cameraBinder = null;
            isCameraBound = false;
        }

    };

    public CameraShield() {

    }

    public CameraShield(Activity activity, String tag) {
        super(activity, tag, true);
    }

    public static String getLastImageAbsoultePath() {
        return lastImageAbsoultePath;
    }

    @Override
    public ControllerParent<CameraShield> init(String tag) {
        UIHandler = new Handler();
        return super.init(tag, true);
    }

    void bindService() {
        getApplication().bindService(new Intent(getActivity(), CameraHeadService.class), cameraServiceConnector, Context.BIND_AUTO_CREATE);
    }

    @Override
    public ControllerParent<CameraShield> invalidate(
            com.integreight.onesheeld.shields.ControllerParent.SelectionAction selectionAction,
            boolean isToastable) {
        this.selectionAction = selectionAction;
        if (!checkCameraHardware(getApplication().getApplicationContext())) {
            if (selectionAction != null)
                selectionAction.onFailure();
            if (isToastable)
                activity.showToast(R.string.camera_camera_is_unavailable_maybe_its_used_by_another_application_toast);
        } else {
            addRequiredPremission(Manifest.permission.CAMERA);
            addRequiredPremission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            if (Build.VERSION.SDK_INT >= 16)
                addRequiredPremission(Manifest.permission.READ_EXTERNAL_STORAGE);
            if (checkForPermissions()) {
                if (!activity.canDrawOverApps()) {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(
                            activity);
                    builder.setMessage(
                            R.string.camera_we_need_you_to_enable_the_draw_over_apps_permission_in_order_to_show_the_camera_preview_correctly)
                            .setCancelable(false)
                            .setPositiveButton(R.string.camera_validation_dialog_ok_button,
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(final DialogInterface dialog,
                                                            final int id) {
                                            activity.requestDrawOverApps();
                                        }
                                    })
                            .setNegativeButton(R.string.camera_validation_dialog_later_button, new DialogInterface.OnClickListener() {
                                public void onClick(final DialogInterface dialog,
                                                    final int id) {
                                    dialog.cancel();
                                    activity.showToast(R.string.camera_please_enable_the_permission_to_be_able_to_select_this_shield_toast);
                                }
                            });
                    final AlertDialog alert = builder.create();
                    alert.show();
                    if (this.selectionAction != null) {
                        this.selectionAction.onFailure();
                    }
                } else {
                    if (selectionAction != null)
                        selectionAction.onSuccess();
                    hasFrontCamera = CameraUtils.checkFrontCamera(activity.getApplicationContext());
                    bindService();
                    UIHandler = new Handler();
                }
            } else {
                if (this.selectionAction != null) {
                    this.selectionAction.onFailure();
                }
            }
        }
        return super.invalidate(selectionAction, isToastable);
    }

    public boolean isBackPreview() {
        return isBackPreview;
    }

    public boolean setCameraToPreview(boolean isBack) {
        if (!isBack && !CameraUtils.checkFrontCamera(getActivity().getApplicationContext()))
            return false;
        if (isChangingPreview)
            return false;
        isChangingPreview = true;
        Log.d("Acc", isBack + "   **");
        Message msg = Message.obtain(null, CameraHeadService.SET_CAMERA_PREVIEW_TYPE);
        msg.replyTo = mMessenger;
        Bundle b = new Bundle();
        b.putBoolean("isBack", isBack);
        msg.setData(b);
        if (cameraBinder != null) {
            try {
                cameraBinder.send(msg);
            } catch (RemoteException e) {
                return false;
            }
        } else {
            bindService();
        }
        isBackPreview = isBack;
        return true;
    }

    private synchronized void checkQueue() {
        if (capturesQueue != null && !capturesQueue.isEmpty() && !isCameraCapturing) {
            if (isCameraBound) {
                capture = capturesQueue.peek();
                if (capture.isFront()) {
                    if (hasFrontCamera)
                        sendFrontCaptureImageIntent(capture);
                    else {
                        Toast.makeText(getActivity(), R.string.camera_your_device_doesnt_have_a_front_camera_toast, Toast.LENGTH_SHORT).show();
                        capturesQueue.poll();
                    }
                } else {
                    sendCaptureImageIntent(capture);
                }
            } else bindService();
        }
    }

    /**
     * Check if this device has a camera
     */
    private synchronized boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_CAMERA)) {
            // this device has a camera
            return true;
        } else {
            // no camera on this device
            return false;
        }
    }

    public void setCameraEventHandler(CameraEventHandler eventHandler) {
        this.eventHandler = eventHandler;
    }

    public boolean showPreview() throws RemoteException {
        Message msg = Message.obtain(null, CameraHeadService.SHOW_PREVIEW);
        msg.replyTo = mMessenger;
        if (cameraBinder != null) {
            cameraBinder.send(msg);
            return true;
        } else {
            bindService();
            return false;
        }
    }

    public void invalidatePreview() throws RemoteException {
        Message msg = Message.obtain(null, CameraHeadService.INVALIDATE_PREVIEW);
        msg.replyTo = mMessenger;
        if (cameraBinder != null)
            cameraBinder.send(msg);
        else bindService();
    }

    public boolean hidePreview() throws RemoteException {
        Message msg = Message.obtain(null, CameraHeadService.HIDE_PREVIEW);
        msg.replyTo = mMessenger;
        if (cameraBinder != null) {
            cameraBinder.send(msg);
            return true;
        } else {
            return false;
        }
    }

    @Override
    public void onNewShieldFrameReceived(ShieldFrame frame) {

        if (frame.getShieldId() == UIShield.CAMERA_SHIELD.getId()) {
            switch (frame.getFunctionId()) {
                case QUALITY_METHOD_ID:
                    byte quality_mode = frame.getArgument(0)[0];
                    switch (quality_mode) {
                        case 1:
                            QUALITY_MODE = 40;
                            break;
                        case 2:
                            QUALITY_MODE = 70;
                            break;
                        case 3:
                            QUALITY_MODE = 100;
                            break;

                        default:
                            break;
                    }
                    break;

                case FLASH_METHOD_ID:
                    byte flash_mode = frame.getArgument(0)[0];
                    switch (flash_mode) {
                        case 0:
                            FLASH_MODE = "off";
                            break;
                        case 1:
                            FLASH_MODE = "on";
                            break;
                        case 2:
                            FLASH_MODE = "auto";
                            break;
                        default:
                            break;
                    }
                    break;

                case CAPTURE_METHOD_ID:

                    numberOfFrames++;
                    Log.d("Camera", "Frames number = " + numberOfFrames);
                    CameraCapture camCapture = new CameraCapture(FLASH_MODE, false,
                            QUALITY_MODE, new Date().getTime());
                    if (capturesQueue == null)
                        capturesQueue = new ConcurrentLinkedQueue<>();
                    capturesQueue.add(camCapture);
                    checkQueue();
                    break;
                case FRONT_CAPTURE:
                    numberOfFrames++;
                    Log.d("Camera", "Frames number front = " + numberOfFrames);
                    CameraCapture frontCamCapture = new CameraCapture(FLASH_MODE,
                            true, QUALITY_MODE, new Date().getTime());
                    if (capturesQueue == null)
                        capturesQueue = new ConcurrentLinkedQueue<>();
                    capturesQueue.add(frontCamCapture);
                    checkQueue();
                    break;

                default:
                    break;
            }
        }

    }

    @Override
    public void reset() {
        Message msg = Message.obtain(null, UNBIND_CAMERA_CAPTURE);
        try {
            if (cameraBinder != null)
                cameraBinder.send(msg);
        } catch (RemoteException e) {
        }
        try {
            getApplication().unbindService(cameraServiceConnector);
        } catch (IllegalArgumentException e) {

        }
        capturesQueue = new ConcurrentLinkedQueue<>();
        isCameraBound = false;

    }

    @Override
    public void preConfigChange() {
        super.preConfigChange();
    }

    @Override
    public void postConfigChange() {
        super.postConfigChange();
    }

    private void sendCaptureImageIntent(CameraShield.CameraCapture camCapture) {
        if (camCapture != null) {
            if (isCameraBound) {
                isCameraCapturing = true;
                Bundle intent = new Bundle();
                intent.putString("FLASH", camCapture.getFlash());
                intent.putInt("Quality_Mode", camCapture.getQuality());
                Message msg = Message.obtain(null, CameraHeadService.CAPTURE_IMAGE);
                msg.setData(intent);
                try {
                    cameraBinder.send(msg);
                } catch (RemoteException e) {
//                    capturesQueue.add(camCapture);
                    checkQueue();
                }
            } else bindService();
            Log.d("ImageTakin", "OnTakeBack()");
        }
    }

    private void sendFrontCaptureImageIntent(CameraShield.CameraCapture camCapture) {
        if (camCapture != null) {
            if (isCameraBound) {
                isCameraCapturing = true;
                Bundle intent = new Bundle();
                intent.putInt("Quality_Mode", camCapture.getQuality());
                intent.putBoolean("Front_Request", true);
                Message msg = Message.obtain(null, CameraHeadService.CAPTURE_IMAGE);
                msg.setData(intent);
                try {
                    cameraBinder.send(msg);
                } catch (RemoteException e) {
                    checkQueue();
                }
//                    service.takeImage(front_translucent);
            } else {
                bindService();
            }
        }
    }

    public interface CameraEventHandler {
        void OnPictureTaken();

        void checkCameraHardware(boolean isHasCamera);

        void takePicture();

        void setFlashMode(String flash_mode);

        void setOnCameraPreviewTypeChanged(boolean isBack);

        void updatePreviewButton(String lastImagePath);
    }

    public class CameraCapture implements Serializable {
        private String flash;
        private boolean isFrontCamera;

        private long tag;
        private int mquality;

        public CameraCapture(String flash, boolean isFront, int quality, long tag) {
            this.flash = flash;
            isFrontCamera = isFront;
            mquality = quality;
            this.tag = tag;
        }

        public int getQuality() {
            return mquality;

        }

        public String getFlash() {
            return flash;
        }

        public boolean isFront() {
            return isFrontCamera;

        }

        public long getTag() {
            return tag;
        }

        public void setTag(long tag) {
            this.tag = tag;
        }
    }

} public class ColorDetectionShield extends
        ControllerParent<ColorDetectionShield> {
    private static final byte SHIELD_ID = (byte) 0x05;
    private static final byte SEND_NORMAL_COLOR = (byte) 0x01;
    private static final byte SEND_FULL_COLORS = (byte) 0x02;
    private static final byte ENABLE_FULL_COLORS = (byte) 0x02;
    private static final byte ENABLE_NORMAL_COLOR = (byte) 0x03;
    private static final byte SET_CALC_MODE = (byte) 0x04;
    private static final byte SET_PATCH_SIZE = (byte) 0x05;
    private static final byte SMALL_PATCH = (byte) 0x01;
    private static final byte MED_PATCH = (byte) 0x02;
    private static final byte AVERAGE_COLOR = (byte) 0x02;
    private static final byte SET_PALLETE = (byte) 0x01;
    private ColorDetectionEventHandler colorEventHandler;
    boolean isCameraBound = false;
    private Messenger mService;
    public static final int UNBIND_COLOR_DETECTOR = 2, SET_COLOR_DETECTION_OPERATION = 10, SET_COLOR_DETECTION_TYPE = 11, SET_COLOR_PATCH_SIZE = 12;
    private RECEIVED_FRAMES recevedFramesOperation = RECEIVED_FRAMES.CENTER;
    private COLOR_TYPE colorType = COLOR_TYPE.COMMON;
    private long lastSentMS = SystemClock.elapsedRealtime();
    private ShieldFrame frame;
    int[] detected;
    ColorPalette currentPallete = ColorPalette._24_BIT_RGB;
    private PATCH_SIZE patchSize = PATCH_SIZE.LARGE;
    public boolean isBackPreview = true;

    @Override

    public ControllerParent<ColorDetectionShield> init(String tag) {
        // TODO Auto-generated method stub
        initMessenger();
        return super.init(tag, true);
    }

    @Override
    public ControllerParent<ColorDetectionShield> invalidate(
            com.integreight.onesheeld.shields.ControllerParent.SelectionAction selectionAction,
            boolean isToastable) {
        this.selectionAction = selectionAction;
        addRequiredPremission(Manifest.permission.CAMERA);
        if (!CameraUtils.checkCameraHardware(getApplication().getApplicationContext())) {
            if (selectionAction != null)
                selectionAction.onFailure();
            if (isToastable)
                activity.showToast(R.string.color_detector_camera_is_unavailable_maybe_its_used_by_another_application_toast);
        } else {
            if (checkForPermissions()) {
                if(!activity.canDrawOverApps()){
                    final AlertDialog.Builder builder = new AlertDialog.Builder(
                            activity);
                    builder.setMessage(
                            R.string.color_detector_we_need_you_to_enable_the_draw_over_apps_permission_in_order_to_show_the_camera_preview_correctly)
                            .setCancelable(false)
                            .setPositiveButton(R.string.color_detector_validation_dialog_ok_button,
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(final DialogInterface dialog,
                                                            final int id) {
                                            activity.requestDrawOverApps();
                                        }
                                    })
                            .setNegativeButton(R.string.color_detector_validation_dialog_later_button, new DialogInterface.OnClickListener() {
                                public void onClick(final DialogInterface dialog,
                                                    final int id) {
                                    dialog.cancel();
                                    activity.showToast(R.string.color_detector_please_enable_the_permission_to_be_able_to_select_this_shield_toast);
                                }
                            });
                    final AlertDialog alert = builder.create();
                    alert.show();
                    if (this.selectionAction != null) {
                        this.selectionAction.onFailure();
                    }
                }
                else {
                    if (selectionAction != null)
                        selectionAction.onSuccess();
                    bindService();
                }
            }else {
                if (selectionAction != null)
                    selectionAction.onFailure();
            }
          }
        return super.invalidate(selectionAction, isToastable);
    }

    private void bindService(){
        getApplication().bindService(new Intent(getActivity(), CameraHeadService.class), mConnection, Context.BIND_AUTO_CREATE);
    }

    public ColorDetectionShield(Activity activity, String tag) {
        super(activity, tag, true);
    }

    public ColorDetectionShield() {
        super();
    }

    private void notifyPatchSize() {
        if (isCameraBound) {
            Message msg = Message.obtain(null, SET_COLOR_PATCH_SIZE);
            msg.replyTo = mMessenger;
            Bundle data = new Bundle();
            data.putInt("size", patchSize.value);
            msg.setData(data);
            try {
                if (mService != null)
                    mService.send(msg);
            } catch (RemoteException e) {
            }
        } else
            bindService();

    }

    private void notifyColorDetectionOperation() {
        if (isCameraBound) {
            Message msg = Message.obtain(null, SET_COLOR_DETECTION_OPERATION);
            msg.replyTo = mMessenger;
            Bundle data = new Bundle();
            data.putInt("type", recevedFramesOperation.type);
            msg.setData(data);
            try {
                if (mService != null)
                    mService.send(msg);
            } catch (RemoteException e) {
            }
        } else
            bindService();
    }

    private void notifyColorDetectionType() {
        if (isCameraBound) {
            Message msg = Message.obtain(null, SET_COLOR_DETECTION_TYPE);
            msg.replyTo = mMessenger;
            Bundle data = new Bundle();
            data.putInt("type", colorType.type);
            msg.setData(data);
            try {
                if (mService != null)
                    mService.send(msg);
            } catch (RemoteException e) {
            }
        } else
            bindService();

    }

    @Override
    public void onNewShieldFrameReceived(ShieldFrame frame) {
        if (frame.getShieldId() == SHIELD_ID) {
            switch (frame.getFunctionId()) {
                case ENABLE_FULL_COLORS:
                    if (colorEventHandler != null) {
                        colorEventHandler.enableFullColor();
                    }
                    recevedFramesOperation = RECEIVED_FRAMES.NINE_FRAMES;
                    notifyColorDetectionOperation();
                    break;
                case ENABLE_NORMAL_COLOR:
                    if (colorEventHandler != null) {
                        colorEventHandler.enableNormalColor();
                    }
                    recevedFramesOperation = RECEIVED_FRAMES.CENTER;
                    notifyColorDetectionOperation();
                    break;
                case SET_PALLETE:
                    currentPallete = ColorPalette.get(frame.getArgument(0)[0]);
                    if (colorEventHandler != null) {
                        colorEventHandler.setPallete(currentPallete);
                    }
                    break;
                case SET_CALC_MODE:
                    colorType = frame.getArgument(0)[0] == AVERAGE_COLOR ? COLOR_TYPE.AVERAGE : COLOR_TYPE.COMMON;
                    if (colorEventHandler != null) {
                        colorEventHandler.changeCalculationMode(colorType);
                    }
                    break;
                case SET_PATCH_SIZE:
                    patchSize = frame.getArgument(0)[0] == SMALL_PATCH ? PATCH_SIZE.SMALL : frame.getArgument(0)[0] == MED_PATCH ? PATCH_SIZE.MEDIUM : PATCH_SIZE.LARGE;
                    if (colorEventHandler != null) {
                        colorEventHandler.changePatchSize(patchSize);
                    }
                    notifyPatchSize();
                    break;
            }
        }
    }

    public void setColorEventHandler(ColorDetectionEventHandler colorEventHandler) {
        this.colorEventHandler = colorEventHandler;

    }

    public void showPreview(float x, float y, int width, int height) throws RemoteException {
        Message msg = Message.obtain(null, CameraHeadService.SHOW_PREVIEW);
        msg.replyTo = mMessenger;
        Bundle b = new Bundle();
        b.putFloat("x", x);
        b.putFloat("y", y);
        b.putInt("w", width);
        b.putInt("h", height);
        msg.setData(b);
        if (mService != null)
            mService.send(msg);
        else
            bindService();

    }

    public void invalidatePreview(float x, float y) throws RemoteException {
        Message msg = Message.obtain(null, CameraHeadService.INVALIDATE_PREVIEW);
        msg.replyTo = mMessenger;
        Bundle b = new Bundle();
        b.putFloat("x", x);
        b.putFloat("y", y);
        msg.setData(b);
        if (mService != null)
            mService.send(msg);
        else
            bindService();

    }

    public void hidePreview() throws RemoteException {
        Message msg = Message.obtain(null, CameraHeadService.HIDE_PREVIEW);
        msg.replyTo = mMessenger;
        if (mService != null)
            mService.send(msg);
    }

    public static interface ColorDetectionEventHandler {
        void onColorChanged(int... color);

        void enableFullColor();

        void enableNormalColor();

        void setPallete(ColorPalette pallete);

        void changeCalculationMode(COLOR_TYPE type);

        void changePatchSize(PATCH_SIZE patchSize);

        void onCameraPreviewTypeChanged(final boolean isBack);
    }

    public void setCurrentPallete(ColorPalette currentPallete) {
        this.currentPallete = currentPallete;
    }

    public ColorPalette getCurrentPallete() {
        return currentPallete;
    }

    public RECEIVED_FRAMES getRecevedFramesOperation() {
        return recevedFramesOperation;
    }

    @Override
    public void preConfigChange() {
        super.preConfigChange();
    }

    @Override
    public void postConfigChange() {
        super.postConfigChange();
   }

    @Override
    public void reset() {
        Message msg = Message.obtain(null, UNBIND_COLOR_DETECTOR);
        msg.replyTo = mMessenger;
        try {
            if (mService != null)
                mService.send(msg);
        } catch (RemoteException e) {
        }
        try {
            getApplication().unbindService(mConnection);
        }catch(IllegalArgumentException e){

        }
    }

    boolean fullFrame = true;
    private Messenger mMessenger;

    private void initMessenger() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                mMessenger = new Messenger(new Handler() {

                    public void handleMessage(Message msg) {
                        if (msg.what == CameraHeadService.GET_RESULT && msg.getData() != null) {
                            detected = msg.getData().getIntArray("detected");
                            frame = new ShieldFrame(SHIELD_ID, recevedFramesOperation == RECEIVED_FRAMES.NINE_FRAMES ? SEND_FULL_COLORS : SEND_NORMAL_COLOR);
                            int i = 0;
                            for (int det : detected) {
                                int color = getColorInRange(det, currentPallete);
                                detected[i] = color;
                                frame.addArgument(3, color);
                                fullFrame = true;
                                i++;
                            }
                            if (fullFrame && colorEventHandler != null) {
                                colorEventHandler.onColorChanged(detected);
                            }
                            if (fullFrame && SystemClock.elapsedRealtime() - lastSentMS >= 100) {
                                sendShieldFrame(frame);
                                lastSentMS = SystemClock.elapsedRealtime();
                            }
                        } else if (msg.what == CameraHeadService.CRASHED) {
                            bindService();
                        } else if (msg.what == CameraHeadService.SET_CAMERA_PREVIEW_TYPE) {
                            isBackPreview = msg.getData().getBoolean("isBack");
                            if (colorEventHandler != null)
                                colorEventHandler.onCameraPreviewTypeChanged(isBackPreview);
                            isChangingPreview = false;
                        }
                        super.handleMessage(msg);
                    }
                });
                Looper.loop();
            }
        }).start();
    }

    public boolean isBackPreview() {
        return isBackPreview;
    }

    private boolean isChangingPreview = false;

    public boolean setCameraToPreview(boolean isBack) {
        if (!isBack && !CameraUtils.checkFrontCamera(getActivity().getApplicationContext()))
            return false;
        if (isChangingPreview)
            return false;
        isChangingPreview = true;
        Message msg = Message.obtain(null, CameraHeadService.SET_CAMERA_PREVIEW_TYPE);
        msg.replyTo = mMessenger;
        Bundle b = new Bundle();
        b.putBoolean("isBack", isBack);
        msg.setData(b);
        if (mService != null) {
            try {
                mService.send(msg);
            } catch (RemoteException e) {
                return false;
            }
        }
        isBackPreview = isBack;
        return true;
    }

    private ServiceConnection mConnection = new ServiceConnection() {

        public void onServiceConnected(ComponentName className,
                                       IBinder binder) {
            notifyHardwareOfShieldSelection();
            isCameraBound = true;
            mService = new Messenger(binder);
            Message msg = Message.obtain(null, CameraHeadService.GET_RESULT);
            msg.replyTo = mMessenger;
            try {
                mService.send(msg);
                notifyPatchSize();
                notifyColorDetectionType();
                notifyColorDetectionOperation();
            } catch (RemoteException e) {
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            isCameraBound = false;
        }
    };

    public void setRecevedFramesOperation(RECEIVED_FRAMES recevedFramesOperation) {
        this.recevedFramesOperation = recevedFramesOperation;
        notifyColorDetectionOperation();
    }

    public COLOR_TYPE getColorType() {
        return colorType;
    }

    public void setColorType(COLOR_TYPE colorType) {
        this.colorType = colorType;
        notifyColorDetectionType();
    }

    int getColorInRange(int color, ColorPalette palette) {
        int i = 0;
        if (palette.isGrayscale) {
            i = palette.getNumberOfBits();
            int grayscale = (Color.red(color) + Color.green(color) + Color
                    .blue(color)) / 3;
            color = Color.rgb(grayscale, grayscale, grayscale);
        } else
            i = palette.getNumberOfBits() / 3;

        int newR = (int) Math
                .round(((Color.red(color) >>> (8 - i)) * (255 / (Math.pow(2, i) - 1))));
        int newG = (int) Math
                .round(((Color.green(color) >>> (8 - i)) * (255 / (Math.pow(2, i) - 1))));
        int newB = (int) Math
                .round(((Color.blue(color) >>> (8 - i)) * (255 / (Math.pow(2, i) - 1))));
        return Color.rgb(newR, newG, newB);
    }

    public PATCH_SIZE getPatchSize() {
        return patchSize;
    }

    public void setPatchSize(PATCH_SIZE patchSize) {
        this.patchSize = patchSize;
        notifyPatchSize();
    }

    public enum ColorPalette {
        _1_BIT_GRAYSCALE(true, 1, 0), _2_BIT_GRAYSCALE(true, 2, 1), _4_BIT_GRAYSCALE(
                true, 4, 2), _8_BIT_GRAYSCALE(true, 8, 3), _3_BIT_RGB(3, 0), _6_BIT_RGB(
                6, 1), _9_BIT_RGB(9, 2), _12_BIT_RGB(12, 3), _15_BIT_RGB(15, 4), _18_BIT_RGB(
                18, 5), _24_BIT_RGB(24, 6);
        private boolean isGrayscale;
        private int numberOfBits;
        private int index;

        ColorPalette(int numberOfBits, int index) {
            this.isGrayscale = false;
            this.numberOfBits = numberOfBits;
            this.index = index;
        }

        ColorPalette(boolean isGrayscale, int numberOfBits, int index) {
            this.isGrayscale = isGrayscale;
            this.numberOfBits = numberOfBits;
            this.index = index;
        }

        public int getIndex() {
            return index;
        }

        public boolean isGrayscale() {
            return isGrayscale;
        }

        public int getNumberOfBits() {
            return numberOfBits;
        }

        @Override
        public String toString() {
            double colorRange = Math.pow(2, numberOfBits);
            DecimalFormat formatter = new DecimalFormat("#,###");
            return formatter.format(colorRange)
                    + (isGrayscale ? " Grayscale" : "") + " Colors Palette";
        }

        public static ColorPalette get(byte key) {
            switch (key) {
                case 1:
                    return _1_BIT_GRAYSCALE;
                case 2:
                    return _2_BIT_GRAYSCALE;
                case 3:
                    return _4_BIT_GRAYSCALE;
                case 4:
                    return _8_BIT_GRAYSCALE;
                case 5:
                    return _3_BIT_RGB;
                case 6:
                    return _6_BIT_RGB;
                case 7:
                    return _9_BIT_RGB;
                case 8:
                    return _12_BIT_RGB;
                case 9:
                    return _15_BIT_RGB;
                case 10:
                    return _18_BIT_RGB;
                case 11:
                default:
                    return _24_BIT_RGB;
            }
        }
    }

    public static enum RECEIVED_FRAMES {
        CENTER(0), NINE_FRAMES(1);
        public int type;

        private RECEIVED_FRAMES(int type) {
            this.type = type;
        }

        public static RECEIVED_FRAMES getEnum(int type) {
            return type == 0 ? CENTER : NINE_FRAMES;
        }
    }

    public static enum COLOR_TYPE {
        COMMON(0), AVERAGE(1);
        public int type;

        private COLOR_TYPE(int type) {
            this.type = type;
        }

        public static COLOR_TYPE getEnum(int type) {
            return type == 0 ? COMMON : AVERAGE;
        }
    }

    public static enum PATCH_SIZE {
        SMALL(4), MEDIUM(2), LARGE(1);
        public int value;

        private PATCH_SIZE(int value) {
            this.value = value;
        }

        public static PATCH_SIZE getEnum(byte type) {
            return type == SMALL_PATCH ? SMALL : type == MED_PATCH ? MEDIUM : LARGE;
        }
    }
} public class FaceDetectionShield extends ControllerParent<FaceDetectionShield> {
    private static final String TAG = FaceDetectionShield.class.getName();
    public static final int FACE_CRASHED = 18;
    public static final int BIND_FACE_DETECTION = 9;
    public static final int START_DETECTION = 14;
    public static final int SEND_FACES = 20;
    public static final int SEND_EMPTY = 21;
    public static final int IS_FACE_ACTIVE = 25;
    public static final int UNBIND_FACE_DETECTION = 6;
    private static final byte DETECTED_FACES = 0x01;
    private static final byte MISSING_FACES = 0x02;
    private Messenger faceBinder;
    private boolean isCameraBound = false;
    public boolean isBackPreview = true;
    public boolean isFaceSelected = false;
    private boolean isChangingPreview = false;
    private FaceDetectionHandler eventHandler;
    private byte[] faceId = new byte[2];
    private byte[] xPosition = new byte[2];
    private byte[] yPosition = new byte[2];
    private byte[] height = new byte[2];
    private byte[] width = new byte[2];
    private byte[] leftEye = new byte[2];
    private byte[] rightEye = new byte[2];
    private byte[] isSmile = new byte[2];
    private ShieldFrame frame;
    ArrayList<FaceDetectionObj> tmpArray = null;
    private int previewWidth, previewHeight;
    private int rotation;

    public FaceDetectionShield() {
    }

    public FaceDetectionShield(Activity activity, String tag) {
        super(activity, tag);
    }

    @Override
    public ControllerParent<FaceDetectionShield> init(String tag) {
        return super.init(tag);
    }

    @Override
    public ControllerParent<FaceDetectionShield> invalidate(SelectionAction selectionAction, boolean isToastable) {
        this.selectionAction = selectionAction;
        if (!checkCameraHardware(getApplication().getApplicationContext())) {
            if (selectionAction != null)
                selectionAction.onFailure();
            if (isToastable)
                activity.showToast(R.string.camera_camera_is_unavailable_maybe_its_used_by_another_application_toast);
        } else {
            addRequiredPremission(Manifest.permission.CAMERA);
            addRequiredPremission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            if (Build.VERSION.SDK_INT >= 16)
                addRequiredPremission(Manifest.permission.READ_EXTERNAL_STORAGE);
            if (checkForPermissions()) {
                if (!activity.canDrawOverApps()) {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(
                            activity);
                    builder.setMessage(
                            R.string.camera_we_need_you_to_enable_the_draw_over_apps_permission_in_order_to_show_the_camera_preview_correctly)
                            .setCancelable(false)
                            .setPositiveButton(R.string.camera_validation_dialog_ok_button,
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(final DialogInterface dialog,
                                                            final int id) {
                                            activity.requestDrawOverApps();
                                        }
                                    })
                            .setNegativeButton(R.string.camera_validation_dialog_later_button, new DialogInterface.OnClickListener() {
                                public void onClick(final DialogInterface dialog,
                                                    final int id) {
                                    dialog.cancel();
                                    activity.showToast(R.string.camera_please_enable_the_permission_to_be_able_to_select_this_shield_toast);
                                }
                            });
                    final AlertDialog alert = builder.create();
                    alert.show();
                    if (this.selectionAction != null) {
                        this.selectionAction.onFailure();
                    }
                } else {
                    if (selectionAction != null)
                        selectionAction.onSuccess();
                    bindService();
                }
            } else {
                if (this.selectionAction != null) {
                    this.selectionAction.onFailure();
                }
            }
        }

        return super.invalidate(selectionAction, isToastable);
    }

    private Messenger mMessenger = new Messenger(new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == FACE_CRASHED) {
                faceBinder = null;
                isCameraBound = false;
                bindService();
            } else if (msg.what == CameraHeadService.SET_CAMERA_PREVIEW_TYPE) {
                isBackPreview = msg.getData().getBoolean("isBack");
                if (eventHandler != null)
                    eventHandler.setOnCameraPreviewTypeChanged(isBackPreview);
                isChangingPreview = false;

            } else if (msg.what == SEND_FACES) {
                Bundle bundle = msg.getData();
                if (tmpArray == null)
                    tmpArray = new ArrayList<>();
                bundle.setClassLoader(FaceDetectionObj.class.getClassLoader());
                ArrayList<FaceDetectionObj> faceDetectionObjArrayList;
                faceDetectionObjArrayList = bundle.getParcelableArrayList("face_array");
                previewHeight = bundle.getInt("height");
                previewWidth = bundle.getInt("width");
                rotation = bundle.getInt("rotation");
                for (int i = 0; i < faceDetectionObjArrayList.size(); i++) {
                    boolean isMatched = false;
                    for (int j = 0; j < tmpArray.size(); j++)
                        if (faceDetectionObjArrayList.get(i).getFaceId() == tmpArray.get(j).getFaceId()) {
                            isMatched = true;
                            if (tmpArray.get(j).getxPosition() != faceDetectionObjArrayList.get(i).getxPosition() ||
                                    tmpArray.get(j).getyPosition() != faceDetectionObjArrayList.get(i).getyPosition() ||
                                    tmpArray.get(j).getWidth() != faceDetectionObjArrayList.get(i).getWidth() ||
                                    tmpArray.get(j).getHeight() != faceDetectionObjArrayList.get(i).getHeight() ||
                                    tmpArray.get(j).getLeftEye() != faceDetectionObjArrayList.get(i).getLeftEye() ||
                                    tmpArray.get(j).getRightEye() != faceDetectionObjArrayList.get(i).getRightEye() ||
                                    tmpArray.get(j).getIsSmile() != faceDetectionObjArrayList.get(i).getIsSmile()) {
                                sendDetectedFaces(tmpArray.get(j), previewWidth, previewHeight);
                                tmpArray.remove(j);
                            }
                            break;
                        }
                    if (!isMatched)
                        sendDetectedFaces(faceDetectionObjArrayList.get(i), previewWidth, previewHeight);
                }
                if (tmpArray.size() > 0)
                    for (int k = 0; k < tmpArray.size(); k++)
                        sendMissingFaces(tmpArray.get(k));
                tmpArray = faceDetectionObjArrayList;
            }
            if (msg.what == SEND_EMPTY) {
                if (tmpArray != null)
                    for (int i = 0; i < tmpArray.size(); i++)
                        sendMissingFaces(tmpArray.get(i));
                tmpArray = null;
            }
            super.handleMessage(msg);
        }
    });

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            notifyHardwareOfShieldSelection();
            faceBinder = new Messenger(service);
            Message msg = Message.obtain(null, BIND_FACE_DETECTION);
            msg.replyTo = mMessenger;
            try {
                faceBinder.send(msg);
            } catch (RemoteException e) {
            }
            isCameraBound = true;
            try {
                setStartDetection();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isCameraBound = false;
        }
    };

    private void bindService() {
        getApplication().bindService(new Intent(getActivity(), CameraHeadService.class), serviceConnection, Context.BIND_AUTO_CREATE);

    }

    /**
     * Check if this device has a camera
     */
    private synchronized boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_CAMERA)) {
            // this device has a camera
            return true;
        } else {
            // no camera on this device
            return false;
        }
    }

    public boolean isBackPreview() {
        return isBackPreview;
    }

    public boolean isFaceSelected() {
        return isFaceSelected;
    }

    public void setStartDetection() throws RemoteException {
        if (isCameraBound) {
            Message msg = Message.obtain(null, START_DETECTION);
            msg.replyTo = mMessenger;
            if (faceBinder != null) {
                faceBinder.send(msg);
            }
        } else {
            bindService();
        }
    }

    public void setIsFaceSelected(boolean isFaceSelected) {
        if (faceBinder != null) {
            Message msg = Message.obtain(null, IS_FACE_ACTIVE);
            msg.replyTo = mMessenger;
            Bundle b = new Bundle();
            b.putBoolean("setIsFaceSelected", isFaceSelected);
            msg.setData(b);
            try {
                faceBinder.send(msg);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        } else {
            bindService();
        }
        this.isFaceSelected = isFaceSelected;
    }

    public boolean setCameraToPreview(boolean isBack) {
        if (faceBinder != null) {
            if (!isBack && !CameraUtils.checkFrontCamera(getActivity().getApplicationContext()))
                return false;
            if (isChangingPreview)
                return false;
            isChangingPreview = true;
            Log.d("Acc", isBack + "   **");
            Message msg = Message.obtain(null, CameraHeadService.SET_CAMERA_PREVIEW_TYPE);
            msg.replyTo = mMessenger;
            Bundle b = new Bundle();
            b.putBoolean("isBack", isBack);
            msg.setData(b);
            try {
                faceBinder.send(msg);
            } catch (RemoteException e) {
                return false;
            }
        } else {
            bindService();
        }
        isBackPreview = isBack;
        return true;
    }

    public boolean showPreview() throws RemoteException {
        if (faceBinder != null) {
            Message msg = Message.obtain(null, CameraHeadService.SHOW_PREVIEW);
            msg.replyTo = mMessenger;
            faceBinder.send(msg);
            return true;
        } else {
            bindService();
            return false;
        }
    }

    public boolean hidePreview() throws RemoteException {
        if (faceBinder != null) {
            Message msg = Message.obtain(null, CameraHeadService.HIDE_PREVIEW);
            msg.replyTo = mMessenger;
            faceBinder.send(msg);
            return true;
        } else {
            return false;
        }
    }

    public void invalidatePreview() throws RemoteException {
        if (faceBinder != null) {
            Message msg = Message.obtain(null, CameraHeadService.INVALIDATE_PREVIEW);
            msg.replyTo = mMessenger;
            faceBinder.send(msg);
        } else
            bindService();
    }

    @Override
    public void onNewShieldFrameReceived(ShieldFrame frame) {
    }

    public interface FaceDetectionHandler {
        void setOnCameraPreviewTypeChanged(boolean isBack);
    }

    @Override
    public void reset() {
        android.util.Log.d(TAG, "unbind: ");
        Message msg = Message.obtain(null, UNBIND_FACE_DETECTION);
        msg.replyTo = mMessenger;
        try {
            if (faceBinder != null)
                faceBinder.send(msg);
        } catch (RemoteException e) {
        }
        try {
            getApplication().unbindService(serviceConnection);
        } catch (IllegalArgumentException e) {
        }
        isCameraBound = false;
    }

    public void setCameraEventHandler(FaceDetectionHandler eventHandler) {
        this.eventHandler = eventHandler;
    }

    @Override
    public void preConfigChange() {
        super.preConfigChange();
    }

    @Override
    public void postConfigChange() {
        super.postConfigChange();
    }

    private static byte[] intTo2ByteArray(int value) {
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (value & 0xff);
        bytes[1] = (byte) ((value >>> 8) & 0xff);
        return bytes;
    }

    private static byte[] float2ByteArray(float value) {
        int bits = Math.round(value);
        byte[] bytes = new byte[2];
        bytes[0] = (byte) (bits & 0xff);
        bytes[1] = (byte) ((bits >>> 8) & 0xff);
        return bytes;
    }

    private static byte[] twoByteArraysInto4ByteArray(byte[] value1, byte[] value2) {
        byte[] bytes = new byte[4];
        bytes[0] = value1[0];
        bytes[1] = value1[1];
        bytes[2] = value2[0];
        bytes[3] = value2[1];
        return bytes;
    }

    private static byte[] threeByteArraysTo4ByteArray(byte[] value, byte[] value1, byte[] value2) {
        byte[] bytes = new byte[4];
        bytes[0] = value[0];
        bytes[1] = value1[0];
        bytes[2] = value2[0];
        bytes[3] = 0;
        return bytes;
    }

    private static float transform(float value, float inMin, float inMax, float outMin, float outMax) {
        return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
    }

    public void sendDetectedFaces(FaceDetectionObj faceDetection, int previewWidth, int previewHeight) {
        float x = faceDetection.getxPosition();
        float y = faceDetection.getyPosition();
        float scaledX, scaledY, scaleSmile, scaleRightEye, scaleLeftEye;
        switch (rotation) {
            case 0: {
                if (!isBackPreview)
                    x = previewHeight - x;
                break;
            }
            case 1: {
                if (!isBackPreview)
                    x = previewWidth - x;
                break;
            }
            case 2: {
                if (!isBackPreview)
                    x = previewHeight - x;
                break;
            }
            case 3: {
                if (!isBackPreview)
                    x = previewWidth - x;
                break;
            }
        }
        frame = new ShieldFrame(UIShield.FACE_DETECTION.getId(), DETECTED_FACES);
        faceId = intTo2ByteArray(faceDetection.getFaceId());
        scaledX = transform(x, 0, previewWidth, -500, 500);
        scaledY = transform(y, 0, previewHeight, 500, -500);
        if (faceDetection.getIsSmile() == -1)
            isSmile = float2ByteArray(faceDetection.getIsSmile());
        else if (faceDetection.getRightEye() == -1)
            rightEye = float2ByteArray(faceDetection.getRightEye());
        else if (faceDetection.getLeftEye() == -1)
            leftEye = float2ByteArray(faceDetection.getLeftEye());
        else {
            scaleSmile = transform(faceDetection.getIsSmile(), 0, 1, 0, 100);
            scaleRightEye = transform(faceDetection.getRightEye(), 0, 1, 0, 100);
            scaleLeftEye = transform(faceDetection.getLeftEye(), 0, 1, 0, 100);
            leftEye = float2ByteArray(scaleLeftEye);
            rightEye = float2ByteArray(scaleRightEye);
            isSmile = float2ByteArray(scaleSmile);
        }
        xPosition = float2ByteArray(scaledX);
        yPosition = float2ByteArray(scaledY);
        height = float2ByteArray(faceDetection.getHeight());
        width = float2ByteArray(faceDetection.getWidth());
        frame.addArgument(faceId);
        frame.addArgument(twoByteArraysInto4ByteArray(xPosition, yPosition));
        if (rotation == 1 || rotation == 3)
            frame.addArgument(twoByteArraysInto4ByteArray(height, width));
        else
            frame.addArgument(twoByteArraysInto4ByteArray(width, height));
        frame.addArgument(threeByteArraysTo4ByteArray(leftEye, rightEye, isSmile));
        sendShieldFrame(frame);
    }

    public void sendMissingFaces(FaceDetectionObj faceDetectionObj) {
        frame = new ShieldFrame(UIShield.FACE_DETECTION.getId(), MISSING_FACES);
        faceId = intTo2ByteArray(faceDetectionObj.getFaceId());
        frame.addArgument(faceId);
        sendShieldFrame(frame);
    }


} public class FaceGraphic extends GraphicOverlay.Graphic {
    private static final float FACE_POSITION_RADIUS = 10.0f;
    private static final float ID_TEXT_SIZE = 40.0f;
    private static final float ID_Y_OFFSET = 50.0f;
    private static final float ID_X_OFFSET = -50.0f;
    private static final float BOX_STROKE_WIDTH = 5.0f;
    int previewWidth = 0;
    int previewHeight = 0;
    boolean isBack = true;
    int faceRotation;
    private static final int COLOR_CHOICES[] = {
            Color.BLUE,
            Color.CYAN,
            Color.GREEN,
            Color.MAGENTA,
            Color.RED,
            Color.WHITE,
            Color.YELLOW
    };
    private static int mCurrentColorIndex = 0;

    private Paint mFacePositionPaint;
    private Paint mIdPaint;
    private Paint mBoxPaint;

    private volatile Face mFace;
    private int mFaceId;
    private float mFaceHappiness;

    public FaceGraphic(GraphicOverlay overlay) {
        super(overlay);

        mCurrentColorIndex = (mCurrentColorIndex + 1) % COLOR_CHOICES.length;
        final int selectedColor = COLOR_CHOICES[mCurrentColorIndex];

        mFacePositionPaint = new Paint();
        mFacePositionPaint.setColor(selectedColor);

        mIdPaint = new Paint();
        mIdPaint.setColor(selectedColor);
        mIdPaint.setTextSize(ID_TEXT_SIZE);

        mBoxPaint = new Paint();
        mBoxPaint.setColor(selectedColor);
        mBoxPaint.setStyle(Paint.Style.STROKE);
        mBoxPaint.setStrokeWidth(BOX_STROKE_WIDTH);
    }

    public void setId(int id) {
        mFaceId = id;
    }

    public int getId() {
        return mFaceId;
    }

    public void setCameraInfo(int previewWidth, int previewHeight, boolean isBack, int faceRotation) {
        this.isBack = isBack;
        this.previewHeight = previewHeight;
        this.previewWidth = previewWidth;
        this.faceRotation = faceRotation;
    }


    /**
     * Updates the face instance from the detection of the most recent frame.  Invalidates the
     * relevant portions of the overlay to trigger a redraw.
     */
    public void updateFace(Face face) {
        mFace = face;
        postInvalidate();
    }

    /**
     * Draws the face annotations for position on the supplied canvas.
     */
    @Override
    public void draw(Canvas canvas) {
        Face face = mFace;
        if (face == null) {
            return;
        }
        // Draws a circle at the position of the detected face, with the face's track id below.
        float x = translateX(face.getPosition().x + face.getWidth() / 2);
        float y = translateY(face.getPosition().y + face.getHeight() / 2);
        float xOffset = scaleX(face.getWidth() / 2.0f);
        float yOffset = scaleY(face.getHeight() / 2.0f);
        float tmp = 0;
        // Draws a bounding box around the face.
        float left = 0, top = 0, right = 0, bottom = 0;
        switch (faceRotation) {
            case 0: {
                if (!isBack)
                    x = previewHeight - x;
                tmp = y;
                y = x;
                x = previewWidth - tmp;
                left = x - yOffset;
                top = y - xOffset;
                right = x + yOffset;
                bottom = y + xOffset;
                break;
            }
            case 1: {
                if (!isBack)
                    x = previewWidth - x;
                left = x - xOffset;
                top = y - yOffset;
                right = x + xOffset;
                bottom = y + yOffset;
                break;
            }
            case 2: {
                if (!isBack)
                    x = previewHeight - x;
                tmp = x;
                x = y;
                y = previewHeight - tmp;
                left = x - yOffset;
                top = y - xOffset;
                right = x + yOffset;
                bottom = y + xOffset;
                break;
            }
            case 3: {
                if (isBack)
                    x = previewWidth - x;
                y = previewHeight - y;
                left = x - xOffset;
                top = y - yOffset;
                right = x + xOffset;
                bottom = y + yOffset;
                break;
            }
        }


        canvas.drawRect(left, top, right, bottom, mBoxPaint);
    }
} public class GraphicOverlay extends View {
    private final Object mLock = new Object();
    private int mPreviewWidth;
    private float mWidthScaleFactor = 1.0f;
    private int mPreviewHeight;
    private float mHeightScaleFactor = 1.0f;
    private int mFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
    private List<Graphic> mGraphics = new ArrayList<>();

    public Graphic get(int i) {
        return mGraphics.get(i);
    }


    /**
     * Base class for a custom graphics object to be rendered within the graphic overlay.  Subclass
     * this and implement the {@link Graphic#draw(Canvas)} method to define the
     * graphics element.  Add instances to the overlay using {@link GraphicOverlay#add(Graphic)}.
     */
    public static abstract class Graphic {
        private GraphicOverlay mOverlay;

        public Graphic(GraphicOverlay overlay) {
            mOverlay = overlay;
        }

        /**
         * Draw the graphic on the supplied canvas.  Drawing should use the following methods to
         * convert to view coordinates for the graphics that are drawn:
         * <ol>
         * <li>{@link Graphic#scaleX(float)} and {@link Graphic#scaleY(float)} adjust the size of
         * the supplied value from the preview scale to the view scale.</li>
         * <li>{@link Graphic#translateX(float)} and {@link Graphic#translateY(float)} adjust the
         * coordinate from the preview's coordinate system to the view coordinate system.</li>
         * </ol>
         *
         * @param canvas drawing canvas
         */
        public abstract void draw(Canvas canvas);

        /**
         * Adjusts a horizontal value of the supplied value from the preview scale to the view
         * scale.
         */
        public float scaleX(float horizontal) {
            return horizontal * mOverlay.mWidthScaleFactor;
        }

        /**
         * Adjusts a vertical value of the supplied value from the preview scale to the view scale.
         */
        public float scaleY(float vertical) {
            return vertical * mOverlay.mHeightScaleFactor;
        }

        /**
         * Adjusts the x coordinate from the preview's coordinate system to the view coordinate
         * system.
         */
        public float translateX(float x) {
            if (mOverlay.mFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                return mOverlay.getWidth() - scaleX(x);
            } else {
                return scaleX(x);
            }
        }

        /**
         * Adjusts the y coordinate from the preview's coordinate system to the view coordinate
         * system.
         */
        public float translateY(float y) {
            return scaleY(y);
        }

        public void postInvalidate() {
            mOverlay.postInvalidate();
        }
    }

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

    /**
     * Removes all graphics from the overlay.
     */
    public void clear() {
        synchronized (mLock) {
            mGraphics.clear();
        }
        postInvalidate();
    }

    /**
     * Adds a graphic to the overlay.
     */
    public void add(Graphic graphic) {
        synchronized (mLock) {
            mGraphics.add(graphic);
        }
        postInvalidate();
    }

    /**
     * Returns a new set of all graphics.
     */
    public List<Graphic> getFaceGraphicList() {
        List<Graphic> mGraphicsList = new ArrayList<>();
        synchronized (mLock) {
            for (Graphic g : mGraphics) {
                mGraphicsList.add(g);
            }
        }
        return mGraphicsList;
    }

    /**
     * Removes a graphic from the overlay.
     */
    public void remove(Graphic graphic) {
        synchronized (mLock) {
            mGraphics.remove(graphic);
        }
        postInvalidate();
    }

    /**
     * Sets the camera attributes for size and facing direction, which informs how to transform
     * image coordinates later.
     */
    public void setCameraInfo(int previewWidth, int previewHeight, int facing) {
        synchronized (mLock) {
            mPreviewWidth = previewWidth;
            mPreviewHeight = previewHeight;
            mFacing = facing;
        }
        postInvalidate();
    }

    /**
     * Draws the overlay with its associated graphic objects.
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        synchronized (mLock) {
            if ((mPreviewWidth != 0) && (mPreviewHeight != 0)) {
                mWidthScaleFactor = (float) canvas.getWidth() / (float) mPreviewWidth;
                mHeightScaleFactor = (float) canvas.getHeight() / (float) mPreviewHeight;
            }

            for (Graphic graphic : mGraphics) {
                graphic.draw(canvas);
            }
        }
    }
} public static final int IS_FACE_ACTIVE = 25; public static final int SEND_EMPTY = 21; public static final int SEND_FACES = 20; public static final int START_DETECTION = 14;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.SensorManager;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;
import com.crashlytics.android.Crashlytics;
import com.google.android.gms.vision.Detector;
import com.google.android.gms.vision.Frame;
import com.google.android.gms.vision.MultiProcessor;
import com.google.android.gms.vision.Tracker;
import com.google.android.gms.vision.face.Face;
import com.google.android.gms.vision.face.FaceDetector;
import com.integreight.onesheeld.R;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.integreight.onesheeld.enums.UIShield;
import com.integreight.onesheeld.shields.controller.CameraShield;
import com.integreight.onesheeld.shields.controller.ColorDetectionShield;
import com.integreight.onesheeld.shields.controller.FaceDetectionShield;
import com.integreight.onesheeld.utils.CrashlyticsUtils;
import com.integreight.onesheeld.utils.Log;
import com.integreight.onesheeld.utils.customviews.utils.FaceGraphic;
import com.integreight.onesheeld.utils.customviews.utils.GraphicOverlay;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import io.fabric.sdk.android.Fabric;
import static com.integreight.onesheeld.shields.controller.FaceDetectionShield.IS_FACE_ACTIVE;
import static com.integreight.onesheeld.shields.controller.FaceDetectionShield.SEND_EMPTY;
import static com.integreight.onesheeld.shields.controller.FaceDetectionShield.SEND_FACES;
import static com.integreight.onesheeld.shields.controller.FaceDetectionShield.START_DETECTION;
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
            Log.d("ImageTakin", "Done");
            if (bmp != null)
                bmp.recycle();
            // decode with options and set rotation
            bmp = ImageUtils.decodeBitmap(data, bitmapMatrix);

            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
            if (bmp != null && QUALITY_MODE == 0)
                bmp.compress(Bitmap.CompressFormat.JPEG, 70, bytes);
            else if (bmp != null && QUALITY_MODE != 0)
                bmp.compress(Bitmap.CompressFormat.JPEG, QUALITY_MODE, bytes);

            File imagesFolder = new File(
                    Environment.getExternalStorageDirectory(), "OneSheeld");
            if (!imagesFolder.exists())
                imagesFolder.mkdirs(); // <----
            File image = new File(imagesFolder, System.currentTimeMillis()
                    + ".jpg");

            // write the bytes in file
            try {
                fo = new FileOutputStream(image);
            } catch (FileNotFoundException e) {
                Log.e("TAG", "FileNotFoundException", e);
                // TODO Auto-generated catch block
            }
            try {
                fo.write(bytes.toByteArray());
            } catch (IOException e) {
                Log.e("TAG", "fo.write::PictureTaken", e);
                // TODO Auto-generated catch block
            }
            // remember close de FileOutput
            try {
                fo.close();
                if (Build.VERSION.SDK_INT < 19)
                    sendBroadcast(new Intent(
                            Intent.ACTION_MEDIA_MOUNTED,
                            Uri.parse("file://"
                                    + Environment.getExternalStorageDirectory())));
                else {
                    MediaScannerConnection
                            .scanFile(
                                    getApplicationContext(),
                                    new String[]{image.toString()},
                                    null,
                                    new MediaScannerConnection.OnScanCompletedListener() {
                                        public void onScanCompleted(
                                                String path, Uri uri) {
                                            Log.i("ExternalStorage", "Scanned "
                                                    + path + ":");
                                            Log.i("ExternalStorage", "-> uri="
                                                    + uri);
                                        }
                                    });
                }

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            com.integreight.onesheeld.utils.Log.d("Camera", "Image Taken !");
            if (bmp != null) {
                bmp.recycle();
                bmp = null;
                System.gc();
            }
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(),
                            R.string.camera_your_picture_has_been_taken_toast, Toast.LENGTH_SHORT)
                            .show();
                }
            });
            resetPreview();
            takenSuccessfully = true;
            updateLastImage(image.getAbsolutePath());
            notifyFinished();
            return;
        }
    };

    Detector.Processor<Face> detectionProcessor = new Detector.Processor<Face>() {
        @Override
        public void release() {
        }

        @Override
        public void receiveDetections(Detector.Detections<Face> detectionResults) {
            if (graphicsList == null)
                graphicsList = new ArrayList<>();
            ArrayList<FaceDetectionObj> faceDetectionObjArrayList = new ArrayList<>();
            for (int i = 0; i < detectionResults.getDetectedItems().size(); i++) {
                android.util.Log.d(TAG, "receiveDetections: " + detectionResults.getDetectedItems().valueAt(i).getId());
                faceDetectionObjArrayList.add(new FaceDetectionObj(detectionResults.getDetectedItems().valueAt(i)));
                boolean isFound = false;
                for (int j = 0; j < graphicsList.size(); j++)
                    if (detectionResults.getDetectedItems().valueAt(i).getId() == ((FaceGraphic) graphicsList.get(j)).getId()) {
                        isFound = true;
                        mFaceGraphic.updateFace(detectionResults.getDetectedItems().valueAt(i));
                        graphicsList.remove(j);
                        break;
                    }
                if (isFound) {
                    ((FaceGraphic) mGraphicOverlay.get(i)).updateFace(detectionResults.getDetectedItems().valueAt(i));
                } else {
                    mFaceGraphic = new FaceGraphic(mGraphicOverlay);
                    mFaceGraphic.setCameraInfo(previewWidth, previewHeight, isBackPreview, faceRotation);
                    mFaceGraphic.setId(detectionResults.getDetectedItems().valueAt(i).getId());
                    mGraphicOverlay.add(mFaceGraphic);
                    mFaceGraphic.updateFace(detectionResults.getDetectedItems().valueAt(i));
                }

            }
            if (detectionResults.getDetectedItems().size() > 0) {
                Message msg = Message.obtain(null, SEND_FACES);