summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/drawable-hdpi/zoom_background.9.pngbin0 -> 310 bytes
-rw-r--r--res/drawable-hdpi/zoom_finetickmark.pngbin0 -> 189 bytes
-rw-r--r--res/drawable-hdpi/zoom_shape.pngbin407 -> 0 bytes
-rw-r--r--res/drawable-hdpi/zoom_tickmark.pngbin0 -> 189 bytes
-rw-r--r--res/drawable-hdpi/zoom_tickmarks.pngbin259 -> 0 bytes
-rw-r--r--res/drawable-mdpi/menu_popup.9.pngbin1728 -> 1848 bytes
-rw-r--r--res/drawable-mdpi/menu_popup_triangle.pngbin994 -> 867 bytes
-rw-r--r--res/drawable-mdpi/zoom_background.9.pngbin0 -> 350 bytes
-rw-r--r--res/drawable-mdpi/zoom_finetickmark.pngbin0 -> 189 bytes
-rw-r--r--res/drawable-mdpi/zoom_shape.pngbin441 -> 0 bytes
-rw-r--r--res/drawable-mdpi/zoom_tickmark.pngbin0 -> 189 bytes
-rw-r--r--res/drawable-mdpi/zoom_tickmarks.pngbin407 -> 0 bytes
-rw-r--r--res/values/strings.xml1
-rw-r--r--res/xml/camera_preferences.xml4
-rw-r--r--src/com/android/camera/Camera.java179
-rw-r--r--src/com/android/camera/CameraSettings.java48
-rw-r--r--src/com/android/camera/ListPreference.java8
-rw-r--r--src/com/android/camera/Menu3DTest.java4
-rw-r--r--src/com/android/camera/Util.java12
-rw-r--r--src/com/android/camera/ui/AbstractIndicator.java8
-rw-r--r--src/com/android/camera/ui/BasicIndicator.java4
-rw-r--r--src/com/android/camera/ui/GLListView.java12
-rw-r--r--src/com/android/camera/ui/GLOptionHeader.java37
-rw-r--r--src/com/android/camera/ui/GLOptionItem.java29
-rw-r--r--src/com/android/camera/ui/GLRootView.java5
-rw-r--r--src/com/android/camera/ui/GLView.java128
-rw-r--r--src/com/android/camera/ui/HeadUpDisplay.java41
-rw-r--r--src/com/android/camera/ui/IndicatorBar.java9
-rw-r--r--src/com/android/camera/ui/LinearLayout.java38
-rw-r--r--src/com/android/camera/ui/NinePatchTexture.java7
-rw-r--r--src/com/android/camera/ui/PopupWindow.java16
-rw-r--r--src/com/android/camera/ui/PopupWindowStencilImpl.java10
-rw-r--r--src/com/android/camera/ui/PreferenceAdapter.java23
-rw-r--r--src/com/android/camera/ui/ZoomController.java269
-rw-r--r--src/com/android/camera/ui/ZoomIndicator.java99
35 files changed, 740 insertions, 251 deletions
diff --git a/res/drawable-hdpi/zoom_background.9.png b/res/drawable-hdpi/zoom_background.9.png
new file mode 100644
index 0000000..40f6fc0
--- /dev/null
+++ b/res/drawable-hdpi/zoom_background.9.png
Binary files differ
diff --git a/res/drawable-hdpi/zoom_finetickmark.png b/res/drawable-hdpi/zoom_finetickmark.png
new file mode 100644
index 0000000..e36841a
--- /dev/null
+++ b/res/drawable-hdpi/zoom_finetickmark.png
Binary files differ
diff --git a/res/drawable-hdpi/zoom_shape.png b/res/drawable-hdpi/zoom_shape.png
deleted file mode 100644
index c12ce6b..0000000
--- a/res/drawable-hdpi/zoom_shape.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/zoom_tickmark.png b/res/drawable-hdpi/zoom_tickmark.png
new file mode 100644
index 0000000..2c6a7be
--- /dev/null
+++ b/res/drawable-hdpi/zoom_tickmark.png
Binary files differ
diff --git a/res/drawable-hdpi/zoom_tickmarks.png b/res/drawable-hdpi/zoom_tickmarks.png
deleted file mode 100644
index a4191d7..0000000
--- a/res/drawable-hdpi/zoom_tickmarks.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/menu_popup.9.png b/res/drawable-mdpi/menu_popup.9.png
index 3e197a1..a655a03 100644
--- a/res/drawable-mdpi/menu_popup.9.png
+++ b/res/drawable-mdpi/menu_popup.9.png
Binary files differ
diff --git a/res/drawable-mdpi/menu_popup_triangle.png b/res/drawable-mdpi/menu_popup_triangle.png
index 4262398..91b6523 100644
--- a/res/drawable-mdpi/menu_popup_triangle.png
+++ b/res/drawable-mdpi/menu_popup_triangle.png
Binary files differ
diff --git a/res/drawable-mdpi/zoom_background.9.png b/res/drawable-mdpi/zoom_background.9.png
new file mode 100644
index 0000000..5cae3e5
--- /dev/null
+++ b/res/drawable-mdpi/zoom_background.9.png
Binary files differ
diff --git a/res/drawable-mdpi/zoom_finetickmark.png b/res/drawable-mdpi/zoom_finetickmark.png
new file mode 100644
index 0000000..1b70845
--- /dev/null
+++ b/res/drawable-mdpi/zoom_finetickmark.png
Binary files differ
diff --git a/res/drawable-mdpi/zoom_shape.png b/res/drawable-mdpi/zoom_shape.png
deleted file mode 100644
index c3155f7..0000000
--- a/res/drawable-mdpi/zoom_shape.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/zoom_tickmark.png b/res/drawable-mdpi/zoom_tickmark.png
new file mode 100644
index 0000000..1b70845
--- /dev/null
+++ b/res/drawable-mdpi/zoom_tickmark.png
Binary files differ
diff --git a/res/drawable-mdpi/zoom_tickmarks.png b/res/drawable-mdpi/zoom_tickmarks.png
deleted file mode 100644
index 32f207e..0000000
--- a/res/drawable-mdpi/zoom_tickmarks.png
+++ /dev/null
Binary files differ
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1c14243..59b7ea3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -287,6 +287,7 @@
<!-- Exposure settings in preference -->
<string name="pref_exposure_title">Exposure</string>
+ <string name="pref_exposure_default" translatable="false">0</string>
<!-- Framing grid settings in preference -->
<string name="pref_framing_grid">Framing grid</string>
diff --git a/res/xml/camera_preferences.xml b/res/xml/camera_preferences.xml
index 37fc9ff..8b5b089 100644
--- a/res/xml/camera_preferences.xml
+++ b/res/xml/camera_preferences.xml
@@ -27,6 +27,10 @@
camera:entries="@array/pref_camera_flashmode_entries"
camera:entryValues="@array/pref_camera_flashmode_entryvalues" />
<ListPreference
+ camera:key="pref_camera_exposure_key"
+ camera:defaultValue="@string/pref_exposure_default"
+ camera:title="@string/pref_exposure_title" />
+ <ListPreference
camera:key="pref_camera_scenemode_key"
camera:defaultValue="@string/pref_camera_scenemode_default"
camera:title="@string/pref_camera_scenemode_title"
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 93a6853..a2dce08 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -67,13 +67,14 @@ import android.view.Window;
import android.view.WindowManager;
import android.view.MenuItem.OnMenuItemClickListener;
import android.widget.ImageView;
-import android.widget.ZoomButtonsController;
+
+import com.google.android.camera.R;
import com.android.camera.gallery.IImage;
import com.android.camera.gallery.IImageList;
import com.android.camera.ui.GLRootView;
import com.android.camera.ui.HeadUpDisplay;
-import com.google.android.camera.R;
+import com.android.camera.ui.ZoomController;
import java.io.File;
import java.io.FileNotFoundException;
@@ -106,10 +107,16 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
private static final int SCREEN_DELAY = 2 * 60 * 1000;
private static final int FOCUS_BEEP_VOLUME = 100;
- private boolean mZooming = false;
+
+ private static final int ZOOM_STOPPED = 0;
+ private static final int ZOOM_START = 1;
+ private static final int ZOOM_STOPPING = 2;
+
+ private int mZoomState = ZOOM_STOPPED;
private boolean mSmoothZoomSupported = false;
private int mZoomValue; // The current zoom value.
private int mZoomMax;
+ private int mTargetZoomValue;
private Parameters mParameters;
private Parameters mInitialParams;
@@ -134,7 +141,6 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
private ShutterButton mShutterButton;
private FocusRectangle mFocusRectangle;
private ToneGenerator mFocusToneGenerator;
- private ZoomButtonsController mZoomButtons;
private GestureDetector mGestureDetector;
private Switcher mSwitcher;
private boolean mStartPreviewFail = false;
@@ -324,15 +330,14 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
initializeFocusTone();
- initializeZoom();
-
- mFirstTimeInitialized = true;
-
mHeadUpDisplay = new HeadUpDisplay(this);
CameraSettings settings = new CameraSettings(this, mInitialParams);
mHeadUpDisplay.initialize(this,
settings.getPreferenceGroup(R.xml.camera_preferences));
mGLRootView.setContentPane(mHeadUpDisplay);
+
+ initializeZoom();
+ mFirstTimeInitialized = true;
}
private void updateThumbnailButton() {
@@ -362,9 +367,7 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
keepMediaProviderInstance();
checkStorage();
- if (mZoomButtons != null) {
- mCameraDevice.setZoomCallback(mZoomCallback);
- }
+ mCameraDevice.setZoomCallback(mZoomCallback);
if (!mIsImageCaptureIntent) {
updateThumbnailButton();
@@ -376,50 +379,61 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
mZoomMax = mParameters.getMaxZoom();
mSmoothZoomSupported = mParameters.isSmoothZoomSupported();
-
mGestureDetector = new GestureDetector(this, new ZoomGestureListener());
+
mCameraDevice.setZoomCallback(mZoomCallback);
- mZoomButtons = new ZoomButtonsController(mSurfaceView);
- mZoomButtons.setAutoDismissed(true);
- mZoomButtons.setZoomSpeed(100);
- mZoomButtons.setOnZoomListener(
- new ZoomButtonsController.OnZoomListener() {
- public void onVisibilityChanged(boolean visible) {
- if (visible) {
- updateZoomButtonsEnabled();
- }
- }
- public void onZoom(boolean zoomIn) {
- if (isZooming()) return;
-
- if (zoomIn) {
- if (mZoomValue < mZoomMax) {
- if (mSmoothZoomSupported) {
- mCameraDevice.startSmoothZoom(mZoomValue + 1);
- mZooming = true;
- } else {
- mParameters.setZoom(++mZoomValue);
- mCameraDevice.setParameters(mParameters);
- updateZoomButtonsEnabled();
- }
- }
- } else {
- if (mZoomValue > 0) {
- if (mSmoothZoomSupported) {
- mCameraDevice.startSmoothZoom(mZoomValue - 1);
- mZooming = true;
- } else {
- mParameters.setZoom(--mZoomValue);
- mCameraDevice.setParameters(mParameters);
- updateZoomButtonsEnabled();
- }
+ mHeadUpDisplay.setZoomRatios(getZoomRatios());
+
+ mHeadUpDisplay.setZoomListener(new ZoomController.ZoomListener() {
+ public void onZoomChanged(
+ final int index, float ratio, boolean isMoving) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ onZoomValueChanged(index);
}
- }
+ });
}
});
}
+ private void onZoomValueChanged(int index) {
+ if (mSmoothZoomSupported) {
+ if (mTargetZoomValue != index && mZoomState != ZOOM_STOPPED) {
+ mTargetZoomValue = index;
+ if (mZoomState == ZOOM_START) {
+ mZoomState = ZOOM_STOPPING;
+ mCameraDevice.stopSmoothZoom();
+ }
+ } else if (mZoomState == ZOOM_STOPPED && mZoomValue != index) {
+ mTargetZoomValue = index;
+ mCameraDevice.startSmoothZoom(index);
+ mZoomState = ZOOM_START;
+ }
+ } else {
+ mParameters.setZoom(index);
+ mCameraDevice.setParameters(mParameters);
+ }
+ }
+
+ private float[] getZoomRatios() {
+ List<Integer> zoomRatios = mParameters.getZoomRatios();
+ if (zoomRatios != null) {
+ float result[] = new float[zoomRatios.size()];
+ for (int i = 0, n = result.length; i < n; ++i) {
+ result[i] = (float) zoomRatios.get(i) / 100f;
+ }
+ return result;
+ } else {
+ //1.0, 1.2, 1.44, 1.6, 1.8, 2.0
+ float result[] = new float[mZoomMax + 1];
+ for (int i = 0, n = result.length; i < n; ++i) {
+ result[i] = 1 + i * 0.2f;
+ }
+ return result;
+ }
+ }
+
public void onVisibilityChanged(boolean visible) {
// When the on-screen setting is not displayed, we show the gripper.
// When the on-screen setting is displayed, we hide the gripper.
@@ -434,36 +448,15 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
}
}
- private boolean isZooming() {
- Log.v(TAG, "mZooming=" + mZooming);
- return mZooming;
- }
-
- private void updateZoomButtonsEnabled() {
- mZoomButtons.setZoomInEnabled(mZoomValue < mZoomMax);
- mZoomButtons.setZoomOutEnabled(mZoomValue > 0);
- }
-
private class ZoomGestureListener extends
GestureDetector.SimpleOnGestureListener {
- @Override
- public boolean onDown(MotionEvent e) {
- // Show zoom buttons only when preview is started and snapshot
- // is not in progress. mZoomButtons may be null if it is not
- // initialized.
- if (!mPausing && isCameraIdle() && mPreviewing
- && mZoomButtons != null) {
- mZoomButtons.setVisible(true);
- }
- return true;
- }
@Override
public boolean onDoubleTap(MotionEvent e) {
// Perform zoom only when preview is started and snapshot is not in
// progress.
if (mPausing || !isCameraIdle() || !mPreviewing
- || mZoomButtons == null || isZooming()) {
+ || mHeadUpDisplay == null || mZoomState != ZOOM_STOPPED) {
return false;
}
@@ -490,7 +483,7 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
}
}
}
- updateZoomButtonsEnabled();
+ mHeadUpDisplay.setZoomIndex(mZoomValue);
return true;
}
}
@@ -733,8 +726,8 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
private final class ZoomCallback
implements android.hardware.Camera.ZoomCallback {
- public void onZoomUpdate(int zoomValue, boolean stopped,
- android.hardware.Camera camera) {
+ public void onZoomUpdate(
+ int zoomValue, boolean stopped, android.hardware.Camera camera) {
Log.v(TAG, "ZoomCallback: zoom value=" + zoomValue + ". stopped="
+ stopped);
mZoomValue = zoomValue;
@@ -743,8 +736,14 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
mParameters.setZoom(zoomValue);
// We only care if the zoom is stopped. mZooming is set to true when
// we start smooth zoom.
- if (stopped) mZooming = false;
- updateZoomButtonsEnabled();
+ if (stopped && mZoomState != ZOOM_STOPPED) {
+ if (zoomValue != mTargetZoomValue) {
+ mCameraDevice.startSmoothZoom(mTargetZoomValue);
+ mZoomState = ZOOM_START;
+ } else {
+ mZoomState = ZOOM_STOPPED;
+ }
+ }
}
}
@@ -1324,12 +1323,6 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
mImageCapture.clearLastData();
mImageCapture = null;
- // This is necessary to make the ZoomButtonsController unregister
- // its configuration change receiver.
- if (mZoomButtons != null) {
- mZoomButtons.setVisible(false);
- }
-
// Remove the messages in the event queue.
mHandler.removeMessages(RESTART_PREVIEW);
mHandler.removeMessages(FIRST_TIME_INIT);
@@ -1369,7 +1362,7 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
// in progress.
if (canTakePicture()) {
Log.v(TAG, "Start autofocus.");
- if (mZoomButtons != null) mZoomButtons.setVisible(false);
+ if (mHeadUpDisplay != null) mHeadUpDisplay.collapse();
mFocusStartTime = System.currentTimeMillis();
mFocusState = FOCUSING;
updateFocusIndicator();
@@ -1471,7 +1464,7 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
if (mFocusMode.equals(Parameters.FOCUS_MODE_INFINITY)
|| (mFocusState == FOCUS_SUCCESS
|| mFocusState == FOCUS_FAIL)) {
- if (mZoomButtons != null) mZoomButtons.setVisible(false);
+ if (mHeadUpDisplay != null) mHeadUpDisplay.collapse();
mImageCapture.onSnap();
} else if (mFocusState == FOCUSING) {
// Half pressing the shutter (i.e. the focus button event) will
@@ -1549,7 +1542,7 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
private void closeCamera() {
if (mCameraDevice != null) {
CameraHolder.instance().release();
- if (mZoomButtons != null) mCameraDevice.setZoomCallback(null);
+ mCameraDevice.setZoomCallback(null);
mCameraDevice = null;
mPreviewing = false;
}
@@ -1632,7 +1625,7 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
throw new RuntimeException("startPreview failed", ex);
}
mPreviewing = true;
- mZooming = false;
+ mZoomState = ZOOM_STOPPED;
mStatus = IDLE;
long threadTimeEnd = Debug.threadCpuTimeNanos();
@@ -1786,6 +1779,23 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
mParameters.setColorEffect(colorEffect);
}
+ // Set exposure compensation
+ String exposure = mPreferences.getString(
+ CameraSettings.KEY_EXPOSURE,
+ getString(R.string.pref_exposure_default));
+ try {
+ int value = Integer.parseInt(exposure);
+ int max = mParameters.getMaxExposureCompensation();
+ int min = mParameters.getMinExposureCompensation();
+ if (value >= min && value <= max) {
+ mParameters.setExposureCompensation(value);
+ } else {
+ Log.w(TAG, "invalid exposure range: " + exposure);
+ }
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "invalid exposure: " + exposure);
+ }
+
// If scene mode is set, we cannot set flash mode, white balance, and
// focus mode, instead, we read it from driver
if (!Parameters.SCENE_MODE_AUTO.equals(sceneMode)) {
@@ -1859,7 +1869,6 @@ public class Camera extends NoSearchActivity implements View.OnClickListener,
mFocusMode = Parameters.FOCUS_MODE_AUTO;
}
}
-
mCameraDevice.setParameters(mParameters);
}
}
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index 2b824a3..7010c9d 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -20,9 +20,9 @@ import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
-import android.media.CamcorderProfile;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
+import android.media.CamcorderProfile;
import android.preference.PreferenceManager;
import android.util.Log;
@@ -38,23 +38,19 @@ public class CameraSettings {
private static final int NOT_FOUND = -1;
public static final String KEY_VERSION = "pref_version_key";
- public static final String KEY_RECORD_LOCATION =
- RecordLocationPreference.KEY;
- public static final String KEY_VIDEO_QUALITY =
- "pref_camera_videoquality_key";
- public static final String KEY_VIDEO_DURATION =
- "pref_camera_video_duration_key";
+ public static final String KEY_RECORD_LOCATION = RecordLocationPreference.KEY;
+ public static final String KEY_VIDEO_QUALITY = "pref_camera_videoquality_key";
+ public static final String KEY_VIDEO_DURATION = "pref_camera_video_duration_key";
public static final String KEY_PICTURE_SIZE = "pref_camera_picturesize_key";
public static final String KEY_JPEG_QUALITY = "pref_camera_jpegquality_key";
public static final String KEY_FOCUS_MODE = "pref_camera_focusmode_key";
public static final String KEY_FLASH_MODE = "pref_camera_flashmode_key";
public static final String KEY_VIDEOCAMERA_FLASH_MODE = "pref_camera_video_flashmode_key";
public static final String KEY_COLOR_EFFECT = "pref_camera_coloreffect_key";
- public static final String KEY_WHITE_BALANCE =
- "pref_camera_whitebalance_key";
+ public static final String KEY_WHITE_BALANCE = "pref_camera_whitebalance_key";
public static final String KEY_SCENE_MODE = "pref_camera_scenemode_key";
- public static final String KEY_QUICK_CAPTURE =
- "pref_camera_quickcapture_key";
+ public static final String KEY_QUICK_CAPTURE = "pref_camera_quickcapture_key";
+ public static final String KEY_EXPOSURE = "pref_camera_exposure_key";
public static final String QUICK_CAPTURE_ON = "on";
public static final String QUICK_CAPTURE_OFF = "off";
@@ -136,6 +132,7 @@ public class CameraSettings {
ListPreference sceneMode = group.findPreference(KEY_SCENE_MODE);
ListPreference flashMode = group.findPreference(KEY_FLASH_MODE);
ListPreference focusMode = group.findPreference(KEY_FOCUS_MODE);
+ ListPreference exposure = group.findPreference(KEY_EXPOSURE);
// Since the screen could be loaded from different resources, we need
// to check if the preference is available here
@@ -173,6 +170,35 @@ public class CameraSettings {
filterUnsupportedOptions(group,
focusMode, mParameters.getSupportedFocusModes());
}
+
+ if (exposure != null) {
+ buildExposureCompensation(group, exposure);
+ }
+ }
+
+ private void buildExposureCompensation(
+ PreferenceGroup group, ListPreference exposure) {
+ int max = mParameters.getMaxExposureCompensation();
+ int min = mParameters.getMinExposureCompensation();
+ if (max == 0 && min == 0) {
+ removePreference(group, exposure.getKey());
+ return;
+ }
+ float step = mParameters.getExposureCompensationStep();
+
+ // show only integer values for exposure compensation
+ int maxValue = (int) Math.floor(max * step);
+ int minValue = (int) Math.ceil(min * step);
+ CharSequence entries[] = new CharSequence[maxValue - minValue + 1];
+ CharSequence entryValues[] = new CharSequence[maxValue - minValue + 1];
+ for (int i = minValue; i <= maxValue; ++i) {
+ entryValues[maxValue - i] = Integer.toString(Math.round(i / step));
+ StringBuilder builder = new StringBuilder();
+ if (i > 0) builder.append('+');
+ entries[maxValue - i] = builder.append(i).toString();
+ }
+ exposure.setEntries(entries);
+ exposure.setEntryValues(entryValues);
}
private static boolean removePreference(PreferenceGroup group, String key) {
diff --git a/src/com/android/camera/ListPreference.java b/src/com/android/camera/ListPreference.java
index 6ae5c59..0ed3ce0 100644
--- a/src/com/android/camera/ListPreference.java
+++ b/src/com/android/camera/ListPreference.java
@@ -29,9 +29,9 @@ import com.google.android.camera.R;
*/
public class ListPreference extends CameraPreference {
- private String mKey;
+ private final String mKey;
private String mValue;
- private String mDefaultValue;
+ private final String mDefaultValue;
private CharSequence[] mEntries;
private CharSequence[] mEntryValues;
@@ -66,11 +66,11 @@ public class ListPreference extends CameraPreference {
}
public void setEntries(CharSequence entries[]) {
- mEntries = Util.checkNotNull(entries);
+ mEntries = entries == null ? new CharSequence[0] : entries;
}
public void setEntryValues(CharSequence values[]) {
- mEntryValues = Util.checkNotNull(values);
+ mEntryValues = values == null ? new CharSequence[0] : values;
}
public String getValue() {
diff --git a/src/com/android/camera/Menu3DTest.java b/src/com/android/camera/Menu3DTest.java
index 53ebbfe..574003a 100644
--- a/src/com/android/camera/Menu3DTest.java
+++ b/src/com/android/camera/Menu3DTest.java
@@ -5,9 +5,10 @@ import android.os.Bundle;
import android.view.OrientationEventListener;
import android.widget.FrameLayout;
+import com.google.android.camera.R;
+
import com.android.camera.ui.GLRootView;
import com.android.camera.ui.HeadUpDisplay;
-import com.google.android.camera.R;
public class Menu3DTest extends Activity {
@@ -31,6 +32,7 @@ public class Menu3DTest extends Activity {
(PreferenceGroup) inflater.inflate(R.xml.camera_preferences);
hud.initialize(this, preferenceGroup);
hud.overrideSettings(CameraSettings.KEY_FOCUS_MODE, "macro");
+ hud.setZoomRatios(new float[]{1, 2, 3, 4, 5});
setContentView(mRootView);
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index d2914f3..54c1e4d 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -264,4 +264,16 @@ public class Util {
n |= n >>> 1;
return n + 1;
}
+
+ public static float distance(float x, float y, float sx, float sy) {
+ float dx = x - sx;
+ float dy = y - sy;
+ return (float) Math.sqrt(dx * dx + dy * dy);
+ }
+
+ public static int clamp(int x, int min, int max) {
+ if (x > max) return max;
+ if (x < min) return min;
+ return x;
+ }
}
diff --git a/src/com/android/camera/ui/AbstractIndicator.java b/src/com/android/camera/ui/AbstractIndicator.java
index 38ea73f..473634c 100644
--- a/src/com/android/camera/ui/AbstractIndicator.java
+++ b/src/com/android/camera/ui/AbstractIndicator.java
@@ -9,7 +9,7 @@ import javax.microedition.khronos.opengles.GL11;
public abstract class AbstractIndicator extends GLView {
private static final int DEFAULT_PADDING = 3;
- abstract protected ResourceTexture getIcon();
+ abstract protected Texture getIcon();
public AbstractIndicator(Context context) {
int padding = GLRootView.dpToPixel(context, DEFAULT_PADDING);
@@ -18,7 +18,7 @@ public abstract class AbstractIndicator extends GLView {
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
- ResourceTexture icon = getIcon();
+ Texture icon = getIcon();
new MeasureHelper(this)
.setPreferredContentSize(icon.getWidth(), icon.getHeight())
.measure(widthSpec, heightSpec);
@@ -26,13 +26,13 @@ public abstract class AbstractIndicator extends GLView {
@Override
protected void render(GLRootView root, GL11 gl) {
- ResourceTexture icon = getIcon();
+ Texture icon = getIcon();
Rect p = mPaddings;
int width = getWidth() - p.left - p.right;
int height = getHeight() - p.top - p.bottom;
- if (icon != null && icon.bind(root, gl)) {
+ if (icon != null) {
icon.draw(root,
p.left + (width - icon.getWidth()) / 2,
p.top + (height - icon.getHeight()) / 2);
diff --git a/src/com/android/camera/ui/BasicIndicator.java b/src/com/android/camera/ui/BasicIndicator.java
index d507617..e6c9ccb 100644
--- a/src/com/android/camera/ui/BasicIndicator.java
+++ b/src/com/android/camera/ui/BasicIndicator.java
@@ -2,8 +2,9 @@ package com.android.camera.ui;
import android.content.Context;
-import com.android.camera.IconListPreference;
import com.google.android.camera.R;
+
+import com.android.camera.IconListPreference;
import com.android.camera.Util;
import com.android.camera.ui.GLListView.OnItemSelectedListener;
@@ -56,6 +57,7 @@ public class BasicIndicator extends AbstractIndicator {
}
protected void onPreferenceChanged(int newIndex) {
+ if (newIndex == mIndex) return;
mIndex = newIndex;
invalidate();
}
diff --git a/src/com/android/camera/ui/GLListView.java b/src/com/android/camera/ui/GLListView.java
index a6474be..3134433 100644
--- a/src/com/android/camera/ui/GLListView.java
+++ b/src/com/android/camera/ui/GLListView.java
@@ -65,10 +65,8 @@ public class GLListView extends GLView {
int width = bounds.width();
int height = bounds.height();
mHighLight.setSize(width, height);
- if (mHighLight.bind(root, gl)) {
- mHighLight.draw(root,
- bounds.left - mScrollX, bounds.top - mScrollY);
- }
+ mHighLight.draw(root,
+ bounds.left - mScrollX, bounds.top - mScrollY);
}
}
super.render(root, gl);
@@ -77,11 +75,9 @@ public class GLListView extends GLView {
if (mScrollbar != null && mScrollHeight > getHeight()) {
int width = this.mScrollbar.getIntrinsicWidth();
int height = getHeight() * getHeight() / mScrollHeight;
+ int yoffset = mScrollY * getHeight() / mScrollHeight;
mScrollbar.setSize(width, height);
- if (mScrollbar.bind(root, gl)) {
- int yoffset = mScrollY * getHeight() / mScrollHeight;
- mScrollbar.draw(root, getWidth() - width, yoffset);
- }
+ mScrollbar.draw(root, getWidth() - width, yoffset);
}
}
diff --git a/src/com/android/camera/ui/GLOptionHeader.java b/src/com/android/camera/ui/GLOptionHeader.java
index 38da70a..bc943af 100644
--- a/src/com/android/camera/ui/GLOptionHeader.java
+++ b/src/com/android/camera/ui/GLOptionHeader.java
@@ -1,29 +1,40 @@
package com.android.camera.ui;
+import static com.android.camera.ui.GLRootView.dpToPixel;
import android.content.Context;
import android.graphics.Rect;
-import com.android.camera.ListPreference;
+import com.google.android.camera.R;
import javax.microedition.khronos.opengles.GL11;
public class GLOptionHeader extends GLView {
private static final int FONT_COLOR = 0xFF979797;
private static final float FONT_SIZE = 12;
+ private static final int HORIZONTAL_PADDINGS = 4;
+ private static final int VERTICAL_PADDINGS = 2;
+
+ private static int sHorizontalPaddings = -1;
+ private static int sVerticalPaddings;
- private final ListPreference mPreference;
private final StringTexture mTitle;
private NinePatchTexture mBackground;
- public GLOptionHeader(Context context, ListPreference preference) {
- float fontSize = GLRootView.dpToPixel(context, FONT_SIZE);
- mPreference = preference;
- mTitle = StringTexture.newInstance(
- preference.getTitle(), fontSize, FONT_COLOR);
+ private static void initializeStaticVariables(Context context) {
+ if (sHorizontalPaddings >= 0) return;
+ sHorizontalPaddings = dpToPixel(context, HORIZONTAL_PADDINGS);
+ sVerticalPaddings = dpToPixel(context, VERTICAL_PADDINGS);
}
- public ListPreference getPreference() {
- return mPreference;
+ public GLOptionHeader(Context context, String title) {
+ initializeStaticVariables(context);
+
+ float fontSize = GLRootView.dpToPixel(context, FONT_SIZE);
+ mTitle = StringTexture.newInstance(title, fontSize, FONT_COLOR);
+ setBackground(new NinePatchTexture(
+ context, R.drawable.optionheader_background));
+ setPaddings(sHorizontalPaddings,
+ sVerticalPaddings, sHorizontalPaddings, sVerticalPaddings);
}
public void setBackground(NinePatchTexture background) {
@@ -43,11 +54,9 @@ public class GLOptionHeader extends GLView {
protected void render(GLRootView root, GL11 gl) {
if (mBackground != null) {
mBackground.setSize(getWidth(), getHeight());
- if (mBackground.bind(root, gl)) mBackground.draw(root, 0, 0);
- }
- if (mTitle.bind(root, gl)) {
- Rect p = mPaddings;
- mTitle.draw(root, p.left, p.top);
+ mBackground.draw(root, 0, 0);
}
+ Rect p = mPaddings;
+ mTitle.draw(root, p.left, p.top);
}
}
diff --git a/src/com/android/camera/ui/GLOptionItem.java b/src/com/android/camera/ui/GLOptionItem.java
index 57c99e2..6494883 100644
--- a/src/com/android/camera/ui/GLOptionItem.java
+++ b/src/com/android/camera/ui/GLOptionItem.java
@@ -24,6 +24,9 @@ public class GLOptionItem extends GLView {
private static final float ENABLED_ALPHA = 1f;
private static final float DISABLED_ALPHA = 0.3f;
+ private static final int HORIZONTAL_PADDINGS = 4;
+ private static final int VERTICAL_PADDINGS = 2;
+
private static ResourceTexture sCheckOn;
private static ResourceTexture sCheckOff;
@@ -33,6 +36,8 @@ public class GLOptionItem extends GLView {
private static int sMinimalWidth;
private static int sMinimalHeight;
private static float sFontSize;
+ private static int sHorizontalPaddings = -1;
+ private static int sVerticalPaddings;
private final ResourceTexture mIcon;
private final StringTexture mText;
@@ -52,6 +57,8 @@ public class GLOptionItem extends GLView {
sTextRightPadding = dpToPixel(context, TEXT_RIGHT_PADDING);
sMinimalWidth = dpToPixel(context, MINIMAL_WIDTH);
sMinimalHeight = dpToPixel(context, MINIMAL_HEIGHT);
+ sHorizontalPaddings = dpToPixel(context, HORIZONTAL_PADDINGS);
+ sVerticalPaddings = dpToPixel(context, VERTICAL_PADDINGS);
sFontSize = dpToPixel(context, FONT_SIZE);
}
@@ -61,6 +68,8 @@ public class GLOptionItem extends GLView {
mIcon = iconId == 0 ? null : new ResourceTexture(context, iconId);
mText = StringTexture.newInstance(title, sFontSize, FONT_COLOR);
mCheckBox = sCheckOff;
+ setPaddings(sHorizontalPaddings,
+ sVerticalPaddings, sHorizontalPaddings, sVerticalPaddings);
}
@Override
@@ -95,10 +104,8 @@ public class GLOptionItem extends GLView {
ResourceTexture icon = mIcon;
if (icon != null) {
- if (icon.bind(root, gl)) {
- icon.draw(root, xoffset,
- p.top + (height - icon.getHeight()) / 2);
- }
+ icon.draw(root, xoffset,
+ p.top + (height - icon.getHeight()) / 2);
xoffset += icon.getWidth();
} else {
xoffset += sNoIconLeadingSpace;
@@ -106,17 +113,13 @@ public class GLOptionItem extends GLView {
StringTexture title = mText;
xoffset += sTextLeftPadding;
- if (title.bind(root, gl)) {
- int yoffset = p.top + (height - title.getHeight()) / 2;
- //TODO: cut the text if it is too long
- title.draw(root, xoffset, yoffset);
- }
+ int yoffset = p.top + (height - title.getHeight()) / 2;
+ //TODO: cut the text if it is too long
+ title.draw(root, xoffset, yoffset);
ResourceTexture checkbox = mCheckBox;
- if (checkbox.bind(root, gl)) {
- int yoffset = p.top + (height - checkbox.getHeight()) / 2;
- checkbox.draw(root, width - checkbox.getWidth(), yoffset);
- }
+ yoffset = p.top + (height - checkbox.getHeight()) / 2;
+ checkbox.draw(root, width - checkbox.getWidth(), yoffset);
trans.setAlpha(oldAlpha);
}
diff --git a/src/com/android/camera/ui/GLRootView.java b/src/com/android/camera/ui/GLRootView.java
index b16d443..84eea06 100644
--- a/src/com/android/camera/ui/GLRootView.java
+++ b/src/com/android/camera/ui/GLRootView.java
@@ -152,7 +152,7 @@ public class GLRootView extends GLSurfaceView
public void setContentPane(GLView content) {
mContentView = content;
- content.mRootView = this;
+ content.onAttachToRoot(this);
// no parent for the content pane
content.onAddToParent(null);
@@ -346,6 +346,9 @@ public class GLRootView extends GLSurfaceView
public void drawTexture(
Texture texture, int x, int y, int width, int height, float alpha) {
+ if (!texture.bind(this, mGL)) {
+ throw new RuntimeException("cannot bind" + texture.toString());
+ }
if (width <= 0 || height <= 0) return ;
Matrix matrix = mTransformation.getMatrix();
diff --git a/src/com/android/camera/ui/GLView.java b/src/com/android/camera/ui/GLView.java
index cdbb760..090de39 100644
--- a/src/com/android/camera/ui/GLView.java
+++ b/src/com/android/camera/ui/GLView.java
@@ -2,6 +2,7 @@ package com.android.camera.ui;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.animation.Animation;
import android.view.animation.Transformation;
@@ -11,10 +12,7 @@ import java.util.ArrayList;
import javax.microedition.khronos.opengles.GL11;
public class GLView {
- GLRootView mRootView;
-
- public static final int STATE_EMPTY = 0;
- public static final int STATE_PRESSED = 1;
+ private static final String TAG = "GLView";
public static final int VISIBLE = 0;
public static final int INVISIBLE = 1;
@@ -23,18 +21,17 @@ public class GLView {
public static final int FLAG_SET_MEASURED_SIZE = 2;
public static final int FLAG_LAYOUT_REQUESTED = 4;
- private static final String TAG = "GLView";
-
protected final Rect mBounds = new Rect();
protected final Rect mPaddings = new Rect();
+ private GLRootView mRootView;
private GLView mParent;
private ArrayList<GLView> mComponents;
+ private GLView mMotionTarget;
private OnTouchListener mOnTouchListener;
private Animation mAnimation;
- protected int mViewState = STATE_EMPTY;
protected int mViewFlags = 0;
protected int mMeasuredWidth = 0;
@@ -48,25 +45,6 @@ public class GLView {
protected int mScrollHeight = 0;
protected int mScrollWidth = 0;
- protected void onStateChanged(int oldState, int newState) {
- }
-
- protected void addStates(int states) {
- int newState = (mViewState | states);
- if (newState != mViewState) {
- onStateChanged(mViewState, newState);
- mViewState = newState;
- }
- }
-
- protected void removeStates(int states) {
- int newState = (mViewState & ~states);
- if (newState != mViewState) {
- onStateChanged(mViewState, newState);
- mViewState = newState;
- }
- }
-
public void startAnimation(Animation animation) {
GLRootView root = getGLRootView();
if (root == null) throw new IllegalStateException();
@@ -105,7 +83,23 @@ public class GLView {
}
protected void onAddToParent(GLView parent) {
+ // TODO: enable the check
+ // if (mParent != null) throw new IllegalStateException();
mParent = parent;
+ if (parent != null && parent.mRootView != null) {
+ onAttachToRoot(parent.mRootView);
+ }
+ }
+
+ protected void onRemoveFromParent(GLView parent) {
+ if (parent != null && parent.mMotionTarget == this) {
+ long now = SystemClock.uptimeMillis();
+ dispatchTouchEvent(MotionEvent.obtain(
+ now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0));
+ parent.mMotionTarget = null;
+ }
+ onDetachFromRoot();
+ mParent = null;
}
public void clearComponents() {
@@ -131,6 +125,15 @@ public class GLView {
component.onAddToParent(this);
}
+ public boolean removeComponent(GLView component) {
+ if (mComponents == null) return false;
+ if (mComponents.remove(component)) {
+ component.onRemoveFromParent(this);
+ return true;
+ }
+ return false;
+ }
+
public Rect bounds() {
return mBounds;
}
@@ -144,9 +147,6 @@ public class GLView {
}
public GLRootView getGLRootView() {
- if (mRootView == null && mParent != null) {
- mRootView = mParent.getGLRootView();
- }
return mRootView;
}
@@ -218,20 +218,49 @@ public class GLView {
return false;
}
+ private boolean dispatchTouchEvent(
+ MotionEvent event, int x, int y, GLView component) {
+ Rect rect = component.mBounds;
+ int left = rect.left;
+ int top = rect.top;
+ if (rect.contains(x, y)) {
+ event.offsetLocation(-left, -top);
+ if (component.dispatchTouchEvent(event)) {
+ event.offsetLocation(left, top);
+ return true;
+ }
+ event.offsetLocation(left, top);
+ }
+ return false;
+ }
+
protected boolean dispatchTouchEvent(MotionEvent event) {
if (mComponents != null) {
- int eventX = (int) event.getX();
- int eventY = (int) event.getY();
- for (int i = 0, n = getComponentCount(); i < n; ++i) {
- GLView component = getComponent(i);
- if (component.getVisibility() != GLView.VISIBLE) continue;
- Rect rect = component.mBounds;
- int left = rect.left;
- int top = rect.top;
- if (rect.contains(eventX, eventY)) {
- event.offsetLocation(-left, -top);
- if (component.dispatchTouchEvent(event)) return true;
- event.offsetLocation(left, top);
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ int action = event.getAction();
+ if (mMotionTarget != null) {
+ if (action == MotionEvent.ACTION_DOWN) {
+ MotionEvent cancel = MotionEvent.obtain(event);
+ cancel.setAction(MotionEvent.ACTION_CANCEL);
+ mMotionTarget = null;
+ } else {
+ dispatchTouchEvent(event, x, y, mMotionTarget);
+ if (action == MotionEvent.ACTION_CANCEL
+ || action == MotionEvent.ACTION_UP) {
+ mMotionTarget = null;
+ }
+ return true;
+ }
+ }
+ if (action == MotionEvent.ACTION_DOWN) {
+ for (int i = 0, n = getComponentCount(); i < n; ++i) {
+ GLView component = getComponent(i);
+ if (component.getVisibility() != GLView.VISIBLE) continue;
+ if (dispatchTouchEvent(event, x, y, component)) {
+ mMotionTarget = component;
+ return true;
+ }
}
}
}
@@ -318,4 +347,21 @@ public class GLView {
return true;
}
+ protected void onAttachToRoot(GLRootView root) {
+ mRootView = root;
+ if (mComponents != null) {
+ for (GLView view : mComponents) {
+ view.onAttachToRoot(root);
+ }
+ }
+ }
+
+ protected void onDetachFromRoot() {
+ if (mComponents != null) {
+ for (GLView view : mComponents) {
+ view.onDetachFromRoot();
+ }
+ }
+ mRootView = null;
+ }
}
diff --git a/src/com/android/camera/ui/HeadUpDisplay.java b/src/com/android/camera/ui/HeadUpDisplay.java
index 8e71178..0f77336 100644
--- a/src/com/android/camera/ui/HeadUpDisplay.java
+++ b/src/com/android/camera/ui/HeadUpDisplay.java
@@ -13,11 +13,12 @@ import android.view.View.MeasureSpec;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
+import com.google.android.camera.R;
+
import com.android.camera.CameraSettings;
import com.android.camera.IconListPreference;
import com.android.camera.ListPreference;
import com.android.camera.PreferenceGroup;
-import com.google.android.camera.R;
import java.util.ArrayList;
import java.util.concurrent.Callable;
@@ -41,7 +42,11 @@ public class HeadUpDisplay extends GLView {
protected static final String TAG = "HeadUpDisplay";
private IndicatorBar mIndicatorBar;
+ private OtherSettingsIndicator mOtherSettings;
private GpsIndicator mGpsIndicator;
+ private ZoomIndicator mZoomIndicator;
+
+ private PreferenceGroup mPreferenceGroup;
private PopupWindow mPopupWindow;
@@ -155,6 +160,7 @@ public class HeadUpDisplay extends GLView {
}
public void initialize(Context context, PreferenceGroup preferenceGroup) {
+ mPreferenceGroup = preferenceGroup;
initializeIndicatorBar(context, preferenceGroup);
}
@@ -193,9 +199,9 @@ public class HeadUpDisplay extends GLView {
private void scheduleDeactiviateIndicatorBar() {
mHandler.removeMessages(HIDE_POPUP_WINDOW);
- mHandler.sendEmptyMessageDelayed(HIDE_POPUP_WINDOW, 2000);
+ mHandler.sendEmptyMessageDelayed(HIDE_POPUP_WINDOW, 3000);
mHandler.removeMessages(DEACTIVATE_INDICATOR_BAR);
- mHandler.sendEmptyMessageDelayed(DEACTIVATE_INDICATOR_BAR, 3000);
+ mHandler.sendEmptyMessageDelayed(DEACTIVATE_INDICATOR_BAR, 4000);
}
public void hidePopupWindow() {
@@ -219,6 +225,10 @@ public class HeadUpDisplay extends GLView {
mPopupWindow.setOrientation(orientation);
}
+ public void reloadPreferences() {
+
+ }
+
private void initializePopupWindow(Context context) {
mPopupWindow = new PopupWindow();
mPopupWindow.setBackground(
@@ -291,15 +301,16 @@ public class HeadUpDisplay extends GLView {
mIndicatorBar.setHighlight(new NinePatchTexture(
context, R.drawable.ic_viewfinder_iconbar_highlight));
- OtherSettingsIndicator otherSettings = new OtherSettingsIndicator(
+ mOtherSettings = new OtherSettingsIndicator(
context,
getListPreferences(group,
CameraSettings.KEY_FOCUS_MODE,
+ CameraSettings.KEY_EXPOSURE,
CameraSettings.KEY_SCENE_MODE,
CameraSettings.KEY_PICTURE_SIZE,
CameraSettings.KEY_JPEG_QUALITY,
CameraSettings.KEY_COLOR_EFFECT));
- mIndicatorBar.addComponent(otherSettings);
+ mIndicatorBar.addComponent(mOtherSettings);
GpsIndicator gpsIndicator = new GpsIndicator(
context, (IconListPreference)
@@ -313,10 +324,21 @@ public class HeadUpDisplay extends GLView {
addIndicator(context, mIndicatorBar, group,
CameraSettings.KEY_FLASH_MODE);
+ mZoomIndicator = new ZoomIndicator(context);
+ mIndicatorBar.addComponent(mZoomIndicator);
+
addComponent(mIndicatorBar);
mIndicatorBar.setOnItemSelectedListener(new IndicatorBarListener());
}
+ public void setZoomListener(ZoomController.ZoomListener listener) {
+ mZoomIndicator.setZoomListener(listener);
+ }
+
+ public void setZoomIndex(int index) {
+ mZoomIndicator.setZoomIndex(index);
+ }
+
public void setGpsHasSignal(final boolean hasSignal) {
GLRootView root = getGLRootView();
if (root != null) {
@@ -356,4 +378,13 @@ public class HeadUpDisplay extends GLView {
mPopupWindow.popoff();
}
}
+
+ public void setZoomRatios(float[] zoomRatios) {
+ mZoomIndicator.setZoomRatios(zoomRatios);
+ }
+
+ public void collapse() {
+ mIndicatorBar.setSelectedIndex(IndicatorBar.INDEX_NONE);
+ mIndicatorBar.setActivated(false);
+ }
}
diff --git a/src/com/android/camera/ui/IndicatorBar.java b/src/com/android/camera/ui/IndicatorBar.java
index afda3d7..3be4af5 100644
--- a/src/com/android/camera/ui/IndicatorBar.java
+++ b/src/com/android/camera/ui/IndicatorBar.java
@@ -22,17 +22,14 @@ public class IndicatorBar extends GLView {
@Override
protected void render(GLRootView root, GL11 gl) {
mBackground.setSize(getWidth(), getHeight());
- if (mBackground.bind(root, gl)) {
- mBackground.draw(root, 0, 0);
- }
+ mBackground.draw(root, 0, 0);
+
if (mActivated && mSelectedIndex != INDEX_NONE
&& mHighlight != null) {
Rect bounds = IndicatorBar.this.getComponent(
mSelectedIndex + 1).mBounds;
mHighlight.setSize(bounds.width(), bounds.height());
- if (mHighlight.bind(root, gl)) {
- mHighlight.draw(root, bounds.left, bounds.top);
- }
+ mHighlight.draw(root, bounds.left, bounds.top);
}
}
}
diff --git a/src/com/android/camera/ui/LinearLayout.java b/src/com/android/camera/ui/LinearLayout.java
new file mode 100644
index 0000000..4f251d9
--- /dev/null
+++ b/src/com/android/camera/ui/LinearLayout.java
@@ -0,0 +1,38 @@
+package com.android.camera.ui;
+
+import android.graphics.Rect;
+import android.view.View.MeasureSpec;
+
+public class LinearLayout extends GLView {
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ int width = 0;
+ int height = 0;
+ for (int i = 0, n = getComponentCount(); i < n; ++i) {
+ GLView view = getComponent(i);
+ view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ width = Math.max(width, view.getMeasuredWidth());
+ height += view.getMeasuredHeight();
+ }
+ new MeasureHelper(this)
+ .setPreferredContentSize(width, height)
+ .measure(widthSpec, heightSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ Rect p = mPaddings;
+ int offsetX = p.left;
+ int width = (r - l) - p.left - p.right;
+ int offsetY = p.top;
+ for (int i = 0, n = getComponentCount(); i < n; ++i) {
+ GLView view = getComponent(i);
+ view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ int nextOffsetY = offsetY + view.getMeasuredHeight();
+ view.layout(offsetX, offsetY, offsetX + width, nextOffsetY);
+ offsetY = nextOffsetY;
+ }
+ }
+
+}
diff --git a/src/com/android/camera/ui/NinePatchTexture.java b/src/com/android/camera/ui/NinePatchTexture.java
index 4dd772a..5993cd4 100644
--- a/src/com/android/camera/ui/NinePatchTexture.java
+++ b/src/com/android/camera/ui/NinePatchTexture.java
@@ -33,7 +33,7 @@ public class NinePatchTexture extends FrameTexture {
}
@Override
- public boolean bind(GLRootView root, GL11 gl) {
+ protected boolean bind(GLRootView root, GL11 gl) {
if (mLastWidth != mWidth || mLastHeight != mHeight) {
if (mDelegate != null) mDelegate.deleteFromGL(gl);
mDelegate = new MyTexture(mWidth, mHeight);
@@ -43,6 +43,11 @@ public class NinePatchTexture extends FrameTexture {
return mDelegate.bind(root, gl);
}
+ @Override
+ public void getTextureCoords(float coord[], int offset) {
+ mDelegate.getTextureCoords(coord, offset);
+ }
+
protected NinePatchDrawable getNinePatch() {
if (mNinePatch == null) {
mNinePatch = (NinePatchDrawable)
diff --git a/src/com/android/camera/ui/PopupWindow.java b/src/com/android/camera/ui/PopupWindow.java
index cc77bc4..3d650cf 100644
--- a/src/com/android/camera/ui/PopupWindow.java
+++ b/src/com/android/camera/ui/PopupWindow.java
@@ -102,9 +102,7 @@ public class PopupWindow extends GLView {
aYoffset = Math.min(aYoffset, height - p.bottom - aHeight);
if (mAnchor != null) {
- if (mAnchor.bind(root, gl)) {
- mAnchor.draw(root, aXoffset, aYoffset);
- }
+ mAnchor.draw(root, aXoffset, aYoffset);
}
if (mBackupTexture == null || mBackupTexture.getBoundGL() != gl) {
@@ -123,16 +121,12 @@ public class PopupWindow extends GLView {
if (mBackground != null) {
mBackground.setSize(width - aWidth + mAnchorOffset, height);
- if (mBackground.bind(root, gl)) {
- mBackground.draw(root, 0, 0);
- }
+ mBackground.draw(root, 0, 0);
}
- if (backup.bind(root, gl)) {
- gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ZERO);
- backup.draw(root, aXoffset, aYoffset, aWidth, aHeight, 1);
- gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
- }
+ gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ZERO);
+ backup.draw(root, aXoffset, aYoffset, aWidth, aHeight, 1);
+ gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
public void setContent(GLView content) {
diff --git a/src/com/android/camera/ui/PopupWindowStencilImpl.java b/src/com/android/camera/ui/PopupWindowStencilImpl.java
index b05b4e5..87267c4 100644
--- a/src/com/android/camera/ui/PopupWindowStencilImpl.java
+++ b/src/com/android/camera/ui/PopupWindowStencilImpl.java
@@ -6,7 +6,6 @@ import javax.microedition.khronos.opengles.GL11;
public class PopupWindowStencilImpl extends PopupWindow {
-
@Override
protected void renderBackground(GLRootView rootView, GL11 gl) {
int width = getWidth();
@@ -22,19 +21,14 @@ public class PopupWindowStencilImpl extends PopupWindow {
if (mAnchor != null) {
gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
gl.glStencilFunc(GL11.GL_ALWAYS, 1, 1);
- if (mAnchor.bind(rootView, gl)) {
- mAnchor.draw(rootView, aXoffset, aYoffset);
- }
+ mAnchor.draw(rootView, aXoffset, aYoffset);
gl.glStencilFunc(GL11.GL_NOTEQUAL, 1, 1);
gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
}
if (mBackground != null) {
mBackground.setSize(width - aWidth + mAnchorOffset, height);
- if (mBackground.bind(rootView, gl)) {
- mBackground.draw(rootView, 0, 0);
- }
+ mBackground.draw(rootView, 0, 0);
}
}
-
}
diff --git a/src/com/android/camera/ui/PreferenceAdapter.java b/src/com/android/camera/ui/PreferenceAdapter.java
index d4f135d..d66137a 100644
--- a/src/com/android/camera/ui/PreferenceAdapter.java
+++ b/src/com/android/camera/ui/PreferenceAdapter.java
@@ -1,11 +1,9 @@
package com.android.camera.ui;
-import static com.android.camera.ui.GLRootView.dpToPixel;
import android.content.Context;
import com.android.camera.IconListPreference;
import com.android.camera.ListPreference;
-import com.google.android.camera.R;
import com.android.camera.Util;
import java.util.ArrayList;
@@ -14,24 +12,12 @@ public class PreferenceAdapter
implements GLListView.Model, GLListView.OnItemSelectedListener {
private static final int ICON_NONE = 0;
- private static final int HORIZONTAL_PADDINGS = 4;
- private static final int VERTICAL_PADDINGS = 2;
-
- private static int sHorizontalPaddings = -1;
- private static int sVerticalPaddings;
private final ArrayList<GLView> mContent = new ArrayList<GLView>();
private final ListPreference mPreference;
private String mOverride;
- private static void initializeStaticVariable(Context context) {
- if (sHorizontalPaddings >= 0) return;
- sHorizontalPaddings = dpToPixel(context, HORIZONTAL_PADDINGS);
- sVerticalPaddings = dpToPixel(context, VERTICAL_PADDINGS);
- }
-
public PreferenceAdapter(Context context, ListPreference preference) {
- initializeStaticVariable(context);
mPreference = preference;
generateContent(context, preference);
}
@@ -59,11 +45,8 @@ public class PreferenceAdapter
}
private void generateContent(Context context, ListPreference preference) {
- GLOptionHeader header = new GLOptionHeader(context, preference);
- header.setBackground(new NinePatchTexture(
- context, R.drawable.optionheader_background));
- header.setPaddings(sHorizontalPaddings,
- sVerticalPaddings, sHorizontalPaddings, sVerticalPaddings);
+ GLOptionHeader header =
+ new GLOptionHeader(context, preference.getTitle());
mContent.add(header);
CharSequence[] entries = preference.getEntries();
CharSequence[] values = preference.getEntryValues();
@@ -77,8 +60,6 @@ public class PreferenceAdapter
GLOptionItem item = new GLOptionItem(
context, icons == null ? ICON_NONE : icons[i],
entries[i].toString());
- item.setPaddings(sHorizontalPaddings,
- sVerticalPaddings, sHorizontalPaddings, sVerticalPaddings);
item.setChecked(values[i].equals(value));
mContent.add(item);
}
diff --git a/src/com/android/camera/ui/ZoomController.java b/src/com/android/camera/ui/ZoomController.java
new file mode 100644
index 0000000..69861bf
--- /dev/null
+++ b/src/com/android/camera/ui/ZoomController.java
@@ -0,0 +1,269 @@
+package com.android.camera.ui;
+
+import static com.android.camera.ui.GLRootView.dpToPixel;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+
+import com.google.android.camera.R;
+
+import com.android.camera.Util;
+
+import java.text.DecimalFormat;
+import java.util.Arrays;
+
+import javax.microedition.khronos.opengles.GL11;
+
+public class ZoomController extends GLView {
+ private static final int LABEL_COLOR = Color.WHITE;
+
+ private static final DecimalFormat sZoomFormat = new DecimalFormat("#.#x");
+ private static final int INVALID_POSITION = Integer.MAX_VALUE;
+
+ private static final float LABEL_FONT_SIZE = 18;
+ private static final int HORIZONTAL_PADDING = 3;
+ private static final int VERTICAL_PADDING = 3;
+ private static final int MINIMAL_HEIGHT = 150;
+ private static final float TOLERANCE_RADIUS = 30;
+
+ private static float sLabelSize;
+ private static int sHorizontalPadding;
+ private static int sVerticalPadding;
+ private static int sMinimalHeight;
+ private static float sToleranceRadius;
+
+ private static NinePatchTexture sBackground;
+ private static Texture sSlider;
+ private static Texture sTickMark;
+ private static Texture sFineTickMark;
+
+ private StringTexture mTickLabels[];
+ private float mRatios[];
+ private int mIndex;
+
+ private int mFineTickStep;
+ private int mLabelStep;
+
+ private int mMaxLabelWidth;
+ private int mMaxLabelHeight;
+
+ private int mSliderTop;
+ private int mSliderBottom;
+ private int mSliderLeft;
+ private int mSliderPosition = INVALID_POSITION;
+ private float mValueGap;
+ private ZoomListener mZoomListener;
+
+ public interface ZoomListener {
+ public void onZoomChanged(int index, float ratio, boolean isMoving);
+ }
+
+ public ZoomController(Context context) {
+ initializeStaticVariable(context);
+ }
+
+ private void onSliderMoved(int position, boolean isMoving) {
+ mSliderPosition = Util.clamp(position,
+ mSliderTop, mSliderBottom - sSlider.getHeight());
+ invalidate();
+ int index = mRatios.length - 1 - (int)
+ ((position - mSliderTop) / mValueGap + .5f);
+ if (index != mIndex || !isMoving) {
+ mIndex = index;
+ if (mZoomListener != null) {
+ mZoomListener.onZoomChanged(mIndex, mRatios[mIndex], isMoving);
+ }
+ }
+ }
+
+ private static void initializeStaticVariable(Context context) {
+ if (sBackground != null) return;
+
+ sLabelSize = dpToPixel(context, LABEL_FONT_SIZE);
+ sHorizontalPadding = dpToPixel(context, HORIZONTAL_PADDING);
+ sVerticalPadding = dpToPixel(context, VERTICAL_PADDING);
+ sMinimalHeight = dpToPixel(context, MINIMAL_HEIGHT);
+ sToleranceRadius = dpToPixel(context, TOLERANCE_RADIUS);
+
+ sBackground = new NinePatchTexture(context, R.drawable.zoom_background);
+ sSlider = new ResourceTexture(context, R.drawable.zoom_slider);
+ sTickMark = new ResourceTexture(context, R.drawable.zoom_tickmark);
+ sFineTickMark = new ResourceTexture(
+ context, R.drawable.zoom_finetickmark);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ if (!changed) return;
+ Rect p = mPaddings;
+ int height = b - t - p.top - p.bottom;
+ int margin = Math.max(sSlider.getHeight(), mMaxLabelHeight);
+ mValueGap = (float) (height - margin) / (mRatios.length - 1);
+
+ mSliderLeft = p.left + mMaxLabelWidth + sHorizontalPadding
+ + sTickMark.getWidth() + sHorizontalPadding;
+
+ mSliderTop = p.top + margin / 2 - sSlider.getHeight() / 2;
+ mSliderBottom = mSliderTop + height - margin + sSlider.getHeight();
+ }
+
+ private boolean withInToleranceRange(float x, float y) {
+ float sx = mSliderLeft + sSlider.getWidth() / 2;
+ float sy = mSliderTop + (mRatios.length - 1 - mIndex) * mValueGap
+ + sSlider.getHeight() / 2;
+ float dist = Util.distance(x, y, sx, sy);
+ return dist <= sToleranceRadius;
+ }
+
+ @Override
+ protected boolean onTouch(MotionEvent e) {
+ float x = e.getX();
+ float y = e.getY();
+ switch (e.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if (withInToleranceRange(x, y)) {
+ onSliderMoved((int) (y - sSlider.getHeight()), true);
+ }
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ if (mSliderPosition != INVALID_POSITION) {
+ onSliderMoved((int) (y - sSlider.getHeight()), true);
+ }
+ return true;
+ case MotionEvent.ACTION_UP:
+ if (mSliderPosition != INVALID_POSITION) {
+ onSliderMoved((int) (y - sSlider.getHeight()), false);
+ mSliderPosition = INVALID_POSITION;
+ }
+ return true;
+ }
+ return true;
+ }
+
+ public void setAvailableZoomRatios(float ratios[]) {
+ if (Arrays.equals(ratios, mRatios)) return;
+ mRatios = ratios;
+ mLabelStep = getLabelStep(ratios.length);
+ mTickLabels = new StringTexture[
+ (ratios.length + mLabelStep - 1) / mLabelStep];
+ for (int i = 0, n = mTickLabels.length; i < n; ++i) {
+ mTickLabels[i] = StringTexture.newInstance(
+ sZoomFormat.format(ratios[i * mLabelStep]),
+ sLabelSize, LABEL_COLOR);
+ }
+ mFineTickStep = mLabelStep % 3 == 0
+ ? mLabelStep / 3
+ : mLabelStep %2 == 0 ? mLabelStep / 2 : 0;
+
+ int maxHeight = 0;
+ int maxWidth = 0;
+ int labelCount = mTickLabels.length;
+ for (int i = 0; i < labelCount; ++i) {
+ maxWidth = Math.max(maxWidth, mTickLabels[i].getWidth());
+ maxHeight = Math.max(maxHeight, mTickLabels[i].getHeight());
+ }
+
+ mMaxLabelHeight = maxHeight;
+ mMaxLabelWidth = maxWidth;
+ invalidate();
+ }
+
+ private int getLabelStep(final int valueCount) {
+ if (valueCount < 5) return 1;
+ for (int step = valueCount / 5;; ++step) {
+ if (valueCount / step <= 5) return step;
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ int labelCount = mTickLabels.length;
+ int ratioCount = mRatios.length;
+
+ int height = (mMaxLabelHeight + sVerticalPadding)
+ * (labelCount - 1) * ratioCount / (mLabelStep * labelCount)
+ + Math.max(sSlider.getHeight(), mMaxLabelHeight);
+
+ int width = mMaxLabelWidth + sHorizontalPadding + sTickMark.getWidth()
+ + sHorizontalPadding + sBackground.getIntrinsicWidth();
+ height = Math.max(sMinimalHeight, height);
+
+ new MeasureHelper(this)
+ .setPreferredContentSize(width, height)
+ .measure(widthSpec, heightSpec);
+ }
+
+ @Override
+ protected void render(GLRootView root, GL11 gl) {
+ renderTicks(root, gl);
+ renderSlider(root, gl);
+ }
+
+ private void renderTicks(GLRootView root, GL11 gl) {
+ float gap = mValueGap;
+ int labelStep = mLabelStep;
+
+ // render the tick labels
+ int xoffset = mPaddings.left + mMaxLabelWidth;
+ float yoffset = mSliderBottom - sSlider.getHeight() / 2;
+ for (int i = 0, n = mTickLabels.length; i < n; ++i) {
+ Texture t = mTickLabels[i];
+ t.draw(root, xoffset - t.getWidth(),
+ (int) (yoffset - t.getHeight() / 2));
+ yoffset -= labelStep * gap;
+ }
+
+ // render the main tick marks
+ Texture tickMark = sTickMark;
+ xoffset += sHorizontalPadding;
+ yoffset = mSliderBottom - sSlider.getHeight() / 2;
+ int halfHeight = tickMark.getHeight() / 2;
+ for (int i = 0, n = mTickLabels.length; i < n; ++i) {
+ tickMark.draw(root, xoffset, (int) (yoffset - halfHeight));
+ yoffset -= labelStep * gap;
+ }
+
+ if (mFineTickStep > 0) {
+ // render the fine tick marks
+ tickMark = sFineTickMark;
+ xoffset += sTickMark.getWidth() - tickMark.getWidth();
+ yoffset = mSliderBottom - sSlider.getHeight() / 2;
+ halfHeight = tickMark.getHeight() / 2;
+ for (int i = 0, n = mRatios.length; i < n; ++i) {
+ if (i % mLabelStep != 0) {
+ tickMark.draw(root, xoffset, (int) (yoffset - halfHeight));
+ }
+ yoffset -= gap;
+ }
+ }
+ }
+
+ private void renderSlider(GLRootView root, GL11 gl) {
+ int left = mSliderLeft;
+ int bottom = mSliderBottom;
+ int top = mSliderTop;
+ sBackground.setSize(sBackground.getIntrinsicWidth(), bottom - top);
+ sBackground.draw(root, left, top);
+
+ if (mSliderPosition == INVALID_POSITION) {
+ sSlider.draw(root, left, (int)
+ (top + mValueGap * (mRatios.length - 1 - mIndex)));
+ } else {
+ sSlider.draw(root, left, mSliderPosition);
+ }
+ }
+
+ public void setZoomListener(ZoomListener listener) {
+ mZoomListener = listener;
+ }
+
+ public void setZoomIndex(int index) {
+ index = Util.clamp(index, 0, mRatios.length - 1);
+ if (mIndex == index) return;
+ mIndex = index;
+ if (mZoomListener != null) {
+ mZoomListener.onZoomChanged(mIndex, mRatios[mIndex], false);
+ }
+ }
+}
diff --git a/src/com/android/camera/ui/ZoomIndicator.java b/src/com/android/camera/ui/ZoomIndicator.java
index c15643f..ab2f212 100644
--- a/src/com/android/camera/ui/ZoomIndicator.java
+++ b/src/com/android/camera/ui/ZoomIndicator.java
@@ -2,19 +2,36 @@ package com.android.camera.ui;
import android.content.Context;
import android.graphics.Color;
-import android.graphics.Rect;
-import javax.microedition.khronos.opengles.GL11;
+import com.google.android.camera.R;
-public class ZoomIndicator extends GLView {
+import com.android.camera.ui.ZoomController.ZoomListener;
- private static final int FONT_SIZE = 16;
+import java.text.DecimalFormat;
- private final StringTexture mTitle;
+public class ZoomIndicator extends AbstractIndicator {
+ private static final DecimalFormat sZoomFormat = new DecimalFormat("#.#x");
+ private static final float FONT_SIZE = 18;
+ private static final int FONT_COLOR = Color.WHITE;
- public ZoomIndicator(Context context, String title) {
- float fontSize = GLRootView.dpToPixel(context, FONT_SIZE);
- mTitle = StringTexture.newInstance(title, fontSize, Color.WHITE);
+ protected static final String TAG = "ZoomIndicator";
+
+ private final float mFontSize;
+
+ private ZoomController mZoomController;
+ private LinearLayout mPopupContent;
+ private ZoomListener mZoomListener;
+ private int mZoomIndex = 0;
+ private float mZoomRatios[];
+
+ private StringTexture mTitle;
+ private float mZoom = 1.0f;
+
+ public ZoomIndicator(Context context) {
+ super(context);
+ mFontSize = GLRootView.dpToPixel(context, FONT_SIZE);
+ mTitle = StringTexture.newInstance(
+ sZoomFormat.format(mZoom), mFontSize, FONT_COLOR);
}
@Override
@@ -25,14 +42,64 @@ public class ZoomIndicator extends GLView {
}
@Override
- protected void render(GLRootView root, GL11 gl) {
- if (mTitle.bind(root, gl)) {
- Rect p = mPaddings;
- int width = getWidth() - p.left - p.right;
- int height = getHeight() - p.top - p.bottom;
- mTitle.draw(root,
- p.left + (width - mTitle.getWidth()) / 2,
- p.top + (height - mTitle.getHeight()) / 2);
+ protected Texture getIcon() {
+ return mTitle;
+ }
+
+ @Override
+ public GLView getPopupContent() {
+ if (mZoomController == null) {
+ Context context = getGLRootView().getContext();
+ mZoomController = new ZoomController(context);
+ mZoomController.setAvailableZoomRatios(mZoomRatios);
+ mZoomController.setPaddings(15, 6, 15, 6);
+
+ mPopupContent = new LinearLayout();
+ GLOptionHeader header = new GLOptionHeader(context,
+ context.getString(R.string.zoom_control_title));
+ header.setBackground(new NinePatchTexture(
+ context, R.drawable.optionheader_background));
+ header.setPaddings(6, 3, 6, 3);
+ mPopupContent.addComponent(header);
+ mPopupContent.addComponent(mZoomController);
+
+ mZoomController.setZoomListener(new MyZoomListener());
+ mZoomController.setZoomIndex(mZoomIndex);
+ }
+ return mPopupContent;
+ }
+
+ @Override
+ public void overrideSettings(String key, String settings) {
+ // do nothing
+ }
+
+ public void setZoomRatios(float[] ratios) {
+ mZoomRatios = ratios;
+ }
+
+ private class MyZoomListener implements ZoomController.ZoomListener {
+ public void onZoomChanged(int index, float value, boolean isMoving) {
+ if (mZoomListener != null) {
+ mZoomListener.onZoomChanged(index, value, isMoving);
+ }
+ if (mZoom != value) {
+ mZoom = value;
+ mTitle = StringTexture.newInstance(
+ sZoomFormat.format(value), mFontSize, Color.WHITE);
+ invalidate();
+ }
+ }
+ }
+
+ public void setZoomListener(ZoomListener listener) {
+ mZoomListener = listener;
+ }
+
+ public void setZoomIndex(int index) {
+ if (mZoomController != null) {
+ mZoomController.setZoomIndex(index);
}
+ mZoomIndex = index;
}
}