diff options
author | Jack Yoo <jyoo@codeaurora.org> | 2016-06-30 14:16:44 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-08-16 16:10:18 -0700 |
commit | 2fceef1ed0dfb3cb35062b6f6ebe8ca68e7bf87c (patch) | |
tree | 86a0cfd7ddb6ddde91dfb310d47d8f6e289f9d78 /src/com/android/camera | |
parent | 039e6e3a2baa4c510306d32683cf258eb8e00e10 (diff) | |
download | android_packages_apps_Snap-2fceef1ed0dfb3cb35062b6f6ebe8ca68e7bf87c.tar.gz android_packages_apps_Snap-2fceef1ed0dfb3cb35062b6f6ebe8ca68e7bf87c.tar.bz2 android_packages_apps_Snap-2fceef1ed0dfb3cb35062b6f6ebe8ca68e7bf87c.zip |
SnapdragonCamera: Bestpicture scene filter
Adding best picture selection scene filter
Change-Id: Ifa0f544e80d161eaef743d611c712d8db48e5631
CRs-Fixed: 1050663
Diffstat (limited to 'src/com/android/camera')
-rw-r--r-- | src/com/android/camera/BestpictureActivity.java | 348 | ||||
-rw-r--r-- | src/com/android/camera/BestpictureFragment.java | 93 | ||||
-rwxr-xr-x | src/com/android/camera/CameraActivity.java | 9 | ||||
-rw-r--r-- | src/com/android/camera/CaptureModule.java | 8 | ||||
-rw-r--r-- | src/com/android/camera/SettingsManager.java | 3 | ||||
-rw-r--r-- | src/com/android/camera/imageprocessor/PostProcessor.java | 24 | ||||
-rw-r--r-- | src/com/android/camera/imageprocessor/filter/BestpictureFilter.java | 252 | ||||
-rw-r--r-- | src/com/android/camera/imageprocessor/filter/UbifocusFilter.java | 21 | ||||
-rw-r--r-- | src/com/android/camera/ui/DotsView.java | 98 | ||||
-rw-r--r-- | src/com/android/camera/ui/DotsViewItem.java | 35 |
10 files changed, 876 insertions, 15 deletions
diff --git a/src/com/android/camera/BestpictureActivity.java b/src/com/android/camera/BestpictureActivity.java new file mode 100644 index 000000000..bb519e74f --- /dev/null +++ b/src/com/android/camera/BestpictureActivity.java @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.android.camera; + +import android.app.ProgressDialog; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.Point; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v13.app.FragmentStatePagerAdapter; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.Log; +import android.view.Display; +import android.view.Menu; +import android.view.View; +import android.support.v4.app.FragmentActivity; +import android.widget.Toast; + +import com.android.camera.exif.ExifInterface; +import com.android.camera.ui.DotsView; +import com.android.camera.ui.DotsViewItem; +import com.android.camera.ui.RotateTextToast; +import com.android.camera.util.CameraUtil; + +import org.codeaurora.snapcam.R; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; + +public class BestpictureActivity extends FragmentActivity{ + private static final String TAG = "BestpictureActivity"; + public static final String[] NAMES = { + "00", "01", "02", "03", "04", "05", "06", "07", "08", "09" + }; + + public static final int NUM_IMAGES = 10; + + private ViewPager mImagePager; + private PagerAdapter mImagePagerAdapter; + private int mWidth; + private int mHeight; + private String mFilesPath; + private ProgressDialog mProgressDialog; + private BestpictureActivity mActivity; + private DotsView mDotsView; + private ImageItems mImageItems; + private ImageLoadingThread mLoadingThread; + private PhotoModule.NamedImages mNamedImages; + private Uri mPlaceHolderUri; + public static int BESTPICTURE_ACTIVITY_CODE = 11; + + static class ImageItems implements Parcelable, DotsViewItem { + private Bitmap[] mBitmap; + private boolean[] mChosen; + private BestpictureActivity mActivity; + + public ImageItems(BestpictureActivity activity) { + mBitmap = new Bitmap[NUM_IMAGES]; + mChosen = new boolean[NUM_IMAGES]; + for (int i = 0; i < mChosen.length; i++) { + if (i == 0) { + mChosen[i] = true; + } else { + mChosen[i] = false; + } + } + mActivity = activity; + } + + @Override + public int describeContents() { + return 0; + } + + public Bitmap getBitmap(int index) { + return mBitmap[index]; + } + + public void setBitmap(int index, Bitmap bitmap) { + mBitmap[index] = bitmap; + } + + @Override + public int getTotalItemNums() { + return NUM_IMAGES; + } + + public boolean isChosen(int index) { + return mChosen[index]; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + } + + public void toggleImageSelection(int num) { + mChosen[num] = !mChosen[num]; + boolean isChosen = false; + for(int i=0; i < mChosen.length; i++) { + isChosen |= mChosen[i]; + } + if(!isChosen) { + mChosen[num] = true; + RotateTextToast.makeText(mActivity, + mActivity.getResources().getString(R.string.bestpicture_at_least_one_picture), + Toast.LENGTH_SHORT).show(); + } + mActivity.mDotsView.update(); + } + } + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + mActivity = this; + mFilesPath = getFilesDir()+"/Bestpicture"; + setContentView(R.layout.bestpicture_editor); + Display display = getWindowManager().getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + mWidth = size.x/2; + mHeight = size.y/2; + mNamedImages = new PhotoModule.NamedImages(); + + mImageItems = new ImageItems(mActivity); + mDotsView = (DotsView) findViewById(R.id.dots_view); + mDotsView.setItems(mImageItems); + mPlaceHolderUri = getIntent().getData(); + + mImagePager = (ViewPager) findViewById(R.id.bestpicture_pager); + mImagePagerAdapter = new ImagePagerAdapter(getFragmentManager()); + mImagePager.setAdapter(mImagePagerAdapter); + mImagePager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mDotsView.update(position, positionOffset); + } + + @Override + public void onPageSelected(int position) { + } + }); + findViewById(R.id.bestpicture_done).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + int index = -1; + for(int i=0; i < mImageItems.mChosen.length; i++) { + if (mImageItems.mChosen[i]) { + if(index != -1) { + new SaveImageTask().execute(mFilesPath + "/" + NAMES[i] + ".jpg"); + } else { + index = i; + saveForground(mFilesPath + "/" + NAMES[i] + ".jpg"); + } + } + } + setResult(RESULT_OK, new Intent()); + finish(); + } + }); + } + + private class ImageLoadingThread extends Thread { + public void run() { + showProgressDialog(); + for(int i=0; i < NUM_IMAGES; i++) { + String path = mFilesPath + "/" + BestpictureActivity.NAMES[i] + ".jpg"; + final BitmapFactory.Options o = new BitmapFactory.Options(); + o.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, o); + ExifInterface exif = new ExifInterface(); + int orientation = 0; + try { + exif.readExif(path); + orientation = Exif.getOrientation(exif); + } catch (IOException e) { + } + int h = o.outHeight; + int w = o.outWidth; + int sample = 1; + if (h > mHeight || w > mWidth) { + while (h / sample / 2 > mHeight && w / sample / 2 > mWidth) { + sample *= 2; + } + } + + o.inJustDecodeBounds = false; + o.inSampleSize = sample; + Bitmap bitmap = BitmapFactory.decodeFile(path, o); + if (orientation != 0) { + Matrix matrix = new Matrix(); + matrix.setRotate(orientation); + bitmap = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), matrix, false); + } + mImageItems.setBitmap(i, bitmap); + } + dismissProgressDialog(); + } + } + + @Override + public void onResume() { + super.onResume(); + if (mLoadingThread == null) { + mLoadingThread = new ImageLoadingThread(); + mLoadingThread.start(); + } + } + + @Override + public void onPause() { + super.onPause(); + } + + private void showProgressDialog() { + mActivity.runOnUiThread(new Runnable() { + public void run() { + mProgressDialog = ProgressDialog.show(mActivity, "", "Processing...", true, false); + mProgressDialog.show(); + } + }); + } + + private void dismissProgressDialog() { + mActivity.runOnUiThread(new Runnable() { + public void run() { + if (mProgressDialog != null && mProgressDialog.isShowing()) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + return true; + } + + private class ImagePagerAdapter extends FragmentStatePagerAdapter { + public ImagePagerAdapter(android.app.FragmentManager manager) { + super(manager); + } + + @Override + public android.app.Fragment getItem(int imageNum) { + while(mImageItems.getBitmap(imageNum) == null) { + try { + Thread.sleep(5); + } catch (Exception e) { + } + } + return BestpictureFragment.create(imageNum, mImageItems); + } + + @Override + public int getCount() { + return NUM_IMAGES; + } + } + + private void saveForground(String path) { + long captureStartTime = System.currentTimeMillis(); + mNamedImages.nameNewImage(captureStartTime); + PhotoModule.NamedImages.NamedEntity name = mNamedImages.getNextNameEntity(); + String title = (name == null) ? null : name.title; + String outPath = mPlaceHolderUri.getPath(); + try { + FileOutputStream out = new FileOutputStream(outPath); + FileInputStream in = new FileInputStream(path); + byte[] buf = new byte[4096]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } catch (Exception e) { + } + } + + private class SaveImageTask extends AsyncTask<String, Void, Void> { + protected Void doInBackground(String... path) { + long captureStartTime = System.currentTimeMillis(); + mNamedImages.nameNewImage(captureStartTime); + PhotoModule.NamedImages.NamedEntity name = mNamedImages.getNextNameEntity(); + String title = (name == null) ? null : name.title; + String outPath = Storage.generateFilepath(title, "jpeg"); + try { + FileOutputStream out = new FileOutputStream(outPath); + FileInputStream in = new FileInputStream(path[0]); + byte[] buf = new byte[4096]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.close(); + } catch (Exception e) { + } + Uri uri = Uri.fromFile(new File(outPath)); + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri); + sendBroadcast(intent); + return null; + } + + protected void onPostExecute(Void v) { + } + } +} diff --git a/src/com/android/camera/BestpictureFragment.java b/src/com/android/camera/BestpictureFragment.java new file mode 100644 index 000000000..6dc4ebd59 --- /dev/null +++ b/src/com/android/camera/BestpictureFragment.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.camera; + +import android.app.Fragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import org.codeaurora.snapcam.R; + +public class BestpictureFragment extends Fragment { + public static final String PARAM_IMAGE_NUM = "image_num"; + private static final String TAG = "BestpictureFilter"; + private int mImageNum; + private ImageView mImageView; + private ImageView mPictureSelectButton; + private BestpictureActivity.ImageItems mImageItems; + + public static BestpictureFragment create(int imageNum, BestpictureActivity.ImageItems items) { + BestpictureFragment fragment = new BestpictureFragment(); + Bundle args = new Bundle(); + args.putInt(PARAM_IMAGE_NUM, imageNum); + args.putParcelable("imageItems", items); + fragment.setArguments(args); + return fragment; + } + + public BestpictureFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mImageNum = getArguments().getInt(PARAM_IMAGE_NUM); + mImageItems = getArguments().getParcelable("imageItems"); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + ViewGroup rootView = (ViewGroup) inflater + .inflate(R.layout.bestpicture_page, container, false); + mImageView = (ImageView) rootView.findViewById(R.id.image_view); + mPictureSelectButton = (ImageView) rootView.findViewById(R.id.picture_select); + initSelectButton(); + mImageView.setImageBitmap(mImageItems.getBitmap(mImageNum)); + rootView.findViewById(R.id.picture_select).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + mImageItems.toggleImageSelection(mImageNum); + initSelectButton(); + } + }); + return rootView; + } + + private void initSelectButton() { + if(mImageItems.isChosen(mImageNum)) { + mPictureSelectButton.setBackground(getResources().getDrawable(R.drawable.pick_the_best_photo_selected, null)); + } else { + mPictureSelectButton.setBackground(getResources().getDrawable(R.drawable.pick_the_best_photo_unselected, null)); + } + } +}
\ No newline at end of file diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 5666331fa..a330f6a5f 100755 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -16,6 +16,8 @@ package com.android.camera; +import android.os.Parcel; +import android.os.Parcelable; import android.view.Display; import android.graphics.Point; import android.Manifest; @@ -1642,6 +1644,13 @@ public class CameraActivity extends Activity if(resultCode == RESULT_OK) { mCaptureModule.setRefocusLastTaken(false); } + } else if (requestCode == BestpictureActivity.BESTPICTURE_ACTIVITY_CODE) { + if(resultCode == RESULT_OK) { + byte[] jpeg = data.getByteArrayExtra("thumbnail"); + if(jpeg != null) { + updateThumbnail(jpeg); + } + } } else { super.onActivityResult(requestCode, resultCode, data); } diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index cace45ba7..899f40f7d 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -158,8 +158,6 @@ public class CaptureModule implements CameraModule, PhotoController, // we can change it based on memory status or other requirements. private static final int LONGSHOT_CANCEL_THRESHOLD = 40 * 1024 * 1024; - private static final int MAX_IMAGE_NUM = 8; - MeteringRectangle[][] mAFRegions = new MeteringRectangle[MAX_NUM_CAM][]; MeteringRectangle[][] mAERegions = new MeteringRectangle[MAX_NUM_CAM][]; CaptureRequest.Key<Byte> BayerMonoLinkEnableKey = @@ -1266,7 +1264,7 @@ public class CaptureModule implements CameraModule, PhotoController, } else { // No Clearsight mImageReader[i] = ImageReader.newInstance(mPictureSize.getWidth(), - mPictureSize.getHeight(), imageFormat, MAX_IMAGE_NUM); + mPictureSize.getHeight(), imageFormat, PostProcessor.MAX_REQUIRED_IMAGE_NUM); if((mPostProcessor.isFilterOn() || getFrameFilters().size() != 0) && i == getMainCameraId()) { mImageReader[i].setOnImageAvailableListener(mPostProcessor, mImageAvailableHandler); @@ -1316,7 +1314,7 @@ public class CaptureModule implements CameraModule, PhotoController, mVideoSnapshotImageReader.close(); } mVideoSnapshotImageReader = ImageReader.newInstance(mVideoSnapshotSize.getWidth(), - mVideoSnapshotSize.getHeight(), ImageFormat.JPEG, MAX_IMAGE_NUM); + mVideoSnapshotSize.getHeight(), ImageFormat.JPEG, mPostProcessor.MAX_REQUIRED_IMAGE_NUM); mVideoSnapshotImageReader.setOnImageAvailableListener( new ImageReader.OnImageAvailableListener() { @Override @@ -1667,6 +1665,8 @@ public class CaptureModule implements CameraModule, PhotoController, return PostProcessor.FILTER_UBIFOCUS; } else if (mode == SettingsManager.SCENE_MODE_AUTO_INT && StillmoreFilter.isSupportedStatic()) { return PostProcessor.FILTER_STILLMORE; + } else if (mode == SettingsManager.SCENE_MODE_BESTPICTURE_INT) { + return PostProcessor.FILTER_BESTPICTURE; } return PostProcessor.FILTER_NONE; } diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java index 23c472698..ae46b9587 100644 --- a/src/com/android/camera/SettingsManager.java +++ b/src/com/android/camera/SettingsManager.java @@ -45,6 +45,7 @@ import android.util.Rational; import android.util.Size; import com.android.camera.imageprocessor.filter.BeautificationFilter; +import com.android.camera.imageprocessor.filter.BestpictureFilter; import com.android.camera.imageprocessor.filter.OptizoomFilter; import com.android.camera.imageprocessor.filter.TrackingFocusFrameListener; import com.android.camera.imageprocessor.filter.UbifocusFilter; @@ -77,6 +78,7 @@ public class SettingsManager implements ListMenu.SettingsListener { public static final int SCENE_MODE_DUAL_INT = 100; public static final int SCENE_MODE_OPTIZOOM_INT = 101; public static final int SCENE_MODE_UBIFOCUS_INT = 102; + public static final int SCENE_MODE_BESTPICTURE_INT = 103; public static final String SCENE_MODE_DUAL_STRING = "100"; public static final String KEY_CAMERA_SAVEPATH = "pref_camera2_savepath_key"; public static final String KEY_RECORD_LOCATION = "pref_camera2_recordlocation_key"; @@ -846,6 +848,7 @@ public class SettingsManager implements ListMenu.SettingsListener { if (mIsMonoCameraPresent) modes.add(SCENE_MODE_DUAL_STRING); // need special case handle for dual mode if (OptizoomFilter.isSupportedStatic()) modes.add(SCENE_MODE_OPTIZOOM_INT + ""); if (UbifocusFilter.isSupportedStatic() && cameraId == CaptureModule.BAYER_ID) modes.add(SCENE_MODE_UBIFOCUS_INT + ""); + if (BestpictureFilter.isSupportedStatic() && cameraId == CaptureModule.BAYER_ID) modes.add(SCENE_MODE_BESTPICTURE_INT + ""); for (int mode : sceneModes) { modes.add("" + mode); } diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java index 1fa908945..295707afd 100644 --- a/src/com/android/camera/imageprocessor/PostProcessor.java +++ b/src/com/android/camera/imageprocessor/PostProcessor.java @@ -51,6 +51,7 @@ import com.android.camera.MediaSaveService; import com.android.camera.PhotoModule; import com.android.camera.SettingsManager; import com.android.camera.exif.ExifInterface; +import com.android.camera.imageprocessor.filter.BestpictureFilter; import com.android.camera.imageprocessor.filter.OptizoomFilter; import com.android.camera.imageprocessor.filter.SharpshooterFilter; import com.android.camera.imageprocessor.filter.StillmoreFilter; @@ -78,8 +79,11 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{ public static final int FILTER_SHARPSHOOTER = 2; public static final int FILTER_UBIFOCUS = 3; public static final int FILTER_STILLMORE = 4; - public static final int FILTER_MAX = 5; + public static final int FILTER_BESTPICTURE = 5; + public static final int FILTER_MAX = 6; + //Max image is now Bestpicture filter with 10 + public static final int MAX_REQUIRED_IMAGE_NUM = 10; private int mCurrentNumImage = 0; private ImageFilter mFilter; private int mFilterIndex; @@ -290,6 +294,9 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{ case FILTER_STILLMORE: mFilter = new StillmoreFilter(mController); break; + case FILTER_BESTPICTURE: + mFilter = new BestpictureFilter(mController, mActivity); + break; } } @@ -440,10 +447,12 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{ } } } - //Start processing FrameProcessor filter as well - for (ImageFilter filter : mController.getFrameFilters()) { - filter.init(resultImage.width, resultImage.height, resultImage.stride, resultImage.stride); - filter.addImage(resultImage.outBuffer, null, 0, new Boolean(false)); + if(resultImage != null) { + //Start processing FrameProcessor filter as well + for (ImageFilter filter : mController.getFrameFilters()) { + filter.init(resultImage.width, resultImage.height, resultImage.stride, resultImage.stride); + filter.addImage(resultImage.outBuffer, null, 0, new Boolean(false)); + } } //End processing FrameProessor filter clear(); @@ -451,10 +460,11 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{ if(mWatchdog != null) { mWatchdog.stopMonitor(); } - if((resultImage.outRoi.left + resultImage.outRoi.width() > resultImage.width) || + if(resultImage == null || + (resultImage.outRoi.left + resultImage.outRoi.width() > resultImage.width) || (resultImage.outRoi.top + resultImage.outRoi.height() > resultImage.height) ) { - Log.e(TAG, "Processed outRoi is not within picture range"); + Log.d(TAG, "Result image is not valid."); } else { if(mFilter != null && DEBUG_FILTER) { bytes = nv21ToJpeg(mDebugResultImage, mOrientation); diff --git a/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java b/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java new file mode 100644 index 000000000..638d037ce --- /dev/null +++ b/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java @@ -0,0 +1,252 @@ +/* +Copyright (c) 2016, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.android.camera.imageprocessor.filter; + +import android.content.Intent; +import android.graphics.ImageFormat; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.CaptureResult; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; + +import com.android.camera.BestpictureActivity; +import com.android.camera.CameraActivity; +import com.android.camera.CaptureModule; +import com.android.camera.MediaSaveService; +import com.android.camera.PhotoModule; +import com.android.camera.imageprocessor.PostProcessor; +import com.android.camera.util.CameraUtil; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +public class BestpictureFilter implements ImageFilter { + public static final int NUM_REQUIRED_IMAGE = 10; + private int mWidth; + private int mHeight; + private int mStrideY; + private int mStrideVU; + private static String TAG = "BestpictureFilter"; + private static final boolean DEBUG = false; + private static boolean mIsSupported = true; + private CaptureModule mModule; + private CameraActivity mActivity; + private int mOrientation = 0; + final String[] NAMES = {"00.jpg", "01.jpg", "02.jpg", "03.jpg", + "04.jpg", "05.jpg", "06.jpg", "07.jpg", "08.jpg" + ,"09.jpg"}; + + private final static int TIME_DELAY = 50; + private int mSavedCount = 0; + private PhotoModule.NamedImages mNamedImages; + private ByteBuffer mBY; + private ByteBuffer mBVU; + + private static void Log(String msg) { + if (DEBUG) { + Log.d(TAG, msg); + } + } + + public BestpictureFilter(CaptureModule module, CameraActivity activity) { + mModule = module; + mActivity = activity; + mNamedImages = new PhotoModule.NamedImages(); + } + + @Override + public List<CaptureRequest> setRequiredImages(CaptureRequest.Builder builder) { + List<CaptureRequest> list = new ArrayList<CaptureRequest>(); + for(int i=0; i < NUM_REQUIRED_IMAGE; i++) { + list.add(builder.build()); + } + return list; + } + + @Override + public String getStringName() { + return "BestpictureFilter"; + } + + @Override + public int getNumRequiredImage() { + return NUM_REQUIRED_IMAGE; + } + + @Override + public void init(int width, int height, int strideY, int strideVU) { + Log("init"); + mWidth = width/2*2; + mHeight = height/2*2; + mStrideY = strideY/2*2; + mStrideVU = strideVU / 2 * 2; + Log("width: " + mWidth + " height: " + mHeight + " strideY: " + mStrideY + " strideVU: " + mStrideVU); + } + + @Override + public void deinit() { + Log("deinit"); + } + + @Override + public void addImage(final ByteBuffer bY, final ByteBuffer bVU, final int imageNum, Object param) { + Log("addImage"); + if(imageNum == 0) { + mOrientation = CameraUtil.getJpegRotation(mModule.getMainCameraId(), mModule.getDisplayOrientation()); + mSavedCount = 0; + mBY = bY; + mBVU = bVU; + } + new Thread() { + public void run() { + saveToPrivateFile(imageNum, nv21ToJpeg(bY, bVU, new Rect(0, 0, mWidth, mHeight), mOrientation)); + mSavedCount++; + } + }.start(); + } + + @Override + public ResultImage processImage() { + long captureStartTime = System.currentTimeMillis(); + mNamedImages.nameNewImage(captureStartTime); + PhotoModule.NamedImages.NamedEntity name = mNamedImages.getNextNameEntity(); + String title = (name == null) ? null : name.title; + long date = (name == null) ? -1 : name.date; + mActivity.getMediaSaveService().addImage( + nv21ToJpeg(mBY, mBVU, new Rect(0, 0, mWidth, mHeight), mOrientation), title, date, null, mWidth, mHeight, + mOrientation, null, new MediaSaveService.OnMediaSavedListener() { + @Override + public void onMediaSaved(Uri uri) { + if (uri != null) { + mActivity.notifyNewMedia(uri); + } + startBestpictureActivity(uri); + } + } + , mActivity.getContentResolver(), "jpeg"); + while(mSavedCount < NUM_REQUIRED_IMAGE) { + try { + Thread.sleep(1); + } catch (Exception e) { + } + } + return null; + } + + private void startBestpictureActivity(Uri uri) { + Intent intent = new Intent(); + intent.setData(uri); + intent.setClass(mActivity, BestpictureActivity.class); + mActivity.startActivityForResult(intent, BestpictureActivity.BESTPICTURE_ACTIVITY_CODE); + } + + @Override + public boolean isSupported() { + return mIsSupported; + } + + @Override + public boolean isFrameListener() { + return false; + } + + @Override + public boolean isManualMode() { + return false; + } + + @Override + public void manualCapture(CaptureRequest.Builder builder, CameraCaptureSession captureSession, + CameraCaptureSession.CaptureCallback callback, Handler handler) throws CameraAccessException { + for(int i=0; i < NUM_REQUIRED_IMAGE; i++) { + captureSession.capture(builder.build(), callback, handler); + try { + Thread.sleep(TIME_DELAY); + } catch (InterruptedException e) { + } + } + } + + public static boolean isSupportedStatic() { + return mIsSupported; + } + + private byte[] nv21ToJpeg(ByteBuffer bY, ByteBuffer bVU, Rect roi, int orientation) { + ByteBuffer buf = ByteBuffer.allocate(mStrideY*mHeight*3/2); + buf.put(bY); + bY.rewind(); + if(bVU != null) { + buf.put(bVU); + bVU.rewind(); + } + BitmapOutputStream bos = new BitmapOutputStream(1024); + YuvImage im = new YuvImage(buf.array(), ImageFormat.NV21, + mWidth, mHeight, new int[]{mStrideY, mStrideVU}); + im.compressToJpeg(roi, 50, bos); + byte[] bytes = bos.getArray(); + bytes = PostProcessor.addExifTags(bytes, orientation); + return bytes; + } + + private class BitmapOutputStream extends ByteArrayOutputStream { + public BitmapOutputStream(int size) { + super(size); + } + + public byte[] getArray() { + return buf; + } + } + + private void saveToPrivateFile(final int index, final byte[] bytes) { + String filesPath = mActivity.getFilesDir()+"/Bestpicture"; + File file = new File(filesPath); + if(!file.exists()) { + file.mkdir(); + } + file = new File(filesPath+"/"+NAMES[index]); + try { + FileOutputStream out = new FileOutputStream(file); + out.write(bytes, 0, bytes.length); + out.close(); + } catch (Exception e) { + } + } +} diff --git a/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java b/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java index b410e01b4..c68b5091e 100644 --- a/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java +++ b/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java @@ -63,7 +63,7 @@ public class UbifocusFilter implements ImageFilter { private int mStrideY; private int mStrideVU; private static String TAG = "UbifocusFilter"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private static final int FOCUS_ADJUST_TIME_OUT = 200; private static final int META_BYTES_SIZE = 25; private int temp; @@ -76,6 +76,8 @@ public class UbifocusFilter implements ImageFilter { final String[] NAMES = {"00.jpg", "01.jpg", "02.jpg", "03.jpg", "04.jpg", "DepthMapImage.y", "AllFocusImage.jpg"}; + private int mSavedCount = 0; + private static void Log(String msg) { if (DEBUG) { Log.d(TAG, msg); @@ -122,18 +124,24 @@ public class UbifocusFilter implements ImageFilter { } @Override - public void addImage(ByteBuffer bY, ByteBuffer bVU, int imageNum, Object param) { + public void addImage(final ByteBuffer bY, final ByteBuffer bVU, final int imageNum, Object param) { Log("addImage"); if(imageNum == 0) { mModule.setRefocusLastTaken(false); mOrientation = CameraUtil.getJpegRotation(mModule.getMainCameraId(), mModule.getDisplayOrientation()); + mSavedCount = 0; } - saveToPrivateFile(imageNum, nv21ToJpeg(bY, bVU, new Rect(0, 0, mWidth, mHeight), mOrientation)); int yActualSize = bY.remaining(); int vuActualSize = bVU.remaining(); if(nativeAddImage(bY, bVU, yActualSize, vuActualSize, imageNum) < 0) { Log.e(TAG, "Fail to add image"); } + new Thread() { + public void run() { + saveToPrivateFile(imageNum, nv21ToJpeg(bY, bVU, new Rect(0, 0, mWidth, mHeight), mOrientation)); + mSavedCount++; + } + }.start(); } @Override @@ -151,7 +159,12 @@ public class UbifocusFilter implements ImageFilter { saveToPrivateFile(NAMES.length - 1, nv21ToJpeg(mOutBuf, null, new Rect(roi[0], roi[1], roi[0] + roi[2], roi[1] + roi[3]), mOrientation)); mModule.setRefocusLastTaken(true); } - + while(mSavedCount < NUM_REQUIRED_IMAGE) { + try { + Thread.sleep(1); + } catch (Exception e) { + } + } ResultImage result = new ResultImage(mOutBuf, new Rect(roi[0], roi[1], roi[0]+roi[2], roi[1] + roi[3]), mWidth, mHeight, mStrideY); Log("processImage done"); return result; diff --git a/src/com/android/camera/ui/DotsView.java b/src/com/android/camera/ui/DotsView.java new file mode 100644 index 000000000..f08b96713 --- /dev/null +++ b/src/com/android/camera/ui/DotsView.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.camera.ui; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.View; + +public class DotsView extends View { + private Paint mTargetPaint; + private int mPosition; + private float mPositionOffset; + private DotsViewItem mItems; + + public DotsView(Context context, AttributeSet attrs) { + super(context, attrs); + mTargetPaint = new Paint(); + mTargetPaint.setColor(Color.WHITE); + mTargetPaint.setStyle(Paint.Style.FILL_AND_STROKE); + } + + public void update(int position, float positionOffest) { + mPosition = position; + mPositionOffset = positionOffest; + invalidate(); + } + + public void setItems(DotsViewItem item) { + mItems = item; + } + + public void update() { + invalidate(); + } + + @Override + public void onDraw(Canvas canvas) { + if(mItems == null) { + return; + } + + int dx = canvas.getWidth()/(mItems.getTotalItemNums()+1); + int dy = canvas.getHeight()/(mItems.getTotalItemNums()+1); + int y = canvas.getHeight()/2; + float radius = Math.min(dx, dy)/2f; + for(int i=0; i < mItems.getTotalItemNums(); i++) { + if(i-1 == mPosition && mPositionOffset > 0f) { + drawDot(canvas, (i + 1) * dx, y, radius + radius * mPositionOffset, mItems.isChosen(i)); + } else if(i+1 == mPosition && mPositionOffset < 0f) { + drawDot(canvas, (i + 1) * dx, y, radius - radius*mPositionOffset, mItems.isChosen(i)); + } else if(i == mPosition) { + drawDot(canvas, (i + 1) * dx, y, radius + radius * (1 - Math.abs(mPositionOffset)), mItems.isChosen(i)); + } else { + drawDot(canvas, (i + 1) * dx, y, radius, mItems.isChosen(i)); + } + } + } + + private void drawDot(Canvas canvas, float cx, float cy, float radius, boolean isChosen) { + if(isChosen) { + mTargetPaint.setStyle(Paint.Style.FILL_AND_STROKE); + canvas.drawCircle(cx, cy, radius, mTargetPaint); + } else { + mTargetPaint.setStyle(Paint.Style.STROKE); + canvas.drawCircle(cx, cy, radius, mTargetPaint); + } + } +} diff --git a/src/com/android/camera/ui/DotsViewItem.java b/src/com/android/camera/ui/DotsViewItem.java new file mode 100644 index 000000000..eb342938c --- /dev/null +++ b/src/com/android/camera/ui/DotsViewItem.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.camera.ui; + +public interface DotsViewItem { + int getTotalItemNums(); + boolean isChosen(int index); +} |