public void run() {
   mAllImages.removeImageAt(mCurrentPosition);
   if (mAllImages.getCount() == 0) {
     finish();
     return;
   } else {
     if (mCurrentPosition == mAllImages.getCount()) {
       mCurrentPosition -= 1;
     }
   }
   mImageView.clear();
   mCache.clear(); // Because the position number is changed.
   setImage(mCurrentPosition, true);
 }
  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
      case MenuHelper.RESULT_COMMON_MENU_CROP:
        if (resultCode == RESULT_OK) {
          // The CropImage activity passes back the Uri of the
          // cropped image as the Action rather than the Data.
          mSavedUri = Uri.parse(data.getAction());

          // if onStart() runs before, then set the returned
          // image as currentImage.
          if (mAllImages != null) {
            IImage image = mAllImages.getImageForUri(mSavedUri);
            // image could be null if SD card is removed.
            if (image == null) {
              finish();
            } else {
              mCurrentPosition = mAllImages.getImageIndex(image);
              setImage(mCurrentPosition, false);
            }
          }
        }
        break;
    }
  }
 private boolean init(Uri uri) {
   if (uri == null) return false;
   mAllImages =
       (mParam == null)
           ? buildImageListFromUri(uri)
           : ImageManager.makeImageList(getContentResolver(), mParam);
   IImage image = mAllImages.getImageForUri(uri);
   if (image == null) return false;
   mCurrentPosition = mAllImages.getImageIndex(image);
   mLastSlideShowImage = mCurrentPosition;
   return true;
 }
  @Override
  public void onStop() {
    super.onStop();
    mPaused = true;

    // mGetter could be null if we call finish() and leave early in
    // onStart().
    if (mGetter != null) {
      mGetter.cancelCurrent();
      mGetter.stop();
      mGetter = null;
    }
    setMode(MODE_NORMAL);

    // removing all callback in the message queue
    mHandler.removeAllGetterCallbacks();

    if (mAllImages != null) {
      mSavedUri = getCurrentUri();
      mAllImages.close();
      mAllImages = null;
    }

    hideOnScreenControls();
    mImageView.clear();
    mCache.clear();

    for (ImageViewTouchBase iv : mSlideShowImageViews) {
      iv.clear();
    }
  }
  private void showOnScreenControls() {
    if (mPaused) return;
    // If the view has not been attached to the window yet, the
    // zoomButtonControls will not able to show up. So delay it until the
    // view has attached to window.
    if (mActionIconPanel.getWindowToken() == null) {
      mHandler.postGetterCallback(
          new Runnable() {
            public void run() {
              showOnScreenControls();
            }
          });
      return;
    }
    updateNextPrevControls();

    IImage image = mAllImages.getImageAt(mCurrentPosition);
    if (image instanceof VideoObject) {
      mZoomButtonsController.setVisible(false);
    } else {
      updateZoomButtonsEnabled();
      mZoomButtonsController.setVisible(true);
    }

    if (mShowActionIcons && mActionIconPanel.getVisibility() != View.VISIBLE) {
      Animation animation = new AlphaAnimation(0, 1);
      animation.setDuration(500);
      mActionIconPanel.startAnimation(animation);
      mActionIconPanel.setVisibility(View.VISIBLE);
    }
  }
  private void updateNextPrevControls() {
    boolean showPrev = mCurrentPosition > 0;
    boolean showNext = mCurrentPosition < mAllImages.getCount() - 1;

    boolean prevIsVisible = mPrevImageView.getVisibility() == View.VISIBLE;
    boolean nextIsVisible = mNextImageView.getVisibility() == View.VISIBLE;

    if (showPrev && !prevIsVisible) {
      Animation a = mShowPrevImageViewAnimation;
      a.setDuration(500);
      mPrevImageView.startAnimation(a);
      mPrevImageView.setVisibility(View.VISIBLE);
    } else if (!showPrev && prevIsVisible) {
      Animation a = mHidePrevImageViewAnimation;
      a.setDuration(500);
      mPrevImageView.startAnimation(a);
      mPrevImageView.setVisibility(View.GONE);
    }

    if (showNext && !nextIsVisible) {
      Animation a = mShowNextImageViewAnimation;
      a.setDuration(500);
      mNextImageView.startAnimation(a);
      mNextImageView.setVisibility(View.VISIBLE);
    } else if (!showNext && nextIsVisible) {
      Animation a = mHideNextImageViewAnimation;
      a.setDuration(500);
      mNextImageView.startAnimation(a);
      mNextImageView.setVisibility(View.GONE);
    }
  }
 private void moveNextOrPrevious(int delta) {
   int nextImagePos = mCurrentPosition + delta;
   if ((0 <= nextImagePos) && (nextImagePos < mAllImages.getCount())) {
     setImage(nextImagePos, true);
     showOnScreenControls();
   }
 }
  @Override
  public void onStart() {
    super.onStart();
    mPaused = false;

    if (!init(mSavedUri)) {
      Log.w(TAG, "init failed: " + mSavedUri);
      finish();
      return;
    }

    // normally this will never be zero but if one "backs" into this
    // activity after removing the sdcard it could be zero.  in that
    // case just "finish" since there's nothing useful that can happen.
    int count = mAllImages.getCount();
    if (count == 0) {
      finish();
      return;
    } else if (count <= mCurrentPosition) {
      mCurrentPosition = count - 1;
    }

    if (mGetter == null) {
      makeGetter();
    }

    if (mMode == MODE_SLIDESHOW) {
      loadNextImage(mCurrentPosition, 0, true);
    } else { // MODE_NORMAL
      setImage(mCurrentPosition, mShowControls);
      mShowControls = false;
    }
  }
 @Override
 protected void onDestroy() {
   if (mAllImages != null) {
     mAllImages.close();
   }
   super.onDestroy();
 }
  private void generateShuffleOrder() {
    if (mShuffleOrder == null || mShuffleOrder.length != mAllImages.getCount()) {
      mShuffleOrder = new int[mAllImages.getCount()];
      for (int i = 0, n = mShuffleOrder.length; i < n; i++) {
        mShuffleOrder[i] = i;
      }
    }

    for (int i = mShuffleOrder.length - 1; i >= 0; i--) {
      int r = mRandom.nextInt(i + 1);
      if (r != i) {
        int tmp = mShuffleOrder[r];
        mShuffleOrder[r] = mShuffleOrder[i];
        mShuffleOrder[i] = tmp;
      }
    }
  }
 @Override
 public boolean onMenuItemSelected(int featureId, MenuItem item) {
   boolean b = super.onMenuItemSelected(featureId, item);
   if (mImageMenuRunnable != null) {
     mImageMenuRunnable.aboutToCall(item, mAllImages.getImageAt(mCurrentPosition));
   }
   return b;
 }
 private void startPlayVideoActivity() {
   IImage image = mAllImages.getImageAt(mCurrentPosition);
   Intent intent = new Intent(Intent.ACTION_VIEW, image.fullSizeImageUri());
   try {
     startActivity(intent);
   } catch (android.content.ActivityNotFoundException ex) {
     Log.e(TAG, "Couldn't view video " + image.fullSizeImageUri(), ex);
   }
 }
  @Override
  public boolean onPrepareOptionsMenu(Menu menu) {

    super.onPrepareOptionsMenu(menu);
    if (mPaused) return false;

    setMode(MODE_NORMAL);
    IImage image = mAllImages.getImageAt(mCurrentPosition);

    if (mImageMenuRunnable != null) {
      mImageMenuRunnable.gettingReadyToOpen(menu, image);
    }

    Uri uri = mAllImages.getImageAt(mCurrentPosition).fullSizeImageUri();
    MenuHelper.enableShareMenuItem(menu, MenuHelper.isWhiteListUri(uri));

    MenuHelper.enableShowOnMapMenuItem(menu, MenuHelper.hasLatLngData(image));

    return true;
  }
  private void updateActionIcons() {
    if (isPickIntent()) return;

    IImage image = mAllImages.getImageAt(mCurrentPosition);
    View panel = mActionIconPanel;
    if (image instanceof VideoObject) {
      panel.findViewById(R.id.setas).setVisibility(View.GONE);
      panel.findViewById(R.id.play).setVisibility(View.VISIBLE);
    } else {
      panel.findViewById(R.id.setas).setVisibility(View.VISIBLE);
      panel.findViewById(R.id.play).setVisibility(View.GONE);
    }
  }
 public void onClick(View v) {
   switch (v.getId()) {
     case R.id.discard:
       MenuHelper.deletePhoto(this, mDeletePhotoRunnable);
       break;
     case R.id.play:
       startPlayVideoActivity();
       break;
     case R.id.share:
       {
         IImage image = mAllImages.getImageAt(mCurrentPosition);
         if (!MenuHelper.isWhiteListUri(image.fullSizeImageUri())) {
           return;
         }
         startShareMediaActivity(image);
         break;
       }
     case R.id.setas:
       {
         IImage image = mAllImages.getImageAt(mCurrentPosition);
         Intent intent = Util.createSetAsIntent(image);
         try {
           startActivity(Intent.createChooser(intent, getText(R.string.setImage)));
         } catch (android.content.ActivityNotFoundException ex) {
           Toast.makeText(this, R.string.no_way_to_share_video, Toast.LENGTH_SHORT).show();
         }
         break;
       }
     case R.id.next_image:
       moveNextOrPrevious(1);
       break;
     case R.id.prev_image:
       moveNextOrPrevious(-1);
       break;
   }
 }
  void setImage(int pos, boolean showControls) {
    mCurrentPosition = pos;

    Bitmap b = mCache.getBitmap(pos);
    if (b != null) {
      IImage image = mAllImages.getImageAt(pos);
      mImageView.setImageRotateBitmapResetBase(
          new RotateBitmap(b, image.getDegreesRotated()), true);
      updateZoomButtonsEnabled();
    }

    ImageGetterCallback cb =
        new ImageGetterCallback() {
          public void completed() {}

          public boolean wantsThumbnail(int pos, int offset) {
            return !mCache.hasBitmap(pos + offset);
          }

          public boolean wantsFullImage(int pos, int offset) {
            return offset == 0;
          }

          public int fullImageSizeToUse(int pos, int offset) {
            // this number should be bigger so that we can zoom.  we may
            // need to get fancier and read in the fuller size image as the
            // user starts to zoom.
            // Originally the value is set to 480 in order to avoid OOM.
            // Now we set it to 2048 because of using
            // native memory allocation for Bitmaps.
            final int imageViewSize = 2048;
            return imageViewSize;
          }

          public int[] loadOrder() {
            return sOrderAdjacents;
          }

          public void imageLoaded(int pos, int offset, RotateBitmap bitmap, boolean isThumb) {
            // shouldn't get here after onPause()

            // We may get a result from a previous request. Ignore it.
            if (pos != mCurrentPosition) {
              bitmap.recycle();
              return;
            }

            if (isThumb) {
              mCache.put(pos + offset, bitmap.getBitmap());
            }
            if (offset == 0) {
              // isThumb: We always load thumb bitmap first, so we will
              // reset the supp matrix for then thumb bitmap, and keep
              // the supp matrix when the full bitmap is loaded.
              mImageView.setImageRotateBitmapResetBase(bitmap, isThumb);
              updateZoomButtonsEnabled();
            }
          }
        };

    // Could be null if we're stopping a slide show in the course of pausing
    if (mGetter != null) {
      mGetter.setPosition(pos, cb, mAllImages, mHandler);
    }
    updateActionIcons();
    if (showControls) showOnScreenControls();
    scheduleDismissOnScreenControls();
  }
 private Uri getCurrentUri() {
   if (mAllImages.getCount() == 0) return null;
   IImage image = mAllImages.getImageAt(mCurrentPosition);
   if (image == null) return null;
   return image.fullSizeImageUri();
 }
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    mContentResolver = getContentResolver();

    setContentView(getContentViewId());

    mImageView = getCropImageView();

    // Work-around for devices incapable of using hardware-accelerated clipPath.
    // (android.view.GLES20Canvas.clipPath)
    //
    // See also:
    // - https://code.google.com/p/android/issues/detail?id=20474
    // - https://github.com/lvillani/android-cropimage/issues/20
    //
    if (Build.VERSION.SDK_INT > 10
        && Build.VERSION.SDK_INT < 16) { // >= Gingerbread && < Jelly Bean
      mImageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    Intent intent = getIntent();
    Bundle extras = intent.getExtras();

    if (extras != null) {
      if (extras.getBoolean("circleCrop", false)) {
        mCircleCrop = true;
        mAspectX = 1;
        mAspectY = 1;
        mOutputFormat = Bitmap.CompressFormat.PNG;
      }
      mSaveUri = (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT);
      if (mSaveUri != null) {
        String outputFormatString = extras.getString("outputFormat");
        if (outputFormatString != null) {
          mOutputFormat = Bitmap.CompressFormat.valueOf(outputFormatString);
        }
        mOutputQuality = extras.getInt("outputQuality", 100);
      } else {
        mSetWallpaper = extras.getBoolean("setWallpaper");
      }
      mBitmap = (Bitmap) extras.getParcelable("data");
      mAspectX = extras.getInt("aspectX");
      mAspectY = extras.getInt("aspectY");
      mOutputX = extras.getInt("outputX");
      mOutputY = extras.getInt("outputY");
      mOutlineColor = extras.getInt("outlineColor", HighlightView.DEFAULT_OUTLINE_COLOR);
      mOutlineCircleColor =
          extras.getInt("outlineCircleColor", HighlightView.DEFAULT_OUTLINE_CIRCLE_COLOR);
      mScale = extras.getBoolean("scale", true);
      mScaleUp = extras.getBoolean("scaleUpIfNeeded", true);
      mDoFaceDetection =
          extras.containsKey("noFaceDetection") ? !extras.getBoolean("noFaceDetection") : true;
    }

    if (mBitmap == null) {
      Uri target = intent.getData();
      mAllImages =
          ImageManager.makeImageList(mContentResolver, target, ImageManager.SORT_ASCENDING);
      mImage = mAllImages.getImageForUri(target);
      if (mImage != null) {
        // Don't read in really large bitmaps. Use the (big) thumbnail
        // instead.
        // TODO when saving the resulting bitmap use the
        // decode/crop/encode api so we don't lose any resolution.
        mBitmap = mImage.thumbBitmap(IImage.ROTATE_AS_NEEDED);
      }
    }

    if (mBitmap == null) {
      finish();
      return;
    }

    // Make UI fullscreen.
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

    Button discardButton = getDiscardButton();
    if (discardButton != null) {
      discardButton.setOnClickListener(
          new View.OnClickListener() {
            public void onClick(View v) {
              setResult(RESULT_CANCELED);
              finish();
            }
          });
    }

    Button saveButton = getSaveButton();
    if (saveButton != null) {
      saveButton.setOnClickListener(
          new View.OnClickListener() {
            public void onClick(View v) {
              onSaveClicked();
            }
          });
    }

    startFaceDetection();
  }
 @Override
 public void onSaveInstanceState(Bundle b) {
   super.onSaveInstanceState(b);
   b.putParcelable(STATE_URI, mAllImages.getImageAt(mCurrentPosition).fullSizeImageUri());
   b.putBoolean(STATE_SLIDESHOW, mMode == MODE_SLIDESHOW);
 }