summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLikai Ding <likaid@codeaurora.org>2014-12-10 18:09:27 +0800
committerGerrit - the friendly Code Review server <code-review@localhost>2015-01-14 02:10:45 -0800
commit762b4350b731e1c2189c871dc77627df2be87549 (patch)
tree53c044e25c0c270b98bef785a86b74d04a00149d
parentee168be7e40e15c1921b32f6b863ad3843c91bfd (diff)
downloadandroid_packages_apps_Snap-762b4350b731e1c2189c871dc77627df2be87549.tar.gz
android_packages_apps_Snap-762b4350b731e1c2189c871dc77627df2be87549.tar.bz2
android_packages_apps_Snap-762b4350b731e1c2189c871dc77627df2be87549.zip
SnapdragonCamera: implement refocus feature
Add a scene mode for refocus. If the latest photo is taken with refocus, user can click on the preview thumbnail, then refocus it by tapping on the photo. Change-Id: I2fd69439467f5a1e33d23d8d239aa3472d88b585
-rw-r--r--AndroidManifest.xml5
-rw-r--r--res/drawable-xxhdpi/ic_refocus_editor_cancel.pngbin0 -> 1744 bytes
-rw-r--r--res/drawable-xxhdpi/ic_refocus_editor_confirm.pngbin0 -> 1566 bytes
-rw-r--r--res/drawable-xxhdpi/ic_scene_mode_refocus.pngbin0 -> 13604 bytes
-rw-r--r--res/layout/refocus_editor.xml68
-rw-r--r--res/raw/camera_click_x5.oggbin0 -> 21306 bytes
-rw-r--r--res/values/arrays.xml3
-rw-r--r--res/values/qcomstrings.xml4
-rw-r--r--res/values/strings.xml4
-rw-r--r--src/com/android/camera/CameraActivity.java9
-rw-r--r--src/com/android/camera/CameraSettings.java14
-rw-r--r--src/com/android/camera/PhotoMenu.java11
-rw-r--r--src/com/android/camera/PhotoModule.java59
-rw-r--r--src/com/android/camera/PhotoUI.java5
-rw-r--r--src/com/android/camera/RefocusActivity.java249
-rw-r--r--src/com/android/camera/ui/CameraControls.java106
16 files changed, 522 insertions, 15 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c827e6013..aa7db4e4c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -157,6 +157,11 @@
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
+ <activity
+ android:name="com.android.camera.RefocusActivity"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ </activity>
+
<receiver android:name="com.android.camera.DisableCameraReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
diff --git a/res/drawable-xxhdpi/ic_refocus_editor_cancel.png b/res/drawable-xxhdpi/ic_refocus_editor_cancel.png
new file mode 100644
index 000000000..e58839ddd
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_refocus_editor_cancel.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_refocus_editor_confirm.png b/res/drawable-xxhdpi/ic_refocus_editor_confirm.png
new file mode 100644
index 000000000..9e4dd5e6f
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_refocus_editor_confirm.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_scene_mode_refocus.png b/res/drawable-xxhdpi/ic_scene_mode_refocus.png
new file mode 100644
index 000000000..1bfab604b
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_scene_mode_refocus.png
Binary files differ
diff --git a/res/layout/refocus_editor.xml b/res/layout/refocus_editor.xml
new file mode 100644
index 000000000..c4b42bb4c
--- /dev/null
+++ b/res/layout/refocus_editor.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2015, 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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/refocus_image"
+ android:adjustViewBounds="true"
+ android:scaleType="fitXY"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#80000000">
+
+ <ImageView
+ android:id="@+id/refocus_cancel"
+ android:src="@drawable/ic_refocus_editor_cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true" />
+ <TextView
+ android:id="@+id/refocus_all"
+ android:text="@string/all_in_focus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"
+ android:onClick="allInFocus" />
+ <ImageView
+ android:id="@+id/refocus_done"
+ android:src="@drawable/ic_refocus_editor_confirm"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true" />
+ </RelativeLayout>
+</FrameLayout>
diff --git a/res/raw/camera_click_x5.ogg b/res/raw/camera_click_x5.ogg
new file mode 100644
index 000000000..542432fd7
--- /dev/null
+++ b/res/raw/camera_click_x5.ogg
Binary files differ
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 581146cc6..bb87126b2 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -397,6 +397,7 @@
<!-- Camera Preferences Scene Mode dialog box entries -->
<string-array name="pref_camera_scenemode_entries" translatable="false">
<item>@string/pref_camera_scenemode_entry_auto</item>
+ <item>@string/pref_camera_scenemode_entry_refocus</item>
<!-- <item>@string/pref_camera_scenemode_entry_portrait</item> -->
<item>@string/pref_camera_scenemode_entry_landscape</item>
<item>@string/pref_camera_scenemode_entry_sports</item>
@@ -411,6 +412,7 @@
<array name="scenemode_thumbnails" translatable="false">
<item>@drawable/ic_scene_mode_auto</item>
+ <item>@drawable/ic_scene_mode_refocus</item>
<!-- <item>@drawable/ic_scene_mode_portrait</item> -->
<item>@drawable/ic_scene_mode_landscape</item>
<item>@drawable/ic_scene_mode_sports</item>
@@ -441,6 +443,7 @@
<string-array name="pref_camera_scenemode_entryvalues" translatable="false">
<item>auto</item>
+ <item>@string/pref_camera_advanced_feature_value_refocus_on</item>
<!-- <item>portrait</item> -->
<item>landscape</item>
<item>sports</item>
diff --git a/res/values/qcomstrings.xml b/res/values/qcomstrings.xml
index 77a905ae3..6ba2af63f 100644
--- a/res/values/qcomstrings.xml
+++ b/res/values/qcomstrings.xml
@@ -1,5 +1,5 @@
<!--
- Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Not a Contribution.
@@ -865,5 +865,7 @@
<!-- The alas of CameraActivity for gesture operation -->
<string name="camera_gesture_title">Launch camera</string>
+
+ <string name="all_in_focus">All in Focus</string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0ad549a41..33597b74b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -396,6 +396,8 @@
<string name="pref_camera_scenemode_entry_sunset">Sunset</string>
<!-- Scene mode optimized for taking indoor low-lights pictures. [CHAR LIMIT=16] -->
<string name="pref_camera_scenemode_entry_party">Party</string>
+ <!-- Scene mode for refocus feature [CHAR LIMIT=16] -->
+ <string name="pref_camera_scenemode_entry_refocus">Macro+</string>
<!-- Settings menu, scene mode labels [CHAR LIMIT=50] -->
<string name="pref_camera_scenemode_label_auto">NONE</string>
@@ -714,4 +716,6 @@ CHAR LIMIT = NONE] -->
<string name="pref_camera_video_rotation_label_270">270</string>
<string name="remaining_photos_format">%d left</string>
+
+ <string name="refocus_toast">To re-focus last photo, tap here</string>
</resources>
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index d460867a6..849dc33e3 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -527,6 +527,15 @@ public class CameraActivity extends Activity
if (img == null)
return;
Uri uri = img.getContentUri();
+ if (mCurrentModule instanceof PhotoModule) {
+ if (((PhotoModule) mCurrentModule).isRefocus()) {
+ Intent intent = new Intent();
+ intent.setClass(this, RefocusActivity.class);
+ intent.setData(uri);
+ startActivity(intent);
+ return;
+ }
+ }
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index 37fc39718..63581b8ba 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -769,9 +769,19 @@ public class CameraSettings {
filterUnsupportedOptions(group,
whiteBalance, mParameters.getSupportedWhiteBalance());
}
+
if (sceneMode != null) {
- filterUnsupportedOptions(group,
- sceneMode, mParameters.getSupportedSceneModes());
+ List<String> supportedSceneModes = mParameters.getSupportedSceneModes();
+ List<String> supportedAdvancedFeatures =
+ getSupportedAdvancedFeatures(mParameters);
+ if (CameraUtil.isSupported(
+ mContext.getString(R.string
+ .pref_camera_advanced_feature_value_refocus_on),
+ supportedAdvancedFeatures)) {
+ supportedSceneModes.add(mContext.getString(R.string
+ .pref_camera_advanced_feature_value_refocus_on));
+ }
+ filterUnsupportedOptions(group, sceneMode, supportedSceneModes);
}
if (flashMode != null) {
filterUnsupportedOptions(group,
diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java
index 1aea279a3..b7c126f36 100644
--- a/src/com/android/camera/PhotoMenu.java
+++ b/src/com/android/camera/PhotoMenu.java
@@ -1097,6 +1097,17 @@ public class PhotoMenu extends MenuController
}
}
+ String refocusOn = mActivity.getString(R.string
+ .pref_camera_advanced_feature_value_refocus_on);
+ if (notSame(pref, CameraSettings.KEY_SCENE_MODE, refocusOn)) {
+ ListPreference lp = mPreferenceGroup
+ .findPreference(CameraSettings.KEY_ADVANCED_FEATURES);
+ if (lp != null && refocusOn.equals(lp.getValue())) {
+ setPreference(CameraSettings.KEY_ADVANCED_FEATURES,
+ mActivity.getString(R.string.pref_camera_advanced_feature_default));
+ }
+ }
+
if (notSame(pref, CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO)) {
buttonSetEnabled(mFilterModeSwitcher, false);
} else {
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 1e238be80..0e97889f5 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -35,7 +35,9 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
+import android.media.AudioManager;
import android.media.CameraProfile;
+import android.media.SoundPool;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -192,6 +194,7 @@ public class PhotoModule
private boolean mTouchAfAecFlag;
private boolean mLongshotSave = false;
private boolean mRefocus = false;
+ private boolean mLastPhotoTakenWithRefocus = false;
// The degrees of the device rotated clockwise from its natural orientation.
private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
@@ -253,6 +256,9 @@ public class PhotoModule
// when the image is ready to be saved.
private NamedImages mNamedImages;
+ private SoundPool mSoundPool;
+ private int mRefocusSound;
+
private Runnable mDoSnapRunnable = new Runnable() {
@Override
public void run() {
@@ -558,6 +564,8 @@ public class PhotoModule
mAm.getMemoryInfo(memInfo);
SECONDARY_SERVER_MEM = memInfo.secondaryServerThreshold;
+ mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
+ mRefocusSound = mSoundPool.load(mActivity, R.raw.camera_click_x5, 1);
}
private void initializeControlByIntent() {
@@ -1028,6 +1036,9 @@ public class PhotoModule
}
});
}
+ if (mRefocus) {
+ mSoundPool.play(mRefocusSound, 1.0f, 1.0f, 0, 0, 1.0f);
+ }
}
}
private final class StatsCallback
@@ -1243,7 +1254,20 @@ public class PhotoModule
}
startFaceDetection();
}
- if ((mRefocus) && (mReceivedSnapNum == 6)) {
+
+ mLastPhotoTakenWithRefocus = mRefocus;
+ if (mRefocus) {
+ final String[] NAMES = { "00.jpg", "01.jpg", "02.jpg", "03.jpg",
+ "04.jpg", "DepthMapImage.y", "AllFocusImage.jpg" };
+ try {
+ FileOutputStream out = mActivity.openFileOutput(NAMES[mReceivedSnapNum - 1],
+ Context.MODE_PRIVATE);
+ out.write(jpegData, 0, jpegData.length);
+ out.close();
+ } catch (Exception e) {
+ }
+ }
+ if (mRefocus && (mReceivedSnapNum == 7)) {
Size s = mParameters.getPictureSize();
mNamedImages.nameNewImage(mCaptureStartTime, mRefocus);
NamedEntity name = mNamedImages.getNextNameEntity();
@@ -1259,9 +1283,9 @@ public class PhotoModule
}
mActivity.getMediaSaveService().addImage(
jpegData, title, date, mLocation, s.width, s.height,
- 0, null, mOnMediaSavedListener, mContentResolver, ".jpeg");
-
- } else {
+ 0, null, mOnMediaSavedListener, mContentResolver, PIXEL_FORMAT_JPEG);
+ mUI.showRefocusToast(mRefocus);
+ } else if (!mRefocus) {
ExifInterface exif = Exif.getExif(jpegData);
int orientation = Exif.getOrientation(exif);
if (!mIsImageCaptureIntent) {
@@ -1604,6 +1628,7 @@ public class PhotoModule
new JpegPictureCallback(loc));
}
} else {
+ mCameraDevice.enableShutterSound(!mRefocus);
mCameraDevice.takePicture(mHandler,
new ShutterCallback(!animateBefore),
mRawPictureCallback, mPostViewPictureCallback,
@@ -1763,9 +1788,7 @@ public class PhotoModule
} else {
mUI.overrideSettings(CameraSettings.KEY_PICTURE_FORMAT, null);
}
- if ((ubiFocus != null && ubiFocus.equals(ubiFocusOn)) ||
- (multiTouchFocus != null && multiTouchFocus.equals(multiTouchFocusOn)) ||
- (reFocus != null && reFocus.equals(reFocusOn)) ||
+ if ((multiTouchFocus != null && multiTouchFocus.equals(multiTouchFocusOn)) ||
(chromaFlash != null && chromaFlash.equals(chromaFlashOn)) ||
(optiZoom != null && optiZoom.equals(optiZoomOn)) ||
(fssr != null && fssr.equals(fssrOn)) ||
@@ -3472,6 +3495,10 @@ public class PhotoModule
mActivity.getString(R.string.pref_camera_scenemode_default));
}
}
+
+ String refocusOn = mActivity.getString(R.string
+ .pref_camera_advanced_feature_value_refocus_on);
+
if (CameraUtil.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) {
if (!mParameters.getSceneMode().equals(mSceneMode)) {
mParameters.setSceneMode(mSceneMode);
@@ -3483,9 +3510,16 @@ public class PhotoModule
mParameters = mCameraDevice.getParameters();
}
} else {
- mSceneMode = mParameters.getSceneMode();
- if (mSceneMode == null) {
- mSceneMode = Parameters.SCENE_MODE_AUTO;
+ if (refocusOn.equals(mSceneMode)) {
+ try {
+ mUI.setPreference(CameraSettings.KEY_ADVANCED_FEATURES, refocusOn);
+ } catch (NullPointerException e) {
+ }
+ } else {
+ mSceneMode = mParameters.getSceneMode();
+ if (mSceneMode == null) {
+ mSceneMode = Parameters.SCENE_MODE_AUTO;
+ }
}
}
@@ -4423,6 +4457,10 @@ public class PhotoModule
}
}
}
+
+ public boolean isRefocus() {
+ return mLastPhotoTakenWithRefocus;
+ }
}
/* Below is no longer needed, except to get rid of compile error
@@ -4600,5 +4638,4 @@ class DrawAutoHDR extends View{
public void setPhotoModuleObject (PhotoModule photoModule) {
mPhotoModule = photoModule;
}
-
}
diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java
index b4e08c398..86be3165d 100644
--- a/src/com/android/camera/PhotoUI.java
+++ b/src/com/android/camera/PhotoUI.java
@@ -529,6 +529,10 @@ public class PhotoUI implements PieListener,
task.execute();
}
+ public void showRefocusToast(boolean show) {
+ mCameraControls.showRefocusToast(show);
+ }
+
private void openMenu() {
if (mPieRenderer != null) {
// If autofocus is not finished, cancel autofocus so that the
@@ -962,6 +966,7 @@ public class PhotoUI implements PieListener,
ret = true;
}
onShowSwitcherPopup();
+ mCameraControls.showRefocusToast(false);
return ret;
}
diff --git a/src/com/android/camera/RefocusActivity.java b/src/com/android/camera/RefocusActivity.java
new file mode 100644
index 000000000..2102d1a78
--- /dev/null
+++ b/src/com/android/camera/RefocusActivity.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2015, 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 java.io.File;
+import java.io.FileInputStream;
+import java.io.OutputStream;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Build;
+import android.view.Display;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.ImageView;
+
+import org.codeaurora.snapcam.R;
+
+public class RefocusActivity extends Activity {
+ private static final String TAG = "RefocusActivity";
+ private static final String[] NAMES = {
+ "00", "01", "02", "03", "04", "AllFocusImage"
+ };
+
+ private Uri mUri;
+
+ private ImageView mImageView;
+ private int mWidth;
+ private int mHeight;
+
+ private DepthMap mDepthMap;
+ private int mCurrentImage = -1;
+ private int mRequestedImage = -1;
+ private LoadImageTask mLoadImageTask;
+
+ @Override
+ public void onCreate(Bundle state) {
+ super.onCreate(state);
+
+ new Thread(new Runnable() {
+ public void run() {
+ mDepthMap = new DepthMap(getFilesDir() + "/DepthMapImage.y");
+ }
+ }).start();
+
+ mUri = getIntent().getData();
+ setResult(RESULT_CANCELED, new Intent());
+
+ setContentView(R.layout.refocus_editor);
+ mImageView = (ImageView) findViewById(R.id.refocus_image);
+ mImageView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_UP:
+ float x = event.getX();
+ float y = event.getY();
+ int w = v.getWidth();
+ int h = v.getHeight();
+ if (mDepthMap != null) {
+ int depth = mDepthMap.getDepth(x / (float) w, y / (float) h);
+ setCurrentImage(depth);
+ }
+ break;
+ }
+ return true;
+ }
+ });
+
+ findViewById(R.id.refocus_all).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ allInFocus();
+ }
+ });
+
+ findViewById(R.id.refocus_cancel).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ finish();
+ }
+ });
+
+ findViewById(R.id.refocus_done).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ if (mRequestedImage != NAMES.length - 1) {
+ new SaveImageTask().execute(getFilesDir() + "/" + NAMES[mRequestedImage]
+ + ".jpg");
+ } else {
+ finish();
+ }
+ }
+ });
+
+ Display display = getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ mWidth = size.x;
+ mHeight = size.y;
+
+ allInFocus();
+ }
+
+ private void setCurrentImage(int depth) {
+ if (depth >= 0 && depth < NAMES.length && depth != mRequestedImage) {
+ mRequestedImage = depth;
+ if (mLoadImageTask != null) {
+ mLoadImageTask.cancel(true);
+ }
+ if (depth != mCurrentImage) {
+ mCurrentImage = depth;
+ mLoadImageTask = new LoadImageTask();
+ mLoadImageTask.execute(getFilesDir() + "/" + NAMES[depth] + ".jpg");
+ }
+ }
+ }
+
+ private void allInFocus() {
+ setCurrentImage(NAMES.length - 1);
+ }
+
+ private class SaveImageTask extends AsyncTask<String, Void, Void> {
+ protected Void doInBackground(String... path) {
+ try {
+ OutputStream out = getContentResolver().openOutputStream(mUri);
+ 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) {
+ }
+ Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, mUri);
+ sendBroadcast(intent);
+ return null;
+ }
+
+ protected void onPostExecute(Void v) {
+ finish();
+ }
+ }
+
+ private class LoadImageTask extends AsyncTask<String, Void, Bitmap> {
+ protected Bitmap doInBackground(String... path) {
+ final BitmapFactory.Options o = new BitmapFactory.Options();
+ o.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(path[0], o);
+
+ 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;
+ return BitmapFactory.decodeFile(path[0], o);
+ }
+
+ protected void onPostExecute(Bitmap result) {
+ mImageView.setImageBitmap(result);
+ }
+ }
+
+ private class DepthMap {
+ private byte[] mData;
+ private int mWidth;
+ private int mHeight;
+ private boolean mFail = true;
+
+ public DepthMap(final String path) {
+ File file = new File(path);
+ try {
+ FileInputStream stream = new FileInputStream(file);
+ mData = new byte[(int) file.length()];
+ stream.read(mData);
+ stream.close();
+ } catch (Exception e) {
+ }
+
+ int length = (int) mData.length;
+ if (length > 25) {
+ mFail = (mData[length - 25] != 0);
+ mWidth = readInteger(length - 24);
+ mHeight = readInteger(length - 20);
+ }
+ if (mWidth * mHeight + 25 > length) {
+ mFail = true;
+ }
+ }
+
+ public int getDepth(float x, float y) {
+ if (mFail || x > 1.0f || y > 1.0f) {
+ return NAMES.length - 1;
+ } else {
+ return mData[(int) ((y * mHeight + x) * mWidth)];
+ }
+ }
+
+ private int readInteger(int offset) {
+ int result = mData[offset] & 0xff;
+ for (int i = 1; i < 4; ++i) {
+ result <<= 8;
+ result += mData[offset + i] & 0xff;
+ }
+ return result;
+ }
+ }
+}
diff --git a/src/com/android/camera/ui/CameraControls.java b/src/com/android/camera/ui/CameraControls.java
index c2c33e785..bb3d80c8d 100644
--- a/src/com/android/camera/ui/CameraControls.java
+++ b/src/com/android/camera/ui/CameraControls.java
@@ -19,13 +19,18 @@ package com.android.camera.ui;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.content.Context;
-import android.util.Log;
+import android.graphics.Canvas;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.Paint;
+import android.graphics.Path;
import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -50,6 +55,8 @@ public class CameraControls extends RotatableLayout {
private View mPreview;
private View mSceneModeSwitcher;
private View mFilterModeSwitcher;
+ private ArrowTextView mRefocusToast;
+
private int mSize;
private static final int WIDTH_GRID = 5;
private static final int HEIGHT_GRID = 7;
@@ -152,8 +159,15 @@ public class CameraControls extends RotatableLayout {
public CameraControls(Context context, AttributeSet attrs) {
super(context, attrs);
+
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
setWillNotDraw(false);
+
+ mRefocusToast = new ArrowTextView(context);
+ addView(mRefocusToast);
+ setClipChildren(false);
+
+ setMeasureAllChildren(true);
}
public CameraControls(Context context) {
@@ -291,6 +305,46 @@ public class CameraControls extends RotatableLayout {
toIndex(mHdrSwitcher, w, h, rotation, 3, 0, HDR_INDEX);
toIndex(mFilterModeSwitcher, w, h, rotation, 1, 0, FILTER_MODE_INDEX);
toIndex(mSceneModeSwitcher, w, h, rotation, 0, 0, SCENE_MODE_INDEX);
+ layoutToast(mRefocusToast, w, h, rotation);
+ }
+
+ private void layoutToast(final View v, int w, int h, int rotation) {
+ int tw = v.getMeasuredWidth();
+ int th = v.getMeasuredHeight();
+ int l, t, r, b, c;
+ switch (rotation) {
+ case 90:
+ c = (int) (h / WIDTH_GRID * (WIDTH_GRID - 0.5));
+ t = c - th / 2;
+ b = c + th / 2;
+ r = (int) (w / HEIGHT_GRID * (HEIGHT_GRID - 1.25));
+ l = r - tw;
+ mRefocusToast.setArrow(tw, th / 2, tw + th / 2, th, tw, th);
+ break;
+ case 180:
+ t = (int) (h / HEIGHT_GRID * 1.25);
+ b = t + th;
+ r = (int) (w / WIDTH_GRID * (WIDTH_GRID - 0.25));
+ l = r - tw;
+ mRefocusToast.setArrow(tw - th / 2, 0, tw, 0, tw, - th / 2);
+ break;
+ case 270:
+ c = (int) (h / WIDTH_GRID * 0.5);
+ t = c - th / 2;
+ b = c + th / 2;
+ l = (int) (w / HEIGHT_GRID * 1.25);
+ r = l + tw;
+ mRefocusToast.setArrow(0, 0, 0, th / 2, - th / 2, 0);
+ break;
+ default:
+ l = w / WIDTH_GRID / 4;
+ b = (int) (h / HEIGHT_GRID * (HEIGHT_GRID - 1.25));
+ r = l + tw;
+ t = b - th;
+ mRefocusToast.setArrow(0, th, th / 2, th, 0, th * 3 / 2);
+ break;
+ }
+ mRefocusToast.layout(l, t, r, b);
}
private void center(View v, int l, int t, int r, int b, int orientation, int rotation,
@@ -430,6 +484,7 @@ public class CameraControls extends RotatableLayout {
break;
}
mRemainingPhotos.setVisibility(View.INVISIBLE);
+ mRefocusToast.setVisibility(View.GONE);
}
public void showUI() {
@@ -520,6 +575,7 @@ public class CameraControls extends RotatableLayout {
if (mRemainingPhotos.getVisibility() == View.INVISIBLE) {
mRemainingPhotos.setVisibility(View.VISIBLE);
}
+ mRefocusToast.setVisibility(View.GONE);
}
private void center(View v, Rect other, int rotation) {
@@ -765,4 +821,52 @@ public class CameraControls extends RotatableLayout {
}
invalidate();
}
+
+ public void showRefocusToast(boolean show) {
+ mRefocusToast.setVisibility(show ? View.VISIBLE : View.GONE);
+ mRemainingPhotos.setVisibility(show ? View.GONE : View.VISIBLE);
+ }
+
+ private class ArrowTextView extends TextView {
+ private static final int TEXT_SIZE = 14;
+ private static final int PADDING_SIZE = 18;
+ private static final int BACKGROUND = 0x80000000;
+
+ private Paint mPaint;
+ private Path mPath;
+
+ public ArrowTextView(Context context) {
+ super(context);
+
+ setText(context.getString(R.string.refocus_toast));
+ setBackgroundColor(BACKGROUND);
+ setVisibility(View.GONE);
+ setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ setTextSize(TEXT_SIZE);
+ setPadding(PADDING_SIZE, PADDING_SIZE, PADDING_SIZE, PADDING_SIZE);
+
+ mPaint = new Paint();
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setColor(BACKGROUND);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mPath != null) {
+ canvas.drawPath(mPath, mPaint);
+ }
+ }
+
+ public void setArrow(float x1, float y1, float x2, float y2, float x3, float y3) {
+ mPath = new Path();
+ mPath.reset();
+ mPath.moveTo(x1, y1);
+ mPath.lineTo(x2, y2);
+ mPath.lineTo(x3, y3);
+ mPath.lineTo(x1, y1);
+ }
+ }
}