diff options
32 files changed, 974 insertions, 291 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bf13fac83..9ff2d16fc 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -93,18 +93,6 @@ </intent-filter> </activity-alias> - <activity-alias - android:name="com.android.camera.CameraGestureActivity" - android:icon="@mipmap/ic_launcher_camera" - android:label="@string/camera_gesture_title" - android:targetActivity="com.android.camera.CameraActivity"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity-alias> - <!-- Video camera and capture use the Camcorder label and icon. --> <activity-alias android:name="com.android.camera.VideoCamera" @@ -150,6 +138,17 @@ android:resource="@layout/keyguard_widget" /> </activity> + <activity-alias + android:name="com.android.camera.CameraGestureActivity" + android:icon="@mipmap/ic_launcher_camera" + android:label="@string/camera_gesture_title" + android:targetActivity="com.android.camera.SecureCameraActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity-alias> + <activity android:name="com.android.camera.crop.CropActivity" android:label="@string/crop_action" @@ -157,6 +156,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/jni/feature_mos/src/mosaic_renderer/Renderer.cpp b/jni/feature_mos/src/mosaic_renderer/Renderer.cpp index 8d0632402..b9938eb6b 100644..100755 --- a/jni/feature_mos/src/mosaic_renderer/Renderer.cpp +++ b/jni/feature_mos/src/mosaic_renderer/Renderer.cpp @@ -111,8 +111,8 @@ GLuint Renderer::createProgram(const char* pVertexSource, const char* pFragmentS } // Set this renderer to use the default frame-buffer (screen) and -// set the viewport size to be the given x, y, width and height (pixels). -bool Renderer::SetupGraphics(int x, int y, int width, int height) +// set the viewport size to be the given width and height (pixels). +bool Renderer::SetupGraphics(int width, int height) { bool succeeded = false; do { @@ -131,10 +131,8 @@ bool Renderer::SetupGraphics(int x, int y, int width, int height) mFrameBuffer = NULL; mSurfaceWidth = width; mSurfaceHeight = height; - mSurfaceXOffset = x; - mSurfaceYOffset = y; - glViewport(mSurfaceXOffset, mSurfaceYOffset, mSurfaceWidth, mSurfaceHeight); + glViewport(0, 0, mSurfaceWidth, mSurfaceHeight); if (!checkGlError("glViewport")) break; succeeded = true; } while (false); @@ -178,7 +176,7 @@ bool Renderer::Clear(float r, float g, float b, float a) bool succeeded = false; do { bool rt = (mFrameBuffer == NULL)? - SetupGraphics(mSurfaceXOffset, mSurfaceYOffset, mSurfaceWidth, mSurfaceHeight) : + SetupGraphics(mSurfaceWidth, mSurfaceHeight) : SetupGraphics(mFrameBuffer); if(!rt) diff --git a/jni/feature_mos/src/mosaic_renderer/Renderer.h b/jni/feature_mos/src/mosaic_renderer/Renderer.h index ffb9cbd25..a43e8028e 100644..100755 --- a/jni/feature_mos/src/mosaic_renderer/Renderer.h +++ b/jni/feature_mos/src/mosaic_renderer/Renderer.h @@ -18,7 +18,7 @@ class Renderer { virtual bool InitializeGLProgram() = 0; bool SetupGraphics(FrameBuffer* buffer); - bool SetupGraphics(int x, int y, int width, int height); + bool SetupGraphics(int width, int height); bool Clear(float r, float g, float b, float a); @@ -59,8 +59,6 @@ class Renderer { int mSurfaceWidth; // Width of target surface. int mSurfaceHeight; // Height of target surface. - int mSurfaceXOffset; // X Offset target surface. - int mSurfaceYOffset; // Y Offset of target surface. FrameBuffer *mFrameBuffer; }; diff --git a/jni/feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp b/jni/feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp index 4725463f2..88aac3626 100644..100755 --- a/jni/feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp +++ b/jni/feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp @@ -119,7 +119,7 @@ bool SurfaceTextureRenderer::DrawTexture(GLfloat *affine) bool succeeded = false; do { bool rt = (mFrameBuffer == NULL)? - SetupGraphics(mSurfaceXOffset, mSurfaceYOffset, mSurfaceWidth, mSurfaceHeight) : + SetupGraphics(mSurfaceWidth, mSurfaceHeight) : SetupGraphics(mFrameBuffer); if(!rt) diff --git a/jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp b/jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp index c030ce25e..af6779a3f 100644..100755 --- a/jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp +++ b/jni/feature_mos/src/mosaic_renderer/WarpRenderer.cpp @@ -110,7 +110,7 @@ bool WarpRenderer::DrawTexture(GLfloat *affine) bool succeeded = false; do { bool rt = (mFrameBuffer == NULL)? - SetupGraphics(mSurfaceXOffset, mSurfaceYOffset, mSurfaceWidth, mSurfaceHeight) : + SetupGraphics(mSurfaceWidth, mSurfaceHeight) : SetupGraphics(mFrameBuffer); if(!rt) diff --git a/jni/feature_mos/src/mosaic_renderer/YVURenderer.cpp b/jni/feature_mos/src/mosaic_renderer/YVURenderer.cpp index b30e6f7b6..f7dcf6f61 100644..100755 --- a/jni/feature_mos/src/mosaic_renderer/YVURenderer.cpp +++ b/jni/feature_mos/src/mosaic_renderer/YVURenderer.cpp @@ -79,7 +79,7 @@ bool YVURenderer::DrawTexture() bool succeeded = false; do { bool rt = (mFrameBuffer == NULL)? - SetupGraphics(mSurfaceXOffset, mSurfaceYOffset, mSurfaceWidth, mSurfaceHeight) : + SetupGraphics(mSurfaceWidth, mSurfaceHeight) : SetupGraphics(mFrameBuffer); if(!rt) diff --git a/jni/mosaic_renderer_jni.cpp b/jni/mosaic_renderer_jni.cpp index f35599375..36f8064c7 100644 --- a/jni/mosaic_renderer_jni.cpp +++ b/jni/mosaic_renderer_jni.cpp @@ -27,7 +27,6 @@ #include "mosaic_renderer/SurfaceTextureRenderer.h" #include "mosaic_renderer/YVURenderer.h" - #include "mosaic/Log.h" #define LOG_TAG "MosaicRenderer" @@ -37,7 +36,6 @@ GLuint gSurfaceTextureID[1]; bool gWarpImage = true; -bool gPreviewBackgroundImage = true; // Low-Res input image frame in YUVA format for preview rendering and processing // and high-res YUVA input image for processing. @@ -89,9 +87,6 @@ FrameBuffer gBuffer[2]; // Shader to warp and render the preview FBO to the screen WarpRenderer gPreview; -// Shader to render the fullscreen preview background FBO to the screen -WarpRenderer gPreviewBackground; - // Index of the gBuffer FBO gWarper1 is going to write into int gCurrentFBOIndex = 0; @@ -145,12 +140,6 @@ double g_dAffinetransPan[16]; GLfloat g_dTranslationToFBOCenterGL[16]; double g_dTranslationToFBOCenter[16]; - - - - - - // GL 4x4 Identity transformation GLfloat g_dAffinetransIdentGL[] = { 1., 0., 0., 0., @@ -326,8 +315,8 @@ void UpdateWarpTransformation(float *trs) // Alignment is done based on low-res data. // To render the preview mosaic, the translation of the high-res mosaic is estimated to // H2L_FACTOR x low-res-based tranlation. - //gThisH1t[2] *= H2L_FACTOR; - //gThisH1t[5] *= H2L_FACTOR; + gThisH1t[2] *= H2L_FACTOR; + gThisH1t[5] *= H2L_FACTOR; db_Identity3x3(T); T[2] = -gCenterOffsetX; @@ -379,7 +368,6 @@ void UpdateWarpTransformation(float *trs) db_Identity3x3(H); H[2] = gPanOffset; - // Hp = inv(Km) * H * Km db_Identity3x3(Htemp1); db_Multiply3x3_3x3(Htemp1, H, gKm); @@ -409,13 +397,13 @@ void AllocateTextureMemory(int widthHR, int heightHR, int widthLR, int heightLR) gPreviewImageHeight[HR], 4); sem_post(&gPreviewImage_semaphore); - gPreviewFBOWidth = PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[LR]; - gPreviewFBOHeight = PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[LR]; + gPreviewFBOWidth = PREVIEW_FBO_WIDTH_SCALE * gPreviewImageWidth[HR]; + gPreviewFBOHeight = PREVIEW_FBO_HEIGHT_SCALE * gPreviewImageHeight[HR]; // The origin is such that the current frame will sit with its center // at the center of the previewFBO - gCenterOffsetX = (gPreviewFBOWidth / 2 - gPreviewImageWidth[LR] / 2); - gCenterOffsetY = (gPreviewFBOHeight / 2 - gPreviewImageHeight[LR] / 2); + gCenterOffsetX = (gPreviewFBOWidth / 2 - gPreviewImageWidth[HR] / 2); + gCenterOffsetY = (gPreviewFBOHeight / 2 - gPreviewImageHeight[HR] / 2); gPanOffset = 0.0f; @@ -424,8 +412,8 @@ void AllocateTextureMemory(int widthHR, int heightHR, int widthLR, int heightLR) gPanViewfinder = true; - int w = gPreviewImageWidth[LR]; - int h = gPreviewImageHeight[LR]; + int w = gPreviewImageWidth[HR]; + int h = gPreviewImageHeight[HR]; int wm = gPreviewFBOWidth; int hm = gPreviewFBOHeight; @@ -505,8 +493,6 @@ extern "C" JNIEnv * env, jobject obj); JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setWarping( JNIEnv * env, jobject obj, jboolean flag); - JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setPreviewBackground( - JNIEnv * env, jobject obj, jboolean flag); }; @@ -538,7 +524,6 @@ JNIEXPORT jint JNICALL Java_com_android_camera_MosaicRenderer_init( gBufferInput[HR].InitializeGLContext(); gBufferInputYVU[LR].InitializeGLContext(); gBufferInputYVU[HR].InitializeGLContext(); - gPreviewBackground.InitializeGLProgram(); glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -563,16 +548,13 @@ void calculateUILayoutScaling(int width, int height, bool isLandscape) { // // Scale the preview FBO's height to the height of view and // maintain the aspect ratio of the current frame on the screen. - gUILayoutScalingY = PREVIEW_FBO_HEIGHT_SCALE; // Note that OpenGL scales a texture to view's width and height automatically. // The "width / height" inverts the scaling, so as to maintain the aspect ratio // of the current frame. - gUILayoutScalingX = ((float) gPreviewFBOWidth / gPreviewFBOHeight) / ((float) width / height) * PREVIEW_FBO_HEIGHT_SCALE; - } else { // ___ // __________ | | ______ @@ -591,10 +573,8 @@ void calculateUILayoutScaling(int width, int height, bool isLandscape) { // Note that OpenGL scales a texture to view's width and height automatically. // The "height / width" inverts the scaling, so as to maintain the aspect ratio // of the current frame. - gUILayoutScalingX = ((float) gPreviewFBOHeight / gPreviewFBOWidth) / ((float) width / height) * PREVIEW_FBO_WIDTH_SCALE; - } } @@ -602,7 +582,7 @@ JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_reset( JNIEnv * env, jobject obj, jint width, jint height, jboolean isLandscapeOrientation) { gIsLandscapeOrientation = isLandscapeOrientation; - calculateUILayoutScaling(gPreviewFBOWidth, gPreviewFBOHeight, gIsLandscapeOrientation); + calculateUILayoutScaling(width, height, gIsLandscapeOrientation); gBuffer[0].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA); gBuffer[1].Init(gPreviewFBOWidth, gPreviewFBOHeight, GL_RGBA); @@ -656,23 +636,20 @@ JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_reset( gWarper1.SetInputTextureName(gBuffer[1 - gCurrentFBOIndex].GetTextureName()); gWarper1.SetInputTextureType(GL_TEXTURE_2D); - // gBufferInput[LR] --> gWarper2 --> gBuffer[gCurrentFBOIndex] + // gBufferInput[HR] --> gWarper2 --> gBuffer[gCurrentFBOIndex] gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]); // gWarp2's destination buffer is the same to gWarp1's. No need to clear it // again. - gWarper2.SetViewportMatrix(gPreviewImageWidth[LR], - gPreviewImageHeight[LR], gBuffer[gCurrentFBOIndex].GetWidth(), + gWarper2.SetViewportMatrix(gPreviewImageWidth[HR], + gPreviewImageHeight[HR], gBuffer[gCurrentFBOIndex].GetWidth(), gBuffer[gCurrentFBOIndex].GetHeight()); gWarper2.SetScalingMatrix(1.0f, 1.0f); - gWarper2.SetInputTextureName(gBufferInput[LR].GetTextureName()); + gWarper2.SetInputTextureName(gBufferInput[HR].GetTextureName()); gWarper2.SetInputTextureType(GL_TEXTURE_2D); - int xoffset = (width/2 - gPreviewFBOWidth/2); - int yoffset = (height/2 - gPreviewFBOHeight/2); - // gBuffer[gCurrentFBOIndex] --> gPreview --> Screen - gPreview.SetupGraphics(xoffset,yoffset,gPreviewFBOWidth, gPreviewFBOHeight); + gPreview.SetupGraphics(width, height); gPreview.SetViewportMatrix(1, 1, 1, 1); // Scale the previewFBO so that the viewfinder window fills the layout height @@ -680,13 +657,6 @@ JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_reset( gPreview.SetScalingMatrix(gUILayoutScalingX, -1.0f * gUILayoutScalingY); gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName()); gPreview.SetInputTextureType(GL_TEXTURE_2D); - - // gBufferInput[HR] --> gPreviewBackground --> screen - gPreviewBackground.SetupGraphics(0,0,width, height); - gPreviewBackground.SetViewportMatrix(1,1,1,1); - gPreviewBackground.SetScalingMatrix(1.0f, -1.0f); - gPreviewBackground.SetInputTextureName(gBufferInput[HR].GetTextureName()); - gPreviewBackground.SetInputTextureType(GL_TEXTURE_2D); } JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_preprocess( @@ -761,18 +731,15 @@ JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_step( { if(!gWarpImage) // ViewFinder { - if (gIsLandscapeOrientation) { - gPreviewBackground.DrawTexture(g_dAffinetransIdentGL); - } else { - gPreviewBackground.DrawTexture(g_dAffinetransRotation90GL); - } - } - else if(gPreviewBackgroundImage) - { + gWarper2.SetupGraphics(&gBuffer[gCurrentFBOIndex]); + gPreview.SetInputTextureName(gBuffer[gCurrentFBOIndex].GetTextureName()); + + gWarper2.DrawTexture(g_dTranslationToFBOCenterGL); + if (gIsLandscapeOrientation) { - gPreviewBackground.DrawTexture(g_dAffinetransIdentGL); + gPreview.DrawTexture(g_dAffinetransIdentGL); } else { - gPreviewBackground.DrawTexture(g_dAffinetransRotation90GL); + gPreview.DrawTexture(g_dAffinetransRotation90GL); } } else @@ -807,7 +774,7 @@ JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setWarping( gWarper1.Clear(0.0, 0.0, 0.0, 1.0); // Clear the screen to black. gPreview.Clear(0.0, 0.0, 0.0, 1.0); - gPreviewBackground.Clear(0.0, 0.0, 0.0, 1.0); + gLastTx = 0.0f; gPanOffset = 0.0f; gPanViewfinder = true; @@ -835,9 +802,3 @@ JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_updateMatrix( g_dTranslationToFBOCenterGL[i] = g_dTranslationToFBOCenter[i]; } } - -JNIEXPORT void JNICALL Java_com_android_camera_MosaicRenderer_setPreviewBackground( - JNIEnv * env, jobject obj, jboolean flag) -{ - gPreviewBackgroundImage = (bool)flag; -} diff --git a/res/drawable-xxhdpi/ic_refocus_editor_cancel.png b/res/drawable-xxhdpi/ic_refocus_editor_cancel.png Binary files differnew file mode 100644 index 000000000..e58839ddd --- /dev/null +++ b/res/drawable-xxhdpi/ic_refocus_editor_cancel.png diff --git a/res/drawable-xxhdpi/ic_refocus_editor_confirm.png b/res/drawable-xxhdpi/ic_refocus_editor_confirm.png Binary files differnew file mode 100644 index 000000000..9e4dd5e6f --- /dev/null +++ b/res/drawable-xxhdpi/ic_refocus_editor_confirm.png diff --git a/res/drawable-xxhdpi/ic_scene_mode_refocus.png b/res/drawable-xxhdpi/ic_scene_mode_refocus.png Binary files differnew file mode 100644 index 000000000..1bfab604b --- /dev/null +++ b/res/drawable-xxhdpi/ic_scene_mode_refocus.png diff --git a/res/layout-land/pano_preview_progress.xml b/res/layout-land/pano_preview_progress.xml index 772b8529e..c6c131741 100644 --- a/res/layout-land/pano_preview_progress.xml +++ b/res/layout-land/pano_preview_progress.xml @@ -14,37 +14,106 @@ limitations under the License. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/panorama_preview_progress" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:layout_gravity="bottom|center_horizontal"> - - <com.android.camera.PanoProgressBar - android:id="@+id/pano_pan_progress_bar" - android:visibility="gone" - android:src="@drawable/ic_pan_progression" - android:layout_centerInParent="true" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <ImageView - android:id="@+id/pano_pan_left_indicator" - android:src="@drawable/pano_direction_left_indicator" - android:visibility="gone" - android:layout_marginRight="5dp" - android:layout_toLeftOf="@id/pano_pan_progress_bar" - android:layout_centerVertical="true" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <ImageView - android:id="@+id/pano_pan_right_indicator" - android:src="@drawable/pano_direction_right_indicator" - android:visibility="gone" - android:layout_marginLeft="5dp" - android:layout_toRightOf="@id/pano_pan_progress_bar" - android:layout_centerVertical="true" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/panorama_capture_layout" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <!-- The top bar with capture indication --> + <FrameLayout + style="@style/PanoViewHorizontalBar" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <TextView + android:id="@+id/pano_capture_indicator" + android:text="@string/pano_capture_indication" + android:textAppearance="?android:textAppearanceMedium" + android:layout_gravity="center" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </FrameLayout> + + <FrameLayout + android:layout_gravity="center" + android:id="@+id/pano_preview_layout" + android:layout_weight="@integer/SRI_pano_layout_weight" + android:layout_width="match_parent" + android:layout_height="0dp"> + + <TextureView + android:id="@+id/pano_preview_textureview" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <View + android:id="@+id/pano_preview_area_border" + android:visibility="gone" + android:background="@drawable/ic_pan_border_fast" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </FrameLayout> + + <!-- The bottom bar with progress bar and direction indicators --> + <FrameLayout + style="@style/PanoViewHorizontalBar" + android:paddingTop="20dp" + android:gravity="top" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.android.camera.PanoProgressBar + android:id="@+id/pano_pan_progress_bar" + android:visibility="gone" + android:src="@drawable/ic_pan_progression" + android:layout_centerInParent="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <ImageView + android:id="@+id/pano_pan_left_indicator" + android:src="@drawable/pano_direction_left_indicator" + android:visibility="gone" + android:layout_marginRight="5dp" + android:layout_toLeftOf="@id/pano_pan_progress_bar" + android:layout_centerVertical="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <ImageView + android:id="@+id/pano_pan_right_indicator" + android:src="@drawable/pano_direction_right_indicator" + android:visibility="gone" + android:layout_marginLeft="5dp" + android:layout_toRightOf="@id/pano_pan_progress_bar" + android:layout_centerVertical="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </RelativeLayout> + </FrameLayout> + + + </LinearLayout> + + <!-- The hint for "Too fast" text view --> + <TextView + android:id="@+id/pano_capture_too_fast_textview" + android:text="@string/pano_too_fast_prompt" + android:textAppearance="?android:textAppearanceMedium" android:layout_width="wrap_content" - android:layout_height="wrap_content" /> -</RelativeLayout> + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone" /> +</FrameLayout> diff --git a/res/layout-port/pano_preview_progress.xml b/res/layout-port/pano_preview_progress.xml index 426ef0ba7..c6c131741 100644 --- a/res/layout-port/pano_preview_progress.xml +++ b/res/layout-port/pano_preview_progress.xml @@ -14,38 +14,106 @@ limitations under the License. --> -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/panorama_preview_progress" - android:layout_height="wrap_content" - android:layout_width="match_parent" - android:layout_gravity="bottom|center_horizontal" - android:layout_marginBottom="100dp"> - - <com.android.camera.PanoProgressBar - android:id="@+id/pano_pan_progress_bar" - android:visibility="gone" - android:src="@drawable/ic_pan_progression" - android:layout_centerInParent="true" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <ImageView - android:id="@+id/pano_pan_left_indicator" - android:src="@drawable/pano_direction_left_indicator" - android:visibility="gone" - android:layout_marginRight="5dp" - android:layout_toLeftOf="@id/pano_pan_progress_bar" - android:layout_centerVertical="true" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <ImageView - android:id="@+id/pano_pan_right_indicator" - android:src="@drawable/pano_direction_right_indicator" - android:visibility="gone" - android:layout_marginLeft="5dp" - android:layout_toRightOf="@id/pano_pan_progress_bar" - android:layout_centerVertical="true" +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/panorama_capture_layout" + android:layout_height="match_parent" + android:layout_width="match_parent"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <!-- The top bar with capture indication --> + <FrameLayout + style="@style/PanoViewHorizontalBar" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <TextView + android:id="@+id/pano_capture_indicator" + android:text="@string/pano_capture_indication" + android:textAppearance="?android:textAppearanceMedium" + android:layout_gravity="center" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </FrameLayout> + + <FrameLayout + android:layout_gravity="center" + android:id="@+id/pano_preview_layout" + android:layout_weight="@integer/SRI_pano_layout_weight" + android:layout_width="match_parent" + android:layout_height="0dp"> + + <TextureView + android:id="@+id/pano_preview_textureview" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <View + android:id="@+id/pano_preview_area_border" + android:visibility="gone" + android:background="@drawable/ic_pan_border_fast" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </FrameLayout> + + <!-- The bottom bar with progress bar and direction indicators --> + <FrameLayout + style="@style/PanoViewHorizontalBar" + android:paddingTop="20dp" + android:gravity="top" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.android.camera.PanoProgressBar + android:id="@+id/pano_pan_progress_bar" + android:visibility="gone" + android:src="@drawable/ic_pan_progression" + android:layout_centerInParent="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <ImageView + android:id="@+id/pano_pan_left_indicator" + android:src="@drawable/pano_direction_left_indicator" + android:visibility="gone" + android:layout_marginRight="5dp" + android:layout_toLeftOf="@id/pano_pan_progress_bar" + android:layout_centerVertical="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <ImageView + android:id="@+id/pano_pan_right_indicator" + android:src="@drawable/pano_direction_right_indicator" + android:visibility="gone" + android:layout_marginLeft="5dp" + android:layout_toRightOf="@id/pano_pan_progress_bar" + android:layout_centerVertical="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </RelativeLayout> + </FrameLayout> + + + </LinearLayout> + + <!-- The hint for "Too fast" text view --> + <TextView + android:id="@+id/pano_capture_too_fast_textview" + android:text="@string/pano_too_fast_prompt" + android:textAppearance="?android:textAppearanceMedium" android:layout_width="wrap_content" - android:layout_height="wrap_content" /> -</RelativeLayout> + android:layout_height="wrap_content" + android:layout_gravity="center" + android:visibility="gone" /> +</FrameLayout> diff --git a/res/layout/pano_module_capture.xml b/res/layout/pano_module_capture.xml index d842ea12c..c6c131741 100644 --- a/res/layout/pano_module_capture.xml +++ b/res/layout/pano_module_capture.xml @@ -19,36 +19,94 @@ android:layout_height="match_parent" android:layout_width="match_parent"> - <FrameLayout - android:layout_gravity="center" - android:id="@+id/pano_preview_layout" - android:layout_weight="@integer/SRI_pano_layout_weight" + <LinearLayout android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:orientation="vertical"> - <TextureView - android:id="@+id/pano_preview_textureview" + <!-- The top bar with capture indication --> + <FrameLayout + style="@style/PanoViewHorizontalBar" android:layout_width="match_parent" - android:layout_height="match_parent" /> + android:layout_height="0dp" + android:layout_weight="1"> + + <TextView + android:id="@+id/pano_capture_indicator" + android:text="@string/pano_capture_indication" + android:textAppearance="?android:textAppearanceMedium" + android:layout_gravity="center" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </FrameLayout> - <View - android:id="@+id/pano_preview_area_border" - android:visibility="gone" - android:background="@drawable/ic_pan_border_fast" + <FrameLayout + android:layout_gravity="center" + android:id="@+id/pano_preview_layout" + android:layout_weight="@integer/SRI_pano_layout_weight" android:layout_width="match_parent" - android:layout_height="match_parent" /> - </FrameLayout> + android:layout_height="0dp"> - <include layout="@layout/pano_preview_progress" /> + <TextureView + android:id="@+id/pano_preview_textureview" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + <View + android:id="@+id/pano_preview_area_border" + android:visibility="gone" + android:background="@drawable/ic_pan_border_fast" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + </FrameLayout> + + <!-- The bottom bar with progress bar and direction indicators --> + <FrameLayout + style="@style/PanoViewHorizontalBar" + android:paddingTop="20dp" + android:gravity="top" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"> + + <RelativeLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <com.android.camera.PanoProgressBar + android:id="@+id/pano_pan_progress_bar" + android:visibility="gone" + android:src="@drawable/ic_pan_progression" + android:layout_centerInParent="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <ImageView + android:id="@+id/pano_pan_left_indicator" + android:src="@drawable/pano_direction_left_indicator" + android:visibility="gone" + android:layout_marginRight="5dp" + android:layout_toLeftOf="@id/pano_pan_progress_bar" + android:layout_centerVertical="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <ImageView + android:id="@+id/pano_pan_right_indicator" + android:src="@drawable/pano_direction_right_indicator" + android:visibility="gone" + android:layout_marginLeft="5dp" + android:layout_toRightOf="@id/pano_pan_progress_bar" + android:layout_centerVertical="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + </RelativeLayout> + </FrameLayout> + + + </LinearLayout> - <TextView - android:id="@+id/pano_capture_indicator" - android:text="@string/pano_capture_indication" - android:textAppearance="?android:textAppearanceMedium" - android:layout_gravity="top|center_horizontal" - android:visibility="gone" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> <!-- The hint for "Too fast" text view --> <TextView android:id="@+id/pano_capture_too_fast_textview" 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 Binary files differnew file mode 100644 index 000000000..542432fd7 --- /dev/null +++ b/res/raw/camera_click_x5.ogg 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 8fd8f9daa..e9786431b 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -49,6 +49,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.SystemProperties; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.provider.Settings; @@ -101,6 +102,8 @@ import java.io.File; import static com.android.camera.CameraManager.CameraOpenErrorCallback; +import android.media.AudioManager; + public class CameraActivity extends Activity implements ModuleSwitcher.ModuleSwitchListener, ActionBar.OnMenuVisibilityListener, @@ -122,6 +125,9 @@ public class CameraActivity extends Activity // panorama. If the extra is not set, it is in the normal camera mode. public static final String SECURE_CAMERA_EXTRA = "secure_camera"; + // This string is used for judge start activity from screenoff or not + public static final String GESTURE_CAMERA_NAME = "com.android.camera.CameraGestureActivity"; + /** * Request code from an activity we started that indicated that we do not * want to reset the view to the preview in onResume. @@ -187,7 +193,6 @@ public class CameraActivity extends Activity private ViewGroup mUndoDeletionBar; private boolean mIsUndoingDeletion = false; private boolean mIsEditActivityInProgress = false; - protected boolean mIsModuleSwitchInProgress = false; private View mPreviewCover; private FrameLayout mPreviewContentLayout; @@ -210,6 +215,10 @@ public class CameraActivity extends Activity public static int SETTING_LIST_WIDTH_2 = 250; private Bitmap mPreviewThumbnailBitmap; + private AudioManager mAudioManager; + private int mShutterVol; + private int mOriginalMasterVol; + private class MyOrientationEventListener extends OrientationEventListener { public MyOrientationEventListener(Context context) { @@ -524,6 +533,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); } @@ -1156,11 +1174,14 @@ public class CameraActivity extends Activity super.onCreate(state); GcamHelper.init(getContentResolver()); + mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + mOriginalMasterVol = mAudioManager.getMasterVolume(); + mShutterVol = SystemProperties.getInt("persist.camera.snapshot.volume", -1); + if (mShutterVol >= 0 && mShutterVol <= 100 ) + mAudioManager.setMasterVolume(mShutterVol,0); + getWindow().requestFeature(Window.FEATURE_ACTION_BAR); setContentView(R.layout.camera_filmstrip); - int flags = WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; - getWindow().addFlags(flags); mActionBar = getActionBar(); mActionBar.addOnMenuVisibilityListener(this); @@ -1174,7 +1195,8 @@ public class CameraActivity extends Activity Intent intent = getIntent(); String action = intent.getAction(); if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action) - || ACTION_IMAGE_CAPTURE_SECURE.equals(action)) { + || ACTION_IMAGE_CAPTURE_SECURE.equals(action) + || intent.getComponent().getClassName().equals(GESTURE_CAMERA_NAME)) { mSecureCamera = true; } else { mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false); @@ -1185,6 +1207,9 @@ public class CameraActivity extends Activity Window win = getWindow(); WindowManager.LayoutParams params = win.getAttributes(); params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; + if (intent.getComponent().getClassName().equals(GESTURE_CAMERA_NAME)) { + params.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; + } win.setAttributes(params); // Filter for screen off so that we can finish secure camera activity @@ -1365,6 +1390,8 @@ public class CameraActivity extends Activity @Override public void onPause() { + if (mShutterVol >= 0 && mShutterVol <= 100) + mAudioManager.setMasterVolume(mOriginalMasterVol,0); // Delete photos that are pending deletion performDeletion(); mOrientationListener.disable(); @@ -1388,6 +1415,8 @@ public class CameraActivity extends Activity @Override public void onResume() { + if (mShutterVol >= 0 && mShutterVol <= 100) + mAudioManager.setMasterVolume(mShutterVol,0); // TODO: Handle this in OrientationManager. // Auto-rotate off if (Settings.System.getInt(getContentResolver(), @@ -1455,6 +1484,8 @@ public class CameraActivity extends Activity @Override public void onDestroy() { + if (mShutterVol >= 0 && mShutterVol <= 100) + mAudioManager.setMasterVolume(mOriginalMasterVol,0); if (mSecureCamera) { unregisterReceiver(mScreenOffReceiver); } @@ -1583,7 +1614,6 @@ public class CameraActivity extends Activity return; } - mIsModuleSwitchInProgress = true; CameraHolder.instance().keep(); closeModule(mCurrentModule); setModuleFromIndex(moduleIndex); @@ -1598,7 +1628,6 @@ public class CameraActivity extends Activity // starts up. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); prefs.edit().putInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, moduleIndex).apply(); - mIsModuleSwitchInProgress = false; } /** 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/MosaicPreviewRenderer.java b/src/com/android/camera/MosaicPreviewRenderer.java index 77c260eb5..42da4d9e7 100644 --- a/src/com/android/camera/MosaicPreviewRenderer.java +++ b/src/com/android/camera/MosaicPreviewRenderer.java @@ -83,13 +83,10 @@ public class MosaicPreviewRenderer { mInputSurfaceTexture.updateTexImage(); mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); - // Call setPreviewBackground to render high-res RGB textures to full screen. - MosaicRenderer.setPreviewBackground(true); - MosaicRenderer.preprocess(mTransformMatrix); - MosaicRenderer.step(); - MosaicRenderer.setPreviewBackground(false); - MosaicRenderer.setWarping(true); + // Call preprocess to render it to low-res and high-res RGB textures. + MosaicRenderer.preprocess(mTransformMatrix); + // Now, transfer the textures from GPU to CPU memory for processing MosaicRenderer.transferGPUtoCPU(); MosaicRenderer.updateMatrix(); MosaicRenderer.step(); diff --git a/src/com/android/camera/MosaicRenderer.java b/src/com/android/camera/MosaicRenderer.java index daf94abe6..92d9cb7b6 100644 --- a/src/com/android/camera/MosaicRenderer.java +++ b/src/com/android/camera/MosaicRenderer.java @@ -86,14 +86,4 @@ public class MosaicRenderer * @param flag boolean flag to set the warping to true or false. */ public static native void setWarping(boolean flag); - /** - * This function allows toggling between drawing the background full - * screen preview image data to screen and drawing the warped smaller - * preview on top of it. To render the full screen background preview, - * we set the falsg to true and to render the warped image on top of this - * we set the flag to false and flag in setWarping to true. - * - * @param flag boolean flag to set the warping to true or false. - */ - public static native void setPreviewBackground(boolean flag); } diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java index 1568c32c0..d10a679b3 100644 --- a/src/com/android/camera/PhotoMenu.java +++ b/src/com/android/camera/PhotoMenu.java @@ -69,7 +69,8 @@ public class PhotoMenu extends MenuController private static final int POPUP_NONE = 0; private static final int POPUP_FIRST_LEVEL = 1; private static final int POPUP_SECOND_LEVEL = 2; - private static final int POPUP_IN_ANIMATION = 3; + private static final int POPUP_IN_ANIMATION_SLIDE = 3; + private static final int POPUP_IN_ANIMATION_FADE = 4; private static final int PREVIEW_MENU_NONE = 0; private static final int PREVIEW_MENU_IN_ANIMATION = 1; private static final int PREVIEW_MENU_ON = 2; @@ -225,9 +226,9 @@ public class PhotoMenu extends MenuController } private void animateFadeOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_FADE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_FADE; ViewPropertyAnimator vp = v.animate(); vp.alpha(0f).setDuration(ANIMATION_DURATION); @@ -274,9 +275,9 @@ public class PhotoMenu extends MenuController } private void animateSlideOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_SLIDE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_SLIDE; ViewPropertyAnimator vp = v.animate(); vp.translationX(v.getX() - v.getWidth()).setDuration(ANIMATION_DURATION); @@ -413,7 +414,9 @@ public class PhotoMenu extends MenuController } public boolean isOverMenu(MotionEvent ev) { - if (mPopupStatus == POPUP_NONE || mPopupStatus == POPUP_IN_ANIMATION) + if (mPopupStatus == POPUP_NONE + || mPopupStatus == POPUP_IN_ANIMATION_SLIDE + || mPopupStatus == POPUP_IN_ANIMATION_FADE) return false; if (mUI.getMenuLayout() == null) return false; @@ -439,7 +442,7 @@ public class PhotoMenu extends MenuController } public boolean isMenuBeingAnimated() { - return mPopupStatus == POPUP_IN_ANIMATION; + return mPopupStatus == POPUP_IN_ANIMATION_SLIDE || mPopupStatus == POPUP_IN_ANIMATION_FADE; } public boolean isPreviewMenuBeingShown() { @@ -681,8 +684,11 @@ public class PhotoMenu extends MenuController @Override public void onClick(View v) { addSceneMode(); - View view = mUI.getPreviewMenuLayout().getChildAt(0); - animateSlideIn(view, previewMenuSize, false); + ViewGroup menuLayout = mUI.getPreviewMenuLayout(); + if (menuLayout != null) { + View view = menuLayout.getChildAt(0); + animateSlideIn(view, previewMenuSize, false); + } } }); } @@ -830,8 +836,11 @@ public class PhotoMenu extends MenuController @Override public void onClick(View v) { addFilterMode(); - View view = mUI.getPreviewMenuLayout().getChildAt(0); - animateSlideIn(view, previewMenuSize, false); + ViewGroup menuLayout = mUI.getPreviewMenuLayout(); + if (menuLayout != null) { + View view = mUI.getPreviewMenuLayout().getChildAt(0); + animateSlideIn(view, previewMenuSize, false); + } } }); } @@ -1094,6 +1103,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..843d860f7 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() { @@ -358,6 +364,7 @@ public class PhotoModule private boolean mAnimateCapture = true; private int mJpegFileSizeEstimation = 0; + private int mRemainingPhotos = -1; private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = new MediaSaveService.OnMediaSavedListener() { @@ -524,7 +531,7 @@ public class PhotoModule mPreferences.setLocalId(mActivity, mCameraId); CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - if (mOpenCameraThread == null && !mActivity.mIsModuleSwitchInProgress) { + if (mOpenCameraThread == null) { mOpenCameraThread = new OpenCameraThread(); mOpenCameraThread.start(); } @@ -558,6 +565,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 +1037,9 @@ public class PhotoModule } }); } + if (mRefocus) { + mSoundPool.play(mRefocusSound, 1.0f, 1.0f, 0, 0, 1.0f); + } } } private final class StatsCallback @@ -1243,7 +1255,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 +1284,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) { @@ -1351,7 +1376,7 @@ public class PhotoModule // the mean time and fill it, but that could have happened between the // shutter press and saving the JPEG too. mActivity.updateStorageSpaceAndHint(); - updateRemainingPhotos(); + mUI.updateRemainingPhotos(--mRemainingPhotos); long now = System.currentTimeMillis(); mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; Log.v(TAG, "mJpegCallbackFinishTime = " @@ -1604,6 +1629,7 @@ public class PhotoModule new JpegPictureCallback(loc)); } } else { + mCameraDevice.enableShutterSound(!mRefocus); mCameraDevice.takePicture(mHandler, new ShutterCallback(!animateBefore), mRawPictureCallback, mPostViewPictureCallback, @@ -1763,9 +1789,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)) || @@ -2097,10 +2121,12 @@ public class PhotoModule } //Need to disable focus for ZSL mode - if(mSnapshotMode == CameraInfo.CAMERA_SUPPORT_MODE_ZSL) { - mFocusManager.setZslEnable(true); - } else { - mFocusManager.setZslEnable(false); + if (mFocusManager != null) { + if (mSnapshotMode == CameraInfo.CAMERA_SUPPORT_MODE_ZSL) { + mFocusManager.setZslEnable(true); + } else { + mFocusManager.setZslEnable(false); + } } // If the user wants to do a snapshot while the previous one is still @@ -2108,7 +2134,8 @@ public class PhotoModule // one and re-start the preview. Snapshot in progress also includes the // state that autofocus is focusing and a picture will be taken when // focus callback arrives. - if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS) + if ((((mFocusManager != null) && mFocusManager.isFocusingSnapOnFinish()) + || mCameraState == SNAPSHOT_IN_PROGRESS) && !mIsImageCaptureIntent) { mSnapshotOnIdle = true; return; @@ -2240,11 +2267,12 @@ public class PhotoModule private void updateRemainingPhotos() { if (mJpegFileSizeEstimation != 0) { - mUI.updateRemainingPhotos((int) (mActivity.getStorageSpaceBytes() - / mJpegFileSizeEstimation)); + mRemainingPhotos = (int) (mActivity.getStorageSpaceBytes() + / mJpegFileSizeEstimation); } else { - mUI.updateRemainingPhotos(-1); + mRemainingPhotos = -1; } + mUI.updateRemainingPhotos(mRemainingPhotos); } private void onResumeTasks() { @@ -2844,7 +2872,16 @@ public class PhotoModule //mUnsupportedJpegQuality = true; }else { mParameters.setJpegQuality(JpegEncodingQualityMappings.getQualityNumber(jpegQuality)); - setJpegFileSizeEstimation(pic_size, jpegQuality); + int jpegFileSize = estimateJpegFileSize(pic_size, jpegQuality); + if (jpegFileSize != mJpegFileSizeEstimation) { + mJpegFileSizeEstimation = jpegFileSize; + mHandler.post(new Runnable() { + @Override + public void run() { + updateRemainingPhotos(); + } + }); + } } } @@ -3242,7 +3279,7 @@ public class PhotoModule } } - private void setJpegFileSizeEstimation(final Size size, final String quality) { + private int estimateJpegFileSize(final Size size, final String quality) { int[] ratios = mActivity.getResources().getIntArray(R.array.jpegquality_compression_ratio); String[] qualities = mActivity.getResources().getStringArray( R.array.pref_camera_jpegquality_entryvalues); @@ -3255,9 +3292,9 @@ public class PhotoModule } if (ratio == 0) { - mJpegFileSizeEstimation = 0; + return 0; } else { - mJpegFileSizeEstimation = size.width * size.height * 3 / ratio; + return size.width * size.height * 3 / ratio; } } @@ -3472,6 +3509,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 +3524,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; + } } } @@ -4124,6 +4172,12 @@ public class PhotoModule return; } + if (CameraSettings.KEY_CAMERA_SAVEPATH.equals(pref.getKey())) { + Storage.setSaveSDCard( + mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); + mActivity.updateStorageSpaceAndHint(); + } + //call generic onSharedPreferenceChanged onSharedPreferenceChanged(); } @@ -4171,8 +4225,6 @@ public class PhotoModule disableSkinToneSeekBar(); } } - Storage.setSaveSDCard( - mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); } @Override @@ -4423,6 +4475,10 @@ public class PhotoModule } } } + + public boolean isRefocus() { + return mLastPhotoTakenWithRefocus; + } } /* Below is no longer needed, except to get rid of compile error @@ -4600,5 +4656,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..d4cec7bc0 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 @@ -553,7 +557,9 @@ public class PhotoUI implements PieListener, mMenuButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - mMenu.openFirstLevel(); + if(mMenu != null){ + mMenu.openFirstLevel(); + } } }); if (mController.isImageCaptureIntent()) { @@ -917,8 +923,11 @@ public class PhotoUI implements PieListener, } public boolean sendTouchToMenu(MotionEvent ev) { - View v = mMenuLayout.getChildAt(0); - return v.dispatchTouchEvent(ev); + if (mMenuLayout != null) { + View v = mMenuLayout.getChildAt(0); + return v.dispatchTouchEvent(ev); + } + return false; } public void dismissSceneModeMenu() { @@ -962,6 +971,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/VideoMenu.java b/src/com/android/camera/VideoMenu.java index 3f9cde7f0..1f9c6d1a0 100644 --- a/src/com/android/camera/VideoMenu.java +++ b/src/com/android/camera/VideoMenu.java @@ -66,7 +66,8 @@ public class VideoMenu extends MenuController private static final int POPUP_NONE = 0; private static final int POPUP_FIRST_LEVEL = 1; private static final int POPUP_SECOND_LEVEL = 2; - private static final int POPUP_IN_ANIMATION = 3; + private static final int POPUP_IN_ANIMATION_SLIDE = 3; + private static final int POPUP_IN_ANIMATION_FADE = 4; private static final int PREVIEW_MENU_NONE = 0; private static final int PREVIEW_MENU_IN_ANIMATION = 1; private static final int PREVIEW_MENU_ON = 2; @@ -164,9 +165,9 @@ public class VideoMenu extends MenuController } private void animateFadeOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_FADE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_FADE; ViewPropertyAnimator vp = v.animate(); vp.alpha(0f).setDuration(ANIMATION_DURATION); @@ -213,9 +214,9 @@ public class VideoMenu extends MenuController } private void animateSlideOut(final ListView v, final int level) { - if (v == null || mPopupStatus == POPUP_IN_ANIMATION) + if (v == null || mPopupStatus == POPUP_IN_ANIMATION_SLIDE) return; - mPopupStatus = POPUP_IN_ANIMATION; + mPopupStatus = POPUP_IN_ANIMATION_SLIDE; ViewPropertyAnimator vp = v.animate(); vp.translationX(v.getX() - v.getWidth()).setDuration(ANIMATION_DURATION); @@ -340,7 +341,9 @@ public class VideoMenu extends MenuController } public boolean isOverMenu(MotionEvent ev) { - if (mPopupStatus == POPUP_NONE || mPopupStatus == POPUP_IN_ANIMATION) + if (mPopupStatus == POPUP_NONE + || mPopupStatus == POPUP_IN_ANIMATION_SLIDE + || mPopupStatus == POPUP_IN_ANIMATION_FADE) return false; if (mUI.getMenuLayout() == null) return false; @@ -366,7 +369,7 @@ public class VideoMenu extends MenuController } public boolean isMenuBeingAnimated() { - return mPopupStatus == POPUP_IN_ANIMATION; + return mPopupStatus == POPUP_IN_ANIMATION_SLIDE || mPopupStatus == POPUP_IN_ANIMATION_FADE; } public boolean isPreviewMenuBeingShown() { diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 1bd395188..59874dd81 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -646,6 +646,7 @@ public class VideoModule implements CameraModule, mUI.animateCapture(); } } + mUI.showUIafterRecording(); } public void onVideoSaved() { @@ -687,10 +688,8 @@ public class VideoModule implements CameraModule, if (stop) { onStopVideoRecording(); - mUI.showUIafterRecording(); } else { startVideoRecording(); - mUI.hideUIwhileRecording(); } mUI.enableShutter(false); @@ -1597,6 +1596,7 @@ public class VideoModule implements CameraModule, mStartRecPending = true; mUI.cancelAnimations(); mUI.setSwipingEnabled(false); + mUI.hideUIwhileRecording(); mActivity.updateStorageSpaceAndHint(); if (mActivity.getStorageSpaceBytes() <= Storage.LOW_STORAGE_THRESHOLD_BYTES) { @@ -2276,6 +2276,11 @@ public class VideoModule implements CameraModule, mParameters.setVideoRotation(videoRotation); } + //set low-power mode if supported + String lpmSupported = mParameters.get("low-power-mode-supported"); + if ("true".equals(lpmSupported)) { + mParameters.set("low-power-mode", 1); + } } @SuppressWarnings("deprecation") private void setCameraParameters() { diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java index bc9fd8602..40878581e 100644 --- a/src/com/android/camera/WideAnglePanoramaModule.java +++ b/src/com/android/camera/WideAnglePanoramaModule.java @@ -44,7 +44,6 @@ import android.view.OrientationEventListener; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.view.Display; import android.widget.Toast; import com.android.camera.PhotoModule; import com.android.camera.CameraManager.CameraProxy; @@ -110,8 +109,6 @@ public class WideAnglePanoramaModule private boolean mUsingFrontCamera; private int mCameraPreviewWidth; private int mCameraPreviewHeight; - private int mScreenWidth; - private int mScreenHeight; private int mCameraState; private int mCaptureState; private PowerManager.WakeLock mPartialWakeLock; @@ -372,13 +369,14 @@ public class WideAnglePanoramaModule return true; } - private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, boolean need16To9, + private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, boolean needSmaller) { int pixelsDiff = DEFAULT_CAPTURE_PIXELS; boolean hasFound = false; for (Size size : supportedSizes) { int h = size.height; int w = size.width; + // we only want 4:3 format. int d = DEFAULT_CAPTURE_PIXELS - h * w; if (needSmaller && d < 0) { // no bigger preview than 960x720. continue; @@ -386,9 +384,6 @@ public class WideAnglePanoramaModule if (need4To3 && (h * 4 != w * 3)) { continue; } - if (need16To9 && (h * 16 != w * 9)) { - continue; - } d = Math.abs(d); if (d < pixelsDiff) { mCameraPreviewWidth = w; @@ -401,26 +396,12 @@ public class WideAnglePanoramaModule } private void setupCaptureParams(Parameters parameters) { - boolean need4To3 = false; - boolean need16To9 = false; List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); - Display mDisplay = mActivity.getWindowManager().getDefaultDisplay(); - mScreenWidth = mDisplay.getWidth(); - mScreenHeight = mDisplay.getHeight(); - - if(mScreenHeight * 4 == mScreenWidth * 3) { - need4To3 = true; - } - - if(mScreenHeight * 16 == mScreenWidth * 9) { - need16To9 = true; - } - - if (!findBestPreviewSize(supportedSizes, need4To3, need16To9, true)) { - Log.w(TAG, "No preview size supported matching the screen aspect ratio"); - if (!findBestPreviewSize(supportedSizes, false, false, true)) { + if (!findBestPreviewSize(supportedSizes, true, true)) { + Log.w(TAG, "No 4:3 ratio preview size supported."); + if (!findBestPreviewSize(supportedSizes, false, true)) { Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); - findBestPreviewSize(supportedSizes, false, false, false); + findBestPreviewSize(supportedSizes, false, false); } } Log.d(TAG, "camera preview h = " @@ -511,9 +492,6 @@ public class WideAnglePanoramaModule } mPreviewUIWidth = r - l; mPreviewUIHeight = b - t; - Parameters parameters = mCameraDevice.getParameters(); - setupCaptureParams(parameters); - configureCamera(parameters); configMosaicPreview(); if (capturePending == true){ mMainHandler.post(new Runnable() { diff --git a/src/com/android/camera/WideAnglePanoramaUI.java b/src/com/android/camera/WideAnglePanoramaUI.java index 4b403f2d9..9594ac0e6 100644 --- a/src/com/android/camera/WideAnglePanoramaUI.java +++ b/src/com/android/camera/WideAnglePanoramaUI.java @@ -441,6 +441,14 @@ public class WideAnglePanoramaUI implements private void setViews(Resources appRes) { int weight = appRes.getInteger(R.integer.SRI_pano_layout_weight); + LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mPreviewLayout.getLayoutParams(); + lp.weight = weight; + mPreviewLayout.setLayoutParams(lp); + + lp = (LinearLayout.LayoutParams) mReview.getLayoutParams(); + lp.weight = weight; + mPreviewLayout.setLayoutParams(lp); + mSavingProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_saving_progress_bar); mSavingProgressBar.setIndicatorWidth(0); mSavingProgressBar.setMaxProgress(100); diff --git a/src/com/android/camera/ui/CameraControls.java b/src/com/android/camera/ui/CameraControls.java index 14f27a36d..0938ffc19 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.LinearLayout; @@ -51,6 +56,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; @@ -154,8 +161,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) { @@ -294,6 +308,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, @@ -433,6 +487,7 @@ public class CameraControls extends RotatableLayout { break; } mRemainingPhotos.setVisibility(View.INVISIBLE); + mRefocusToast.setVisibility(View.GONE); } public void showUI() { @@ -523,6 +578,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) { @@ -767,4 +823,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); + } + } } diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index 08ce84d87..dbd2cc36d 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -1073,18 +1073,10 @@ public class CameraUtil { } public static int determineRatio(int width, int height) { - int s = width, l = height; - if (width > height) { - l = width; - s = height; - } - if (l * 3 == s * 4) { - return RATIO_4_3; - } else if (l * 9 == s * 16) { - return RATIO_16_9; - } else { - return RATIO_UNKNOWN; + if (height != 0) { + return determineRatio(((float) width) / height); } + return RATIO_UNKNOWN; } public static int determineRatio(float ratio) { |