Skip to content

Instantly share code, notes, and snippets.

@drewis
Created June 7, 2012 04:28
Show Gist options
  • Save drewis/2886557 to your computer and use it in GitHub Desktop.
Save drewis/2886557 to your computer and use it in GitHub Desktop.
android-4.0.4_r1.2..android-4.0.4_r2.1
[drew@master aosp]$ repo forall -pcv git log --oneline --no-merges android-4.0.4_r1.2..android-4.0.4_r2.1
project build/
1bbaf73 IMM76L
b0936b7 IMM76K
396c8cf IMM76J
project device/moto/stingray/
ca7247e Update for cmda radio 3.1A.65P
project packages/apps/Gallery2/
fd69559 Patch 2 for MR1.
1cdcda4 Patch for MR1.
[drew@master aosp]$ repo forall -pcv git log -p --oneline --no-merges android-4.0.4_r1.2..android-4.0.4_r2.1
project build/
1bbaf73 IMM76L
diff --git a/core/build_id.mk b/core/build_id.mk
index 77e9923..8f1b5ba 100644
--- a/core/build_id.mk
+++ b/core/build_id.mk
@@ -19,4 +19,4 @@
# (like "CRB01"). It must be a single word, and is
# capitalized by convention.
-export BUILD_ID=IMM76K
+export BUILD_ID=IMM76L
b0936b7 IMM76K
diff --git a/core/build_id.mk b/core/build_id.mk
index c7f7c2b..77e9923 100644
--- a/core/build_id.mk
+++ b/core/build_id.mk
@@ -19,4 +19,4 @@
# (like "CRB01"). It must be a single word, and is
# capitalized by convention.
-export BUILD_ID=IMM76J
+export BUILD_ID=IMM76K
396c8cf IMM76J
diff --git a/core/build_id.mk b/core/build_id.mk
index 9d1709c..c7f7c2b 100644
--- a/core/build_id.mk
+++ b/core/build_id.mk
@@ -19,4 +19,4 @@
# (like "CRB01"). It must be a single word, and is
# capitalized by convention.
-export BUILD_ID=IMM76I
+export BUILD_ID=IMM76J
project device/moto/stingray/
ca7247e Update for cmda radio 3.1A.65P
diff --git a/board-info.txt b/board-info.txt
index d69c0e0..0095444 100644
--- a/board-info.txt
+++ b/board-info.txt
@@ -1,4 +1,4 @@
require product=stingray|xoom-cdma|xoom-cdma-lte
require version-bootloader=1050
-require version-baseband=CDMA_N_03.1A.64PS
+require version-baseband=CDMA_N_03.1A.65PS
require-for-product:xoom-cdma-lte version-baseband-2=LTEDC_U_07.1F.00
project external/android-clat/
project external/ant-glob/
project external/apache-qp/
project external/checkpolicy/
project external/eclipse-basebuilder/
project external/eclipse-windowbuilder/
project external/libmtp/
project external/libselinux/
project external/libsepol/
project external/libusb/
project external/libusb-compat/
project external/sepolicy/
project frameworks/opt/carddav/
project hardware/ti/wlan/
project hardware/ti/wpan/
project packages/apps/Gallery2/
fd69559 Patch 2 for MR1.
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
index aeed577..217a290 100644
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -43,6 +43,7 @@ public class PhotoView extends GLView {
private static final int MSG_TRANSITION_COMPLETE = 1;
private static final int MSG_SHOW_LOADING = 2;
+ private static final int MSG_CANCEL_EXTRA_SCALING = 3;
private static final long DELAY_SHOW_LOADING = 250; // 250ms;
@@ -111,6 +112,7 @@ public class PhotoView extends GLView {
private Path mOpenedItemPath;
private GalleryActivity mActivity;
private Point mImageCenter = new Point();
+ private boolean mCancelExtraScalingPending;
public PhotoView(GalleryActivity activity) {
mActivity = activity;
@@ -146,6 +148,12 @@ public class PhotoView extends GLView {
}
break;
}
+ case MSG_CANCEL_EXTRA_SCALING: {
+ cancelScaleGesture();
+ mPositionController.setExtraScalingRange(false);
+ mCancelExtraScalingPending = false;
+ break;
+ }
default: throw new AssertionError(message.what);
}
}
@@ -585,8 +593,22 @@ public class PhotoView extends GLView {
float scale = detector.getScaleFactor();
if (Float.isNaN(scale) || Float.isInfinite(scale)
|| mTransitionMode != TRANS_NONE) return true;
- mPositionController.scaleBy(scale,
+ boolean outOfRange = mPositionController.scaleBy(scale,
detector.getFocusX(), detector.getFocusY());
+ if (outOfRange) {
+ if (!mCancelExtraScalingPending) {
+ mHandler.sendEmptyMessageDelayed(
+ MSG_CANCEL_EXTRA_SCALING, 700);
+ mPositionController.setExtraScalingRange(true);
+ mCancelExtraScalingPending = true;
+ }
+ } else {
+ if (mCancelExtraScalingPending) {
+ mHandler.removeMessages(MSG_CANCEL_EXTRA_SCALING);
+ mPositionController.setExtraScalingRange(false);
+ mCancelExtraScalingPending = false;
+ }
+ }
return true;
}
@@ -605,6 +627,14 @@ public class PhotoView extends GLView {
}
}
+ private void cancelScaleGesture() {
+ long now = SystemClock.uptimeMillis();
+ MotionEvent cancelEvent = MotionEvent.obtain(
+ now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
+ mScaleDetector.onTouchEvent(cancelEvent);
+ cancelEvent.recycle();
+ }
+
public boolean jumpTo(int index) {
if (mTransitionMode != TRANS_NONE) return false;
mModel.jumpTo(index);
diff --git a/src/com/android/gallery3d/ui/PositionController.java b/src/com/android/gallery3d/ui/PositionController.java
index b4dac97..2068446 100644
--- a/src/com/android/gallery3d/ui/PositionController.java
+++ b/src/com/android/gallery3d/ui/PositionController.java
@@ -64,6 +64,9 @@ class PositionController {
private static final float SCALE_LIMIT = 4;
private static final int sHorizontalSlack = GalleryUtils.dpToPixel(12);
+ private static final float SCALE_MIN_EXTRA = 0.6f;
+ private static final float SCALE_MAX_EXTRA = 1.4f;
+
private PhotoView mViewer;
private EdgeView mEdgeView;
private int mImageW, mImageH;
@@ -83,6 +86,7 @@ class PositionController {
// The minimum and maximum scale we allow.
private float mScaleMin, mScaleMax = SCALE_LIMIT;
+ private boolean mExtraScalingRange = false;
// This is used by the fling animation
private FlingScroller mScroller;
@@ -268,7 +272,8 @@ class PositionController {
(focusY - mViewH / 2f) / mCurrentScale);
}
- public void scaleBy(float s, float focusX, float focusY) {
+ // Returns true if the result scale is outside the stable range.
+ public boolean scaleBy(float s, float focusX, float focusY) {
// We want to keep the focus point (on the bitmap) the same as when
// we begin the scale guesture, that is,
@@ -280,6 +285,7 @@ class PositionController {
int y = Math.round(mFocusBitmapY - (focusY - mViewH / 2f) / s);
startAnimation(x, y, s, ANIM_KIND_SCALE);
+ return (s < mScaleMin || s > mScaleMax);
}
public void endScale() {
@@ -287,6 +293,13 @@ class PositionController {
startSnapbackIfNeeded();
}
+ public void setExtraScalingRange(boolean enabled) {
+ mExtraScalingRange = enabled;
+ if (!enabled) {
+ startSnapbackIfNeeded();
+ }
+ }
+
public float getCurrentScale() {
return mCurrentScale;
}
@@ -400,7 +413,8 @@ class PositionController {
mToX = targetX;
mToY = targetY;
- mToScale = Utils.clamp(scale, 0.6f * mScaleMin, 1.4f * mScaleMax);
+ mToScale = Utils.clamp(scale, SCALE_MIN_EXTRA * mScaleMin,
+ SCALE_MAX_EXTRA * mScaleMax);
// If the scaled height is smaller than the view height,
// force it to be in the center.
@@ -540,9 +554,14 @@ class PositionController {
boolean needAnimation = false;
float scale = mCurrentScale;
- if (mCurrentScale < mScaleMin || mCurrentScale > mScaleMax) {
+ float scaleMin = mExtraScalingRange ?
+ mScaleMin * SCALE_MIN_EXTRA : mScaleMin;
+ float scaleMax = mExtraScalingRange ?
+ mScaleMax * SCALE_MAX_EXTRA : mScaleMax;
+
+ if (mCurrentScale < scaleMin || mCurrentScale > scaleMax) {
needAnimation = true;
- scale = Utils.clamp(mCurrentScale, mScaleMin, mScaleMax);
+ scale = Utils.clamp(mCurrentScale, scaleMin, scaleMax);
}
calculateStableBound(scale, sHorizontalSlack);
1cdcda4 Patch for MR1.
diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java
index 9b1c8c4..d7d1168 100644
--- a/src/com/android/gallery3d/app/PhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java
@@ -365,8 +365,9 @@ public class PhotoDataAdapter implements PhotoPage.Model {
return mTileProvider.getLevelCount();
}
- public Bitmap getTile(int level, int x, int y, int tileSize) {
- return mTileProvider.getTile(level, x, y, tileSize);
+ public Bitmap getTile(int level, int x, int y, int tileSize,
+ int borderSize) {
+ return mTileProvider.getTile(level, x, y, tileSize, borderSize);
}
public boolean isFailedToLoad() {
diff --git a/src/com/android/gallery3d/ui/BitmapTileProvider.java b/src/com/android/gallery3d/ui/BitmapTileProvider.java
index a47337f..3d4d4dc 100644
--- a/src/com/android/gallery3d/ui/BitmapTileProvider.java
+++ b/src/com/android/gallery3d/ui/BitmapTileProvider.java
@@ -65,11 +65,28 @@ public class BitmapTileProvider implements TileImageView.Model {
return mMipmaps.length;
}
- public Bitmap getTile(int level, int x, int y, int tileSize) {
- Bitmap result = Bitmap.createBitmap(tileSize, tileSize, mConfig);
+ public Bitmap getTile(int level, int x, int y, int tileSize,
+ int borderSize) {
+ x >>= level;
+ y >>= level;
+ int size = tileSize + 2 * borderSize;
+ Bitmap result = Bitmap.createBitmap(size, size, mConfig);
+ Bitmap mipmap = mMipmaps[level];
Canvas canvas = new Canvas(result);
- canvas.drawBitmap(mMipmaps[level], -(x >> level), -(y >> level), null);
- return result;
+ int offsetX = -x + borderSize;
+ int offsetY = -y + borderSize;
+ canvas.drawBitmap(mipmap, offsetX, offsetY, null);
+
+ // If the valid region (covered by mipmap or border) is smaller than the
+ // result bitmap, subset it.
+ int endX = offsetX + mipmap.getWidth() + borderSize;
+ int endY = offsetY + mipmap.getHeight() + borderSize;
+ if (endX < size || endY < size) {
+ return Bitmap.createBitmap(result, 0, 0, Math.min(size, endX),
+ Math.min(size, endY));
+ } else {
+ return result;
+ }
}
public void recycle() {
diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java
index 5062c0e..aeed577 100644
--- a/src/com/android/gallery3d/ui/PhotoView.java
+++ b/src/com/android/gallery3d/ui/PhotoView.java
@@ -25,12 +25,15 @@ import com.android.gallery3d.ui.PositionRepository.Position;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Message;
import android.os.SystemClock;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
+import android.view.animation.AccelerateInterpolator;
public class PhotoView extends GLView {
@SuppressWarnings("unused")
@@ -64,6 +67,14 @@ public class PhotoView extends GLView {
private static final float SWIPE_THRESHOLD = 300f;
private static final float DEFAULT_TEXT_SIZE = 20;
+ private static float TRANSITION_SCALE_FACTOR = 0.74f;
+
+ // Used to calculate the scaling factor for the fading animation.
+ private ZInterpolator mScaleInterpolator = new ZInterpolator(0.5f);
+
+ // Used to calculate the alpha factor for the fading animation.
+ private AccelerateInterpolator mAlphaInterpolator =
+ new AccelerateInterpolator(0.9f);
public interface PhotoTapListener {
public void onSingleTapUp(int x, int y);
@@ -99,6 +110,7 @@ public class PhotoView extends GLView {
private Path mOpenedItemPath;
private GalleryActivity mActivity;
+ private Point mImageCenter = new Point();
public PhotoView(GalleryActivity activity) {
mActivity = activity;
@@ -164,24 +176,49 @@ public class PhotoView extends GLView {
mPhotoTapListener = listener;
}
- private boolean setTileViewPosition(int centerX, int centerY, float scale) {
+ private void setTileViewPosition(int centerX, int centerY, float scale) {
+ TileImageView t = mTileView;
+
+ // Calculate the move-out progress value.
+ RectF bounds = mPositionController.getImageBounds();
+ int left = Math.round(bounds.left);
+ int right = Math.round(bounds.right);
+ int width = getWidth();
+ float progress = calculateMoveOutProgress(left, right, width);
+ progress = Utils.clamp(progress, -1f, 1f);
+
+ // We only want to apply the fading animation if the scrolling movement
+ // is to the right.
+ if (progress < 0) {
+ if (right - left < width) {
+ // If the picture is narrower than the view, keep it at the center
+ // of the view.
+ centerX = mPositionController.getImageWidth() / 2;
+ } else {
+ // If the picture is wider than the view (it's zoomed-in), keep
+ // the left edge of the object align the the left edge of the view.
+ centerX = Math.round(width / 2f / scale);
+ }
+ scale *= getScrollScale(progress);
+ t.setAlpha(getScrollAlpha(progress));
+ }
+
+ // set the position of the tile view
int inverseX = mPositionController.getImageWidth() - centerX;
int inverseY = mPositionController.getImageHeight() - centerY;
- TileImageView t = mTileView;
int rotation = mImageRotation;
switch (rotation) {
- case 0: return t.setPosition(centerX, centerY, scale, 0);
- case 90: return t.setPosition(centerY, inverseX, scale, 90);
- case 180: return t.setPosition(inverseX, inverseY, scale, 180);
- case 270: return t.setPosition(inverseY, centerX, scale, 270);
+ case 0: t.setPosition(centerX, centerY, scale, 0); break;
+ case 90: t.setPosition(centerY, inverseX, scale, 90); break;
+ case 180: t.setPosition(inverseX, inverseY, scale, 180); break;
+ case 270: t.setPosition(inverseY, centerX, scale, 270); break;
default: throw new IllegalArgumentException(String.valueOf(rotation));
}
}
public void setPosition(int centerX, int centerY, float scale) {
- if (setTileViewPosition(centerX, centerY, scale)) {
- layoutScreenNails();
- }
+ setTileViewPosition(centerX, centerY, scale);
+ layoutScreenNails();
}
private void updateScreenNailEntry(int which, ImageData data) {
@@ -217,6 +254,7 @@ public class PhotoView extends GLView {
case 0: {
// mImageWidth and mImageHeight will get updated
mTileView.notifyModelInvalidated();
+ mTileView.setAlpha(1.0f);
mImageRotation = mModel.getImageRotation();
if (((mImageRotation / 90) & 1) == 0) {
@@ -264,6 +302,7 @@ public class PhotoView extends GLView {
if (mModel == null) {
mTileView.notifyModelInvalidated();
+ mTileView.setAlpha(1.0f);
mImageRotation = 0;
mPositionController.setImageSize(0, 0);
updateLoadingState();
@@ -341,23 +380,40 @@ public class PhotoView extends GLView {
@Override
protected void render(GLCanvas canvas) {
PositionController p = mPositionController;
+ boolean drawScreenNail = (mTransitionMode != TRANS_SLIDE_IN_LEFT
+ && mTransitionMode != TRANS_SLIDE_IN_RIGHT
+ && mTransitionMode != TRANS_OPEN_ANIMATION);
+
+ // Draw the next photo
+ if (drawScreenNail) {
+ ScreenNailEntry nextNail = mScreenNails[ENTRY_NEXT];
+ if (nextNail.mVisible) nextNail.draw(canvas, true);
+ }
// Draw the current photo
if (mLoadingState == LOADING_COMPLETE) {
super.render(canvas);
}
- // Draw the previous and the next photo
- if (mTransitionMode != TRANS_SLIDE_IN_LEFT
- && mTransitionMode != TRANS_SLIDE_IN_RIGHT
- && mTransitionMode != TRANS_OPEN_ANIMATION) {
- ScreenNailEntry prevNail = mScreenNails[ENTRY_PREVIOUS];
- ScreenNailEntry nextNail = mScreenNails[ENTRY_NEXT];
+ // If the photo is loaded, draw the message/icon at the center of it,
+ // otherwise draw the message/icon at the center of the view.
+ if (mLoadingState == LOADING_COMPLETE) {
+ mTileView.getImageCenter(mImageCenter);
+ renderMessage(canvas, mImageCenter.x, mImageCenter.y);
+ } else {
+ renderMessage(canvas, getWidth() / 2, getHeight() / 2);
+ }
- if (prevNail.mVisible) prevNail.draw(canvas);
- if (nextNail.mVisible) nextNail.draw(canvas);
+ // Draw the previous photo
+ if (drawScreenNail) {
+ ScreenNailEntry prevNail = mScreenNails[ENTRY_PREVIOUS];
+ if (prevNail.mVisible) prevNail.draw(canvas, false);
}
+ if (mPositionController.advanceAnimation()) invalidate();
+ }
+
+ private void renderMessage(GLCanvas canvas, int x, int y) {
// Draw the progress spinner and the text below it
//
// (x, y) is where we put the center of the spinner.
@@ -366,8 +422,6 @@ public class PhotoView extends GLView {
// play icon is shown instead of the spinner.
int w = getWidth();
int h = getHeight();
- int x = Math.round(mPositionController.getImageBounds().centerX());
- int y = h / 2;
int s = Math.min(getWidth(), getHeight()) / 6;
if (mLoadingState == LOADING_TIMEOUT) {
@@ -387,8 +441,6 @@ public class PhotoView extends GLView {
&& mLoadingState != LOADING_TIMEOUT) {
mVideoPlayIcon.draw(canvas, x - s / 2, y - s / 2, s, s);
}
-
- if (mPositionController.advanceAnimation()) invalidate();
}
private void stopCurrentSwipingIfNeeded() {
@@ -731,23 +783,107 @@ public class PhotoView extends GLView {
return mEnabled;
}
- public void draw(GLCanvas canvas) {
- int x = mOffsetX;
- int y = getHeight() / 2;
+ public void draw(GLCanvas canvas, boolean applyFadingAnimation) {
+ if (mTexture == null) return;
- if (mTexture != null) {
- if (mRotation != 0) {
- canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
- canvas.translate(x, y, 0);
- canvas.rotate(mRotation, 0, 0, 1); //mRotation
- canvas.translate(-x, -y, 0);
- }
- mTexture.draw(canvas, x - mDrawWidth / 2, y - mDrawHeight / 2,
- mDrawWidth, mDrawHeight);
- if (mRotation != 0) {
- canvas.restore();
- }
+ int w = getWidth();
+ int x = applyFadingAnimation ? w / 2 : mOffsetX;
+ int y = getHeight() / 2;
+ int flags = GLCanvas.SAVE_FLAG_MATRIX;
+
+ if (applyFadingAnimation) flags |= GLCanvas.SAVE_FLAG_ALPHA;
+ canvas.save(flags);
+ canvas.translate(x, y, 0);
+ if (applyFadingAnimation) {
+ float progress = (float) (x - mOffsetX) / w;
+ float alpha = getScrollAlpha(progress);
+ float scale = getScrollScale(progress);
+ canvas.multiplyAlpha(alpha);
+ canvas.scale(scale, scale, 1);
}
+ if (mRotation != 0) {
+ canvas.rotate(mRotation, 0, 0, 1);
+ }
+ canvas.translate(-x, -y, 0);
+ mTexture.draw(canvas, x - mDrawWidth / 2, y - mDrawHeight / 2,
+ mDrawWidth, mDrawHeight);
+ canvas.restore();
+ }
+ }
+
+ // Returns the scrolling progress value for an object moving out of a
+ // view. The progress value measures how much the object has moving out of
+ // the view. The object currently displays in [left, right), and the view is
+ // at [0, viewWidth].
+ //
+ // The returned value is negative when the object is moving right, and
+ // positive when the object is moving left. The value goes to -1 or 1 when
+ // the object just moves out of the view completely. The value is 0 if the
+ // object currently fills the view.
+ private static float calculateMoveOutProgress(int left, int right,
+ int viewWidth) {
+ // w = object width
+ // viewWidth = view width
+ int w = right - left;
+
+ // If the object width is smaller than the view width,
+ // |....view....|
+ // |<-->| progress = -1 when left = viewWidth
+ // |<-->| progress = 1 when left = -w
+ // So progress = 1 - 2 * (left + w) / (viewWidth + w)
+ if (w < viewWidth) {
+ return 1f - 2f * (left + w) / (viewWidth + w);
+ }
+
+ // If the object width is larger than the view width,
+ // |..view..|
+ // |<--------->| progress = -1 when left = viewWidth
+ // |<--------->| progress = 0 between left = 0
+ // |<--------->| and right = viewWidth
+ // |<--------->| progress = 1 when right = 0
+ if (left > 0) {
+ return -left / (float) viewWidth;
+ }
+
+ if (right < viewWidth) {
+ return (viewWidth - right) / (float) viewWidth;
+ }
+
+ return 0;
+ }
+
+ // Maps a scrolling progress value to the alpha factor in the fading
+ // animation.
+ private float getScrollAlpha(float scrollProgress) {
+ return scrollProgress < 0 ? mAlphaInterpolator.getInterpolation(
+ 1 - Math.abs(scrollProgress)) : 1.0f;
+ }
+
+ // Maps a scrolling progress value to the scaling factor in the fading
+ // animation.
+ private float getScrollScale(float scrollProgress) {
+ float interpolatedProgress = mScaleInterpolator.getInterpolation(
+ Math.abs(scrollProgress));
+ float scale = (1 - interpolatedProgress) +
+ interpolatedProgress * TRANSITION_SCALE_FACTOR;
+ return scale;
+ }
+
+
+ // This interpolator emulates the rate at which the perceived scale of an
+ // object changes as its distance from a camera increases. When this
+ // interpolator is applied to a scale animation on a view, it evokes the
+ // sense that the object is shrinking due to moving away from the camera.
+ private static class ZInterpolator {
+ private float focalLength;
+
+ public ZInterpolator(float foc) {
+ focalLength = foc;
+ }
+
+ public float getInterpolation(float input) {
+ return (1.0f - focalLength / (focalLength + input)) /
+ (1.0f - focalLength / (focalLength + 1.0f));
}
}
diff --git a/src/com/android/gallery3d/ui/TileImageView.java b/src/com/android/gallery3d/ui/TileImageView.java
index 980f7b2..5c9f3f4 100644
--- a/src/com/android/gallery3d/ui/TileImageView.java
+++ b/src/com/android/gallery3d/ui/TileImageView.java
@@ -17,6 +17,7 @@
package com.android.gallery3d.ui;
import android.graphics.Bitmap;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -108,6 +109,7 @@ public class TileImageView extends GLView {
protected int mCenterY;
protected float mScale;
protected int mRotation;
+ protected float mAlpha = 1.0f;
// Temp variables to avoid memory allocation
private final Rect mTileRange = new Rect();
@@ -125,8 +127,20 @@ public class TileImageView extends GLView {
public int getImageWidth();
public int getImageHeight();
- // The method would be called in another thread
- public Bitmap getTile(int level, int x, int y, int tileSize);
+ // The tile returned by this method can be specified this way: Assuming
+ // the image size is (width, height), first take the intersection of (0,
+ // 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). Then
+ // extend this intersection region by borderSize pixels on each side. If
+ // in extending the region, we found some part of the region are outside
+ // the image, those pixels are filled with black.
+ //
+ // If level > 0, it does the same operation on a down-scaled version of
+ // the original image (down-scaled by a factor of 2^level), but (x, y)
+ // still refers to the coordinate on the original image.
+ //
+ // The method would be called in another thread.
+ public Bitmap getTile(int level, int x, int y, int tileSize,
+ int borderSize);
public boolean isFailedToLoad();
}
@@ -308,6 +322,30 @@ public class TileImageView extends GLView {
out.set(left, top, right, bottom);
}
+ // Calculate where the center of the image is, in the view coordinates.
+ public void getImageCenter(Point center) {
+ // The width and height of this view.
+ int viewW = getWidth();
+ int viewH = getHeight();
+
+ // The distance between the center of the view to the center of the
+ // bitmap, in bitmap units. (mCenterX and mCenterY are the bitmap
+ // coordinates correspond to the center of view)
+ int distW, distH;
+ if (mRotation % 180 == 0) {
+ distW = mImageWidth / 2 - mCenterX;
+ distH = mImageHeight / 2 - mCenterY;
+ } else {
+ distW = mImageHeight / 2 - mCenterY;
+ distH = mImageWidth / 2 - mCenterX;
+ }
+
+ // Convert to view coordinates. mScale translates from bitmap units to
+ // view units.
+ center.x = Math.round(viewW / 2f + distW * mScale);
+ center.y = Math.round(viewH / 2f + distH * mScale);
+ }
+
public boolean setPosition(int centerX, int centerY, float scale, int rotation) {
if (mCenterX == centerX
&& mCenterY == centerY && mScale == scale) return false;
@@ -320,6 +358,13 @@ public class TileImageView extends GLView {
return true;
}
+ public boolean setAlpha(float alpha) {
+ if (mAlpha == alpha) return false;
+ mAlpha = alpha;
+ invalidate();
+ return true;
+ }
+
public void freeTextures() {
mIsTextureFreed = true;
@@ -365,13 +410,19 @@ public class TileImageView extends GLView {
int level = mLevel;
int rotation = mRotation;
-
- if (rotation != 0) {
- canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
- int centerX = getWidth() / 2, centerY = getHeight() / 2;
- canvas.translate(centerX, centerY, 0);
- canvas.rotate(rotation, 0, 0, 1);
- canvas.translate(-centerX, -centerY, 0);
+ int flags = 0;
+ if (rotation != 0) flags |= GLCanvas.SAVE_FLAG_MATRIX;
+ if (mAlpha != 1.0f) flags |= GLCanvas.SAVE_FLAG_ALPHA;
+
+ if (flags != 0) {
+ canvas.save(flags);
+ if (rotation != 0) {
+ int centerX = getWidth() / 2, centerY = getHeight() / 2;
+ canvas.translate(centerX, centerY, 0);
+ canvas.rotate(rotation, 0, 0, 1);
+ canvas.translate(-centerX, -centerY, 0);
+ }
+ if (mAlpha != 1.0f) canvas.multiplyAlpha(mAlpha);
}
try {
if (level != mLevelCount) {
@@ -392,7 +443,7 @@ public class TileImageView extends GLView {
Math.round(mImageHeight * mScale));
}
} finally {
- if (rotation != 0) canvas.restore();
+ if (flags != 0) canvas.restore();
}
if (mRenderComplete) {
@@ -601,11 +652,9 @@ public class TileImageView extends GLView {
boolean decode() {
// Get a tile from the original image. The tile is down-scaled
// by (1 << mTilelevel) from a region in the original image.
- int tileLength = (TILE_SIZE + 2 * TILE_BORDER);
- int borderLength = TILE_BORDER << mTileLevel;
try {
mDecodedTile = DecodeUtils.ensureGLCompatibleBitmap(mModel.getTile(
- mTileLevel, mX - borderLength, mY - borderLength, tileLength));
+ mTileLevel, mX, mY, TILE_SIZE, TILE_BORDER));
} catch (Throwable t) {
Log.w(TAG, "fail to decode tile", t);
}
@@ -621,6 +670,20 @@ public class TileImageView extends GLView {
return bitmap;
}
+ // We override getTextureWidth() and getTextureHeight() here, so the
+ // texture can be re-used for different tiles regardless of the actual
+ // size of the tile (which may be small because it is a tile at the
+ // boundary).
+ @Override
+ public int getTextureWidth() {
+ return TILE_SIZE + TILE_BORDER * 2;
+ }
+
+ @Override
+ public int getTextureHeight() {
+ return TILE_SIZE + TILE_BORDER * 2;
+ }
+
public void update(int x, int y, int level) {
mX = x;
mY = y;
diff --git a/src/com/android/gallery3d/ui/TileImageViewAdapter.java b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
index 63bb0b2..be255d2 100644
--- a/src/com/android/gallery3d/ui/TileImageViewAdapter.java
+++ b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
@@ -34,9 +34,6 @@ public class TileImageViewAdapter implements TileImageView.Model {
protected int mLevelCount;
protected boolean mFailedToLoad;
- private final Rect mIntersectRect = new Rect();
- private final Rect mRegionRect = new Rect();
-
public TileImageViewAdapter() {
}
@@ -80,16 +77,24 @@ public class TileImageViewAdapter implements TileImageView.Model {
}
@Override
- public synchronized Bitmap getTile(int level, int x, int y, int length) {
+ public synchronized Bitmap getTile(int level, int x, int y, int tileSize,
+ int borderSize) {
if (mRegionDecoder == null) return null;
- Rect region = mRegionRect;
- Rect intersectRect = mIntersectRect;
- region.set(x, y, x + (length << level), y + (length << level));
- intersectRect.set(0, 0, mImageWidth, mImageHeight);
+ // wantRegion is the rectangle on the original image we want. askRegion
+ // is the rectangle on the original image that we will ask from
+ // mRegionDecoder. Both are in the coordinates of the original image,
+ // not the coordinates of the scaled-down images.
+ Rect wantRegion = new Rect();
+ Rect askRegion = new Rect();
+
+ int b = borderSize << level;
+ wantRegion.set(x - b, y - b, x + (tileSize << level) + b,
+ y + (tileSize << level) + b);
- // Get the intersected rect of the requested region and the image.
- Utils.assertTrue(intersectRect.intersect(region));
+ // askRegion is the intersection of wantRegion and the original image.
+ askRegion.set(0, 0, mImageWidth, mImageHeight);
+ Utils.assertTrue(askRegion.intersect(wantRegion));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.ARGB_8888;
@@ -100,25 +105,37 @@ public class TileImageViewAdapter implements TileImageView.Model {
// In CropImage, we may call the decodeRegion() concurrently.
synchronized (mRegionDecoder) {
- bitmap = mRegionDecoder.decodeRegion(intersectRect, options);
+ bitmap = mRegionDecoder.decodeRegion(askRegion, options);
}
- // The returned region may not match with the targetLength.
- // If so, we fill black pixels on it.
- if (intersectRect.equals(region)) return bitmap;
-
if (bitmap == null) {
Log.w(TAG, "fail in decoding region");
return null;
}
- Bitmap tile = Bitmap.createBitmap(length, length, Config.ARGB_8888);
- Canvas canvas = new Canvas(tile);
- canvas.drawBitmap(bitmap,
- (intersectRect.left - region.left) >> level,
- (intersectRect.top - region.top) >> level, null);
+ if (wantRegion.equals(askRegion)) return bitmap;
+
+ // Now the wantRegion does not match the askRegion. This means we are at
+ // a boundary tile, and we need to add paddings. Create a new Bitmap
+ // and copy over.
+ int size = tileSize + 2 * borderSize;
+ Bitmap result = Bitmap.createBitmap(size, size, Config.ARGB_8888);
+ Canvas canvas = new Canvas(result);
+ int offsetX = (askRegion.left - wantRegion.left) >> level;
+ int offsetY = (askRegion.top - wantRegion.top) >> level;
+ canvas.drawBitmap(bitmap, offsetX, offsetY, null);
+
+ // If the valid region (covered by bitmap or border) is smaller than the
+ // result bitmap, subset it.
+ int endX = offsetX + bitmap.getWidth() + borderSize;
+ int endY = offsetY + bitmap.getHeight() + borderSize;
bitmap.recycle();
- return tile;
+ if (endX < size || endY < size) {
+ return Bitmap.createBitmap(result, 0, 0, Math.min(size, endX),
+ Math.min(size, endY));
+ } else {
+ return result;
+ }
}
@Override
diff --git a/src/com/android/gallery3d/ui/UploadedTexture.java b/src/com/android/gallery3d/ui/UploadedTexture.java
index b2b8cd5..1777048 100644
--- a/src/com/android/gallery3d/ui/UploadedTexture.java
+++ b/src/com/android/gallery3d/ui/UploadedTexture.java
@@ -161,6 +161,8 @@ abstract class UploadedTexture extends BasicTexture {
protected void invalidateContent() {
if (mBitmap != null) freeBitmap();
mContentValid = false;
+ mWidth = UNSPECIFIED;
+ mHeight = UNSPECIFIED;
}
/**
project packages/apps/SmartCardService/
project prebuilts/eclipse/
project prebuilts/gcc/darwin-x86/arm/arm-linux-androideabi-4.6/
project prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.4.3/
project prebuilts/gcc/darwin-x86/mips/mipsel-linux-android-4.6/
project prebuilts/gcc/darwin-x86/x86/i686-linux-android-4.6/
project prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.6/
project prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6/
project prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/
project prebuilts/gcc/linux-x86/mips/mipsel-linux-android-4.4.3/
project prebuilts/gcc/linux-x86/mips/mipsel-linux-android-4.6/
project prebuilts/gcc/linux-x86/x86/i686-linux-android-4.6/
project prebuilts/misc/
project prebuilts/qemu-kernel/
project prebuilts/tools/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment