public Bitmap fullSizeBitmap( int minSideLength, int maxNumberOfPixels, boolean rotateAsNeeded, boolean useNative) { Uri url = mContainer.contentUri(mId); if (url == null) return null; Bitmap b = Util.makeBitmap(minSideLength, maxNumberOfPixels, url, mContentResolver, useNative); if (b != null && rotateAsNeeded) { b = Util.rotate(b, getDegreesRotated()); } return b; }
public void initialize( Context context, PreferenceGroup group, boolean isZoomSupported, String[] keys, String[] otherSettingKeys) { mShutterButtonRadius = IndicatorControlWheelContainer.SHUTTER_BUTTON_RADIUS; mStrokeWidth = Util.dpToPixel(IndicatorControlWheelContainer.STROKE_WIDTH); mWheelRadius = mShutterButtonRadius + mStrokeWidth * 0.5; setPreferenceGroup(group); // Add the ZoomControl if supported. if (isZoomSupported) { mZoomControl = (ZoomControlWheel) findViewById(R.id.zoom_control); mZoomControl.setVisibility(View.VISIBLE); } // Add CameraPicker. initializeCameraPicker(); // Add second-level Indicator Icon. mSecondLevelIcon = addImageButton(context, R.drawable.ic_settings_holo_light, true); mSecondLevelStartIndex = getChildCount(); // Add second-level buttons. mCloseIcon = addImageButton(context, R.drawable.btn_wheel_close_settings, false); addControls(keys, otherSettingKeys); // The angle(in radians) of each icon for touch events. mChildRadians = new double[getChildCount()]; presetFirstLevelChildRadians(); presetSecondLevelChildRadians(); mInitialized = true; }
@Override public void onOrientationChanged(int orientation) { if (mOrientation != orientation) { mOrientation = orientation; Util.setOrientation(mView, mOrientation, true); } }
private synchronized void handleShow() { if (mView != mNextView) { // remove the old view if necessary handleHide(); mView = mNextView; // / M: we set hint center_horizontal and bottom in xml. // final int gravity = mGravity; // mParams.gravity = gravity; // if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) // == Gravity.FILL_HORIZONTAL) { // mParams.horizontalWeight = 1.0f; // } // if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) // == Gravity.FILL_VERTICAL) { // mParams.verticalWeight = 1.0f; // } // mParams.x = mX; // mParams.y = mY; // mParams.verticalMargin = mVerticalMargin; // mParams.horizontalMargin = mHorizontalMargin; mParams.x = 0; mParams.y = 0; mParams.height = WindowManager.LayoutParams.MATCH_PARENT; mParams.width = WindowManager.LayoutParams.MATCH_PARENT; try { if (mView.getParent() != null) { mWM.removeView(mView); } mWM.addView(mView, mParams); } catch (BadTokenException ex) { ex.printStackTrace(); } Util.fadeIn(mView); } }
public void saveImageToDatabase(RequestOperator r) { Log.i(TAG, "[saveImageToDatabase]..."); // Insert into MediaStore. ContentValues values = new ContentValues(14); values.put(ImageColumns.TITLE, r.mTitle); values.put(ImageColumns.DISPLAY_NAME, r.mFileName); values.put(ImageColumns.DATE_TAKEN, r.mDateTaken); values.put(ImageColumns.MIME_TYPE, r.mMimeType); values.put(ImageColumns.DATA, r.mFilePath); values.put(ImageColumns.SIZE, r.mDataSize); if (r.mLocation != null) { values.put(ImageColumns.LATITUDE, r.mLocation.getLatitude()); values.put(ImageColumns.LONGITUDE, r.mLocation.getLongitude()); } values.put(ImageColumns.ORIENTATION, r.mOrientation); // M: ConShots values.put(Images.Media.GROUP_ID, r.mGroupId); values.put(Images.Media.GROUP_INDEX, r.mGroupIndex); values.put(Images.Media.FOCUS_VALUE_HIGH, r.mFocusValueHigh); values.put(Images.Media.FOCUS_VALUE_LOW, r.mFocusValueLow); // Add for Refocus image database values.put(Images.Media.CAMERA_REFOCUS, r.mTag); values.put(ImageColumns.WIDTH, r.mWidth); values.put(ImageColumns.HEIGHT, r.mHeight); try { r.mUri = mContentResolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values); if (r.mUri != null) { mContext.addSecureAlbumItemIfNeeded(false, r.mUri); if (mContext.isNonePickIntent()) { // picture taken and saved by camera which is launched // by 3rd apps will // be inserted into DB. But do not broadcast // "New_Picture" intent, // otherwise, it will not pass camera CTS test. Util.broadcastNewPicture(mContext, r.mUri); } Log.i(TAG, "[saveImageToDatabase]mUri = " + r.mUri); } } catch (IllegalArgumentException e) { // Here we keep google // default, don't // follow check style // This can happen when the external volume is already mounted, // but // MediaScanner has not notify MediaProvider to add that volume. // The picture is still safe and MediaScanner will find it and // insert it into MediaProvider. The only problem is that the // user // cannot click the thumbnail to review the picture. Log.e(TAG, "[saveImageToDatabase]Failed to write MediaStore,IllegalArgumentException:", e); } catch (UnsupportedOperationException e) { Log.e( TAG, "[saveImageToDatabase]Failed to write MediaStore," + "UnsupportedOperationException:", e); } }
// Set the override and/or reload the value from preferences. private void updateContent(String override, boolean reloadValue) { if (!reloadValue && Util.equals(mOverride, override)) return; IconListPreference pref = mPreference; mOverride = override; int index = pref.findIndexOfValue(override == null ? pref.getValue() : override); if (mIndex != index) { mIndex = index; invalidate(); } }
@Override protected void onFinishInflate() { mShutterButton = findViewById(R.id.shutter_button); mShutterButtonRadius = Util.dpToPixel(SHUTTER_BUTTON_RADIUS); mZoomControlWheel = (ZoomControlWheel) findViewById(R.id.zoom_control); mZoomControlWheel.setOnIndicatorEventListener(this); mIndicatorControlWheel = (IndicatorControlWheel) findViewById(R.id.indicator_control_wheel); }
@Override protected void onDraw(Canvas canvas) { if (!mBlocked && (mFaces != null) && (mFaces.length > 0)) { final CameraScreenNail sn = ((CameraActivity) getContext()).getCameraScreenNail(); int rw = sn.getUncroppedRenderWidth(); int rh = sn.getUncroppedRenderHeight(); // Prepare the matrix. if (((rh > rw) && ((mDisplayOrientation == 0) || (mDisplayOrientation == 180))) || ((rw > rh) && ((mDisplayOrientation == 90) || (mDisplayOrientation == 270)))) { int temp = rw; rw = rh; rh = temp; } Util.prepareMatrix(mMatrix, mMirror, mDisplayOrientation, rw, rh); int dx = (getWidth() - rw) / 2; int dy = (getHeight() - rh) / 2; // Focus indicator is directional. Rotate the matrix and the canvas // so it looks correctly in all orientations. canvas.save(); mMatrix.postRotate(mOrientation); // postRotate is clockwise canvas.rotate(-mOrientation); // rotate is counter-clockwise (for canvas) for (int i = 0; i < mFaces.length; i++) { // Filter out false positives. if (mFaces[i].score < 50) continue; // Transform the coordinates. mRect.set(mFaces[i].rect); if (LOGV) Util.dumpRect(mRect, "Original rect"); mMatrix.mapRect(mRect); if (LOGV) Util.dumpRect(mRect, "Transformed rect"); mPaint.setColor(mColor); mRect.offset(dx, dy); canvas.drawOval(mRect, mPaint); } canvas.restore(); } super.onDraw(canvas); }
private void setupDimension() { ParcelFileDescriptor input = null; try { input = mContentResolver.openFileDescriptor(mUri, "r"); BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapManager.instance().decodeFileDescriptor(input.getFileDescriptor(), options); mWidth = options.outWidth; mHeight = options.outHeight; } catch (FileNotFoundException ex) { mWidth = 0; mHeight = 0; } finally { Util.closeSilently(input); } }
private synchronized void handleHide() { if (mView != null) { // note: checking parent() just to make sure the view has // been added... i have seen cases where we get here when // the view isn't yet added, so let's try not to crash. Util.fadeOut(mView); try { if (mView.getParent() != null) { mWM.removeView(mView); } } catch (BadTokenException ex) { ex.printStackTrace(); } mView = null; } }
public Bitmap miniThumbBitmap() { Bitmap b = null; try { long id = mId; b = BitmapManager.instance() .getThumbnail(mContentResolver, id, Images.Thumbnails.MICRO_KIND, null, false); } catch (Throwable ex) { Log.e(TAG, "miniThumbBitmap got exception", ex); return null; } if (b != null) { b = Util.rotate(b, getDegreesRotated()); } return b; }
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // Layout the shutter button. int shutterButtonWidth = mShutterButton.getMeasuredWidth(); int shutterButtonHeight = mShutterButton.getMeasuredHeight(); mCenterX = right - left - Util.dpToPixel(FULL_WHEEL_RADIUS); mCenterY = (bottom - top) / 2; mShutterButton.layout( right - left - shutterButtonWidth, mCenterY - shutterButtonHeight / 2, right - left, mCenterY + shutterButtonHeight - shutterButtonHeight / 2); // Layout the control wheel. mIndicatorControlWheel.layout(0, 0, right - left, bottom - top); mZoomControlWheel.layout(0, 0, right - left, bottom - top); }
@Override public void saveRequest() { // title, file path, temp file path is ready FileOutputStream out = null; try { // Write to a temporary file and rename it to the final name. // This // avoids other apps reading incomplete data. out = new FileOutputStream(mTempFilePath); out.write(mData); out.close(); new File(mTempFilePath).renameTo(new File(mFilePath)); } catch (IOException e) { Log.e(TAG, "[saveRequest]PanoOperator,Failed to write image", e); } finally { if (out != null) { try { out.close(); } catch (IOException e) { Log.e(TAG, "[saveRequest]PanoOperator,exception:", e); } } } mDataSize = new File(mFilePath).length(); try { ExifInterface exif = new ExifInterface(mFilePath); int orientation = Util.getExifOrientation(exif); int width = exif.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, 0); int height = exif.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, 0); mWidth = width; mHeight = height; mOrientation = orientation; } catch (IOException ex) { Log.e(TAG, "[saveRequest]PanoOperator,cannot read exif:", ex); } if (null == mFileName) { mTitle = createName(mFileType, mDateTaken, mGroupIndex); mFileName = Storage.generateFileName(mTitle, mTempPictureType); Log.i(TAG, "[saveRequest]PhotoOperator,mFileName = " + mFileName); } mMimeType = Storage.generateMimetype(mTitle, mTempPictureType); saveImageToDatabase(this); }
private void startFaceDetection() { if (isFinishing()) { return; } mImageView.setImageBitmapResetBase(mBitmap, true); Util.startBackgroundJob( this, this, null, getResources().getString(R.string.runningFaceDetection), new Runnable() { public void run() { final CountDownLatch latch = new CountDownLatch(1); final Bitmap b = (mImage != null) ? mImage.fullSizeBitmap(IImage.UNCONSTRAINED, 1024 * 1024) : mBitmap; mHandler.post( new Runnable() { public void run() { if (b != mBitmap && b != null) { mImageView.setImageBitmapResetBase(b, true); mBitmap.recycle(); mBitmap = b; } if (mImageView.getScale() == 1F) { mImageView.center(true, true); } latch.countDown(); } }); try { latch.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } mRunFaceDetection.run(); } }, mHandler); }
@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { if (!mInitialized) return; if (mInAnimation) { rotateWheel(); mHandler.post(mRunnable); } mCenterX = right - left - Util.dpToPixel(IndicatorControlWheelContainer.FULL_WHEEL_RADIUS); mCenterY = (bottom - top) / 2; // Layout the indicators based on the current level. // The icons are spreaded on the left side of the shutter button. for (int i = 0; i < getChildCount(); ++i) { View view = getChildAt(i); // We still need to show the disabled indicators in the second level. double radian = mChildRadians[i]; double startVisibleRadians = mInAnimation ? mStartVisibleRadians[1] : mStartVisibleRadians[mCurrentLevel]; double endVisibleRadians = mInAnimation ? mEndVisibleRadians[1] : mEndVisibleRadians[mCurrentLevel]; if ((!view.isEnabled() && (mCurrentLevel == 0)) || (radian < (startVisibleRadians - HIGHLIGHT_RADIANS / 2)) || (radian > (endVisibleRadians + HIGHLIGHT_RADIANS / 2))) { view.setVisibility(View.GONE); continue; } view.setVisibility(View.VISIBLE); int x = mCenterX + (int) (mWheelRadius * Math.cos(radian)); int y = mCenterY - (int) (mWheelRadius * Math.sin(radian)); int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); if (view == mZoomControl) { // ZoomControlWheel matches the size of its parent view. view.layout(0, 0, right - left, bottom - top); } else { view.layout(x - width / 2, y - height / 2, x + width / 2, y + height / 2); } } }
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; } }
private void saveOutput(Bitmap croppedImage) { if (mSaveUri != null) { OutputStream outputStream = null; try { outputStream = mContentResolver.openOutputStream(mSaveUri); if (outputStream != null) { croppedImage.compress(mOutputFormat, mOutputQuality, outputStream); } } catch (IOException ex) { // TODO: report error to caller Log.e(TAG, "Cannot open file: " + mSaveUri, ex); } finally { Util.closeSilently(outputStream); } Bundle extras = new Bundle(); setResult(RESULT_OK, new Intent(mSaveUri.toString()).putExtras(extras)); } else if (mSetWallpaper) { try { WallpaperManager.getInstance(this).setBitmap(croppedImage); setResult(RESULT_OK); } catch (IOException e) { Log.e(TAG, "Failed to set wallpaper.", e); setResult(RESULT_CANCELED); } } else { Bundle extras = new Bundle(); extras.putString("rect", mCrop.getCropRect().toString()); File oldPath = new File(mImage.getDataPath()); File directory = new File(oldPath.getParent()); int x = 0; String fileName = oldPath.getName(); fileName = fileName.substring(0, fileName.lastIndexOf(".")); // Try file-1.jpg, file-2.jpg, ... until we find a filename which // does not exist yet. while (true) { x += 1; String candidate = directory.toString() + "/" + fileName + "-" + x + ".jpg"; boolean exists = (new File(candidate)).exists(); if (!exists) { break; } } try { int[] degree = new int[1]; Uri newUri = ImageManager.addImage( mContentResolver, mImage.getTitle(), mImage.getDateTaken(), null, // TODO this null is going to cause us to lose // the location (gps). directory.toString(), fileName + "-" + x + ".jpg", croppedImage, null, degree); setResult(RESULT_OK, new Intent().setAction(newUri.toString()).putExtras(extras)); } catch (Exception ex) { // basically ignore this or put up // some ui saying we failed Log.e(TAG, "store image fail, continue anyway", ex); } } final Bitmap b = croppedImage; mHandler.post( new Runnable() { public void run() { mImageView.clear(); b.recycle(); } }); finish(); }
/** A view that contains camera zoom control and its layout. */ public class ZoomControlBar extends ZoomControl { @SuppressWarnings("unused") private static final String TAG = "ZoomControlBar"; private static final int THRESHOLD_FIRST_MOVE = Util.dpToPixel(10); // pixels // Space between indicator icon and the zoom-in/out icon. private static final int ICON_SPACING = Util.dpToPixel(12); private View mBar; private boolean mStartChanging; private int mSliderPosition = 0; private int mSliderLength; // The width of the zoom control bar (including the '+', '-' icons and the // slider bar) for phone in portrait orientation, or the height of that // for phone in landscape orientation. private int mSize; // The width of the '+' icon (the same as '-' icon) for phone in portrait // orientation, or the height of that for phone in landscape orientation. private int mIconSize; // mIconSize + padding private int mTotalIconSize; public ZoomControlBar(Context context, AttributeSet attrs) { super(context, attrs); mBar = new View(context); mBar.setBackgroundResource(R.drawable.zoom_slider_bar); addView(mBar); } @Override public void setActivated(boolean activated) { super.setActivated(activated); mBar.setActivated(activated); } private int getSliderPosition(int offset) { // Calculate the absolute offset of the slider in the zoom control bar. // For left-hand users, as the device is rotated for 180 degree for // landscape mode, the zoom-in bottom should be on the top, so the // position should be reversed. int pos; // the relative position in the zoom slider bar if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { if (mOrientation == 180) { pos = offset - mTotalIconSize; } else { pos = mSize - mTotalIconSize - offset; } } else { if (mOrientation == 90) { pos = mSize - mTotalIconSize - offset; } else { pos = offset - mTotalIconSize; } } if (pos < 0) pos = 0; if (pos > mSliderLength) pos = mSliderLength; return pos; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { mSize = h; mIconSize = mZoomIn.getMeasuredHeight(); } else { mSize = w; mIconSize = mZoomIn.getMeasuredWidth(); } mTotalIconSize = mIconSize + ICON_SPACING; mSliderLength = mSize - (2 * mTotalIconSize); } @Override public boolean dispatchTouchEvent(MotionEvent event) { if (!isEnabled() || (mSize == 0)) return false; int action = event.getAction(); switch (action) { case MotionEvent.ACTION_OUTSIDE: case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: setActivated(false); closeZoomControl(); break; case MotionEvent.ACTION_DOWN: setActivated(true); mStartChanging = false; case MotionEvent.ACTION_MOVE: boolean isLandscape = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); int pos = getSliderPosition((int) (isLandscape ? event.getY() : event.getX())); if (!mStartChanging) { // Make sure the movement is large enough before we start // changing the zoom. int delta = mSliderPosition - pos; if ((delta > THRESHOLD_FIRST_MOVE) || (delta < -THRESHOLD_FIRST_MOVE)) { mStartChanging = true; } } if (mStartChanging) { performZoom(1.0d * pos / mSliderLength); mSliderPosition = pos; } requestLayout(); } return true; } @Override public void setOrientation(int orientation, boolean animation) { // layout for the left-hand camera control if ((orientation == 180) || (mOrientation == 180)) requestLayout(); super.setOrientation(orientation, animation); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { boolean isLandscape = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); if (mZoomMax == 0) return; int size = 0; if (isLandscape) { size = right - left; mBar.layout(0, mTotalIconSize, size, mSize - mTotalIconSize); } else { size = bottom - top; mBar.layout(mTotalIconSize, 0, mSize - mTotalIconSize, size); } // For left-hand users, as the device is rotated for 180 degree, // the zoom-in button should be on the top. int pos; // slider position int sliderPosition; if (mSliderPosition != -1) { // -1 means invalid sliderPosition = mSliderPosition; } else { sliderPosition = (int) ((double) mSliderLength * mZoomIndex / mZoomMax); } if (isLandscape) { if (mOrientation == 180) { mZoomOut.layout(0, 0, size, mIconSize); mZoomIn.layout(0, mSize - mIconSize, size, mSize); pos = mBar.getTop() + sliderPosition; } else { mZoomIn.layout(0, 0, size, mIconSize); mZoomOut.layout(0, mSize - mIconSize, size, mSize); pos = mBar.getBottom() - sliderPosition; } int sliderHeight = mZoomSlider.getMeasuredHeight(); mZoomSlider.layout(0, (pos - sliderHeight / 2), size, (pos + sliderHeight / 2)); } else { if (mOrientation == 90) { mZoomIn.layout(0, 0, mIconSize, size); mZoomOut.layout(mSize - mIconSize, 0, mSize, size); pos = mBar.getRight() - sliderPosition; } else { mZoomOut.layout(0, 0, mIconSize, size); mZoomIn.layout(mSize - mIconSize, 0, mSize, size); pos = mBar.getLeft() + sliderPosition; } int sliderWidth = mZoomSlider.getMeasuredWidth(); mZoomSlider.layout((pos - sliderWidth / 2), 0, (pos + sliderWidth / 2), size); } } @Override public void setZoomIndex(int index) { super.setZoomIndex(index); mSliderPosition = -1; // -1 means invalid } }
private void onSaveClicked() { // TODO this code needs to change to use the decode/crop/encode single // step api so that we don't require that the whole (possibly large) // bitmap doesn't have to be read into memory if (mCrop == null) { return; } if (mSaving) return; mSaving = true; Bitmap croppedImage; // If the output is required to a specific size, create an new image // with the cropped image in the center and the extra space filled. if (mOutputX != 0 && mOutputY != 0 && !mScale) { // Don't scale the image but instead fill it so it's the // required dimension croppedImage = Bitmap.createBitmap(mOutputX, mOutputY, Bitmap.Config.RGB_565); Canvas canvas = new Canvas(croppedImage); Rect srcRect = mCrop.getCropRect(); Rect dstRect = new Rect(0, 0, mOutputX, mOutputY); int dx = (srcRect.width() - dstRect.width()) / 2; int dy = (srcRect.height() - dstRect.height()) / 2; // If the srcRect is too big, use the center part of it. srcRect.inset(Math.max(0, dx), Math.max(0, dy)); // If the dstRect is too big, use the center part of it. dstRect.inset(Math.max(0, -dx), Math.max(0, -dy)); // Draw the cropped bitmap in the center canvas.drawBitmap(mBitmap, srcRect, dstRect, null); // Release bitmap memory as soon as possible mImageView.clear(); mBitmap.recycle(); } else { Rect r = mCrop.getCropRect(); int width = r.width(); int height = r.height(); // If we are circle cropping, we want alpha channel, which is the // third param here. croppedImage = Bitmap.createBitmap( width, height, mCircleCrop ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(croppedImage); Rect dstRect = new Rect(0, 0, width, height); canvas.drawBitmap(mBitmap, r, dstRect, null); // Release bitmap memory as soon as possible mImageView.clear(); mBitmap.recycle(); if (mCircleCrop) { // OK, so what's all this about? // Bitmaps are inherently rectangular but we want to return // something that's basically a circle. So we fill in the // area around the circle with alpha. Note the all important // PortDuff.Mode.CLEAR. Canvas c = new Canvas(croppedImage); Path p = new Path(); p.addCircle(width / 2F, height / 2F, width / 2F, Path.Direction.CW); c.clipPath(p, Region.Op.DIFFERENCE); c.drawColor(0x00000000, PorterDuff.Mode.CLEAR); } // If the required dimension is specified, scale the image. if (mOutputX != 0 && mOutputY != 0 && mScale) { croppedImage = Util.transform( new Matrix(), croppedImage, mOutputX, mOutputY, mScaleUp, Util.RECYCLE_INPUT); } } mImageView.setImageBitmapResetBase(croppedImage, true); mImageView.center(true, true); mImageView.mHighlightViews.clear(); // Return the cropped image directly or save it to the specified URI. Bundle myExtras = getIntent().getExtras(); if (myExtras != null && (myExtras.getParcelable("data") != null || myExtras.getBoolean("return-data"))) { Bundle extras = new Bundle(); extras.putParcelable("data", croppedImage); setResult(RESULT_OK, (new Intent()).setAction("inline-data").putExtras(extras)); finish(); } else { final Bitmap b = croppedImage; final int msdId = mSetWallpaper ? R.string.wallpaper : R.string.savingImage; Util.startBackgroundJob( this, this, null, getResources().getString(msdId), new Runnable() { public void run() { saveOutput(b); } }, mHandler); } }