@Override
  public boolean handleMessage(Message msg) {
    switch (msg.what) {
      case MSG_END_OF_LOADING:
        setupSaveButton();
        postProcessingRun = true;
        break;
      case MSG_LEAVING:
        MainScreen.H.sendEmptyMessage(PluginManager.MSG_POSTPROCESSING_FINISHED);
        mJpegBufferList.clear();

        Message msg2 = new Message();
        msg2.arg1 = PluginManager.MSG_CONTROL_UNLOCKED;
        msg2.what = PluginManager.MSG_BROADCAST;
        MainScreen.H.sendMessage(msg2);

        MainScreen.guiManager.lockControls = false;

        postProcessingRun = false;
        return false;

      case MSG_REDRAW:
        if (PreviewBmp != null) PreviewBmp.recycle();
        if (finishing == true) return true;
        PreviewBmp = mAlmaCLRShot.getPreviewBitmap();
        if (PreviewBmp != null) {
          Matrix matrix = new Matrix();
          matrix.postRotate(90);
          Bitmap rotated =
              Bitmap.createBitmap(
                  PreviewBmp, 0, 0, PreviewBmp.getWidth(), PreviewBmp.getHeight(), matrix, true);
          mImgView.setImageBitmap(rotated);
          mImgView.setRotation(
              MainScreen.getCameraMirrored()
                  ? ((mDisplayOrientation == 0 || mDisplayOrientation == 180) ? 0 : 180)
                  : 0);
        }

        sequenceView.setEnabled(true);
        break;
    }
    return true;
  }
  @Override
  public boolean onBroadcast(int arg1, int arg2) {
    if (arg1 == PluginManager.MSG_NEXT_FRAME) {
      Camera camera = MainScreen.thiz.getCamera();
      if (camera != null) {
        // play tick sound
        MainScreen.guiManager.showCaptureIndication();
        MainScreen.thiz.PlayShutter();

        try {
          camera.setPreviewCallback(null);
          camera.takePicture(null, null, null, MainScreen.thiz);
        } catch (Exception e) {
          e.printStackTrace();
          Log.e("MainScreen takePicture() failed", "takePicture: " + e.getMessage());
          inCapture = false;
          takingAlready = false;
          Message msg = new Message();
          msg.arg1 = PluginManager.MSG_CONTROL_UNLOCKED;
          msg.what = PluginManager.MSG_BROADCAST;
          MainScreen.H.sendMessage(msg);
          MainScreen.guiManager.lockControls = false;
        }
      } else {
        inCapture = false;
        takingAlready = false;
        Message msg = new Message();
        msg.arg1 = PluginManager.MSG_CONTROL_UNLOCKED;
        msg.what = PluginManager.MSG_BROADCAST;
        MainScreen.H.sendMessage(msg);

        MainScreen.guiManager.lockControls = false;
      }
      return true;
    }
    return false;
  }
  @Override
  public void onStartProcessing(long SessionID) {
    finishing = false;
    Message msg = new Message();
    msg.what = PluginManager.MSG_PROCESSING_BLOCK_UI;
    MainScreen.H.sendMessage(msg);

    Message msg2 = new Message();
    msg2.arg1 = PluginManager.MSG_CONTROL_LOCKED;
    msg2.what = PluginManager.MSG_BROADCAST;
    MainScreen.H.sendMessage(msg2);

    MainScreen.guiManager.lockControls = true;

    sessionID = SessionID;

    PluginManager.getInstance()
        .addToSharedMem(
            "modeSaveName" + Long.toString(sessionID),
            PluginManager.getInstance().getActiveMode().modeSaveName);

    mDisplayOrientation = MainScreen.guiManager.getDisplayOrientation();
    int orientation = MainScreen.guiManager.getLayoutOrientation();
    mLayoutOrientationCurrent =
        (orientation == 0 || orientation == 180) ? orientation : (orientation + 180) % 360;
    mCameraMirrored = MainScreen.getCameraMirrored();

    if (mDisplayOrientation == 0 || mDisplayOrientation == 180) {
      imgWidthOR = MainScreen.getImageHeight();
      imgHeightOR = MainScreen.getImageWidth();
    } else {
      imgWidthOR = MainScreen.getImageWidth();
      imgHeightOR = MainScreen.getImageHeight();
    }

    int iSaveImageWidth = MainScreen.getSaveImageWidth();
    int iSaveImageHeight = MainScreen.getSaveImageHeight();

    mAlmaCLRShot = AlmaCLRShot.getInstance();

    getPrefs();

    try {
      Size input = new Size(MainScreen.getImageWidth(), MainScreen.getImageHeight());
      int imagesAmount =
          Integer.parseInt(
              PluginManager.getInstance()
                  .getFromSharedMem("amountofcapturedframes" + Long.toString(sessionID)));
      ArrayList<byte[]> compressed_frame = new ArrayList<byte[]>();
      int minSize = 1000;
      if (mMinSize == 0) {
        minSize = 0;
      } else {
        minSize = input.getWidth() * input.getHeight() / mMinSize;
      }

      if (imagesAmount == 0) imagesAmount = 1;

      thumbnails.clear();
      for (int i = 1; i <= imagesAmount; i++) {
        byte[] in =
            SwapHeap.CopyFromHeap(
                Integer.parseInt(
                    PluginManager.getInstance()
                        .getFromSharedMem("frame" + i + Long.toString(sessionID))),
                Integer.parseInt(
                    PluginManager.getInstance()
                        .getFromSharedMem("framelen" + i + Long.toString(sessionID))));

        compressed_frame.add(i - 1, in);

        BitmapFactory.Options opts = new BitmapFactory.Options();
        thumbnails.add(
            Bitmap.createScaledBitmap(
                BitmapFactory.decodeByteArray(in, 0, in.length, opts),
                MainScreen.thiz.getResources().getDisplayMetrics().heightPixels / imagesAmount,
                (int)
                    (opts.outHeight
                        * (((float) MainScreen.thiz.getResources().getDisplayMetrics().heightPixels
                                / imagesAmount)
                            / opts.outWidth)),
                false));
      }

      mJpegBufferList = compressed_frame;
      getDisplaySize(mJpegBufferList.get(0));
      Size preview = new Size(mDisplayWidth, mDisplayHeight);

      if (SaveInputPreference) {
        try {
          File saveDir = PluginManager.getInstance().GetSaveDir(false);

          SharedPreferences prefs =
              PreferenceManager.getDefaultSharedPreferences(MainScreen.mainContext);
          int saveOption = Integer.parseInt(prefs.getString("exportName", "3"));
          Calendar d = Calendar.getInstance();
          String fileFormat =
              String.format(
                  "%04d%02d%02d_%02d%02d%02d",
                  d.get(Calendar.YEAR),
                  d.get(Calendar.MONTH) + 1,
                  d.get(Calendar.DAY_OF_MONTH),
                  d.get(Calendar.HOUR_OF_DAY),
                  d.get(Calendar.MINUTE),
                  d.get(Calendar.SECOND));
          switch (saveOption) {
            case 1: // YEARMMDD_HHMMSS
              break;

            case 2: // YEARMMDD_HHMMSS_MODE
              fileFormat += "_" + PluginManager.getInstance().getActiveMode().modeSaveName;
              break;

            case 3: // IMG_YEARMMDD_HHMMSS
              fileFormat = "IMG_" + fileFormat;
              break;

            case 4: // IMG_YEARMMDD_HHMMSS_MODE
              fileFormat =
                  "IMG_"
                      + fileFormat
                      + "_"
                      + PluginManager.getInstance().getActiveMode().modeSaveName;
              break;
          }

          ContentValues values = null;

          for (int i = 0; i < imagesAmount; ++i) {

            String index = String.format("_%02d", i);
            File file = new File(saveDir, fileFormat + index + ".jpg");

            FileOutputStream os = null;
            try {
              os = new FileOutputStream(file);
            } catch (Exception e) {
              // save always if not working saving to sdcard
              e.printStackTrace();
              saveDir = PluginManager.getInstance().GetSaveDir(true);
              file = new File(saveDir, fileFormat + index + ".jpg");
              os = new FileOutputStream(file);
            }

            String resultOrientation =
                PluginManager.getInstance()
                    .getFromSharedMem("frameorientation" + (i + 1) + Long.toString(sessionID));
            Boolean orientationLandscape = false;
            if (resultOrientation == null) orientationLandscape = true;
            else orientationLandscape = Boolean.parseBoolean(resultOrientation);

            String resultMirrored =
                PluginManager.getInstance()
                    .getFromSharedMem("framemirrored" + (i + 1) + Long.toString(sessionID));
            Boolean cameraMirrored = false;
            if (resultMirrored != null) cameraMirrored = Boolean.parseBoolean(resultMirrored);

            if (os != null) {
              // ToDo: not enough memory error reporting
              os.write(compressed_frame.get(i));
              os.close();

              ExifInterface ei = new ExifInterface(file.getAbsolutePath());
              int exif_orientation = ExifInterface.ORIENTATION_NORMAL;
              switch (mDisplayOrientation) {
                default:
                case 0:
                  exif_orientation =
                      ExifInterface
                          .ORIENTATION_NORMAL; // cameraMirrored ?
                                               // ExifInterface.ORIENTATION_ROTATE_180 :
                                               // ExifInterface.ORIENTATION_NORMAL;
                  break;
                case 90:
                  exif_orientation =
                      cameraMirrored
                          ? ExifInterface.ORIENTATION_ROTATE_270
                          : ExifInterface.ORIENTATION_ROTATE_90;
                  break;
                case 180:
                  exif_orientation =
                      ExifInterface
                          .ORIENTATION_ROTATE_180; // cameraMirrored ?
                                                   // ExifInterface.ORIENTATION_NORMAL :
                                                   // ExifInterface.ORIENTATION_ROTATE_180;
                  break;
                case 270:
                  exif_orientation =
                      cameraMirrored
                          ? ExifInterface.ORIENTATION_ROTATE_90
                          : ExifInterface.ORIENTATION_ROTATE_270;
                  break;
              }
              ei.setAttribute(ExifInterface.TAG_ORIENTATION, "" + exif_orientation);
              ei.saveAttributes();
            }

            String dateString = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss").format(new Date());
            values = new ContentValues(9);
            values.put(
                ImageColumns.TITLE, file.getName().substring(0, file.getName().lastIndexOf(".")));
            values.put(ImageColumns.DISPLAY_NAME, file.getName());
            values.put(ImageColumns.DATE_TAKEN, System.currentTimeMillis());
            values.put(ImageColumns.MIME_TYPE, "image/jpeg");
            values.put(
                ImageColumns.ORIENTATION,
                (!orientationLandscape && !cameraMirrored)
                    ? 90
                    : (!orientationLandscape && cameraMirrored) ? -90 : 0);
            values.put(ImageColumns.DATA, file.getAbsolutePath());

            if (prefs.getBoolean("useGeoTaggingPrefExport", false)) {
              Location l = MLocation.getLocation(MainScreen.mainContext);

              if (l != null) {
                //    			            	Exiv2.writeGeoDataIntoImage(
                //    			            		file.getAbsolutePath(),
                //    			            		true,
                //    			            		l.getLatitude(),
                //    			            		l.getLongitude(),
                //    			            		dateString,
                //    			            		android.os.Build.MANUFACTURER != null ?
                // android.os.Build.MANUFACTURER : "Google",
                //    			            		android.os.Build.MODEL != null ? android.os.Build.MODEL :
                // "Android device");

                ExifInterface ei = new ExifInterface(file.getAbsolutePath());
                ei.setAttribute(
                    ExifInterface.TAG_GPS_LATITUDE, GPSTagsConverter.convert(l.getLatitude()));
                ei.setAttribute(
                    ExifInterface.TAG_GPS_LATITUDE_REF,
                    GPSTagsConverter.latitudeRef(l.getLatitude()));
                ei.setAttribute(
                    ExifInterface.TAG_GPS_LONGITUDE, GPSTagsConverter.convert(l.getLongitude()));
                ei.setAttribute(
                    ExifInterface.TAG_GPS_LONGITUDE_REF,
                    GPSTagsConverter.longitudeRef(l.getLongitude()));

                ei.saveAttributes();

                values.put(ImageColumns.LATITUDE, l.getLatitude());
                values.put(ImageColumns.LONGITUDE, l.getLongitude());
              }
            }

            MainScreen.thiz.getContentResolver().insert(Images.Media.EXTERNAL_CONTENT_URI, values);
          }
        } catch (IOException e) {
          e.printStackTrace();
          MainScreen.H.sendEmptyMessage(PluginManager.MSG_EXPORT_FINISHED_IOEXCEPTION);
          return;
        } catch (Exception e) {
          // Toast.makeText(MainScreen.mainContext, "Low memory. Can't finish processing.",
          // Toast.LENGTH_LONG).show();
          e.printStackTrace();
        }
      }

      PluginManager.getInstance()
          .addToSharedMem(
              "amountofresultframes" + Long.toString(sessionID), String.valueOf(imagesAmount));

      PluginManager.getInstance()
          .addToSharedMem(
              "saveImageWidth" + String.valueOf(sessionID), String.valueOf(iSaveImageWidth));
      PluginManager.getInstance()
          .addToSharedMem(
              "saveImageHeight" + String.valueOf(sessionID), String.valueOf(iSaveImageHeight));

      this.indexes = new int[imagesAmount];
      for (int i = 0; i < imagesAmount; i++) {
        this.indexes[i] = i;
      }

      // frames!!! should be taken from heap
      mAlmaCLRShot.addInputFrame(compressed_frame, input);

      mAlmaCLRShot.initialize(
          preview,
          mAngle,
          /*
           * sensitivity for objection detection
           *
           */
          mSensitivity - 15,
          /*
           *  Minimum size of object to be able to detect
           *  -15 ~ 15
           *  max -> easy detection dull detection
           *  min ->
           */
          minSize,
          /*
           * ghosting parameter
           * 0 : normal operation
           * 1 : detect ghosted objects but not remove them
           * 2 : detect and remove all object
           */
          Integer.parseInt(mGhosting),
          indexes);
      compressed_frame.clear();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  @Override
  public void onPictureTaken(byte[] paramArrayOfByte, Camera paramCamera) {
    imagesTaken++;
    int frame_len = paramArrayOfByte.length;
    int frame = SwapHeap.SwapToHeap(paramArrayOfByte);

    if (frame == 0) {
      Log.i("Burst", "Load to heap failed");
      Message message = new Message();
      message.obj = String.valueOf(SessionID);
      message.what = PluginManager.MSG_CAPTURE_FINISHED;
      MainScreen.H.sendMessage(message);

      imagesTaken = 0;
      MainScreen.thiz.MuteShutter(false);
      inCapture = false;
      return;
    }
    String frameName = "frame" + imagesTaken;
    String frameLengthName = "framelen" + imagesTaken;

    PluginManager.getInstance()
        .addToSharedMem(frameName + String.valueOf(SessionID), String.valueOf(frame));
    PluginManager.getInstance()
        .addToSharedMem(frameLengthName + String.valueOf(SessionID), String.valueOf(frame_len));
    PluginManager.getInstance()
        .addToSharedMem(
            "frameorientation" + imagesTaken + String.valueOf(SessionID),
            String.valueOf(MainScreen.guiManager.getDisplayOrientation()));
    PluginManager.getInstance()
        .addToSharedMem(
            "framemirrored" + imagesTaken + String.valueOf(SessionID),
            String.valueOf(MainScreen.getCameraMirrored()));

    if (imagesTaken == 1)
      PluginManager.getInstance().addToSharedMem_ExifTagsFromJPEG(paramArrayOfByte, SessionID);

    try {
      paramCamera.startPreview();
    } catch (RuntimeException e) {
      Log.i("Burst", "StartPreview fail");
      Message message = new Message();
      message.obj = String.valueOf(SessionID);
      message.what = PluginManager.MSG_CAPTURE_FINISHED;
      MainScreen.H.sendMessage(message);

      imagesTaken = 0;
      MainScreen.thiz.MuteShutter(false);
      inCapture = false;
      return;
    }
    if (imagesTaken < imageAmount) MainScreen.H.sendEmptyMessage(PluginManager.MSG_TAKE_PICTURE);
    else {
      PluginManager.getInstance()
          .addToSharedMem(
              "amountofcapturedframes" + String.valueOf(SessionID), String.valueOf(imagesTaken));

      Message message = new Message();
      message.obj = String.valueOf(SessionID);
      message.what = PluginManager.MSG_CAPTURE_FINISHED;
      MainScreen.H.sendMessage(message);

      imagesTaken = 0;
      inCapture = false;
    }
    takingAlready = false;
  }