diff options
Diffstat (limited to 'src/com/android/camera/ui')
-rw-r--r-- | src/com/android/camera/ui/CameraRootView.java | 23 | ||||
-rw-r--r-- | src/com/android/camera/ui/FilmStripView.java | 53 | ||||
-rw-r--r-- | src/com/android/camera/ui/PieRenderer.java | 59 | ||||
-rw-r--r-- | src/com/android/camera/ui/ProgressRenderer.java | 127 |
4 files changed, 220 insertions, 42 deletions
diff --git a/src/com/android/camera/ui/CameraRootView.java b/src/com/android/camera/ui/CameraRootView.java index 505549c80..daaefc027 100644 --- a/src/com/android/camera/ui/CameraRootView.java +++ b/src/com/android/camera/ui/CameraRootView.java @@ -37,7 +37,7 @@ public class CameraRootView extends FrameLayout { private int mBottomMargin = 0; private int mLeftMargin = 0; private int mRightMargin = 0; - private Rect mCurrentInsets; + private final Rect mCurrentInsets = new Rect(0, 0, 0, 0); private int mOffset = 0; private Object mDisplayListener; private MyDisplayListener mListener; @@ -53,19 +53,24 @@ public class CameraRootView extends FrameLayout { @Override protected boolean fitSystemWindows(Rect insets) { - mCurrentInsets = insets; // insets include status bar, navigation bar, etc // In this case, we are only concerned with the size of nav bar - if (mOffset > 0) { - return true; + if (mCurrentInsets.equals(insets)) { + // Local copy of the insets is up to date. No need to do anything. + return false; } - if (insets.bottom > 0) { - mOffset = insets.bottom; - } else if (insets.right > 0) { - mOffset = insets.right; + if (mOffset == 0) { + if (insets.bottom > 0) { + mOffset = insets.bottom; + } else if (insets.right > 0) { + mOffset = insets.right; + } } - return true; + mCurrentInsets.set(insets); + // Make sure onMeasure will be called to adapt to the new insets. + requestLayout(); + return false; } public void initDisplayListener() { diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java index 9945952ee..89da0184e 100644 --- a/src/com/android/camera/ui/FilmStripView.java +++ b/src/com/android/camera/ui/FilmStripView.java @@ -43,6 +43,7 @@ import com.android.camera.ui.FilmStripView.ImageData.PanoramaSupportCallback; import com.android.camera.ui.FilmstripBottomControls.BottomControlsListener; import com.android.camera.util.CameraUtil; import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper; +import com.android.camera.util.UsageStatistics; import com.android.camera2.R; import java.util.Arrays; @@ -1453,6 +1454,13 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { mController.setSurroundingViewsVisible(true); } + private void hideZoomView() { + if (mController.isZoomStarted()) { + mController.cancelLoadingZoomedImage(); + mZoomView.setVisibility(GONE); + } + } + // Keeps the view in the view hierarchy if it's camera preview. // Remove from the hierarchy otherwise. private void checkForRemoval(ImageData data, View v) { @@ -1785,6 +1793,8 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { && deltaX < mSlop * (-1)) { // intercept left swipe if (Math.abs(deltaX) >= Math.abs(deltaY) * 2) { + UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, + UsageStatistics.ACTION_FILMSTRIP, null); return true; } } @@ -1908,10 +1918,19 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { mController.stopScrolling(true); mController.stopScale(); mDataIdOnUserScrolling = 0; - // Remove all views from the mViewItem buffer, except the camera view. + // Reload has a side effect that after this call, it will show the + // camera preview. So we want to know whether it starts from the camera + // preview to decide whether we need to call onDataFocusChanged. + boolean stayInPreview = false; + if (mListener != null && mViewItem[mCurrentItem] != null) { - mListener.onDataFocusChanged(mViewItem[mCurrentItem].getId(), false); + stayInPreview = mViewItem[mCurrentItem].getId() == 0; + if (!stayInPreview) { + mListener.onDataFocusChanged(mViewItem[mCurrentItem].getId(), false); + } } + + // Remove all views from the mViewItem buffer, except the camera view. for (int i = 0; i < mViewItem.length; i++) { if (mViewItem[i] == null) { continue; @@ -1920,8 +1939,9 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { if (v != mCameraView) { removeView(v); } - if (mDataAdapter.getImageData(mViewItem[i].getId()) != null) { - mDataAdapter.getImageData(mViewItem[i].getId()).recycle(); + ImageData imageData = mDataAdapter.getImageData(mViewItem[i].getId()); + if (imageData != null) { + imageData.recycle(); } } @@ -1954,7 +1974,9 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { if (mListener != null) { mListener.onReload(); - mListener.onDataFocusChanged(mViewItem[mCurrentItem].getId(), true); + if (!stayInPreview) { + mListener.onDataFocusChanged(mViewItem[mCurrentItem].getId(), true); + } } } @@ -2625,13 +2647,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { if (!mController.stopScrolling(false)) { return false; } - // A down event is usually followed by a gesture, we apply gesture on - // the lower-res image during a gesture to ensure a responsive experience. - // TODO: Delay this until gesture starts. - if (mController.isZoomStarted()) { - mController.cancelLoadingZoomedImage(); - mZoomView.setVisibility(GONE); - } + return true; } @@ -2712,12 +2728,16 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { @Override public boolean onScroll(float x, float y, float dx, float dy) { - if (mViewItem[mCurrentItem] == null) { + ViewItem currItem = mViewItem[mCurrentItem]; + if (currItem == null) { return false; } + if (!mDataAdapter.canSwipeInFullScreen(currItem.getId())) { + return false; + } + hideZoomView(); // When image is zoomed in to be bigger than the screen if (mController.isZoomStarted()) { - mController.cancelLoadingZoomedImage(); ViewItem curr = mViewItem[mCurrentItem]; float transX = curr.getTranslationX() - dx; float transY = curr.getTranslationY() - dy; @@ -2777,6 +2797,9 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { if (currItem == null) { return false; } + if (!mDataAdapter.canSwipeInFullScreen(currItem.getId())) { + return false; + } if (mController.isZoomStarted()) { // Fling within the zoomed image mController.flingInsideZoomView(velocityX, velocityY); @@ -2837,6 +2860,8 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { if (inCameraFullscreen()) { return false; } + + hideZoomView(); mScaleTrend = 1f; // If the image is smaller than screen size, we should allow to zoom // in to full screen size diff --git a/src/com/android/camera/ui/PieRenderer.java b/src/com/android/camera/ui/PieRenderer.java index 008bc40ca..0039aa22c 100644 --- a/src/com/android/camera/ui/PieRenderer.java +++ b/src/com/android/camera/ui/PieRenderer.java @@ -16,9 +16,6 @@ package com.android.camera.ui; -import java.util.ArrayList; -import java.util.List; - import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.ValueAnimator; @@ -40,12 +37,19 @@ import android.view.animation.Animation; import android.view.animation.Transformation; import com.android.camera.drawable.TextDrawable; +import com.android.camera.ui.ProgressRenderer.VisibilityListener; import com.android.camera2.R; +import java.util.ArrayList; +import java.util.List; + +/** + * An overlay renderer that is used to display focus state and progress state. + */ public class PieRenderer extends OverlayRenderer implements FocusIndicator { - private static final String TAG = "CAM Pie"; + private static final String TAG = "PieRenderer"; // Sometimes continuous autofocus starts and stops several times quickly. // These states are used to make sure the animation is run for at least some @@ -143,7 +147,7 @@ public class PieRenderer extends OverlayRenderer private int mAngleZone; private float mCenterAngle; - + private ProgressRenderer mProgressRenderer; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { @@ -227,6 +231,7 @@ public class PieRenderer extends OverlayRenderer mLabel.setDropShadow(true); mDeadZone = res.getDimensionPixelSize(R.dimen.pie_deadzone_width); mAngleZone = res.getDimensionPixelSize(R.dimen.pie_anglezone_width); + mProgressRenderer = new ProgressRenderer(ctx); } private PieItem getRoot() { @@ -309,6 +314,10 @@ public class PieRenderer extends OverlayRenderer return mState == STATE_PIE && isVisible(); } + public void setProgress(int percent) { + mProgressRenderer.setProgress(percent); + } + private void fadeIn() { mFadeIn = new ValueAnimator(); mFadeIn.setFloatValues(0f, 1f); @@ -524,6 +533,8 @@ public class PieRenderer extends OverlayRenderer @Override public void onDraw(Canvas canvas) { + mProgressRenderer.onDraw(canvas, mFocusX, mFocusY); + float alpha = 1; if (mXFade != null) { alpha = (Float) mXFade.getAnimatedValue(); @@ -706,6 +717,11 @@ public class PieRenderer extends OverlayRenderer return false; } + @Override + public boolean isVisible() { + return super.isVisible() || mProgressRenderer.isVisible(); + } + private boolean pulledToCenter(PointF polarCoords) { return polarCoords.y < mArcRadius - mRadiusInc; } @@ -918,17 +934,6 @@ public class PieRenderer extends OverlayRenderer setCircle(mFocusX, mFocusY); } - public void alignFocus(int x, int y) { - mOverlay.removeCallbacks(mDisappear); - mAnimation.cancel(); - mAnimation.reset(); - mFocusX = x; - mFocusY = y; - mDialAngle = DIAL_HORIZONTAL; - setCircle(x, y); - mFocused = false; - } - public int getSize() { return 2 * mCircleSize; } @@ -1022,11 +1027,27 @@ public class PieRenderer extends OverlayRenderer mState = STATE_IDLE; } + public void clear(boolean waitUntilProgressIsHidden) { + if (mState == STATE_PIE) + return; + cancelFocus(); + + if (waitUntilProgressIsHidden) { + mProgressRenderer.setVisibilityListener(new VisibilityListener() { + @Override + public void onHidden() { + mOverlay.post(mDisappear); + } + }); + } else { + mOverlay.post(mDisappear); + mProgressRenderer.setVisibilityListener(null); + } + } + @Override public void clear() { - if (mState == STATE_PIE) return; - cancelFocus(); - mOverlay.post(mDisappear); + clear(false); } private void startAnimation(long duration, boolean timeout, diff --git a/src/com/android/camera/ui/ProgressRenderer.java b/src/com/android/camera/ui/ProgressRenderer.java new file mode 100644 index 000000000..500293133 --- /dev/null +++ b/src/com/android/camera/ui/ProgressRenderer.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2013 The Android Open Source 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.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; + +import com.android.camera2.R; + +/** + * Renders a circular progress bar on the screen. + */ +public class ProgressRenderer { + + public static interface VisibilityListener { + public void onHidden(); + } + + private final int mProgressRadius; + private final Paint mProgressBasePaint; + private final Paint mProgressPaint; + + private RectF mArcBounds = new RectF(0, 0, 1, 1); + private int mProgressAngleDegrees = 270; + private boolean mVisible = false; + private VisibilityListener mVisibilityListener; + + /** + * After we reach 100%, keep on painting the progress for another x milliseconds + * before hiding it. + */ + private static final int SHOW_PROGRESS_X_ADDITIONAL_MS = 100; + + /** When to hide the progress indicator. */ + private long mTimeToHide = 0; + + public ProgressRenderer(Context context) { + mProgressRadius = context.getResources().getDimensionPixelSize(R.dimen.pie_progress_radius); + int pieProgressWidth = context.getResources().getDimensionPixelSize( + R.dimen.pie_progress_width); + mProgressBasePaint = createProgressPaint(pieProgressWidth, 0.2f); + mProgressPaint = createProgressPaint(pieProgressWidth, 1.0f); + } + + /** + * Sets or replaces a visiblity listener. + */ + public void setVisibilityListener(VisibilityListener listener) { + mVisibilityListener = listener; + } + + /** + * Shows a progress indicator. If the progress is '100', the progress + * indicator will be hidden. + * + * @param percent the progress in percent (0-100). + */ + public void setProgress(int percent) { + // Clamp the value. + percent = Math.min(100, Math.max(percent, 0)); + mProgressAngleDegrees = (int) ((360f / 100) * percent); + + // We hide the progress once we drew the 100% state once. + if (percent < 100) { + mVisible = true; + mTimeToHide = System.currentTimeMillis() + SHOW_PROGRESS_X_ADDITIONAL_MS; + } + } + + /** + * Draw the current progress (if < 100%) centered at the given location. + */ + public void onDraw(Canvas canvas, int centerX, int centerY) { + if (!mVisible) { + return; + } + mArcBounds = new RectF(centerX - mProgressRadius, centerY - mProgressRadius, centerX + + mProgressRadius, + centerY + mProgressRadius); + + canvas.drawCircle(centerX, centerY, mProgressRadius, mProgressBasePaint); + canvas.drawArc(mArcBounds, -90, mProgressAngleDegrees, false, mProgressPaint); + + // After we reached 100%, we paint the progress renderer for another x + // milliseconds until we hide it. + if (mProgressAngleDegrees == 360 && System.currentTimeMillis() > mTimeToHide) { + mVisible = false; + if (mVisibilityListener != null) { + mVisibilityListener.onHidden(); + } + } + } + + /** + * @return Whether the progress renderer is visible. + */ + public boolean isVisible() { + return mVisible; + } + + private static Paint createProgressPaint(int width, float alpha) { + Paint paint = new Paint(); + paint.setAntiAlias(true); + // 20% alpha. + paint.setColor(Color.argb((int) (alpha * 255), 255, 255, 255)); + paint.setStrokeWidth(width); + paint.setStyle(Paint.Style.STROKE); + return paint; + } +} |