/**
   * Copy the required binaries and libraries to the data folder
   *
   * @return
   */
  private boolean copyBinaries() {
    try {
      String files[] = {
        "autooptimiser",
        "pto_gen",
        "cpfind",
        "multiblend",
        "enfuse",
        "nona",
        "pano_modify",
        "ptclean",
        "tiffinfo",
        "align_image_stack",
        "pto_var",
        "libexiv2.so",
        "libglib-2.0.so",
        "libgmodule-2.0.so",
        "libgobject-2.0.so",
        "libgthread-2.0.so",
        "libjpeg.so",
        "libpano13.so",
        "libtiff.so",
        "libtiffdecoder.so",
        "libvigraimpex.so"
      };

      final AssetManager am = mContext.getAssets();

      for (String file : files) {
        InputStream is = am.open("picsphere/" + file);

        // Create the output file
        File dir = mContext.getFilesDir();
        File outFile = new File(dir, file);

        if (outFile.exists()) outFile.delete();

        OutputStream os = new FileOutputStream(outFile);

        // Copy the file
        byte[] buffer = new byte[1024];
        int read;
        while ((read = is.read(buffer)) != -1) {
          os.write(buffer, 0, read);
        }

        if (!outFile.getName().endsWith(".so") && !outFile.setExecutable(true)) {
          return false;
        }

        os.flush();
        os.close();
        is.close();
      }
    } catch (Exception e) {
      Log.e(TAG, "Error copying libraries and binaries", e);
      return false;
    }
    return true;
  }
 @Override
 public void onStepChange(PicSphere sphere, int newStep) {
   if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PICSPHERE) {
     mContext.setHelperText(
         String.format(
             mContext.getString(R.string.picsphere_rendering_progress),
             sphere.getRenderProgress()));
   }
 }
  /** Returns the 3D renderer context for PicSphere capture mode */
  public Capture3DRenderer getRenderer() {
    if (mCapture3DRenderer == null) {
      // Initialize the 3D renderer
      mCapture3DRenderer = new Capture3DRenderer(mContext, mContext.getCamManager());

      // We route the camera preview to our texture
      mGLRootView = (FrameLayout) mContext.findViewById(R.id.gl_renderer_container);
    }

    return mCapture3DRenderer;
  }
        @Override
        public void onClick(View view) {
          mContext.setExposureRingVisible(!mContext.isExposureRingVisible());
          if (mContext.isExposureRingVisible()) {
            mToggleExposureRing.activeImage(DRAWABLE_KEY_EXPO_RING);
          } else {
            mToggleExposureRing.resetImage();
          }

          SettingsStorage.storeAppSetting(
              mContext, KEY_SHOW_EXPOSURE_RING, mContext.isExposureRingVisible() ? "1" : "0");
        }
  @Override
  public void onRenderDone(PicSphere sphere) {
    mPicSpheres.remove(sphere);

    if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PICSPHERE) {
      mContext.setHelperText(mContext.getString(R.string.picsphere_start_hint));
    }

    if (mCapture3DRenderer != null) {
      mCapture3DRenderer.setCamPreviewVisible(true);
    }
  }
 private void applyVideoResolution(String resolution) {
   if (resolution.equals("1920x1080")) {
     mContext
         .getSnapManager()
         .setVideoProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_1080P));
   } else if (resolution.equals("1280x720")) {
     mContext
         .getSnapManager()
         .setVideoProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P));
   } else if (resolution.equals("720x480")) {
     mContext
         .getSnapManager()
         .setVideoProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
   } else if (resolution.equals("352x288")) {
     mContext.getSnapManager().setVideoProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_CIF));
   }
 }
  @Override
  public boolean isSupported(Camera.Parameters params) {
    int mode = CameraActivity.getCameraMode();

    return (mode == CameraActivity.CAMERA_MODE_PHOTO
        || mode == CameraActivity.CAMERA_MODE_VIDEO
        || mode == CameraActivity.CAMERA_MODE_PICSPHERE);
  }
  /**
   * Starts rendering the provided PicSphere in a thread, and handles a service that will keep on
   * processing even once Nemesis is closed
   *
   * @param sphere The PicSphere to render
   */
  public void startRendering(final PicSphere sphere, final int orientation) {
    // Notify toast
    CameraActivity.notify(mContext.getString(R.string.picsphere_toast_background_render), 2500);

    if (mIsBound && mBoundService != null) {
      sphere.addProgressListener(this);
      mBoundService.render(sphere, orientation);
    } else {
      doBindService();
      mHandler.postDelayed(
          new Runnable() {
            public void run() {
              startRendering(sphere, orientation);
            }
          },
          500);
    }
  }
 void doBindService() {
   // Establish a connection with the service.  We use an explicit
   // class name because we want a specific service implementation that
   // we know will be running in our own process (and thus won't be
   // supporting component replacement by other applications).
   Log.v(TAG, "Binding PicSphere rendering service");
   mContext.bindService(
       new Intent(mContext, PicSphereRenderingService.class),
       mServiceConnection,
       Context.BIND_AUTO_CREATE);
   mIsBound = true;
 }
  public void tearDown() {
    if (mCapture3DRenderer != null) {
      mCapture3DRenderer.onPause();
      mCapture3DRenderer = null;
    }

    mPicSpheres.clear();

    if (mIsBound) {
      // Detach our existing connection.
      mContext.unbindService(mServiceConnection);
      mIsBound = false;
    }
  }
        @Override
        public void onClick(View view) {
          SnapshotManager snapMan = mContext.getSnapManager();
          snapMan.setAutoEnhance(!snapMan.getAutoEnhance());

          if (snapMan.getAutoEnhance()) {
            mToggleAutoEnhancer.activeImage(DRAWABLE_KEY_AUTO_ENHANCE);
          } else {
            mToggleAutoEnhancer.resetImage();
          }

          SettingsStorage.storeAppSetting(
              mContext, KEY_ENABLE_AUTO_ENHANCE, snapMan.getAutoEnhance() ? "1" : "0");
        }
        @Override
        public void onClick(View view) {
          View rot = mContext.findViewById(R.id.rule_of_thirds);

          if (rot.getVisibility() == View.GONE) {
            mToggleRuleOfThirds.activeImage(DRAWABLE_KEY_RULE_OF_THIRDS);
            rot.setVisibility(View.VISIBLE);
          } else {
            mToggleRuleOfThirds.resetImage();
            rot.setVisibility(View.GONE);
          }

          SettingsStorage.storeAppSetting(
              mContext, KEY_ENABLE_RULE_OF_THIRDS, rot.getVisibility() == View.GONE ? "0" : "1");
        }
  /** Check the capabilities of the device, and populate the sidebar with the toggle buttons. */
  public void checkCapabilities(CameraActivity activity, ViewGroup widgetsContainer) {
    mToggleContainer = (ViewGroup) this.getChildAt(0);

    if (mCapabilities != null) {
      mToggleContainer.removeAllViews();
      mCapabilities = null;
    }

    mCapabilities = new CameraCapabilities(activity);
    Camera.Parameters params = activity.getCamManager().getParameters();

    if (params != null) {
      mCapabilities.populateSidebar(params, mToggleContainer, widgetsContainer);
    } else {
      Log.e(TAG, "Parameters were null when capabilities were checked");
    }
  }
  public SettingsWidget(CameraActivity context, CameraCapabilities capabilities) {
    super(context.getCamManager(), context, R.drawable.ic_widget_settings);
    mContext = context;
    mCapabilities = capabilities;

    CameraManager cam = context.getCamManager();

    getToggleButton().setHintText(R.string.widget_settings);

    if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PHOTO
        || CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PICSPHERE) {
      // Get the available photo size. Unlike AOSP app, we don't
      // store manually each resolution in an XML, but we calculate it directly
      // from the width and height of the picture size.
      mResolutions = cam.getParameters().getSupportedPictureSizes();
      mResolutionsName = new ArrayList<String>();

      DecimalFormat df = new DecimalFormat();
      df.setMaximumFractionDigits(1);
      df.setMinimumFractionDigits(0);
      df.setDecimalSeparatorAlwaysShown(false);

      Collections.sort(mResolutions, mResolutionsSorter);

      for (Camera.Size size : mResolutions) {
        float megapixels = size.width * size.height / 1000000.0f;
        mResolutionsName.add(df.format(megapixels) + "MP (" + size.width + "x" + size.height + ")");
      }

      // Restore picture size if we have any
      String resolution = "";
      if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PHOTO) {
        resolution =
            SettingsStorage.getCameraSetting(
                context,
                mCamManager.getCurrentFacing(),
                "picture-size",
                "" + mResolutions.get(0).width + "x" + mResolutions.get(0).height);
      } else {
        resolution =
            SettingsStorage.getCameraSetting(
                context, mCamManager.getCurrentFacing(), "picsphere-picture-size", "640x480");
      }
      mCamManager.setPictureSize(resolution);
    } else if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_VIDEO) {
      mResolutions = cam.getParameters().getSupportedVideoSizes();
      mResolutionsName = new ArrayList<String>();
      mVideoResolutions = new ArrayList<String>();

      if (mResolutions != null) {
        // We support a fixed set of video resolutions (pretty much like AOSP)
        // because we need to take the CamcorderProfile (media_profiles.xml), which
        // has a fixed set of values...
        for (Camera.Size size : mResolutions) {
          if (size.width == 1920 && size.height == 1080
              || size.width == 1920 && size.height == 1088) {
            mResolutionsName.add(mContext.getString(R.string.video_res_1080p));
            mVideoResolutions.add("1920x1080");
          } else if (size.width == 1280 && size.height == 720) {
            mResolutionsName.add(mContext.getString(R.string.video_res_720p));
            mVideoResolutions.add("1280x720");
          } else if (size.width == 720 && size.height == 480) {
            mResolutionsName.add(mContext.getString(R.string.video_res_480p));
            mVideoResolutions.add("720x480");
          } else if (size.width == 352 && size.height == 288) {
            mResolutionsName.add(mContext.getString(R.string.video_res_mms));
            mVideoResolutions.add("352x288");
          }
        }
      } else if (mResolutions == null || mResolutions.size() == 0) {
        // We detected no compatible video resolution! We add default ones.
        mResolutionsName.add(mContext.getString(R.string.video_res_1080p));
        mVideoResolutions.add("1920x1080");
        mResolutionsName.add(mContext.getString(R.string.video_res_720p));
        mVideoResolutions.add("1280x720");
        mResolutionsName.add(mContext.getString(R.string.video_res_480p));
        mVideoResolutions.add("720x480");
      }

      // TODO: Restore video size if we have any
      String resolution =
          SettingsStorage.getCameraSetting(
              context, mCamManager.getCurrentFacing(), "video-size", mVideoResolutions.get(0));
      applyVideoResolution(resolution);
    }

    mResolutionButton = new WidgetOptionButton(R.drawable.ic_widget_settings_resolution, context);
    mResolutionButton.setOnClickListener(mResolutionClickListener);
    mResolutionButton.setHintText(mContext.getString(R.string.widget_settings_picture_size));
    addViewToContainer(mResolutionButton);

    if (mCamManager.isExposureAreaSupported()
        && CameraActivity.getCameraMode() != CameraActivity.CAMERA_MODE_PICSPHERE) {
      mToggleExposureRing =
          new WidgetOptionButton(R.drawable.ic_widget_settings_exposurering, context);
      mToggleExposureRing.setHintText(mContext.getString(R.string.widget_settings_exposure_ring));
      mToggleExposureRing.setOnClickListener(mExpoRingClickListener);

      // Restore exposure ring state
      if (SettingsStorage.getAppSetting(mContext, KEY_SHOW_EXPOSURE_RING, "0").equals("1")) {
        mContext.setExposureRingVisible(true);
        mToggleExposureRing.activeImage(DRAWABLE_KEY_EXPO_RING);
      } else {
        mContext.setExposureRingVisible(false);
      }
      addViewToContainer(mToggleExposureRing);
    }

    // Toggle auto enhancer
    if (CameraActivity.getCameraMode() != CameraActivity.CAMERA_MODE_PICSPHERE) {
      mToggleAutoEnhancer = new WidgetOptionButton(R.drawable.ic_enhancing, context);
      mToggleAutoEnhancer.setOnClickListener(mAutoEnhanceClickListener);
      mToggleAutoEnhancer.setHintText(mContext.getString(R.string.widget_settings_autoenhance));

      // Restore auto enhancer state
      if (SettingsStorage.getAppSetting(mContext, KEY_ENABLE_AUTO_ENHANCE, "0").equals("1")) {
        mContext.getSnapManager().setAutoEnhance(true);
        mToggleAutoEnhancer.activeImage(DRAWABLE_KEY_AUTO_ENHANCE);
      } else {
        if (mContext.getSnapManager() != null) {
          mContext.getSnapManager().setAutoEnhance(false);
        }
      }

      addViewToContainer(mToggleAutoEnhancer);

      // Toggle rule of thirds
      mToggleRuleOfThirds =
          new WidgetOptionButton(R.drawable.ic_widget_settings_rulethirds, context);
      mToggleRuleOfThirds.setOnClickListener(mRuleOfThirdsClickListener);
      mToggleRuleOfThirds.setHintText(mContext.getString(R.string.widget_settings_ruleofthirds));

      // Restore rule of thirds visibility state
      if (SettingsStorage.getAppSetting(mContext, KEY_ENABLE_RULE_OF_THIRDS, "0").equals("1")) {
        mContext.findViewById(R.id.rule_of_thirds).setVisibility(View.VISIBLE);
        mToggleRuleOfThirds.activeImage(KEY_ENABLE_RULE_OF_THIRDS);
      } else {
        mContext.findViewById(R.id.rule_of_thirds).setVisibility(View.GONE);
        mToggleRuleOfThirds.resetImage();
      }

      addViewToContainer(mToggleRuleOfThirds);
    }

    // Choose widgets to appear
    mToggleWidgetsButton = new WidgetOptionButton(R.drawable.ic_widget_settings_widgets, context);
    mToggleWidgetsButton.setHintText(
        mContext.getString(R.string.widget_settings_choose_widgets_button));
    mToggleWidgetsButton.setOnClickListener(
        new View.OnClickListener() {
          @Override
          public void onClick(View view) {
            openWidgetsToggleDialog();
          }
        });
    addViewToContainer(mToggleWidgetsButton);
  }
  private void openWidgetsToggleDialog() {
    final List<WidgetBase> widgets = mCapabilities.getWidgets();
    List<String> widgetsName = new ArrayList<String>();

    // Construct a list of widgets
    for (WidgetBase widget : widgets) {
      if (widget.getClass().getName().contains("SettingsWidget")) continue;
      widgetsName.add(widget.getToggleButton().getHintText());
    }

    CharSequence[] items = widgetsName.toArray(new CharSequence[widgetsName.size()]);

    AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
    builder.setTitle(mContext.getString(R.string.widget_settings_choose_widgets));
    builder
        .setMultiChoiceItems(
            items,
            null,
            new DialogInterface.OnMultiChoiceClickListener() {
              // indexSelected contains the index of item (of which checkbox checked)
              @Override
              public void onClick(DialogInterface dialog, int indexSelected, boolean isChecked) {
                widgets.get(indexSelected).setHidden(!isChecked);
              }
            })
        // Set the action buttons
        .setPositiveButton(
            "OK",
            new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int id) {
                // Store the widget visibility status in SharedPreferences, using the
                // widget class name as key
                for (WidgetBase widget : widgets) {
                  if (widget.getClass().getName().contains("SettingsWidget")) {
                    continue;
                  }

                  SettingsStorage.storeVisibilitySetting(
                      mContext, widget.getClass().getName(), !widget.isHidden());
                }
              }
            })
        .setNegativeButton(
            "Cancel",
            new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int id) {
                // Restore visibility status from storage
                for (WidgetBase widget : widgets) {
                  if (widget.getClass().getName().contains("SettingsWidget")) {
                    continue;
                  }

                  widget.setHidden(
                      !SettingsStorage.getVisibilitySetting(mContext, widget.getClass().getName()));
                }
              }
            });

    mWidgetsDialog = builder.create();
    mWidgetsDialog.show();
    for (int i = 0; i < widgets.size(); i++) {
      mWidgetsDialog.getListView().setItemChecked(i, !widgets.get(i).isHidden());
    }
    ((ViewGroup) mWidgetsDialog.getListView().getParent().getParent().getParent())
        .animate()
        .rotation(mOrientation)
        .setDuration(300)
        .start();
  }
 private String getActualProfileResolution() {
   CamcorderProfile actualProfile = mContext.getSnapManager().getVideoProfile();
   return "" + actualProfile.videoFrameWidth + "x" + actualProfile.videoFrameHeight;
 }
        @Override
        public void onClick(View view) {
          mInitialOrientation = -1;

          mNumberPicker = new NumberPicker(mContext);
          String[] names = new String[mResolutionsName.size()];
          mResolutionsName.toArray(names);
          if (names.length > 0) {
            mNumberPicker.setDisplayedValues(names);

            mNumberPicker.setMinValue(0);
            mNumberPicker.setMaxValue(names.length - 1);
          } else {
            mNumberPicker.setMinValue(0);
            mNumberPicker.setMaxValue(0);
          }
          mNumberPicker.setWrapSelectorWheel(false);
          mNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
          mNumberPicker.setFormatter(
              new NumberPicker.Formatter() {
                @Override
                public String format(int i) {
                  return mResolutionsName.get(i);
                }
              });

          if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_VIDEO) {
            // TODO set correct menu selection also for video
            String actualSz = getActualProfileResolution();
            if (mVideoResolutions != null) {
              for (int i = 0; i < mVideoResolutions.size(); i++) {
                if (mVideoResolutions.get(i).equals(actualSz)) {
                  mNumberPicker.setValue(i);
                  break;
                }
              }
            }
          } else {
            Camera.Size actualSz = mCamManager.getParameters().getPictureSize();
            if (mResolutions != null) {
              for (int i = 0; i < mResolutions.size(); i++) {
                if (mResolutions.get(i).equals(actualSz)) {
                  mNumberPicker.setValue(i);
                  break;
                }
              }
            }
          }

          AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
          builder.setView(mNumberPicker);
          builder.setTitle(null);
          builder.setCancelable(false);
          builder.setPositiveButton(
              mContext.getString(R.string.ok),
              new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                  mInitialOrientation = -1;

                  if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PHOTO
                      || CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PICSPHERE) {
                    // Set picture size
                    Camera.Size size = mResolutions.get(mNumberPicker.getValue());
                    // TODO: only one method
                    mCamManager.setPictureSize("" + size.width + "x" + size.height);

                    if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_PHOTO) {
                      SettingsStorage.storeCameraSetting(
                          mContext,
                          mCamManager.getCurrentFacing(),
                          "picture-size",
                          "" + size.width + "x" + size.height);
                    } else {
                      SettingsStorage.storeCameraSetting(
                          mContext,
                          mCamManager.getCurrentFacing(),
                          "picsphere-picture-size",
                          "" + size.width + "x" + size.height);
                    }
                  } else if (CameraActivity.getCameraMode() == CameraActivity.CAMERA_MODE_VIDEO) {
                    // Set video size
                    String size = mVideoResolutions.get(mNumberPicker.getValue());
                    applyVideoResolution(size);

                    String[] splat = size.split("x");
                    int width = Integer.parseInt(splat[0]);
                    int height = Integer.parseInt(splat[1]);

                    SettingsStorage.storeCameraSetting(
                        mContext,
                        mCamManager.getCurrentFacing(),
                        "video-size",
                        "" + width + "x" + height);
                  }
                }
              });

          mResolutionDialog = builder.create();
          mResolutionDialog.show();
          ((ViewGroup) mNumberPicker.getParent().getParent().getParent())
              .animate()
              .rotation(mOrientation)
              .setDuration(300)
              .start();
        }