diff --git a/mobile/android/base/ZoomedView.java b/mobile/android/base/ZoomedView.java
index 29cc4036f54a..f8809e86c0ad 100644
--- a/mobile/android/base/ZoomedView.java
+++ b/mobile/android/base/ZoomedView.java
@@ -17,13 +17,19 @@ import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
+import android.content.res.Resources;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
+import android.graphics.RectF;
+import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
@@ -32,6 +38,7 @@ import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
+import android.widget.TextView;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
@@ -40,20 +47,30 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
LayerView.ZoomedViewListener, GeckoEventListener {
private static final String LOGTAG = "Gecko" + ZoomedView.class.getSimpleName();
- private static final int DEFAULT_ZOOM_FACTOR = 3;
- private static final int W_CAPTURED_VIEW_IN_PERCENT = 80;
+ private static final float[] ZOOM_FACTORS_LIST = {2.0f, 3.0f, 1.5f};
+ private static final int W_CAPTURED_VIEW_IN_PERCENT = 50;
private static final int H_CAPTURED_VIEW_IN_PERCENT = 50;
private static final int MINIMUM_DELAY_BETWEEN_TWO_RENDER_CALLS_NS = 1000000;
private static final int DELAY_BEFORE_NEXT_RENDER_REQUEST_MS = 2000;
- private int zoomFactor;
+ private float zoomFactor;
+ private int currentZoomFactorIndex;
private ImageView zoomedImageView;
private LayerView layerView;
private int viewWidth;
- private int viewHeight;
+ private int viewHeight; // Only the zoomed view height, no toolbar, no shadow ...
+ private int viewContainerWidth;
+ private int viewContainerHeight; // Zoomed view height with toolbar and other elements like shadow, ...
+ private int containterSize; // shadow, margin, ...
private Point lastPosition;
private boolean shouldSetVisibleOnUpdate;
private PointF returnValue;
+ private ImageView closeButton;
+ private TextView changeZoomFactorButton;
+ private boolean toolbarOnTop;
+ private float offsetDueToToolBarPosition;
+ private int toolbarHeight;
+ private int cornerRadius;
private boolean stopUpdateView;
@@ -64,6 +81,39 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private long startTimeReRender;
private long lastStartTimeReRender;
+ private class RoundedBitmapDrawable extends BitmapDrawable {
+ private Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
+ final float cornerRadius;
+ final boolean squareOnTopOfDrawable;
+
+ RoundedBitmapDrawable(Resources res, Bitmap bitmap, boolean squareOnTop, int radius) {
+ super(res, bitmap);
+ squareOnTopOfDrawable = squareOnTop;
+ final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP);
+ paint.setAntiAlias(true);
+ paint.setShader(shader);
+ cornerRadius = radius;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ int height = getBounds().height();
+ int width = getBounds().width();
+ RectF rect = new RectF(0.0f, 0.0f, width, height);
+ canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint);
+
+ //draw rectangles over the corners we want to be square
+ if (squareOnTopOfDrawable) {
+ canvas.drawRect(0, 0, cornerRadius, cornerRadius, paint);
+ canvas.drawRect(width - cornerRadius, 0, width, cornerRadius, paint);
+ } else {
+ canvas.drawRect(0, height - cornerRadius, cornerRadius, height, paint);
+ canvas.drawRect(width - cornerRadius, height - cornerRadius, width, height, paint);
+ }
+ }
+ }
+
private class ZoomedViewTouchListener implements View.OnTouchListener {
private float originRawX;
private float originRawY;
@@ -87,16 +137,18 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
if (dragged) {
dragged = false;
} else {
- GeckoEvent eClickInZoomedView = GeckoEvent.createBroadcastEvent("Gesture:ClickInZoomedView", "");
- GeckoAppShell.sendEventToGecko(eClickInZoomedView);
- layerView.dispatchTouchEvent(actionDownEvent);
- actionDownEvent.recycle();
- PointF convertedPosition = getUnzoomedPositionFromPointInZoomedView(event.getX(), event.getY());
- MotionEvent e = MotionEvent.obtain(event.getDownTime(), event.getEventTime(),
- MotionEvent.ACTION_UP, convertedPosition.x, convertedPosition.y,
- event.getMetaState());
- layerView.dispatchTouchEvent(e);
- e.recycle();
+ if (isClickInZoomedView(event.getY())) {
+ GeckoEvent eClickInZoomedView = GeckoEvent.createBroadcastEvent("Gesture:ClickInZoomedView", "");
+ GeckoAppShell.sendEventToGecko(eClickInZoomedView);
+ layerView.dispatchTouchEvent(actionDownEvent);
+ actionDownEvent.recycle();
+ PointF convertedPosition = getUnzoomedPositionFromPointInZoomedView(event.getX(), event.getY());
+ MotionEvent e = MotionEvent.obtain(event.getDownTime(), event.getEventTime(),
+ MotionEvent.ACTION_UP, convertedPosition.x, convertedPosition.y,
+ event.getMetaState());
+ layerView.dispatchTouchEvent(e);
+ e.recycle();
+ }
}
break;
@@ -113,6 +165,11 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
return true;
}
+ private boolean isClickInZoomedView(float y) {
+ return ((toolbarOnTop && y > toolbarHeight) ||
+ (!toolbarOnTop && y < ZoomedView.this.viewHeight));
+ }
+
private boolean moveZoomedView(MotionEvent event) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) ZoomedView.this.getLayoutParams();
if ((!dragged) && (Math.abs((int) (event.getRawX() - originRawX)) < PanZoomController.CLICK_THRESHOLD)
@@ -143,19 +200,21 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
public ZoomedView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
returnValue = new PointF();
+ currentZoomFactorIndex = 0;
+ zoomFactor = ZOOM_FACTORS_LIST[currentZoomFactorIndex];
requestRenderRunnable = new Runnable() {
@Override
public void run() {
requestZoomedViewRender();
}
};
- EventDispatcher.getInstance().registerGeckoThreadListener(this, "Gesture:nothingDoneOnLongPress",
+ EventDispatcher.getInstance().registerGeckoThreadListener(this,
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange");
}
void destroy() {
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
- EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Gesture:nothingDoneOnLongPress",
+ EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange");
}
@@ -165,15 +224,29 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- ImageView closeButton = (ImageView) findViewById(R.id.dialog_close);
+ closeButton = (ImageView) findViewById(R.id.dialog_close);
closeButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
stopZoomDisplay();
}
});
+ changeZoomFactorButton = (TextView) findViewById(R.id.change_zoom_factor);
+ changeZoomFactorButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View view) {
+ changeZoomFactor();
+ }
+ });
+ setTextInZoomFactorButton(ZOOM_FACTORS_LIST[0]);
+
zoomedImageView = (ImageView) findViewById(R.id.zoomed_image_view);
- zoomedImageView.setOnTouchListener(new ZoomedViewTouchListener());
+ this.setOnTouchListener(new ZoomedViewTouchListener());
+
+ toolbarHeight = getResources().getDimensionPixelSize(R.dimen.zoomed_view_toolbar_height);
+ containterSize = getResources().getDimensionPixelSize(R.dimen.drawable_dropshadow_size);
+ cornerRadius = getResources().getDimensionPixelSize(R.dimen.button_corner_radius);
+
+ moveToolbar(true);
}
/*
@@ -181,6 +254,10 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
* LayerView
*/
private PointF getUnzoomedPositionFromPointInZoomedView(float x, float y) {
+ if (toolbarOnTop && y > toolbarHeight) {
+ y = y - toolbarHeight;
+ }
+
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
PointF offset = metrics.getMarginOffset();
final float parentWidth = metrics.getWidth();
@@ -199,14 +276,15 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
*/
(((float) params.leftMargin) - offset.x) *
((parentWidth - offset.x - (viewWidth / zoomFactor)) /
- (parentWidth - offset.x - viewWidth)));
+ (parentWidth - offset.x - viewContainerWidth)));
// Same comments here vertically
returnValue.y = (int) ((y / zoomFactor) +
- offset.y +
+ offset.y -
+ offsetDueToToolBarPosition +
(((float) params.topMargin) - offset.y) *
- ((parentHeight - offset.y - (viewHeight / zoomFactor)) /
- (parentHeight - offset.y - viewHeight)));
+ ((parentHeight - offset.y + offsetDueToToolBarPosition - (viewHeight / zoomFactor)) /
+ (parentHeight - offset.y - viewContainerHeight)));
return returnValue;
}
@@ -232,14 +310,14 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
* the LayerView to the ZoomedView.
*/
((parentWidth - offset.x - (viewWidth / zoomFactor)) /
- (parentWidth - offset.x - viewWidth)))
+ (parentWidth - offset.x - viewContainerWidth)))
+ offset.x); // The offset of the layerView
// Same comments here vertically
- returnValue.y = (int) ((((y - (viewHeight / (2 * zoomFactor)))) /
- ((parentHeight - offset.y - (viewHeight / zoomFactor)) /
- (parentHeight - offset.y - viewHeight)))
+ returnValue.y = (int) ((((y + offsetDueToToolBarPosition - (viewHeight / (2 * zoomFactor)))) /
+ ((parentHeight - offset.y + offsetDueToToolBarPosition - (viewHeight / zoomFactor)) /
+ (parentHeight - offset.y - viewContainerHeight)))
+ offset.y);
return returnValue;
@@ -259,14 +337,20 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
if (newTopMargin < topMarginMin) {
newLayoutParams.topMargin = topMarginMin;
- } else if (newTopMargin + viewHeight > parentHeight) {
- newLayoutParams.topMargin = (int) (parentHeight - viewHeight);
+ } else if (newTopMargin + viewContainerHeight > parentHeight) {
+ newLayoutParams.topMargin = (int) (parentHeight - viewContainerHeight);
}
if (newLeftMargin < leftMarginMin) {
newLayoutParams.leftMargin = leftMarginMin;
- } else if (newLeftMargin + viewWidth > parentWidth) {
- newLayoutParams.leftMargin = (int) (parentWidth - viewWidth);
+ } else if (newLeftMargin + viewContainerWidth > parentWidth) {
+ newLayoutParams.leftMargin = (int) (parentWidth - viewContainerWidth);
+ }
+
+ if (newLayoutParams.topMargin < topMarginMin + 1) {
+ moveToolbar(false);
+ } else if (newLayoutParams.topMargin + viewContainerHeight > parentHeight - 1) {
+ moveToolbar(true);
}
setLayoutParams(newLayoutParams);
@@ -275,6 +359,37 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
requestZoomedViewRender();
}
+ private void moveToolbar(boolean moveTop) {
+ if (toolbarOnTop == moveTop) {
+ return;
+ }
+ toolbarOnTop = moveTop;
+ if (toolbarOnTop) {
+ offsetDueToToolBarPosition = toolbarHeight;
+ } else {
+ offsetDueToToolBarPosition = 0;
+ }
+
+ RelativeLayout.LayoutParams p = (RelativeLayout.LayoutParams) zoomedImageView.getLayoutParams();
+ RelativeLayout.LayoutParams pChangeZoomFactorButton = (RelativeLayout.LayoutParams) changeZoomFactorButton.getLayoutParams();
+ RelativeLayout.LayoutParams pCloseButton = (RelativeLayout.LayoutParams) closeButton.getLayoutParams();
+
+ if (moveTop) {
+ p.addRule(RelativeLayout.BELOW, R.id.change_zoom_factor);
+ pChangeZoomFactorButton.addRule(RelativeLayout.BELOW, 0);
+ pCloseButton.addRule(RelativeLayout.BELOW, 0);
+ } else {
+ p.addRule(RelativeLayout.BELOW, 0);
+ pChangeZoomFactorButton.addRule(RelativeLayout.BELOW, R.id.zoomed_image_view);
+ pCloseButton.addRule(RelativeLayout.BELOW, R.id.zoomed_image_view);
+ }
+ pChangeZoomFactorButton.addRule(RelativeLayout.ALIGN_LEFT, R.id.zoomed_image_view);
+ pCloseButton.addRule(RelativeLayout.ALIGN_RIGHT, R.id.zoomed_image_view);
+ zoomedImageView.setLayoutParams(p);
+ changeZoomFactorButton.setLayoutParams(pChangeZoomFactorButton);
+ closeButton.setLayoutParams(pCloseButton);
+ }
+
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -299,13 +414,12 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private void setCapturedSize(ImmutableViewportMetrics metrics) {
float parentMinSize = Math.min(metrics.getWidth(), metrics.getHeight());
- // For metrics.zoomFactor lower than 1, the zoom factor of the zoomed view is calculated
- // to get always the same size for the content in the zoomed view.
- // For metrics.zoomFactor greater than 1, the zoom factor is always set to the default
- // value DEFAULT_ZOOM_FACTOR, thus the zoomed view is always a zoom of the normal view.
- zoomFactor = Math.max(DEFAULT_ZOOM_FACTOR, (int) (DEFAULT_ZOOM_FACTOR / metrics.zoomFactor));
- viewWidth = (int) (parentMinSize * W_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor;
- viewHeight = (int) (parentMinSize * H_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor;
+ viewWidth = (int) ((parentMinSize * W_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor);
+ viewHeight = (int) ((parentMinSize * H_CAPTURED_VIEW_IN_PERCENT / (zoomFactor * 100.0)) * zoomFactor);
+ viewContainerHeight = viewHeight + toolbarHeight +
+ 2 * containterSize; // Top and bottom shadows
+ viewContainerWidth = viewWidth +
+ 2 * containterSize; // Right and left shadows
// Display in zoomedview is corrupted when width is an odd number
// More details about this issue here: bug 776906 comment 11
viewWidth &= ~0x1;
@@ -343,13 +457,31 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
}
}
+ private void changeZoomFactor() {
+ if (currentZoomFactorIndex < ZOOM_FACTORS_LIST.length - 1) {
+ currentZoomFactorIndex++;
+ } else {
+ currentZoomFactorIndex = 0;
+ }
+ zoomFactor = ZOOM_FACTORS_LIST[currentZoomFactorIndex];
+
+ ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
+ refreshZoomedViewSize(metrics);
+ setTextInZoomFactorButton(zoomFactor);
+ }
+
+ private void setTextInZoomFactorButton(float zoom) {
+ final String percentageValue = Integer.toString((int) (100*zoom));
+ changeZoomFactorButton.setText(getResources().getString(R.string.percent, percentageValue));
+ }
+
@Override
public void handleMessage(final String event, final JSONObject message) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
try {
- if (event.equals("Gesture:nothingDoneOnLongPress") || event.equals("Gesture:clusteredLinksClicked")) {
+ if (event.equals("Gesture:clusteredLinksClicked")) {
final JSONObject clickPosition = message.getJSONObject("clickPosition");
int left = clickPosition.getInt("x");
int top = clickPosition.getInt("y");
@@ -373,6 +505,10 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
private void moveUsingGeckoPosition(int leftFromGecko, int topFromGecko) {
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
+ final float parentHeight = metrics.getHeight();
+ // moveToolbar is called before getZoomedViewTopLeftPositionFromTouchPosition in order to
+ // correctly center vertically the zoomed area
+ moveToolbar((topFromGecko * metrics.zoomFactor > parentHeight / 2));
PointF convertedPosition = getZoomedViewTopLeftPositionFromTouchPosition((leftFromGecko * metrics.zoomFactor),
(topFromGecko * metrics.zoomFactor));
moveZoomedView(metrics, convertedPosition.x, convertedPosition.y);
@@ -406,8 +542,8 @@ public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChange
} catch (Exception iae) {
Log.w(LOGTAG, iae.toString());
}
- BitmapDrawable ob3 = new BitmapDrawable(getResources(), sb3);
if (zoomedImageView != null) {
+ RoundedBitmapDrawable ob3 = new RoundedBitmapDrawable(getResources(), sb3, toolbarOnTop, cornerRadius);
zoomedImageView.setImageDrawable(ob3);
}
}
diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd
index 9b4b9dcf5f75..91a8b97ca47a 100644
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -614,6 +614,14 @@ just addresses the organization to follow, e.g. "This site is run by " -->
+
+
+
diff --git a/mobile/android/base/resources/layout/zoomed_view.xml b/mobile/android/base/resources/layout/zoomed_view.xml
index 2db7a54ecd35..667cb08704ab 100644
--- a/mobile/android/base/resources/layout/zoomed_view.xml
+++ b/mobile/android/base/resources/layout/zoomed_view.xml
@@ -10,24 +10,37 @@
android:id="@+id/zoomed_view_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:background="@android:color/white"
- android:visibility="gone" >
+ android:background="@drawable/dropshadow"
+ android:padding="@dimen/drawable_dropshadow_size"
+ android:visibility="gone">
-
-
-
-
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="@drawable/toolbar_grey_round">
+
+
+
+
\ No newline at end of file
diff --git a/mobile/android/base/resources/values/dimens.xml b/mobile/android/base/resources/values/dimens.xml
index 245c7cb11ae4..b53c1bd1fa59 100644
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -205,6 +205,10 @@
256dp
+
+ 44dp
+ 3dp
+
5dip
12dip
diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in
index 8636378611e7..24213ea6098b 100644
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -528,5 +528,7 @@
:
+ &percent;
+
&remote_tabs_last_synced;