summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Kondik <steve@cyngn.com>2016-11-13 23:27:35 -0800
committerSteve Kondik <steve@cyngn.com>2016-11-13 23:33:37 -0800
commit302dfef488297152978788c2341cd3460727b251 (patch)
treee505947a46b291f22f1ee625ff82ebbec528353b
parent7f040079cb93d6b5180147cd369e73d43078c91a (diff)
downloadandroid_packages_apps_Snap-302dfef488297152978788c2341cd3460727b251.zip
android_packages_apps_Snap-302dfef488297152978788c2341cd3460727b251.tar.gz
android_packages_apps_Snap-302dfef488297152978788c2341cd3460727b251.tar.bz2
snap: UI checkpoint #2
* Fix bugs from previous commit * Factor out recording controls * Clean up layouts * Asynchronous control for video module * Performance improvements Change-Id: I9d5833cecbd9280845b740ee8a3c47f023470625
-rw-r--r--res/layout/camera_controls.xml71
-rw-r--r--res/layout/capture_module.xml8
-rw-r--r--res/layout/panorama_module.xml5
-rw-r--r--res/layout/photo_module.xml59
-rw-r--r--res/layout/recording_time.xml61
-rw-r--r--res/layout/video_module.xml65
-rw-r--r--res/values/colors.xml2
-rw-r--r--res/values/dimens.xml2
-rw-r--r--res/values/styles.xml2
-rw-r--r--src/com/android/camera/BaseUI.java29
-rw-r--r--src/com/android/camera/CameraActivity.java30
-rw-r--r--src/com/android/camera/CaptureUI.java4
-rw-r--r--src/com/android/camera/PhotoModule.java5
-rw-r--r--src/com/android/camera/PhotoUI.java13
-rw-r--r--src/com/android/camera/VideoController.java2
-rw-r--r--src/com/android/camera/VideoModule.java932
-rw-r--r--src/com/android/camera/VideoUI.java166
-rw-r--r--src/com/android/camera/WideAnglePanoramaUI.java6
-rw-r--r--src/com/android/camera/ui/CameraControls.java150
-rw-r--r--src/com/android/camera/ui/ModuleSwitcher.java2
-rw-r--r--src/com/android/camera/ui/RecordingTime.java298
-rw-r--r--src/com/android/camera/ui/ReversibleLinearLayout.java57
-rw-r--r--src/com/android/camera/util/CameraUtil.java14
23 files changed, 1228 insertions, 755 deletions
diff --git a/res/layout/camera_controls.xml b/res/layout/camera_controls.xml
index 5241987..1f12514 100644
--- a/res/layout/camera_controls.xml
+++ b/res/layout/camera_controls.xml
@@ -20,8 +20,9 @@
<LinearLayout
android:id="@+id/top_bar"
+ android:background="@drawable/camera_controls_bg_translucent"
android:layout_width="match_parent"
- android:layout_height="0dp"
+ android:layout_height="@dimen/preview_top_margin"
android:gravity="center_vertical"
android:orientation="horizontal">
@@ -66,26 +67,18 @@
</LinearLayout>
- <include
- android:layout_width="64dip"
- android:layout_height="64dip"
- android:layout_gravity="bottom|right"
- android:layout_marginBottom="8dip"
- android:layout_marginRight="-8dip"
- layout="@layout/menu_indicators" />
-
<LinearLayout
android:id="@+id/bottom_bar"
android:layout_width="match_parent"
- android:layout_height="0dp"
+ android:layout_height="@dimen/preview_bottom_margin"
android:gravity="center_vertical"
- android:weightSum="3"
+ android:background="@drawable/camera_controls_bg_translucent"
android:orientation="horizontal">
<com.android.camera.ui.RotateImageView
android:id="@+id/preview_thumb"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/thumbnail_size"
android:layout_weight="1"
android:layout_gravity="center"
android:background="@android:color/transparent"
@@ -93,32 +86,32 @@
android:elevation="1dp"
android:scaleType="fitCenter" />
- <com.android.camera.ShutterButton
- android:id="@+id/shutter_button"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
+ <com.android.camera.ShutterButton
+ android:id="@+id/shutter_button"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
android:layout_gravity="center"
- android:clickable="true"
- android:contentDescription="@string/accessibility_shutter_button"
- android:focusable="true"
- android:scaleType="fitCenter"
- android:layout_weight="1"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_shutter_button"
+ android:focusable="true"
+ android:scaleType="fitCenter"
android:elevation="1dp"
- android:src="@drawable/btn_new_shutter" />
-
- <ImageView
- android:id="@+id/video_button"
- android:visibility="gone"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:clickable="true"
- android:contentDescription="@string/accessibility_shutter_button"
- android:focusable="true"
- android:scaleType="fitCenter"
- android:layout_weight="1"
+ android:src="@drawable/btn_new_shutter" />
+
+ <ImageView
+ android:id="@+id/video_button"
+ android:visibility="gone"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
android:layout_gravity="center"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:contentDescription="@string/accessibility_shutter_button"
+ android:focusable="true"
+ android:scaleType="fitCenter"
android:elevation="1dp"
- android:src="@drawable/btn_new_shutter_video" />
+ android:src="@drawable/btn_new_shutter_video" />
<com.android.camera.ui.ModuleSwitcher
android:id="@+id/camera_switcher"
@@ -132,6 +125,14 @@
android:contentDescription="@string/accessibility_mode_picker" />
</LinearLayout>
+ <include
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:layout_gravity="bottom|right"
+ android:layout_marginBottom="8dip"
+ android:layout_marginRight="-8dip"
+ layout="@layout/menu_indicators" />
+
<LinearLayout
android:id="@+id/remaining_photos"
android:layout_width="wrap_content"
diff --git a/res/layout/capture_module.xml b/res/layout/capture_module.xml
index dba8de9..eee33f5 100644
--- a/res/layout/capture_module.xml
+++ b/res/layout/capture_module.xml
@@ -103,8 +103,8 @@
</LinearLayout>
</com.android.camera.ui.RotateLayout>
- <include
- style="@style/CameraControls"
- layout="@layout/camera_controls"
- android:layout_gravity="center" />
+ <include layout="@layout/camera_controls"
+ android:layout_gravity="center"
+ style="@style/CameraControls"/>
+
</merge>
diff --git a/res/layout/panorama_module.xml b/res/layout/panorama_module.xml
index 5ae3002..b1d0ded 100644
--- a/res/layout/panorama_module.xml
+++ b/res/layout/panorama_module.xml
@@ -129,6 +129,7 @@
</com.android.camera.ui.RotateLayout>
<include layout="@layout/camera_controls"
- android:layout_gravity="center"
- style="@style/CameraControls"/>
+ android:layout_gravity="center"
+ style="@style/CameraControls"/>
+
</merge>
diff --git a/res/layout/photo_module.xml b/res/layout/photo_module.xml
index 794a968..d972989 100644
--- a/res/layout/photo_module.xml
+++ b/res/layout/photo_module.xml
@@ -21,6 +21,7 @@
layout. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@android:color/black"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" >
@@ -31,25 +32,43 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|center_horizontal" >
- <SurfaceView
+ <com.android.camera.ui.AutoFitSurfaceView
android:id="@+id/mdp_preview_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
+
<View
android:id="@+id/preview_cover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black" />
- <com.android.camera.ui.focus.FocusRingView
- android:id="@+id/focus_ring"
+
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <com.android.camera.ui.CaptureAnimationOverlay
- android:id="@+id/capture_overlay"
+ android:layout_height="match_parent">
+ <ViewStub android:id="@+id/face_view_stub"
+ android:inflatedId="@+id/face_view"
+ android:layout="@layout/face_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"/>
+ <com.android.camera.ui.focus.FocusRingView
+ android:id="@+id/focus_ring"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <com.android.camera.ui.CaptureAnimationOverlay
+ android:id="@+id/capture_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
+ </FrameLayout>
+
+ <com.android.camera.ui.RenderOverlay
+ android:id="@+id/render_overlay"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone" />
+ android:layout_height="match_parent" />
+
<com.android.camera.ui.RotateImageView
android:id="@+id/review_image"
android:layout_width="match_parent"
@@ -58,29 +77,19 @@
android:clickable="true"
android:background="@android:color/black"
android:scaleType="fitCenter"/>
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <ViewStub android:id="@+id/face_view_stub"
- android:inflatedId="@+id/face_view"
- android:layout="@layout/face_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"/>
- </FrameLayout>
- <com.android.camera.ui.RenderOverlay
- android:id="@+id/render_overlay"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <include layout="@layout/camera_controls"
- android:layout_gravity="center"
- style="@style/CameraControls"/>
+
<include layout="@layout/menu_help"
android:layout_gravity="center"
style="@style/CameraControls"/>
+
<RelativeLayout
android:id="@+id/id_tsmakeup_level_layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
+
+ <include layout="@layout/camera_controls"
+ android:layout_gravity="center"
+ style="@style/CameraControls"/>
+
</merge>
diff --git a/res/layout/recording_time.xml b/res/layout/recording_time.xml
new file mode 100644
index 0000000..4a7adee
--- /dev/null
+++ b/res/layout/recording_time.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- This layout is shared by phone and tablet in landscape orientation. -->
+<com.android.camera.ui.RecordingTime
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:visibility="gone"
+ android:layout_gravity="left|top"
+ android:layout_marginTop="@dimen/preview_top_margin"
+ android:padding="16dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent">
+
+ <com.android.camera.ui.ReversibleLinearLayout
+ android:id="@+id/recording_time_container"
+ android:orientation="horizontal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content">
+
+ <com.android.camera.PauseButton android:id="@+id/video_pause"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:gravity="center"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:src="@drawable/btn_pause_recording"/>
+
+ <TextView android:id="@+id/recording_time_text"
+ style="@style/OnViewfinderLabel"
+ android:gravity="center"
+ android:text="@string/initial_recording_seconds"
+ android:drawableLeft="@drawable/ic_recording_indicator"
+ android:drawablePadding="5dp"/>
+
+ </com.android.camera.ui.ReversibleLinearLayout>
+
+ <TextView android:id="@+id/time_lapse_label"
+ android:text="@string/time_lapse_title"
+ android:visibility="gone"
+ style="@style/OnViewfinderLabel"/>
+
+ </LinearLayout>
+
+</com.android.camera.ui.RecordingTime>
diff --git a/res/layout/video_module.xml b/res/layout/video_module.xml
index f12f06c..a6024d5 100644
--- a/res/layout/video_module.xml
+++ b/res/layout/video_module.xml
@@ -15,6 +15,7 @@
-->
<!-- This layout is shared by phone and tablet in landscape orientation. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@android:color/black"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" >
@@ -23,11 +24,18 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|center_horizontal" >
- <SurfaceView
+ <com.android.camera.ui.AutoFitSurfaceView
android:id="@+id/mdp_preview_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
+
+ <View
+ android:id="@+id/preview_cover"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black" />
+
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -37,53 +45,32 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
+ <com.android.camera.ui.focus.FocusRingView
+ android:id="@+id/focus_ring"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <com.android.camera.ui.CaptureAnimationOverlay
+ android:id="@+id/capture_overlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone" />
</FrameLayout>
- <View
- android:id="@+id/preview_cover"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/black" />
- <FrameLayout android:id="@+id/preview_border"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone"
- android:background="@drawable/ic_snapshot_border" />
+
<com.android.camera.ui.RenderOverlay
android:id="@+id/render_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <com.android.camera.ui.RotateLayout
- android:id="@+id/recording_time_rect"
- android:layout_height="match_parent"
- android:layout_width="match_parent">
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_height="match_parent"
- android:layout_width="match_parent">
- <com.android.camera.PauseButton android:id="@+id/video_pause"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginLeft="50dp"
- android:padding="38dp"
- android:src="@drawable/btn_pause_recording"/>
- <include layout="@layout/viewfinder_labels_video"
- android:id="@+id/labels" />
- </LinearLayout>
- </com.android.camera.ui.RotateLayout>
- <com.android.camera.ui.focus.FocusRingView
- android:id="@+id/focus_ring"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
- <com.android.camera.ui.CaptureAnimationOverlay
- android:id="@+id/capture_overlay"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone" />
+
+
+ <include layout="@layout/recording_time"
+ android:id="@+id/recording_time" />
+
<ImageView android:id="@+id/review_image"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:visibility="gone"
android:background="@android:color/black"/>
+
<ImageView
android:id="@+id/btn_play"
style="@style/ReviewControlIcon"
@@ -92,7 +79,9 @@
android:scaleType="center"
android:visibility="gone"
android:onClick="onReviewPlayClicked"/>
+
<include layout="@layout/camera_controls"
android:layout_gravity="center"
style="@style/CameraControls"/>
+
</merge>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 05c7834..518a88c 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -48,7 +48,7 @@
<color name="recording_time_elapsed_text">@color/white</color>
<color name="recording_time_remaining_text">@color/red</color>
- <color name="on_viewfinder_label_background_color">@color/black</color>
+ <color name="on_viewfinder_label_background_color">#401b1b1b</color>
<color name="review_control_pressed_color">@color/blue</color>
<color name="review_control_pressed_fan_color">@color/blue</color>
<color name="review_background">@color/black</color>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c8c1896..c6dde51 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -151,7 +151,7 @@
<dimen name="manage_cache_bottom_height">48dp</dimen>
<!-- configuration for filtershow UI -->
- <dimen name="thumbnail_size">96dip</dimen>
+ <dimen name="thumbnail_size">64dip</dimen>
<dimen name="thumbnail_margin">3dip</dimen>
<dimen name="action_item_height">175dip</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 2528546..3e3ef16 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -125,11 +125,11 @@
<item name="android:background">@drawable/setting_list_item_bg</item>
</style>
<style name="OnViewfinderLabel">
+ <item name="android:layout_gravity">left</item>
<item name="android:gravity">center</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:singleLine">true</item>
- <item name="android:layout_marginTop">38dp</item>
<item name="android:paddingLeft">15dp</item>
<item name="android:paddingRight">15dp</item>
<item name="android:paddingTop">3dp</item>
diff --git a/src/com/android/camera/BaseUI.java b/src/com/android/camera/BaseUI.java
index 7fd3c18..c5c3c2b 100644
--- a/src/com/android/camera/BaseUI.java
+++ b/src/com/android/camera/BaseUI.java
@@ -1,7 +1,10 @@
package com.android.camera;
+import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.RectF;
+import android.util.Log;
+import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStub;
@@ -20,13 +23,14 @@ import java.util.List;
* toward an eventual unification - WF */
public abstract class BaseUI {
- protected final CameraControls mCameraControls;
protected final CaptureAnimationOverlay mCaptureOverlay;
protected final View mPreviewCover;
protected final CameraActivity mActivity;
protected final ViewGroup mRootView;
+ protected CameraControls mCameraControls;
+
protected int mTopMargin = 0;
protected int mBottomMargin = 0;
protected int mScreenRatio = CameraUtil.RATIO_UNKNOWN;
@@ -47,8 +51,10 @@ public abstract class BaseUI {
Point size = new Point();
mActivity.getWindowManager().getDefaultDisplay().getRealSize(size);
mScreenRatio = CameraUtil.determineRatio(size.x, size.y);
- calculateMargins(size);
- mCameraControls.setMargins(mTopMargin, mBottomMargin);
+
+ Pair<Integer, Integer> margins = CameraUtil.calculateMargins(mActivity);
+ mTopMargin = margins.first;
+ mBottomMargin = margins.second;
}
private void calculateMargins(Point size) {
@@ -137,10 +143,25 @@ public abstract class BaseUI {
if (mCaptureOverlay != null) {
mCaptureOverlay.startFlashAnimation(shortFlash);
}
+ mActivity.updateThumbnail(true);
+ }
+
+ public void animateFlash(Bitmap bitmap) {
+ if (mCaptureOverlay != null) {
+ mCaptureOverlay.startFlashAnimation(false);
+ }
+ mActivity.updateThumbnail(bitmap);
}
protected void onPreviewRectChanged(RectF rect) {
- mCaptureOverlay.setPreviewRect(rect);
+ CameraUtil.dumpRect(rect, "onPreviewRectChanged");
+
+ if (mCaptureOverlay != null) {
+ mCaptureOverlay.setPreviewRect(rect);
+ }
+ if (mCameraControls != null) {
+ mCameraControls.setPreviewRect(rect);
+ }
}
private void enableOverlays() {
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 3d630ec..570fad1 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -580,23 +580,25 @@ public class CameraActivity extends Activity
CameraActivity.this.setSystemBarsVisibility(visible);
}
- private boolean stripHasScrolled = false;
+ private float previewCoverAlpha = 1.0f;
- @Override
- public void onFilmStripScroll(int offset) {
- if (offset == 0) {
- if (stripHasScrolled) {
- mCurrentModule.hidePreviewCover();
- mCurrentModule.setPreviewCoverAlpha(1.0f);
- }
- } else {
- // preview cover becomes fully opaque when the film strip has
- // scrolled half the width of the screen
- float rangePx = mDisplayWidth / 2f;
- mCurrentModule.setPreviewCoverAlpha((float)Math.min(1.0, offset/rangePx));
+ private void setPreviewCoverAlpha(float alpha) {
+ if (alpha == previewCoverAlpha || alpha < 0.0f || alpha > 1.0f) {
+ return;
+ }
+ mCurrentModule.setPreviewCoverAlpha(alpha);
+ if (alpha == 0.0f) {
+ mCurrentModule.hidePreviewCover();
+ } else if (previewCoverAlpha == 0.0f) {
mCurrentModule.showPreviewCover();
- stripHasScrolled = true;
}
+ previewCoverAlpha = alpha;
+ }
+
+ @Override
+ public void onFilmStripScroll(int offset) {
+ float rangePx = mDisplayWidth / 2f;
+ setPreviewCoverAlpha((float)Math.min(1.0, offset/rangePx));
}
};
diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java
index 81aa2b0..debd180 100644
--- a/src/com/android/camera/CaptureUI.java
+++ b/src/com/android/camera/CaptureUI.java
@@ -355,7 +355,6 @@ public class CaptureUI extends BaseUI implements PreviewGestures.SingleTapListen
mRenderOverlay.requestLayout();
((ViewGroup)mRootView).removeView(mRecordingTimeRect);
- mCameraControls.setPreviewRatio(0, true);
}
public void onCameraOpened(List<Integer> cameraIds) {
@@ -399,7 +398,8 @@ public class CaptureUI extends BaseUI implements PreviewGestures.SingleTapListen
mModule.onVideoButtonClick();
}
});
- mCameraControls.setPreviewRatio(0, true);
+
+ mCameraControls.disableMuteButton();
}
public void initializeZoom(List<Integer> ids) {
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index ef9c91f..c4434bd 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -230,6 +230,7 @@ public class PhotoModule
private int SCE_FACTOR_STEP = 10;
private boolean mPreviewRestartSupport = false;
+ private boolean mPreviewStarting = false;
// mCropValue and mSaveUri are used only if isImageCaptureIntent() is true.
private String mCropValue;
@@ -2957,11 +2958,12 @@ public class PhotoModule
/** This can run on a background thread, so don't do UI updates here. Post any
view updates to MainHandler or do it on onPreviewStarted() . */
private void startPreview() {
- if (mPaused || mCameraDevice == null || mParameters == null) {
+ if (mPaused || mCameraDevice == null || mParameters == null || mPreviewStarting) {
return;
}
synchronized (mCameraDevice) {
+ mPreviewStarting = true;
SurfaceHolder sh = null;
Log.v(TAG, "startPreview: SurfaceHolder (MDP path)");
if (mUI != null) {
@@ -3021,6 +3023,7 @@ public class PhotoModule
Log.v(TAG, "Trigger snapshot from start preview.");
mHandler.post(mDoSnapRunnable);
}
+ mPreviewStarting = false;
}
@Override
diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java
index 38c6497..1e019a6 100644
--- a/src/com/android/camera/PhotoUI.java
+++ b/src/com/android/camera/PhotoUI.java
@@ -252,8 +252,6 @@ public class PhotoUI extends BaseUI implements PieListener,
mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
mMenuButton = mRootView.findViewById(R.id.menu);
- mCameraControls.disableMuteButton();
-
ViewStub faceViewStub = (ViewStub) mRootView
.findViewById(R.id.face_view_stub);
if (faceViewStub != null) {
@@ -262,11 +260,8 @@ public class PhotoUI extends BaseUI implements PieListener,
setSurfaceTextureSizeChangedListener(mFaceView);
}
mFocusRing = (FocusRing) mRootView.findViewById(R.id.focus_ring);
- initIndicators();
mOrientationResize = false;
mPrevOrientationResize = false;
-
- showFirstTimeHelp();
}
public void setDownFactor(int factor) {
@@ -305,7 +300,6 @@ public class PhotoUI extends BaseUI implements PieListener,
mAspectRatioResize = true;
mAspectRatio = ratio;
}
- mCameraControls.setPreviewRatio(mAspectRatio, false);
layoutPreview(ratio);
}
@@ -580,8 +574,9 @@ public class PhotoUI extends BaseUI implements PieListener,
// called from onResume but only the first time
public void initializeFirstTime() {
+ initIndicators();
+
// Initialize shutter button.
- mShutterButton.setImageResource(R.drawable.shutter_button_anim);
mShutterButton.setImageResource(R.drawable.btn_new_shutter);
mShutterButton.setOnClickListener(new OnClickListener() {
@Override
@@ -596,6 +591,8 @@ public class PhotoUI extends BaseUI implements PieListener,
mShutterButton.addOnShutterButtonListener(mController);
mShutterButton.setVisibility(View.VISIBLE);
+
+ mCameraControls.disableMuteButton();
}
// called from onResume every other time
@@ -634,7 +631,7 @@ public class PhotoUI extends BaseUI implements PieListener,
public void updateOnScreenIndicators(Camera.Parameters params,
PreferenceGroup group, ComboPreferences prefs) {
- if (params == null || group == null) return;
+ if (params == null || group == null || mOnScreenIndicators == null) return;
mOnScreenIndicators.updateSceneOnScreenIndicator(params.getSceneMode());
mOnScreenIndicators.updateExposureOnScreenIndicator(params,
CameraSettings.readExposure(prefs));
diff --git a/src/com/android/camera/VideoController.java b/src/com/android/camera/VideoController.java
index a5b92c1..7bb7bf2 100644
--- a/src/com/android/camera/VideoController.java
+++ b/src/com/android/camera/VideoController.java
@@ -16,6 +16,7 @@
package com.android.camera;
+import android.graphics.Rect;
import android.view.View;
import com.android.camera.ShutterButton.OnShutterButtonListener;
@@ -40,6 +41,7 @@ public interface VideoController extends OnShutterButtonListener, OnPauseButtonL
// Callbacks for camera preview UI events.
public void onPreviewUIReady();
public void onPreviewUIDestroyed();
+ public void onPreviewRectChanged(Rect previewRect);
public void onScreenSizeChanged(int width, int height);
}
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index d6b3b71..43fc7c5 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -30,6 +30,7 @@ import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
+import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
@@ -65,7 +66,6 @@ import android.media.EncoderCapabilities.VideoEncoderCap;
import com.android.camera.CameraManager.CameraAFCallback;
import com.android.camera.CameraManager.CameraPictureCallback;
import com.android.camera.CameraManager.CameraProxy;
-import com.android.camera.app.OrientationManager;
import com.android.camera.exif.ExifInterface;
import com.android.camera.ui.RotateImageView;
import com.android.camera.ui.RotateTextToast;
@@ -97,13 +97,21 @@ public class VideoModule implements CameraModule,
private static final int CHECK_DISPLAY_ROTATION = 3;
private static final int CLEAR_SCREEN_DELAY = 4;
- private static final int UPDATE_RECORD_TIME = 5;
private static final int ENABLE_SHUTTER_BUTTON = 6;
private static final int SHOW_TAP_TO_SNAPSHOT_TOAST = 7;
private static final int SWITCH_CAMERA = 8;
private static final int SWITCH_CAMERA_START_ANIMATION = 9;
private static final int HANDLE_FLASH_TORCH_DELAY = 10;
private static final int SET_FOCUS_RATIO = 11;
+ private static final int CAMERA_OPEN_DONE = 12;
+ private static final int ON_PREVIEW_STARTED = 13;
+ private static final int SET_VIDEO_UI_PARAMS = 14;
+
+ // The subset of parameters we need to update in setCameraParameters().
+ private static final int UPDATE_PARAM_INITIALIZE = 1;
+ private static final int UPDATE_PARAM_ZOOM = 2;
+ private static final int UPDATE_PARAM_PREFERENCE = 4;
+ private static final int UPDATE_PARAM_ALL = -1;
private static final int SCREEN_DELAY = 2 * 60 * 1000;
@@ -127,6 +135,8 @@ public class VideoModule implements CameraModule,
private boolean mPaused;
private int mCameraId;
private Parameters mParameters;
+
+ private Parameters mInitialParams;
private boolean mFocusAreaSupported;
private boolean mMeteringAreaSupported;
private boolean mAeLockSupported;
@@ -141,6 +151,8 @@ public class VideoModule implements CameraModule,
private PreferenceGroup mPreferenceGroup;
private boolean mSaveToSDCard = false;
+ private boolean mCameraPreviewParamsReady = false;
+
// Preference must be read before starting preview. We check this before starting
// preview.
private boolean mPreferenceRead;
@@ -153,9 +165,7 @@ public class VideoModule implements CameraModule,
private boolean mSwitchingCamera;
private boolean mMediaRecorderRecording = false;
private boolean mMediaRecorderPausing = false;
- private long mRecordingStartTime;
- private long mRecordingTotalTime;
- private boolean mRecordingTimeCountsDown = false;
+
private long mOnResumeTime;
// The video file that the hardware camera is about to record into
// (or is recording into.)
@@ -196,7 +206,6 @@ public class VideoModule implements CameraModule,
private FocusOverlayManager mFocusManager;
private LocationManager mLocationManager;
- private OrientationManager mOrientationManager;
private int mPendingSwitchCameraId;
private final Handler mHandler = new MainHandler();
private VideoUI mUI;
@@ -276,27 +285,42 @@ public class VideoModule implements CameraModule,
return mIsMute;
}
- protected class CameraOpenThread extends Thread {
+ private class OpenCameraThread extends Thread {
@Override
public void run() {
openCamera();
- if (mFocusManager == null) initializeFocusManager();
+ readVideoPreferences();
+ startPreview();
}
}
+ private OpenCameraThread mOpenCameraThread = null;
+
private void openCamera() {
- if (mCameraDevice == null) {
- mCameraDevice = CameraUtil.openCamera(
- mActivity, mCameraId, mHandler,
- mActivity.getCameraOpenErrorCallback());
+ if (mPaused) {
+ return;
}
+
+ mCameraDevice = CameraUtil.openCamera(
+ mActivity, mCameraId, mHandler,
+ mActivity.getCameraOpenErrorCallback());
if (mCameraDevice == null) {
// Error.
return;
}
mParameters = mCameraDevice.getParameters();
+ mCameraPreviewParamsReady = true;
+ mInitialParams = mParameters;
+
+ if (mFocusManager == null) {
+ initializeFocusManager();
+ } else {
+ mFocusManager.setParameters(mInitialParams);
+ }
initializeCapabilities();
+
mPreviewFocused = arePreviewControlsVisible();
+ mHandler.sendEmptyMessageDelayed(CAMERA_OPEN_DONE, 100);
}
//QCOM data Members Starts here
@@ -376,10 +400,17 @@ public class VideoModule implements CameraModule,
private String mDefaultAntibanding = null;
boolean mUnsupportedProfile = false;
+ private boolean mFirstTimeInitialized = false;
+
public void onScreenSizeChanged(int width, int height) {
if (mFocusManager != null) mFocusManager.setPreviewSize(width, height);
}
+ @Override
+ public void onPreviewRectChanged(Rect previewRect) {
+ if (mFocusManager != null) mFocusManager.setPreviewRect(previewRect);
+ }
+
// This Handler is used to post message back onto the main thread of the
// application
private class MainHandler extends Handler {
@@ -397,27 +428,6 @@ public class VideoModule implements CameraModule,
break;
}
- case UPDATE_RECORD_TIME: {
- updateRecordingTime();
- break;
- }
-
- case CHECK_DISPLAY_ROTATION: {
- // Restart the preview if display rotation has changed.
- // Sometimes this happens when the device is held upside
- // down and camera app is opened. Rotation animation will
- // take some time and the rotation value we have got may be
- // wrong. Framework does not have a callback for this now.
- if ((CameraUtil.getDisplayRotation(mActivity) != mDisplayRotation)
- && !mMediaRecorderRecording && !mSwitchingCamera) {
- startPreview();
- }
- if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) {
- mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
- }
- break;
- }
-
case SHOW_TAP_TO_SNAPSHOT_TOAST: {
showTapToSnapshotToast();
break;
@@ -437,6 +447,16 @@ public class VideoModule implements CameraModule,
break;
}
+ case CAMERA_OPEN_DONE: {
+ onCameraOpened();
+ break;
+ }
+
+ case ON_PREVIEW_STARTED: {
+ onPreviewStarted();
+ break;
+ }
+
case HANDLE_FLASH_TORCH_DELAY: {
forceFlashOff(!mPreviewFocused);
break;
@@ -447,6 +467,12 @@ public class VideoModule implements CameraModule,
break;
}
+ case SET_VIDEO_UI_PARAMS: {
+ setCameraParameters(UPDATE_PARAM_PREFERENCE);
+ mUI.updateOnScreenIndicators(mParameters, mPreferences);
+ break;
+ }
+
default:
Log.v(TAG, "Unhandled message: " + msg.what);
break;
@@ -470,6 +496,20 @@ public class VideoModule implements CameraModule,
}
}
+ private void initializeFirstTime() {
+ if (mFirstTimeInitialized || mPaused) {
+ return;
+ }
+
+ // Initialize location service.
+ boolean recordLocation = RecordLocationPreference.get(mPreferences);
+ mLocationManager.recordLocation(recordLocation);
+
+ mUI.initializeFirstTime();
+
+ mFirstTimeInitialized = true;
+ }
+
private String createName(long dateTaken) {
Date date = new Date(dateTaken);
SimpleDateFormat dateFormat = new SimpleDateFormat(
@@ -489,12 +529,6 @@ public class VideoModule implements CameraModule,
}
}
- private void initializeSurfaceView() {
- if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // API level < 16
- mUI.initializeSurfaceView();
- }
- }
-
public void reinit() {
mPreferences = ComboPreferences.get(mActivity);
if (mPreferences == null) {
@@ -510,7 +544,7 @@ public class VideoModule implements CameraModule,
@Override
public void init(CameraActivity activity, View root) {
mActivity = activity;
- mUI = new VideoUI(activity, this, (ViewGroup) root);
+
mPreferences = ComboPreferences.get(mActivity);
if (mPreferences == null) {
mPreferences = new ComboPreferences(mActivity);
@@ -518,13 +552,16 @@ public class VideoModule implements CameraModule,
CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal(), activity);
mCameraId = getPreferredCameraId(mPreferences);
+ mContentResolver = mActivity.getContentResolver();
+
+ // Surface texture is from camera screen nail and startPreview needs it.
+ // This must be done before startPreview.
+ mIsVideoCaptureIntent = isVideoCaptureIntent();
mPreferences.setLocalId(mActivity, mCameraId);
CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
- // we need to reset exposure for the preview
- resetExposureCompensation();
- mOrientationManager = new OrientationManager(mActivity);
+ mUI = new VideoUI(activity, this, (ViewGroup) root);
// Power shutter
mActivity.initPowerShutter(mPreferences);
@@ -536,31 +573,14 @@ public class VideoModule implements CameraModule,
* To reduce startup time, we start the preview in another thread.
* We make sure the preview is started at the end of onCreate.
*/
- CameraOpenThread cameraOpenThread = new CameraOpenThread();
- cameraOpenThread.start();
-
- mContentResolver = mActivity.getContentResolver();
+ if (mOpenCameraThread == null) {
+ mOpenCameraThread = new OpenCameraThread();
+ mOpenCameraThread.start();
+ }
Storage.setSaveSDCard(
mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
mSaveToSDCard = Storage.isSaveSDCard();
- // Surface texture is from camera screen nail and startPreview needs it.
- // This must be done before startPreview.
- mIsVideoCaptureIntent = isVideoCaptureIntent();
- initializeSurfaceView();
-
- // Make sure camera device is opened.
- try {
- cameraOpenThread.join();
- if (mCameraDevice == null) {
- return;
- }
- } catch (InterruptedException ex) {
- // ignore
- }
-
- readVideoPreferences();
- mUI.setPrefChangedListener(this);
mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
mLocationManager = new LocationManager(mActivity, this);
@@ -569,10 +589,7 @@ public class VideoModule implements CameraModule,
setDisplayOrientation();
mUI.showTimeLapseUI(mCaptureTimeLapse);
- initializeVideoSnapshot();
- resizeForPreviewAspectRatio();
- initializeVideoControl();
mPendingSwitchCameraId = -1;
}
@@ -627,15 +644,20 @@ public class VideoModule implements CameraModule,
@Override
public void setFocusParameters() {
- if (mFocusAreaSupported)
- mParameters.setFocusAreas(mFocusManager.getFocusAreas());
- if (mMeteringAreaSupported)
- mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
- setAutoExposureLockIfSupported();
- setAutoWhiteBalanceLockIfSupported();
- if (mFocusAreaSupported || mMeteringAreaSupported) {
- mParameters.setFocusMode(mFocusManager.getFocusMode(true));
- mCameraDevice.setParameters(mParameters);
+ if (mCameraDevice == null) {
+ return;
+ }
+ synchronized (mCameraDevice) {
+ if (mFocusAreaSupported)
+ mParameters.setFocusAreas(mFocusManager.getFocusAreas());
+ if (mMeteringAreaSupported)
+ mParameters.setMeteringAreas(mFocusManager.getMeteringAreas());
+ setAutoExposureLockIfSupported();
+ setAutoWhiteBalanceLockIfSupported();
+ if (mFocusAreaSupported || mMeteringAreaSupported) {
+ mParameters.setFocusMode(mFocusManager.getFocusMode(true));
+ mCameraDevice.setParameters(mParameters);
+ }
}
}
@@ -740,11 +762,6 @@ public class VideoModule implements CameraModule,
}
- private void initializeVideoControl() {
- loadCameraPreferences();
- mUI.initializePopup(mPreferenceGroup);
- }
-
@Override
public void onOrientationChanged(int orientation) {
// We keep the last known orientation. So if the user first orient
@@ -758,9 +775,11 @@ public class VideoModule implements CameraModule,
Log.v(TAG, "onOrientationChanged, update parameters");
if ((mCameraDevice != null) && (mParameters != null)
&& (true == mPreviewing) && !mMediaRecorderRecording){
- setFlipValue();
- updatePowerMode();
- mCameraDevice.setParameters(mParameters);
+ synchronized (mCameraDevice) {
+ setFlipValue();
+ updatePowerMode();
+ mCameraDevice.setParameters(mParameters);
+ }
}
mUI.tryToCloseSubList();
mUI.setOrientation(newOrientation, true);
@@ -1167,7 +1186,6 @@ public class VideoModule implements CameraModule,
mDesiredPreviewWidth = optimalSize.width;
mDesiredPreviewHeight = optimalSize.height;
}
- mUI.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight);
Log.v(TAG, "mDesiredPreviewWidth=" + mDesiredPreviewWidth +
". mDesiredPreviewHeight=" + mDesiredPreviewHeight);
}
@@ -1227,51 +1245,35 @@ public class VideoModule implements CameraModule,
@Override
public void onResumeAfterSuper() {
- mUI.enableShutter(false);
+ if (mOpenCameraThread == null) {
+ mOpenCameraThread = new OpenCameraThread();
+ mOpenCameraThread.start();
+ }
+
+ mUI.applySurfaceChange(VideoUI.SURFACE_STATUS.SURFACE_VIEW);
+
+ if (!mFirstTimeInitialized) {
+ initializeFirstTime();
+ }
+
mZoomValue = 0;
- mUI.showSurfaceView();
+
AudioManager am = (AudioManager)mActivity.getSystemService(Context.AUDIO_SERVICE);
mWasMute = am.isMicrophoneMute();
if(mWasMute != mIsMute) {
setMute(mIsMute, false);
}
- initializeVideoControl();
- resetExposureCompensation();
showVideoSnapshotUI(false);
installIntentFilter();
- if (!mPreviewing) {
- openCamera();
- if (mCameraDevice == null) {
- return;
- }
- readVideoPreferences();
- resizeForPreviewAspectRatio();
- startPreview();
- } else {
- // preview already started
- mUI.enableShutter(true);
- }
-
- mUI.applySurfaceChange(VideoUI.SURFACE_STATUS.SURFACE_VIEW);
-
mUI.initDisplayChangeListener();
- // Initializing it here after the preview is started.
- mUI.initializeZoom(mParameters);
- mUI.setPreviewGesturesVideoUI();
- mUI.setSwitcherIndex();
keepScreenOnAwhile();
+ mUI.updateOnScreenIndicators(mParameters, mPreferences);
+ mUI.setSwitcherIndex();
- mOrientationManager.resume();
- // Initialize location service.
- boolean recordLocation = RecordLocationPreference.get(mPreferences);
- mLocationManager.recordLocation(recordLocation);
-
- if (mPreviewing) {
- mOnResumeTime = SystemClock.uptimeMillis();
- mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100);
- }
+ // From onResume
+ mUI.setOrientationIndicator(0, false);
UsageStatistics.onContentViewChanged(
UsageStatistics.COMPONENT_CAMERA, "VideoModule");
@@ -1312,82 +1314,93 @@ public class VideoModule implements CameraModule,
if (mParameters == null || mCameraDevice == null) return index;
// Set zoom parameters asynchronously
mParameters.setZoom(mZoomValue);
- mCameraDevice.setParameters(mParameters);
+ updateCameraParametersZoom();
Parameters p = mCameraDevice.getParameters();
if (p != null) return p.getZoom();
return index;
}
private void startPreview() {
- Log.v(TAG, "startPreview");
+ Log.e(TAG, String.format("startPreview paused=%b device=%b params=%b", mPaused, mCameraDevice == null, mParameters == null), new Throwable());
+ if (mPaused || mCameraDevice == null || mParameters == null) {
+ return;
+ }
+
mStartPrevPending = true;
- SurfaceHolder sh = null;
- Log.v(TAG, "startPreview: SurfaceHolder (MDP path)");
- sh = mUI.getSurfaceHolder();
+ synchronized (mCameraDevice) {
+ SurfaceHolder sh = null;
+ Log.v(TAG, "startPreview: SurfaceHolder (MDP path)");
+ if (mUI != null) {
+ sh = mUI.getSurfaceHolder();
+ }
+
+ // Let UI set its expected aspect ratio
+ mCameraDevice.setPreviewDisplay(sh);
+ }
- if (!mPreferenceRead || mPaused == true || mCameraDevice == null) {
- mStartPrevPending = false;
+ if (!mCameraPreviewParamsReady) {
+ Log.w(TAG, "startPreview: parameters for preview are not ready.");
return;
}
mErrorCallback.setActivity(mActivity);
mCameraDevice.setErrorCallback(mErrorCallback);
- if (mPreviewing == true) {
+
+ if (mRestartPreview && mPreviewing) {
stopPreview();
+ mRestartPreview = false;
}
- setDisplayOrientation();
- mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
- setCameraParameters(true);
+ if (mFocusManager == null) initializeFocusManager();
- try {
- mCameraDevice.setPreviewDisplay(sh);
- mCameraDevice.setOneShotPreviewCallback(mHandler,
- new CameraManager.CameraPreviewDataCallback() {
- @Override
- public void onPreviewFrame(byte[] data, CameraProxy camera) {
- mUI.hidePreviewCover();
- }
- });
- mCameraDevice.startPreview();
- mPreviewing = true;
- mCameraDevice.setOneShotPreviewCallback(mHandler,
+ updateTorchDelayed();
+
+ setCameraParameters(UPDATE_PARAM_ALL);
+
+ mCameraDevice.setOneShotPreviewCallback(mHandler,
new CameraManager.CameraPreviewDataCallback() {
@Override
public void onPreviewFrame(byte[] data, CameraProxy camera) {
mUI.hidePreviewCover();
}
});
- onPreviewStarted();
- } catch (Throwable ex) {
- closeCamera();
- throw new RuntimeException("startPreview failed", ex);
- }
- mStartPrevPending = false;
+ mCameraDevice.startPreview();
- mFocusManager.onPreviewStarted();
+ mHandler.sendEmptyMessage(ON_PREVIEW_STARTED);
+
+ setDisplayOrientation();
+ mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation);
+
+ mStartPrevPending = false;
}
private void onPreviewStarted() {
- mUI.enableShutter(true);
+ mPreviewing = true;
+ mFocusManager.onPreviewStarted();
startFaceDetection();
+ mUI.enableShutter(true);
}
@Override
public void stopPreview() {
- mStopPrevPending = true;
+ if (mCameraDevice == null) {
+ return;
+ }
+ synchronized (mCameraDevice) {
+ mStopPrevPending = true;
- if (mFocusManager != null) mFocusManager.onPreviewStopped();
+ if (mFocusManager != null) mFocusManager.onPreviewStopped();
- if (!mPreviewing) {
+ if (!mPreviewing) {
+ mStopPrevPending = false;
+ return;
+ }
+ mCameraDevice.stopPreview();
+ mPreviewing = false;
mStopPrevPending = false;
- return;
+ mUI.enableShutter(false);
+ stopFaceDetection();
}
- mCameraDevice.stopPreview();
- mPreviewing = false;
- mStopPrevPending = false;
- mUI.enableShutter(false);
- stopFaceDetection();
}
private void closeCamera() {
@@ -1396,13 +1409,15 @@ public class VideoModule implements CameraModule,
Log.d(TAG, "already stopped.");
return;
}
- mCameraDevice.setZoomChangeListener(null);
- mCameraDevice.setErrorCallback(null);
- mCameraDevice.setFaceDetectionCallback(null, null);
- if (mActivity.isForceReleaseCamera()) {
- CameraHolder.instance().strongRelease();
- } else {
- CameraHolder.instance().release();
+ synchronized (mCameraDevice) {
+ mCameraDevice.setZoomChangeListener(null);
+ mCameraDevice.setErrorCallback(null);
+ mCameraDevice.setFaceDetectionCallback(null, null);
+ if (mActivity.isForceReleaseCamera()) {
+ CameraHolder.instance().strongRelease();
+ } else {
+ CameraHolder.instance().release();
+ }
}
mCameraDevice = null;
mPreviewing = false;
@@ -1412,6 +1427,17 @@ public class VideoModule implements CameraModule,
mFaceDetectionStarted = false;
}
+ private void onCameraOpened() {
+ Log.v(TAG, "onCameraOpened");
+ openCameraCommon();
+ initializeVideoSnapshot();
+
+ resizeForPreviewAspectRatio();
+ mFocusManager.setFocusRing(mUI.getFocusRing());
+ mUI.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight);
+ resetExposureCompensation();
+ }
+
private void releasePreviewResources() {
if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) {
mUI.hideSurfaceView();
@@ -1444,9 +1470,7 @@ public class VideoModule implements CameraModule,
resetScreenOn();
if (mLocationManager != null) mLocationManager.recordLocation(false);
- mOrientationManager.pause();
- mHandler.removeMessages(CHECK_DISPLAY_ROTATION);
mHandler.removeMessages(SWITCH_CAMERA);
mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION);
mHandler.removeMessages(HANDLE_FLASH_TORCH_DELAY);
@@ -1465,7 +1489,28 @@ public class VideoModule implements CameraModule,
@Override
public void onPauseAfterSuper() {
- if (mFocusManager != null) mFocusManager.removeMessages();
+ Log.v(TAG, "On pause.");
+
+ mUI.showPreviewCover();
+ mUI.hideSurfaceView();
+
+ // Reset the focus first. Camera CTS does not guarantee that
+ // cancelAutoFocus is allowed after preview stops.
+ if (mCameraDevice != null) {
+ mCameraDevice.cancelAutoFocus();
+ }
+
+ try {
+ if (mOpenCameraThread != null) {
+ mOpenCameraThread.join();
+ }
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ mOpenCameraThread = null;
+
+ stopPreview();
+ closeCamera();
}
/**
@@ -1483,9 +1528,13 @@ public class VideoModule implements CameraModule,
boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
String[] defaultFocusModes = mActivity.getResources().getStringArray(
R.array.pref_video_focusmode_default_array);
- mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
- mParameters, this, mirror,
- mActivity.getMainLooper(), mUI.getFocusRing());
+ synchronized (this) {
+ if (mFocusManager == null) {
+ mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes,
+ mInitialParams, this, mirror,
+ mActivity.getMainLooper(), mUI.getFocusRing());
+ }
+ }
}
}
@@ -1857,6 +1906,8 @@ public class VideoModule implements CameraModule,
private void releaseMediaRecorder() {
Log.v(TAG, "Releasing media recorder.");
+ mUI.stopRecordingTimer();
+
if (mMediaRecorder != null) {
cleanupEmptyFile();
mMediaRecorder.reset();
@@ -2099,12 +2150,12 @@ public class VideoModule implements CameraModule,
mMediaRecorderRecording = true;
mMediaRecorderPausing = false;
- mUI.resetPauseButton();
- mRecordingTotalTime = 0L;
- mRecordingStartTime = SystemClock.uptimeMillis();
+
mUI.showRecordingUI(true);
- updateRecordingTime();
+ mUI.startRecordingTimer(mProfile.videoFrameRate,
+ mTimeBetweenTimeLapseFrameCaptureMs, mMaxVideoDurationInMs);
+
keepScreenOn();
UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
UsageStatistics.ACTION_CAPTURE_START, "Video");
@@ -2149,18 +2200,17 @@ public class VideoModule implements CameraModule,
mUI.showTimeLapseUI(false);
}
- private void pauseVideoRecording() {
+ @Override
+ public void onButtonPause() {
Log.v(TAG, "pauseVideoRecording");
mMediaRecorderPausing = true;
- mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime;
mMediaRecorder.pause();
}
- private void resumeVideoRecording() {
+ @Override
+ public void onButtonContinue() {
Log.v(TAG, "resumeVideoRecording");
mMediaRecorderPausing = false;
- mRecordingStartTime = SystemClock.uptimeMillis();
- updateRecordingTime();
if (!HAS_RESUME_SUPPORTED){
mMediaRecorder.start();
} else {
@@ -2247,7 +2297,9 @@ public class VideoModule implements CameraModule,
} else {
mParameters.setPreviewFrameRate(30);
}
- mCameraDevice.setParameters(mParameters);
+ synchronized (mCameraDevice) {
+ mCameraDevice.setParameters(mParameters);
+ }
}
}
}
@@ -2257,8 +2309,7 @@ public class VideoModule implements CameraModule,
UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA,
fail ? UsageStatistics.ACTION_CAPTURE_FAIL :
UsageStatistics.ACTION_CAPTURE_DONE, "Video",
- mMediaRecorderPausing ? mRecordingTotalTime :
- SystemClock.uptimeMillis() - mRecordingStartTime + mRecordingTotalTime);
+ mUI.getRecordingTime());
mStopRecPending = false;
return fail;
}
@@ -2279,111 +2330,6 @@ public class VideoModule implements CameraModule,
mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
- private static String millisecondToTimeString(long milliSeconds, boolean displayCentiSeconds) {
- long seconds = milliSeconds / 1000; // round down to compute seconds
- long minutes = seconds / 60;
- long hours = minutes / 60;
- long remainderMinutes = minutes - (hours * 60);
- long remainderSeconds = seconds - (minutes * 60);
-
- StringBuilder timeStringBuilder = new StringBuilder();
-
- // Hours
- if (hours > 0) {
- if (hours < 10) {
- timeStringBuilder.append('0');
- }
- timeStringBuilder.append(hours);
-
- timeStringBuilder.append(':');
- }
-
- // Minutes
- if (remainderMinutes < 10) {
- timeStringBuilder.append('0');
- }
- timeStringBuilder.append(remainderMinutes);
- timeStringBuilder.append(':');
-
- // Seconds
- if (remainderSeconds < 10) {
- timeStringBuilder.append('0');
- }
- timeStringBuilder.append(remainderSeconds);
-
- // Centi seconds
- if (displayCentiSeconds) {
- timeStringBuilder.append('.');
- long remainderCentiSeconds = (milliSeconds - seconds * 1000) / 10;
- if (remainderCentiSeconds < 10) {
- timeStringBuilder.append('0');
- }
- timeStringBuilder.append(remainderCentiSeconds);
- }
-
- return timeStringBuilder.toString();
- }
-
- private long getTimeLapseVideoLength(long deltaMs) {
- // For better approximation calculate fractional number of frames captured.
- // This will update the video time at a higher resolution.
- double numberOfFrames = (double) deltaMs / mTimeBetweenTimeLapseFrameCaptureMs;
- return (long) (numberOfFrames / mProfile.videoFrameRate * 1000);
- }
-
- private void updateRecordingTime() {
- if (!mMediaRecorderRecording) {
- return;
- }
- if (mMediaRecorderPausing) {
- return;
- }
-
- long now = SystemClock.uptimeMillis();
- long delta = now - mRecordingStartTime + mRecordingTotalTime;
-
- // Starting a minute before reaching the max duration
- // limit, we'll countdown the remaining time instead.
- boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0
- && delta >= mMaxVideoDurationInMs - 60000);
-
- long deltaAdjusted = delta;
- if (countdownRemainingTime) {
- deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999;
- }
- String text;
-
- long targetNextUpdateDelay;
- if (!mCaptureTimeLapse) {
- text = millisecondToTimeString(deltaAdjusted, false);
- targetNextUpdateDelay = 1000;
- } else {
- // The length of time lapse video is different from the length
- // of the actual wall clock time elapsed. Display the video length
- // only in format hh:mm:ss.dd, where dd are the centi seconds.
- text = millisecondToTimeString(getTimeLapseVideoLength(delta), true);
- targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs;
- }
-
- mUI.setRecordingTime(text);
-
- if (mRecordingTimeCountsDown != countdownRemainingTime) {
- // Avoid setting the color on every update, do it only
- // when it needs changing.
- mRecordingTimeCountsDown = countdownRemainingTime;
-
- int color = mActivity.getResources().getColor(countdownRemainingTime
- ? R.color.recording_time_remaining_text
- : R.color.recording_time_elapsed_text);
-
- mUI.setRecordingTimeTextColor(color);
- }
-
- long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
- mHandler.sendEmptyMessageDelayed(
- UPDATE_RECORD_TIME, actualNextUpdateDelay);
- }
-
private static boolean isSupported(String value, List<String> supported) {
return supported == null ? false : supported.indexOf(value) >= 0;
}
@@ -2439,7 +2385,16 @@ public class VideoModule implements CameraModule,
}
}
- private void qcomSetCameraParameters(){
+ public void overrideSettings(final String... keyvalues) {
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mUI.overrideSettings(keyvalues);
+ }
+ });
+ }
+
+ private void qcomSetCameraParameters() {
// add QCOM Parameters here
// Set color effect parameter.
Log.i(TAG,"NOTE: qcomSetCameraParameters " + videoWidth + " x " + videoHeight);
@@ -2462,8 +2417,10 @@ public class VideoModule implements CameraModule,
CameraSettings.getSupportedDISModes(mParameters))) {
mParameters.set(CameraSettings.KEY_QC_DIS_MODE,
mActivity.getString(R.string.pref_camera_dis_value_disable));
- mUI.overrideSettings(CameraSettings.KEY_DIS,
+
+ overrideSettings(CameraSettings.KEY_DIS,
mActivity.getString(R.string.pref_camera_dis_value_disable));
+
mIsDISEnabled = false;
} else {
Log.e(TAG, "Not supported IS mode = " +
@@ -2607,8 +2564,9 @@ public class VideoModule implements CameraModule,
pref_camera_video_tnr_value_off))) {
mParameters.set(CameraSettings.KEY_QC_VIDEO_CDS_MODE,
mActivity.getString(R.string.pref_camera_video_cds_value_off));
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE,
+ overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE,
mActivity.getString(R.string.pref_camera_video_cds_value_off));
+
if (!mIsVideoCDSUpdated) {
if (video_cds != null) {
mPrevSavedVideoCDS = mTempVideoCDS;
@@ -2618,7 +2576,7 @@ public class VideoModule implements CameraModule,
}
} else if (mIsVideoTNREnabled) {
mParameters.set(CameraSettings.KEY_QC_VIDEO_CDS_MODE, mPrevSavedVideoCDS);
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE, mPrevSavedVideoCDS);
+ overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE, mPrevSavedVideoCDS);
mIsVideoTNREnabled = false;
mIsVideoCDSUpdated = false;
mOverrideCDS = true;
@@ -2626,7 +2584,7 @@ public class VideoModule implements CameraModule,
mTempVideoCDS = video_cds;
}
mParameters.set(CameraSettings.KEY_QC_VIDEO_TNR_MODE, video_tnr);
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_TNR_MODE, video_tnr);
+ overrideSettings(CameraSettings.KEY_VIDEO_TNR_MODE, video_tnr);
}
String noiseReductionMode = mPreferences.getString(
@@ -2643,7 +2601,7 @@ public class VideoModule implements CameraModule,
pref_camera_video_cds_value_on))) {
mParameters.set(CameraSettings.KEY_QC_VIDEO_CDS_MODE,
mActivity.getString(R.string.pref_camera_video_cds_value_off));
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE,
+ overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE,
mActivity.getString(R.string.pref_camera_video_cds_value_off));
Toast.makeText(mActivity, R.string.disable_CDS_during_HighQualityNoiseReduction,
Toast.LENGTH_LONG).show();
@@ -2656,7 +2614,7 @@ public class VideoModule implements CameraModule,
pref_camera_video_tnr_value_on))) {
mParameters.set(CameraSettings.KEY_QC_VIDEO_TNR_MODE,
mActivity.getString(R.string.pref_camera_video_tnr_value_off));
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_TNR_MODE,
+ overrideSettings(CameraSettings.KEY_VIDEO_TNR_MODE,
mActivity.getString(R.string.pref_camera_video_tnr_value_off));
Toast.makeText(mActivity, R.string.disable_TNR_during_HighQualityNoiseReduction,
Toast.LENGTH_LONG).show();
@@ -2677,26 +2635,26 @@ public class VideoModule implements CameraModule,
if (seeMoreMode.equals(
mActivity.getString(R.string.pref_camera_see_more_value_on)) &&
video_cds.equals(mActivity.getString(R.string.
- pref_camera_video_cds_value_on))) {
+ pref_camera_video_cds_value_on))) {
mParameters.set(CameraSettings.KEY_QC_VIDEO_CDS_MODE,
- mActivity.getString(R.string.pref_camera_video_cds_value_off));
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE,
- mActivity.getString(R.string.pref_camera_video_cds_value_off));
+ mActivity.getString(R.string.pref_camera_video_cds_value_off));
+ overrideSettings(CameraSettings.KEY_VIDEO_CDS_MODE,
+ mActivity.getString(R.string.pref_camera_video_cds_value_off));
Toast.makeText(mActivity, R.string.disable_CDS_during_SeeMore,
- Toast.LENGTH_LONG).show();
+ Toast.LENGTH_LONG).show();
}
/* Disable TNR */
if (seeMoreMode.equals(
mActivity.getString(R.string.pref_camera_see_more_value_on)) &&
video_tnr.equals(mActivity.getString(R.string.
- pref_camera_video_tnr_value_on))) {
+ pref_camera_video_tnr_value_on))) {
mParameters.set(CameraSettings.KEY_QC_VIDEO_TNR_MODE,
- mActivity.getString(R.string.pref_camera_video_tnr_value_off));
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_TNR_MODE,
- mActivity.getString(R.string.pref_camera_video_tnr_value_off));
+ mActivity.getString(R.string.pref_camera_video_tnr_value_off));
+ overrideSettings(CameraSettings.KEY_VIDEO_TNR_MODE,
+ mActivity.getString(R.string.pref_camera_video_tnr_value_off));
Toast.makeText(mActivity, R.string.disable_TNR_during_SeeMore,
- Toast.LENGTH_LONG).show();
+ Toast.LENGTH_LONG).show();
}
/* Disable NR */
@@ -2706,7 +2664,7 @@ public class VideoModule implements CameraModule,
pref_camera_noise_reduction_value_off))) {
mParameters.set(CameraSettings.KEY_QC_NOISE_REDUCTION_MODE,
mActivity.getString(R.string.pref_camera_noise_reduction_value_off));
- mUI.overrideSettings(CameraSettings.KEY_NOISE_REDUCTION,
+ overrideSettings(CameraSettings.KEY_NOISE_REDUCTION,
mActivity.getString(R.string.pref_camera_noise_reduction_value_off));
Toast.makeText(mActivity, R.string.disable_NR_during_SeeMore,
Toast.LENGTH_LONG).show();
@@ -2746,9 +2704,9 @@ public class VideoModule implements CameraModule,
(disMode.equals("enable") && (rate > PERSIST_EIS_MAX_FPS)) ||
((hdr != null) && (!hdr.equals("off"))) ) {
Log.v(TAG,"HDR/DIS/Time Lapse ON for HFR/HSR selection, turning HFR/HSR off");
- mParameters.setVideoHighFrameRate("off");
- mParameters.set(CameraSettings.KEY_VIDEO_HSR, "off");
- mUI.overrideSettings(CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE, "off");
+ mParameters.setVideoHighFrameRate("off");
+ mParameters.set(CameraSettings.KEY_VIDEO_HSR, "off");
+ overrideSettings(CameraSettings.KEY_VIDEO_HIGH_FRAME_RATE, "off");
}
}
@@ -2757,15 +2715,15 @@ public class VideoModule implements CameraModule,
if (biggestSize.width <= videoWidth || biggestSize.height <= videoHeight) {
if (disMode.equals("enable")) {
- Log.v(TAG,"DIS is not supported for this video quality");
+ Log.v(TAG, "DIS is not supported for this video quality");
RotateTextToast.makeText(mActivity, R.string.error_app_unsupported_dis,
- Toast.LENGTH_LONG).show();
+ Toast.LENGTH_LONG).show();
mParameters.set(CameraSettings.KEY_QC_DIS_MODE, "disable");
- mUI.overrideSettings(CameraSettings.KEY_DIS,"disable");
+ overrideSettings(CameraSettings.KEY_DIS, "disable");
mIsDISEnabled = false;
}
}
- //setting video rotation
+ //setting video rotation
String videoRotation = mPreferences.getString(
CameraSettings.KEY_VIDEO_ROTATION,
mActivity.getString(R.string.pref_camera_video_rotation_default));
@@ -2802,11 +2760,27 @@ public class VideoModule implements CameraModule,
}
}
- @SuppressWarnings("deprecation")
- private void setCameraParameters(boolean isFlashDelay) {
- Log.d(TAG,"Preview dimension in App->"+mDesiredPreviewWidth+"X"+mDesiredPreviewHeight);
+ private void updateCameraParametersZoom() {
+ if (mCameraDevice == null) {
+ return;
+ }
+ synchronized (mCameraDevice) {
+ // Set zoom.
+ if (mParameters.isZoomSupported()) {
+ Parameters p = mCameraDevice.getParameters();
+ mZoomValue = p.getZoom();
+ mParameters.setZoom(mZoomValue);
+ }
+ }
+ }
+
+ private void updateTorchDelayed() {
+ mHandler.sendEmptyMessageDelayed(HANDLE_FLASH_TORCH_DELAY, 800);
+ }
+
+ private void updateCameraParametersInitialize() {
mParameters.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight);
- mParameters.set("video-size", mProfile.videoFrameWidth+"x"+mProfile.videoFrameHeight);
+ mParameters.set("video-size", mProfile.videoFrameWidth + "x" + mProfile.videoFrameHeight);
int[] fpsRange = CameraUtil.getMaxPreviewFpsRange(mParameters);
if (fpsRange.length > 0) {
mParameters.setPreviewFpsRange(
@@ -2816,49 +2790,17 @@ public class VideoModule implements CameraModule,
mParameters.setPreviewFrameRate(mProfile.videoFrameRate);
}
- if (isFlashDelay) {
- mHandler.sendEmptyMessageDelayed(HANDLE_FLASH_TORCH_DELAY, 800);
- } else {
- forceFlashOffIfSupported(!mPreviewFocused);
- }
+ forceFlashOffIfSupported(!mPreviewFocused);
+
videoWidth = mProfile.videoFrameWidth;
videoHeight = mProfile.videoFrameHeight;
- Log.i(TAG,"NOTE: SetCameraParameters " + videoWidth + " x " + videoHeight);
+ Log.i(TAG, "NOTE: SetCameraParameters " + videoWidth + " x " + videoHeight);
String recordSize = videoWidth + "x" + videoHeight;
- Log.e(TAG,"Video dimension in App->"+recordSize);
+ Log.e(TAG, "Video dimension in App->" + recordSize);
if (CameraUtil.isSupported(mParameters, "video-size")) {
mParameters.set("video-size", recordSize);
}
- // Set exposure compensation
- int value = CameraSettings.readExposure(mPreferences);
- int max = mParameters.getMaxExposureCompensation();
- int min = mParameters.getMinExposureCompensation();
- if (value >= min && value <= max) {
- mParameters.setExposureCompensation(value);
- } else {
- Log.w(TAG, "invalid exposure range: " + value);
- }
- // Set white balance parameter.
- String whiteBalance = mPreferences.getString(
- CameraSettings.KEY_WHITE_BALANCE,
- mActivity.getString(R.string.pref_camera_whitebalance_default));
- if (isSupported(whiteBalance,
- mParameters.getSupportedWhiteBalance())) {
- mParameters.setWhiteBalance(whiteBalance);
- } else {
- whiteBalance = mParameters.getWhiteBalance();
- if (whiteBalance == null) {
- whiteBalance = Parameters.WHITE_BALANCE_AUTO;
- }
- }
-
- // Set zoom.
- if (mParameters.isZoomSupported()) {
- Parameters p = mCameraDevice.getParameters();
- mZoomValue = p.getZoom();
- mParameters.setZoom(mZoomValue);
- }
// Set focus mode
mParameters.setFocusMode(mFocusManager.getFocusMode(true));
@@ -2871,73 +2813,112 @@ public class VideoModule implements CameraModule,
if ("true".equals(vstabSupported)) {
mParameters.set("video-stabilization", "true");
}
+ }
+
+ // We separate the parameters into several subsets, so we can update only
+ // the subsets actually need updating. The PREFERENCE set needs extra
+ // locking because the preference can be changed from GLThread as well.
+ private void setCameraParameters(int updateSet) {
+ if (mCameraDevice == null) {
+ return;
+ }
+ synchronized (mCameraDevice) {
+ if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) {
+ updateCameraParametersInitialize();
+ }
- // Set picture size.
- // The logic here is different from the logic in still-mode camera.
- // There we determine the preview size based on the picture size, but
- // here we determine the picture size based on the preview size.
- String videoSnapshotSize = mPreferences.getString(
- CameraSettings.KEY_VIDEO_SNAPSHOT_SIZE,
- mActivity.getString(R.string.pref_camera_videosnapsize_default));
- Size optimalSize;
- if(videoSnapshotSize.equals("auto")) {
- List<Size> supported = mParameters.getSupportedPictureSizes();
- optimalSize = CameraUtil.getOptimalVideoSnapshotPictureSize(supported,
- (double) mDesiredPreviewWidth / mDesiredPreviewHeight);
- Size original = mParameters.getPictureSize();
- if (!original.equals(optimalSize)) {
- mParameters.setPictureSize(optimalSize.width, optimalSize.height);
+ if ((updateSet & UPDATE_PARAM_ZOOM) != 0) {
+ updateCameraParametersZoom();
}
- } else {
- CameraSettings.setCameraPictureSize(
- videoSnapshotSize,
- mParameters.getSupportedPictureSizes(),
- mParameters);
- optimalSize = mParameters.getPictureSize();
- }
- Log.v(TAG, "Video snapshot size is " + optimalSize.width + "x" +
- optimalSize.height);
+ if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) {
+ updateCameraParametersPreference();
+ }
- // Set jpegthumbnail size
- // Set a jpegthumbnail size that is closest to the Picture height and has
- // the right aspect ratio.
- Size size = mParameters.getPictureSize();
- List<Size> sizes = mParameters.getSupportedJpegThumbnailSizes();
- optimalSize = CameraUtil.getOptimalJpegThumbnailSize(sizes,
- (double) size.width / size.height);
- Size original = mParameters.getJpegThumbnailSize();
- if (!original.equals(optimalSize)) {
- mParameters.setJpegThumbnailSize(optimalSize.width, optimalSize.height);
+ CameraUtil.dumpParameters(mParameters);
+ mCameraDevice.setParameters(mParameters);
+ mFocusManager.setParameters(mParameters);
}
- Log.v(TAG, "Thumbnail size is " + optimalSize.width + "x" + optimalSize.height);
-
- // Set JPEG quality.
- int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
- CameraProfile.QUALITY_HIGH);
- mParameters.setJpegQuality(jpegQuality);
+ }
- CameraUtil.dumpParameters(mParameters);
+ private void updateCameraParametersPreference() {
+ if (mCameraDevice == null) {
+ return;
+ }
+ synchronized (mCameraDevice) {
+ Log.d(TAG, "Preview dimension in App->" + mDesiredPreviewWidth + "X" + mDesiredPreviewHeight);
- //Call Qcom related Camera Parameters
- qcomSetCameraParameters();
+ // Set exposure compensation
+ int value = CameraSettings.readExposure(mPreferences);
+ int max = mParameters.getMaxExposureCompensation();
+ int min = mParameters.getMinExposureCompensation();
+ if (value >= min && value <= max) {
+ mParameters.setExposureCompensation(value);
+ } else {
+ Log.w(TAG, "invalid exposure range: " + value);
+ }
+ // Set white balance parameter.
+ String whiteBalance = mPreferences.getString(
+ CameraSettings.KEY_WHITE_BALANCE,
+ mActivity.getString(R.string.pref_camera_whitebalance_default));
+ if (isSupported(whiteBalance,
+ mParameters.getSupportedWhiteBalance())) {
+ mParameters.setWhiteBalance(whiteBalance);
+ } else {
+ whiteBalance = mParameters.getWhiteBalance();
+ if (whiteBalance == null) {
+ whiteBalance = Parameters.WHITE_BALANCE_AUTO;
+ }
+ }
- boolean flag = false;
- if (mPreviewing) {
- stopPreview();
- flag = true;
- }
- mCameraDevice.setParameters(mParameters);
- if (flag) {
- startPreview();
- }
- // Keep preview size up to date.
- mParameters = mCameraDevice.getParameters();
+ // Set picture size.
+ // The logic here is different from the logic in still-mode camera.
+ // There we determine the preview size based on the picture size, but
+ // here we determine the picture size based on the preview size.
+ String videoSnapshotSize = mPreferences.getString(
+ CameraSettings.KEY_VIDEO_SNAPSHOT_SIZE,
+ mActivity.getString(R.string.pref_camera_videosnapsize_default));
+ Size optimalSize;
+ if (videoSnapshotSize.equals("auto")) {
+ List<Size> supported = mParameters.getSupportedPictureSizes();
+ optimalSize = CameraUtil.getOptimalVideoSnapshotPictureSize(supported,
+ (double) mDesiredPreviewWidth / mDesiredPreviewHeight);
+ Size original = mParameters.getPictureSize();
+ if (!original.equals(optimalSize)) {
+ mParameters.setPictureSize(optimalSize.width, optimalSize.height);
+ }
+ } else {
+ CameraSettings.setCameraPictureSize(
+ videoSnapshotSize,
+ mParameters.getSupportedPictureSizes(),
+ mParameters);
+ optimalSize = mParameters.getPictureSize();
+ }
+
+ Log.v(TAG, "Video snapshot size is " + optimalSize.width + "x" +
+ optimalSize.height);
+
+ // Set jpegthumbnail size
+ // Set a jpegthumbnail size that is closest to the Picture height and has
+ // the right aspect ratio.
+ Size size = mParameters.getPictureSize();
+ List<Size> sizes = mParameters.getSupportedJpegThumbnailSizes();
+ optimalSize = CameraUtil.getOptimalJpegThumbnailSize(sizes,
+ (double) size.width / size.height);
+ Size original = mParameters.getJpegThumbnailSize();
+ if (!original.equals(optimalSize)) {
+ mParameters.setJpegThumbnailSize(optimalSize.width, optimalSize.height);
+ }
+ Log.v(TAG, "Thumbnail size is " + optimalSize.width + "x" + optimalSize.height);
- // Update UI based on the new parameters.
- mUI.updateOnScreenIndicators(mParameters, mPreferences);
+ // Set JPEG quality.
+ int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId,
+ CameraProfile.QUALITY_HIGH);
+ mParameters.setJpegQuality(jpegQuality);
- mFocusManager.setPreviewSize(videoWidth, videoHeight);
+ //Call Qcom related Camera Parameters
+ qcomSetCameraParameters();
+ }
}
@Override
@@ -2989,10 +2970,11 @@ public class VideoModule implements CameraModule,
if (mPaused) {
return;
}
- synchronized (mPreferences) {
- // If mCameraDevice is not ready then we can set the parameter in
- // startPreview().
- if (mCameraDevice == null) return;
+ // If mCameraDevice is not ready then we can set the parameter in
+ // startPreview().
+ if (mCameraDevice == null) return;
+
+ synchronized (mCameraDevice) {
boolean recordLocation = RecordLocationPreference.get(mPreferences);
mLocationManager.recordLocation(recordLocation);
@@ -3008,10 +2990,9 @@ public class VideoModule implements CameraModule,
resizeForPreviewAspectRatio();
startPreview(); // Parameters will be set in startPreview().
} else {
- setCameraParameters(false);
+ mHandler.sendEmptyMessage(SET_VIDEO_UI_PARAMS);
}
mRestartPreview = false;
- mUI.updateOnScreenIndicators(mParameters, mPreferences);
Storage.setSaveSDCard(
mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));
mActivity.updateStorageSpaceAndHint();
@@ -3025,6 +3006,13 @@ public class VideoModule implements CameraModule,
pref.setValue("" + cameraId);
}
+ // either open a new camera or switch cameras
+ private void openCameraCommon() {
+ loadCameraPreferences();
+
+ mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this);
+ }
+
private void switchCamera() {
if (mPaused) {
return;
@@ -3036,48 +3024,64 @@ public class VideoModule implements CameraModule,
mPendingSwitchCameraId = -1;
setCameraId(mCameraId);
+ try {
+ if (mOpenCameraThread != null) {
+ mOpenCameraThread.join();
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ mOpenCameraThread = null;
+
+ // from onPause
+ try {
+ if (mOpenCameraThread != null) {
+ mOpenCameraThread.join();
+ mOpenCameraThread = null;
+ }
+ } catch (InterruptedException ex) {
+ // ignore
+ }
closeCamera();
mUI.collapseCameraControls();
if (mFocusManager != null) mFocusManager.removeMessages();
+
// Restart the camera and initialize the UI. From onCreate.
mPreferences.setLocalId(mActivity, mCameraId);
CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
- openCamera();
+ mCameraDevice = CameraUtil.openCamera(
+ mActivity, mCameraId, mHandler,
+ mActivity.getCameraOpenErrorCallback());
+ if (mCameraDevice == null) {
+ Log.e(TAG, "Failed to open camera:" + mCameraId + ", aborting.");
+ return;
+ }
+ mParameters = mCameraDevice.getParameters();
+ mInitialParams = mParameters;
+ initializeCapabilities();
CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT);
- mParameters = mCameraDevice.getParameters();
mFocusManager.setMirror(mirror);
- mFocusManager.setParameters(mParameters);
-
- readVideoPreferences();
- mUI.applySurfaceChange(VideoUI.SURFACE_STATUS.SURFACE_VIEW);
+ setCameraParameters(UPDATE_PARAM_ALL);
startPreview();
- initializeVideoSnapshot();
- resizeForPreviewAspectRatio();
- initializeVideoControl();
-
- initializeCapabilities();
- // From onResume
+ mUI.applySurfaceChange(VideoUI.SURFACE_STATUS.SURFACE_VIEW);
mZoomValue = 0;
- mUI.initializeZoom(mParameters);
- mUI.setOrientationIndicator(0, false);
-
- // Start switch camera animation. Post a message because
- // onFrameAvailable from the old camera may already exist.
- mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
- mUI.updateOnScreenIndicators(mParameters, mPreferences);
+ resizeForPreviewAspectRatio();
+ openCameraCommon();
//Display timelapse msg depending upon selection in front/back camera.
mUI.showTimeLapseUI(mCaptureTimeLapse);
+
+ mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION);
}
private void initializeCapabilities() {
- mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mParameters);
- mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mParameters);
- mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mParameters);
- mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mParameters);
+ mFocusAreaSupported = CameraUtil.isFocusAreaSupported(mInitialParams);
+ mMeteringAreaSupported = CameraUtil.isMeteringAreaSupported(mInitialParams);
+ mAeLockSupported = CameraUtil.isAutoExposureLockSupported(mInitialParams);
+ mAwbLockSupported = CameraUtil.isAutoWhiteBalanceLockSupported(mInitialParams);
}
// Preview texture has been copied. Now camera can be released and the
@@ -3144,11 +3148,13 @@ public class VideoModule implements CameraModule,
* @param forceOff whether we want to force the flash off.
*/
private void forceFlashOff(boolean forceOff) {
- if (!mPreviewing || mParameters.getFlashMode() == null) {
+ if (mCameraDevice == null || !mPreviewing || mParameters.getFlashMode() == null) {
return;
}
- forceFlashOffIfSupported(forceOff);
- mCameraDevice.setParameters(mParameters);
+ synchronized (mCameraDevice) {
+ forceFlashOffIfSupported(forceOff);
+ mCameraDevice.setParameters(mParameters);
+ }
mUI.updateOnScreenIndicators(mParameters, mPreferences);
}
@@ -3237,14 +3243,12 @@ public class VideoModule implements CameraModule,
if (mPaused || mPendingSwitchCameraId != -1) return;
mPendingSwitchCameraId = cameraId;
- Log.d(TAG, "Start to copy texture.");
+
+ Log.v(TAG, "Start to switch camera. cameraId=" + cameraId);
// We need to keep a preview frame for the animation before
// releasing the camera. This will trigger onPreviewTextureCopied.
- // TODO: ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture();
- // Disable all camera controls.
- mSwitchingCamera = true;
+ //TODO: Need to animate the camera switch
switchCamera();
-
}
@Override
@@ -3279,17 +3283,19 @@ public class VideoModule implements CameraModule,
@Override
public void onPreviewUIDestroyed() {
- stopPreview();
- }
-
- @Override
- public void onButtonPause() {
- pauseVideoRecording();
- }
- @Override
- public void onButtonContinue() {
- resumeVideoRecording();
+ if (mCameraDevice == null) {
+ return;
+ }
+ try {
+ if (mOpenCameraThread != null) {
+ mOpenCameraThread.join();
+ mOpenCameraThread = null;
+ }
+ } catch (InterruptedException ex) {
+ // ignore
+ }
+ stopPreview();
}
private void updatePowerMode() {
@@ -3311,9 +3317,14 @@ public class VideoModule implements CameraModule,
|| mFaceDetectionStarted) return;
if (mParameters.getMaxNumDetectedFaces() > 0) {
mFaceDetectionStarted = true;
- CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
- mUI.onStartFaceDetection(mCameraDisplayOrientation,
- (info.facing == CameraInfo.CAMERA_FACING_FRONT));
+ final CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mUI.onStartFaceDetection(mCameraDisplayOrientation,
+ (info.facing == CameraInfo.CAMERA_FACING_FRONT));
+ }
+ });
mCameraDevice.setFaceDetectionCallback(mHandler, mUI);
Log.d(TAG, "start face detection Video "+mParameters.getMaxNumDetectedFaces());
mCameraDevice.startFaceDetection();
@@ -3339,12 +3350,15 @@ public class VideoModule implements CameraModule,
@Override
public void showPreviewCover() {
+ stopFaceDetection();
+ mUI.getFocusRing().stopFocusAnimations();
mUI.showPreviewCover();
}
@Override
public void hidePreviewCover() {
mUI.hidePreviewCover();
+ startFaceDetection();
}
@Override
diff --git a/src/com/android/camera/VideoUI.java b/src/com/android/camera/VideoUI.java
index 6eff51e..a21b327 100644
--- a/src/com/android/camera/VideoUI.java
+++ b/src/com/android/camera/VideoUI.java
@@ -26,6 +26,7 @@ import android.graphics.Color;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
+import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Face;
import android.util.Log;
@@ -57,9 +58,11 @@ import com.android.camera.ui.FaceView;
import com.android.camera.ui.ListSubMenu;
import com.android.camera.ui.ModuleSwitcher;
import com.android.camera.ui.PieRenderer;
+import com.android.camera.ui.RecordingTime;
import com.android.camera.ui.RenderOverlay;
-import com.android.camera.ui.RotateImageView;
+import com.android.camera.ui.ReversibleLinearLayout;
import com.android.camera.ui.RotateLayout;
+import com.android.camera.ui.RotateImageView;
import com.android.camera.ui.RotateTextToast;
import com.android.camera.ui.ZoomRenderer;
import com.android.camera.ui.focus.FocusRing;
@@ -82,10 +85,8 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
private View mReviewDoneButton;
private View mReviewPlayButton;
private ShutterButton mShutterButton;
- private PauseButton mPauseButton;
- private TextView mRecordingTimeView;
+ private RecordingTime mRecordingTime;
private LinearLayout mLabelsLinearLayout;
- private View mTimeLapseLabel;
private RenderOverlay mRenderOverlay;
private PieRenderer mPieRenderer;
private VideoMenu mVideoMenu;
@@ -94,7 +95,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
private PreviewGestures mGestures;
private View mMenuButton;
private OnScreenIndicators mOnScreenIndicators;
- private RotateLayout mRecordingTimeRect;
private boolean mRecordingStarted = false;
private VideoController mController;
private int mZoomMax;
@@ -102,7 +102,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
private ImageView mThumbnail;
private boolean mOrientationResize;
private boolean mPrevOrientationResize;
- private boolean mIsTimeLapse = false;
private RotateLayout mMenuLayout;
private RotateLayout mSubMenuLayout;
private LinearLayout mPreviewMenuLayout;
@@ -213,6 +212,7 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
}
});
+ mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
mFocusRing = (FocusRing) mRootView.findViewById(R.id.focus_ring);
mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
@@ -236,9 +236,8 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
});
initializeMiscControls();
- initializeOverlay();
initializeControlByIntent();
- initializePauseButton();
+ initializeRecordingTime();
ViewStub faceViewStub = (ViewStub) mRootView
.findViewById(R.id.face_view_stub);
@@ -249,10 +248,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
}
mOrientationResize = false;
mPrevOrientationResize = false;
-
- mCameraControls.disableSceneModes();
-
- ((ViewGroup)mRootView).removeView(mRecordingTimeRect);
}
public void cameraOrientationPreviewResize(boolean orientation){
@@ -264,15 +259,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
mSurfaceTextureSizeListener = listener;
}
- public void initializeSurfaceView() {
- if (mSurfaceView == null) {
- mSurfaceView = new SurfaceView(mActivity);
- ((ViewGroup) mRootView).addView(mSurfaceView, 0);
- mSurfaceHolder = mSurfaceView.getHolder();
- mSurfaceHolder.addCallback(this);
- }
- }
-
private void initializeControlByIntent() {
mMenuButton = mRootView.findViewById(R.id.menu);
mMenuButton.setOnClickListener(new OnClickListener() {
@@ -282,9 +268,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
}
});
- mOnScreenIndicators = new OnScreenIndicators(mActivity,
- mRootView.findViewById(R.id.on_screen_indicators));
- mOnScreenIndicators.resetToDefault();
if (mController.isVideoCaptureIntent()) {
mCameraControls.hideSwitcher();
mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
@@ -337,7 +320,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
mAspectRatio = ratio;
}
- mCameraControls.setPreviewRatio(mAspectRatio, false);
layoutPreview((float) ratio);
}
@@ -535,28 +517,42 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
mSurfaceView.setVisibility(View.VISIBLE);
}
- private void initializeOverlay() {
- mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
+ private void initIndicators() {
+ mOnScreenIndicators = new OnScreenIndicators(mActivity,
+ mRootView.findViewById(R.id.on_screen_indicators));
+ }
+
+ public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs,
+ Camera.Parameters params, OnPreferenceChangedListener listener) {
if (mPieRenderer == null) {
mPieRenderer = new PieRenderer(mActivity);
// mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
mPieRenderer.setPieListener(this);
+ mRenderOverlay.addRenderer(mPieRenderer);
}
if (mVideoMenu == null) {
mVideoMenu = new VideoMenu(mActivity, this);
+ mVideoMenu.setListener(listener);
}
- mRenderOverlay.addRenderer(mPieRenderer);
+ mVideoMenu.initialize(prefGroup);
+
if (mZoomRenderer == null) {
mZoomRenderer = new ZoomRenderer(mActivity);
+ mRenderOverlay.addRenderer(mZoomRenderer);
}
- mRenderOverlay.addRenderer(mZoomRenderer);
+
if (mGestures == null) {
mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
mRenderOverlay.setGestures(mGestures);
}
mGestures.setVideoMenu(mVideoMenu);
+ mGestures.setZoomEnabled(params.isZoomSupported());
mGestures.setRenderOverlay(mRenderOverlay);
+ mRenderOverlay.requestLayout();
+
+ initializeZoom(params);
+ mActivity.setPreviewGestures(mGestures);
if (!mActivity.isSecureCamera()) {
mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
@@ -572,10 +568,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
}
}
- public void setPreviewGesturesVideoUI() {
- mActivity.setPreviewGestures(mGestures);
- }
-
public boolean isCameraControlsAnimating() {
return mCameraControls.isAnimating();
}
@@ -584,31 +576,42 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
mVideoMenu.setListener(listener);
}
- private void initializeMiscControls() {
- mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
+ // called from onResume but only the first time
+ public void initializeFirstTime() {
+ initIndicators();
+
+ // Initialize shutter button.
mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
mShutterButton.addOnShutterButtonListener(mController);
+ mShutterButton.setVisibility(View.VISIBLE);
+
+ mCameraControls.disableSceneModes();
+ }
+
+ private void initializeMiscControls() {
+ mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
mShutterButton.requestFocus();
mShutterButton.enableTouch(true);
- mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
- mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
- mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
+
// The R.id.labels can only be found in phone layout.
// That is, mLabelsLinearLayout should be null in tablet layout.
mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
}
- private void initializePauseButton() {
- mPauseButton = (PauseButton) mRootView.findViewById(R.id.video_pause);
- mPauseButton.setOnPauseButtonListener(this);
+ private void initializeRecordingTime() {
+ mRecordingTime = (RecordingTime) mRootView.findViewById(R.id.recording_time);
+ mRecordingTime.setPauseListener(this);
}
public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
- mOnScreenIndicators.updateExposureOnScreenIndicator(param,
- CameraSettings.readExposure(prefs));
- mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
- boolean location = RecordLocationPreference.get(prefs);
- mOnScreenIndicators.updateLocationIndicator(location);
+ if (param == null) {
+ return;
+ }
+ mOnScreenIndicators.updateExposureOnScreenIndicator(param,
+ CameraSettings.readExposure(prefs));
+ mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
+ boolean location = RecordLocationPreference.get(prefs);
+ mOnScreenIndicators.updateLocationIndicator(location);
}
@@ -622,15 +625,11 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
mAspectRatio = (float)ratio;
}
- mCameraControls.setPreviewRatio(mAspectRatio, false);
layoutPreview((float)ratio);
}
public void showTimeLapseUI(boolean enable) {
- if (mTimeLapseLabel != null) {
- mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
- }
- mIsTimeLapse = enable;
+ mRecordingTime.showTimeLapse(enable);
}
public void dismissPopup(boolean topLevelOnly) {
@@ -865,28 +864,37 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
public void showRecordingUI(boolean recording) {
mRecordingStarted = recording;
- mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
if (recording) {
mShutterButton.setImageResource(R.drawable.shutter_button_video_stop);
mCameraControls.hideSwitcher();
- mRecordingTimeView.setText("");
- ((ViewGroup)mRootView).addView(mRecordingTimeRect);
} else {
mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
if (!mController.isVideoCaptureIntent()) {
mCameraControls.showSwitcher();
}
- ((ViewGroup)mRootView).removeView(mRecordingTimeRect);
+ stopRecordingTimer();
}
}
+ public void startRecordingTimer(int frameRate, long frameInterval, long durationMs) {
+ mRecordingTime.start(frameRate, frameInterval, durationMs);
+ }
+
+ public void stopRecordingTimer() {
+ mRecordingTime.stop();
+ }
+
+ public long getRecordingTime() {
+ return mRecordingTime.getTime();
+ }
+
public void hideUIwhileRecording() {
- mCameraControls.hideCameraSettings();
+ mCameraControls.setMenuAndSwitcherEnabled(false);
}
public void showUIafterRecording() {
- mCameraControls.showCameraSettings();
+ mCameraControls.setMenuAndSwitcherEnabled(true);
}
public void showReviewImage(Bitmap bitmap) {
@@ -899,14 +907,14 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
CameraUtil.fadeIn(mReviewDoneButton);
CameraUtil.fadeIn(mReviewPlayButton);
mReviewImage.setVisibility(View.VISIBLE);
- mMenuButton.setVisibility(View.GONE);
+ mCameraControls.hideCameraSettings();
mOnScreenIndicators.setVisibility(View.GONE);
}
public void hideReviewUI() {
mReviewImage.setVisibility(View.GONE);
mShutterButton.setEnabled(true);
- mMenuButton.setVisibility(View.VISIBLE);
+ mCameraControls.hideCameraSettings();
mOnScreenIndicators.setVisibility(View.VISIBLE);
CameraUtil.fadeOut(mReviewDoneButton);
CameraUtil.fadeOut(mReviewPlayButton);
@@ -937,16 +945,11 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
setShowMenu(previewFocused);
}
- public void initializePopup(PreferenceGroup pref) {
- mVideoMenu.initialize(pref);
- }
-
public void initializeZoom(Parameters param) {
- if (param == null || !param.isZoomSupported()) {
+ if (param == null || !param.isZoomSupported() || mZoomRenderer == null) {
mGestures.setZoomEnabled(false);
return;
}
- mGestures.setZoomEnabled(true);
mZoomMax = param.getMaxZoom();
mZoomRatios = param.getZoomRatios();
// Currently we use immediate zoom for fast zooming to get better UX and
@@ -969,14 +972,6 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
return mShutterButton;
}
- public void setRecordingTime(String text) {
- mRecordingTimeView.setText(text);
- }
-
- public void setRecordingTimeTextColor(int color) {
- mRecordingTimeView.setTextColor(color);
- }
-
public boolean isVisible() {
return mCameraControls.getVisibility() == View.VISIBLE;
}
@@ -1031,6 +1026,8 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
RectF r = new RectF(mSurfaceView.getLeft(), mSurfaceView.getTop(),
mSurfaceView.getRight(), mSurfaceView.getBottom());
+ mController.onPreviewRectChanged(CameraUtil.rectFToRect(r));
+
onPreviewRectChanged(r);
}
@@ -1053,26 +1050,16 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
return mRootView;
}
- @Override
+ @Override
public void onButtonPause() {
- mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
- R.drawable.ic_pausing_indicator, 0, 0, 0);
mController.onButtonPause();
}
@Override
public void onButtonContinue() {
- mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
- R.drawable.ic_recording_indicator, 0, 0, 0);
mController.onButtonContinue();
}
- public void resetPauseButton() {
- mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
- R.drawable.ic_recording_indicator, 0, 0, 0);
- mPauseButton.setPaused(false);
- }
-
public void setPreference(String key, String value) {
mVideoMenu.setPreference(key, value);
}
@@ -1083,14 +1070,9 @@ public class VideoUI extends BaseUI implements PieRenderer.PieListener,
mMenuLayout.setOrientation(orientation, animation);
if (mSubMenuLayout != null)
mSubMenuLayout.setOrientation(orientation, animation);
- if (mRecordingTimeRect != null) {
- if (orientation == 180) {
- mRecordingTimeRect.setOrientation(0, false);
- mRecordingTimeView.setRotation(180);
- } else {
- mRecordingTimeView.setRotation(0);
- mRecordingTimeRect.setOrientation(orientation, false);
- }
+
+ if (mRecordingTime != null) {
+ mRecordingTime.setOrientation(orientation);
}
if (mPreviewMenuLayout != null) {
ViewGroup vg = (ViewGroup) mPreviewMenuLayout.getChildAt(0);
diff --git a/src/com/android/camera/WideAnglePanoramaUI.java b/src/com/android/camera/WideAnglePanoramaUI.java
index 4d48d95..5478368 100644
--- a/src/com/android/camera/WideAnglePanoramaUI.java
+++ b/src/com/android/camera/WideAnglePanoramaUI.java
@@ -24,6 +24,7 @@ import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@@ -654,6 +655,9 @@ public class WideAnglePanoramaUI extends BaseUI implements
}
layoutPreview();
- mCameraControls.setPreviewRatio(mAspectRatio, false);
+
+ RectF r = new RectF(mTextureView.getLeft(), mTextureView.getTop(),
+ mTextureView.getRight(), mTextureView.getBottom());
+ onPreviewRectChanged(r);
}
}
diff --git a/src/com/android/camera/ui/CameraControls.java b/src/com/android/camera/ui/CameraControls.java
index a5f7db6..740a07e 100644
--- a/src/com/android/camera/ui/CameraControls.java
+++ b/src/com/android/camera/ui/CameraControls.java
@@ -21,15 +21,17 @@ import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
+import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.MotionEvent;
+import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
@@ -60,17 +62,18 @@ public class CameraControls extends RotatableLayout {
private View mVideoShutter;
private ModuleSwitcher mSwitcher;
private View mTsMakeupSwitcher;
- private View mPreview;
+ private View mThumbnail;
private View mAutoHdrNotice;
private HistogramView mHistogramView;
private ArrowTextView mRefocusToast;
+ private View mFrontBackSwitcher;
+ private View mMenu;
private View mReviewDoneButton;
private View mReviewCancelButton;
private View mReviewRetakeButton;
private final List<View> mViews = new ArrayList<>();
- private final List<View> mFreeList = new ArrayList<>();
private static final int WIDTH_GRID = 5;
private static final int HEIGHT_GRID = 7;
@@ -102,7 +105,9 @@ public class CameraControls extends RotatableLayout {
}
@Override
public void onAnimationEnd(Animator animation) {
+ setChildrenVisibility(mBottomBar, false);
if (mFullyHidden) {
+ setChildrenVisibility(mTopBar, false);
setVisibility(View.INVISIBLE);
}
}
@@ -111,7 +116,9 @@ public class CameraControls extends RotatableLayout {
AnimatorListener inlistener = new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
+ setChildrenVisibility(mBottomBar, true);
if (mFullyHidden) {
+ setChildrenVisibility(mTopBar, true);
setVisibility(View.VISIBLE);
mFullyHidden = false;
}
@@ -122,14 +129,26 @@ public class CameraControls extends RotatableLayout {
}
};
+ private void setChildrenVisibility(ViewGroup parent, boolean visible) {
+ for (int i = 0; i < parent.getChildCount(); i++) {
+ View v = parent.getChildAt(i);
+ if (v.getVisibility() != View.GONE) {
+ v.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+ }
+
public CameraControls(Context context, AttributeSet attrs) {
super(context, attrs);
-
mRefocusToast = new ArrowTextView(context);
addView(mRefocusToast);
setClipChildren(false);
setMeasureAllChildren(true);
+
+ Pair<Integer, Integer> margins = CameraUtil.calculateMargins((Activity)context);
+ mTopMargin = margins.first;
+ mBottomMargin = margins.second;
}
public CameraControls(Context context) {
@@ -142,12 +161,15 @@ public class CameraControls extends RotatableLayout {
public void enableTouch(boolean enable) {
Log.d(TAG, "ENABLE TOUCH " + enable + " mViews.size=" + mViews.size());
- for (View v : mViews) {
- if (v.getVisibility() != View.GONE) {
- if (enable) {
- v.setPressed(false);
+
+ synchronized (mViews) {
+ for (View v : mViews) {
+ if (v.getVisibility() != View.GONE) {
+ if (enable) {
+ v.setPressed(false);
+ }
+ v.setEnabled(enable);
}
- v.setEnabled(enable);
}
}
@@ -158,11 +180,13 @@ public class CameraControls extends RotatableLayout {
}
public void removeFromViewList(View view) {
- synchronized (mFreeList) {
+ synchronized (mViews) {
if (view == null || !mViews.contains(view)) {
return;
}
- mFreeList.add(view);
+ view.setVisibility(View.GONE);
+ removeView(view);
+ mViews.remove(view);
requestLayout();
}
}
@@ -176,26 +200,30 @@ public class CameraControls extends RotatableLayout {
mShutter = (ShutterButton) findViewById(R.id.shutter_button);
mVideoShutter = findViewById(R.id.video_button);
mTsMakeupSwitcher = findViewById(R.id.ts_makeup_switcher);
- mPreview = findViewById(R.id.preview_thumb);
+ mThumbnail = findViewById(R.id.preview_thumb);
mRemainingPhotos = (LinearLayout) findViewById(R.id.remaining_photos);
mRemainingPhotosText = (TextView) findViewById(R.id.remaining_photos_text);
mAutoHdrNotice = (TextView) findViewById(R.id.auto_hdr_notice);
mHistogramView = (HistogramView) findViewById(R.id.histogram);
+ mFrontBackSwitcher = findViewById(R.id.front_back_switcher);
+ mMenu = findViewById(R.id.menu);
if (!TsMakeupManager.HAS_TS_MAKEUP) {
mTopBar.removeView(mTsMakeupSwitcher);
}
- for (int i = 0; i < mTopBar.getChildCount(); i++) {
- mViews.add(mTopBar.getChildAt(i));
- }
+ synchronized (mViews) {
+ for (int i = 0; i < mTopBar.getChildCount(); i++) {
+ mViews.add(mTopBar.getChildAt(i));
+ }
- for (int i = 0; i < mBottomBar.getChildCount(); i++) {
- mViews.add(mBottomBar.getChildAt(i));
- }
+ for (int i = 0; i < mBottomBar.getChildCount(); i++) {
+ mViews.add(mBottomBar.getChildAt(i));
+ }
- mViews.add(mAutoHdrNotice);
- mViews.add(mHistogramView);
+ mViews.add(mAutoHdrNotice);
+ mViews.add(mHistogramView);
+ }
mShutter.addOnShutterButtonListener(mShutterListener);
@@ -222,13 +250,13 @@ public class CameraControls extends RotatableLayout {
public void hideSwitcher() {
if (mSwitcher != null) {
mSwitcher.closePopup();
- mSwitcher.setVisibility(View.INVISIBLE);
+ mSwitcher.setEnabled(false);
}
}
public void showSwitcher() {
if (mSwitcher != null) {
- mSwitcher.setVisibility(View.VISIBLE);
+ mSwitcher.setEnabled(true);
}
}
@@ -271,26 +299,9 @@ public class CameraControls extends RotatableLayout {
@Override
public void onLayout(boolean changed, int l, int t, int r, int b) {
- synchronized (mFreeList) {
- if (mFreeList.size() > 0) {
- for (View v : mFreeList) {
- v.setVisibility(View.GONE);
- removeView(v);
- mViews.remove(v);
- }
- }
- }
+ Log.d(TAG, String.format("onLayout changed=%b l=%d t=%d r=%d b=%d", changed, l, t, r, b));
- // As l,t,r,b are positions relative to parents, we need to convert them
- // to child's coordinates
- r = r - l;
- b = b - t;
- l = 0;
- t = 0;
- for (int i = 0; i < getChildCount(); i++) {
- View v = getChildAt(i);
- v.layout(l, t, r, b);
- }
+ super.onLayout(changed, l, t, r, b);
ViewGroup.LayoutParams lpTop = mTopBar.getLayoutParams();
lpTop.height = mTopMargin;
@@ -346,6 +357,19 @@ public class CameraControls extends RotatableLayout {
});
}
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mTopBar.setTranslationX(0);
+ mTopBar.setTranslationY(0);
+ mBottomBar.setTranslationX(0);
+ mBottomBar.setTranslationY(0);
+ mHidden = false;
+ mFullyHidden = false;
+ setChildrenVisibility(mTopBar, true);
+ setChildrenVisibility(mBottomBar, true);
+ }
+
private void setLocation(int w, int h) {
int rotation = getUnifiedRotation();
layoutToast(mRefocusToast, w, h, rotation);
@@ -452,6 +476,11 @@ public class CameraControls extends RotatableLayout {
mAnimator.start();
}
+ public void setMenuAndSwitcherEnabled(boolean enable) {
+ mMenu.setEnabled(enable);
+ mFrontBackSwitcher.setEnabled(enable);
+ }
+
public void hideUI(boolean toBlack) {
if (mHidden) {
return;
@@ -493,10 +522,10 @@ public class CameraControls extends RotatableLayout {
}
private void layoutRemaingPhotos() {
- int rl = mPreview.getLeft();
- int rt = mPreview.getTop();
- int rr = mPreview.getRight();
- int rb = mPreview.getBottom();
+ int rl = mThumbnail.getLeft();
+ int rt = mThumbnail.getTop();
+ int rr = mThumbnail.getRight();
+ int rb = mThumbnail.getBottom();
int w = mRemainingPhotos.getMeasuredWidth();
int h = mRemainingPhotos.getMeasuredHeight();
int m = getResources().getDimensionPixelSize(R.dimen.remaining_photos_margin);
@@ -537,25 +566,14 @@ public class CameraControls extends RotatableLayout {
return !mHidden;
}
- public void setMargins(int top, int bottom) {
- mTopMargin = top;
- mBottomMargin = bottom;
- }
-
- private void setBarsBackground(int resId) {
- mTopBar.setBackgroundResource(resId);
- mBottomBar.setBackgroundResource(resId);
- }
-
- public void setPreviewRatio(float ratio, boolean panorama) {
- int r = CameraUtil.determineRatio(ratio);
+ public void setPreviewRect(RectF rectL) {
+ int r = CameraUtil.determineRatio(Math.round(rectL.width()), Math.round(rectL.height()));
mPreviewRatio = r;
if (mPreviewRatio == CameraUtil.RATIO_4_3 && mTopMargin != 0) {
- setBarsBackground(R.drawable.camera_controls_bg_opaque);
+ mBottomBar.setBackgroundResource(R.drawable.camera_controls_bg_opaque);
} else {
- setBarsBackground(R.drawable.camera_controls_bg_translucent);
+ mBottomBar.setBackgroundResource(R.drawable.camera_controls_bg_translucent);
}
- requestLayout();
}
public void showRefocusToast(boolean show) {
@@ -577,11 +595,13 @@ public class CameraControls extends RotatableLayout {
public void setOrientation(int orientation, boolean animation) {
mOrientation = orientation;
- for (View v : mViews) {
- if (v instanceof RotateImageView) {
- ((RotateImageView) v).setOrientation(orientation, animation);
- } else if (v instanceof HistogramView) {
- ((HistogramView) v).setRotation(-orientation);
+ synchronized (mViews) {
+ for (View v : mViews) {
+ if (v instanceof RotateImageView) {
+ ((RotateImageView) v).setOrientation(orientation, animation);
+ } else if (v instanceof HistogramView) {
+ ((HistogramView) v).setRotation(-orientation);
+ }
}
}
layoutRemaingPhotos();
diff --git a/src/com/android/camera/ui/ModuleSwitcher.java b/src/com/android/camera/ui/ModuleSwitcher.java
index d51edb1..90ba054 100644
--- a/src/com/android/camera/ui/ModuleSwitcher.java
+++ b/src/com/android/camera/ui/ModuleSwitcher.java
@@ -159,7 +159,7 @@ public class ModuleSwitcher extends RotateImageView {
// Closes the popup window when touch outside of it - when looses focus
popup.setOutsideTouchable(true);
popup.setFocusable(true);
- popup.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
+ popup.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popup.setAnimationStyle(android.R.style.Animation_Dialog);
return popup;
}
diff --git a/src/com/android/camera/ui/RecordingTime.java b/src/com/android/camera/ui/RecordingTime.java
new file mode 100644
index 0000000..6e07fa6
--- /dev/null
+++ b/src/com/android/camera/ui/RecordingTime.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.camera.ui;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.transition.*;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.camera.PauseButton;
+
+import org.codeaurora.snapcam.R;
+
+public class RecordingTime extends RotateLayout implements PauseButton.OnPauseButtonListener {
+
+ private static final String TAG = "CAM_" + RecordingTime.class.getSimpleName();
+
+ private PauseButton mPauseButton;
+ private TextView mRecordingTimeText;
+ private TextView mTimeLapseLabel;
+ private ReversibleLinearLayout mRecordingTimeContainer;
+
+ private PauseButton.OnPauseButtonListener mPauseListener;
+
+ private boolean mPaused = false;
+ private boolean mStarted = false;
+ private boolean mTimeLapse = false;
+
+ private long mRecordingStartTime;
+ private long mRecordingTotalTime;
+
+ private int mFrameRate = 0;
+ private long mInterval = 0;
+ private long mDurationMs = 0;
+ private boolean mRecordingTimeCountsDown = false;
+
+ private static final int UPDATE_RECORD_TIME = 0;
+
+ private final Handler mHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case UPDATE_RECORD_TIME:
+ updateRecordingTime();
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ public RecordingTime(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mPauseButton = (PauseButton) findViewById(R.id.video_pause);
+ mRecordingTimeText = (TextView) findViewById(R.id.recording_time_text);
+ mRecordingTimeContainer = (ReversibleLinearLayout) findViewById(R.id.recording_time_container);
+ mTimeLapseLabel = (TextView) findViewById(R.id.time_lapse_label);
+ mPauseButton.setOnPauseButtonListener(this);
+ setAlpha(0.0f);
+ }
+
+ public void setOrientation(int orientation) {
+ if (mRecordingTimeText != null) {
+ Log.d(TAG, "orientation=" + orientation);
+ setRotation(orientation);
+ float topBar = getContext().getResources().getDimension(R.dimen.preview_top_margin);
+
+ if (orientation == 0 || orientation == 270) {
+ mRecordingTimeContainer.setOrder(ReversibleLinearLayout.FORWARD);
+ } else {
+ mRecordingTimeContainer.setOrder(ReversibleLinearLayout.REVERSE);
+ }
+
+ if (orientation == 0 || orientation == 180) {
+ setTranslationX(0);
+ setTranslationY(0);
+ mRecordingTimeText.setRotation(0);
+ if (mTimeLapse) {
+ mTimeLapseLabel.setRotation(0);
+ }
+ } else {
+ setTranslationX(-topBar);
+ setTranslationY(topBar);
+ mRecordingTimeText.setRotation(180);
+ if (mTimeLapse) {
+ mTimeLapseLabel.setRotation(180);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onButtonPause() {
+ mPaused = true;
+ mRecordingTotalTime += SystemClock.uptimeMillis() - mRecordingStartTime;
+
+ mRecordingTimeText.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_pausing_indicator, 0, 0, 0);
+ if (mPauseListener != null) {
+ mPauseListener.onButtonPause();
+ }
+ }
+
+ @Override
+ public void onButtonContinue() {
+ mPaused = false;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+
+ mRecordingTimeText.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_recording_indicator, 0, 0, 0);
+ if (mPauseListener != null) {
+ mPauseListener.onButtonContinue();
+ }
+ updateRecordingTime();
+ }
+
+ public void reset() {
+ mRecordingTimeText.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_recording_indicator, 0, 0, 0);
+ mStarted = false;
+ mPauseButton.setPaused(false);
+ mPaused = false;
+ mRecordingTimeText.setText("");
+ }
+
+ public void start() {
+ start(0, 0, 0);
+ }
+
+ public void start(int frameRate, long frameInterval, long durationMs) {
+ reset();
+ mFrameRate = frameRate;
+ mInterval = frameInterval;
+ mDurationMs = durationMs;
+ mRecordingTotalTime = 0L;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ mStarted = true;
+ animate().alpha(1.0f).withStartAction(new Runnable() {
+ @Override
+ public void run() {
+ updateRecordingTime();
+ setVisibility(View.VISIBLE);
+ }
+ });
+
+ Log.d(TAG, "started: frameRate=" + frameRate + " frameInterval=" + frameInterval + " maxDuration=" + durationMs);
+ }
+
+ public void stop() {
+ mStarted = false;
+ animate().alpha(0.0f).withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ setVisibility(View.GONE);
+ }
+ });
+ }
+
+ public void showTimeLapse(boolean show) {
+ mTimeLapse = show;
+ mTimeLapseLabel.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+
+ public long getTime() {
+ return mPaused ? mRecordingTotalTime :
+ SystemClock.uptimeMillis() - mRecordingStartTime + mRecordingTotalTime;
+ }
+
+ public void setPauseListener(PauseButton.OnPauseButtonListener listener) {
+ mPauseListener = listener;
+ }
+
+ private void updateRecordingTime() {
+ if (!mStarted || mPaused) {
+ return;
+ }
+
+ long now = SystemClock.uptimeMillis();
+ long delta = now - mRecordingStartTime + mRecordingTotalTime;
+
+ // Starting a minute before reaching the max duration
+ // limit, we'll countdown the remaining time instead.
+ boolean countdownRemainingTime = (mDurationMs != 0
+ && delta >= mDurationMs - 60000);
+
+ long deltaAdjusted = delta;
+ if (countdownRemainingTime) {
+ deltaAdjusted = Math.max(0, mDurationMs - deltaAdjusted) + 999;
+ }
+ String text;
+
+ long targetNextUpdateDelay;
+ if (mInterval <= 0) {
+ text = millisecondToTimeString(deltaAdjusted, false);
+ targetNextUpdateDelay = 1000;
+ } else {
+ // The length of time lapse video is different from the length
+ // of the actual wall clock time elapsed. Display the video length
+ // only in format hh:mm:ss.dd, where dd are the centi seconds.
+ text = millisecondToTimeString(getTimeLapseVideoLength(delta), true);
+ targetNextUpdateDelay = mInterval;
+ }
+
+ mRecordingTimeText.setText(text);
+
+ if (mRecordingTimeCountsDown != countdownRemainingTime) {
+ // Avoid setting the color on every update, do it only
+ // when it needs changing.
+ mRecordingTimeCountsDown = countdownRemainingTime;
+
+ int color = getContext().getResources().getColor(countdownRemainingTime
+ ? R.color.recording_time_remaining_text
+ : R.color.recording_time_elapsed_text);
+
+ mRecordingTimeText.setTextColor(color);
+ }
+
+ long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay);
+ mHandler.sendEmptyMessageDelayed(
+ UPDATE_RECORD_TIME, actualNextUpdateDelay);
+ }
+
+ private long getTimeLapseVideoLength(long deltaMs) {
+ // For better approximation calculate fractional number of frames captured.
+ // This will update the video time at a higher resolution.
+ double numberOfFrames = (double) deltaMs / mInterval;
+ return (long) (numberOfFrames / mFrameRate * 1000);
+ }
+
+ private static String millisecondToTimeString(long milliSeconds, boolean displayCentiSeconds) {
+ long seconds = milliSeconds / 1000; // round down to compute seconds
+ long minutes = seconds / 60;
+ long hours = minutes / 60;
+ long remainderMinutes = minutes - (hours * 60);
+ long remainderSeconds = seconds - (minutes * 60);
+
+ StringBuilder timeStringBuilder = new StringBuilder();
+
+ // Hours
+ if (hours > 0) {
+ if (hours < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(hours);
+
+ timeStringBuilder.append(':');
+ }
+
+ // Minutes
+ if (remainderMinutes < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(remainderMinutes);
+ timeStringBuilder.append(':');
+
+ // Seconds
+ if (remainderSeconds < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(remainderSeconds);
+
+ // Centi seconds
+ if (displayCentiSeconds) {
+ timeStringBuilder.append('.');
+ long remainderCentiSeconds = (milliSeconds - seconds * 1000) / 10;
+ if (remainderCentiSeconds < 10) {
+ timeStringBuilder.append('0');
+ }
+ timeStringBuilder.append(remainderCentiSeconds);
+ }
+
+ return timeStringBuilder.toString();
+ }
+}
diff --git a/src/com/android/camera/ui/ReversibleLinearLayout.java b/src/com/android/camera/ui/ReversibleLinearLayout.java
new file mode 100644
index 0000000..df9e921
--- /dev/null
+++ b/src/com/android/camera/ui/ReversibleLinearLayout.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.camera.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * A LinearLayout which can have it's elements reversed
+ */
+public class ReversibleLinearLayout extends LinearLayout {
+
+ public static final int FORWARD = 0;
+ public static final int REVERSE = 1;
+
+ private int mState = FORWARD;
+
+ public ReversibleLinearLayout(Context context) {
+ super(context);
+ }
+
+ public ReversibleLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public void setOrder(int state) {
+ if (state < 0 || state > 1 || state == mState) {
+ return;
+ }
+ for(int k = getChildCount()-1 ; k >= 0 ; k--)
+ {
+ View item = getChildAt(k);
+ removeViewAt(k);
+ addView(item);
+ }
+ mState = state;
+ }
+
+ public int getOrder() {
+ return mState;
+ }
+}
diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java
index 653cc9a..5af83bc 100644
--- a/src/com/android/camera/util/CameraUtil.java
+++ b/src/com/android/camera/util/CameraUtil.java
@@ -44,6 +44,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Pair;
import android.util.TypedValue;
import android.view.Display;
import android.view.OrientationEventListener;
@@ -83,7 +84,7 @@ import java.util.TreeSet;
* Collection of utility functions used in this package.
*/
public class CameraUtil {
- private static final String TAG = "Util";
+ private static final String TAG = "CAM_Util";
// For calculate the best fps range for still image capture.
private final static int MAX_PREVIEW_FPS_TIMES_1000 = 400000;
@@ -1285,6 +1286,17 @@ public class CameraUtil {
return ".3gp";
}
+ public static Pair<Integer, Integer> calculateMargins(Activity activity) {
+ Point size = new Point();
+ activity.getWindowManager().getDefaultDisplay().getRealSize(size);
+ int l = size.x > size.y ? size.x : size.y;
+ int tm = activity.getResources().getDimensionPixelSize(R.dimen.preview_top_margin);
+ int bm = activity.getResources().getDimensionPixelSize(R.dimen.preview_bottom_margin);
+ int top = l / 4 * tm / (tm + bm);
+ int bottom = l / 4 - top;
+ return Pair.create(top, bottom);
+ }
+
/**
* Compares two {@code Size}s based on their areas.
*/