[Libreoffice-commits] .: Branch 'feature/remote' - 2 commits - android/sdremote

Andrzej J.R. Hunt ajrhunt at kemper.freedesktop.org
Tue Jul 24 04:19:51 PDT 2012


 android/sdremote/res/drawable-hdpi/handle_default.9.png                      |binary
 android/sdremote/res/drawable-hdpi/handle_light.9.png                        |binary
 android/sdremote/res/drawable-ldpi/handle_default.9.png                      |binary
 android/sdremote/res/drawable-ldpi/handle_light.9.png                        |binary
 android/sdremote/res/drawable-mdpi/handle_default.9.png                      |binary
 android/sdremote/res/drawable-mdpi/handle_light.9.png                        |binary
 android/sdremote/res/drawable-xhdpi/handle_default.9.png                     |binary
 android/sdremote/res/drawable-xhdpi/handle_light.9.png                       |binary
 android/sdremote/res/drawable/handle.xml                                     |    9 
 android/sdremote/res/layout/fragment_presentation.xml                        |   63 -
 android/sdremote/res/values/attrs.xml                                        |   10 
 android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java |    5 
 android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java |  140 +++
 android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java    |    2 
 android/sdremote/src/org/libreoffice/impressremote/communication/Client.java |    1 
 android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java |  125 +++
 android/sdremote/src/pl/polidea/coverflow/CoverFlow.java                     |  388 ++++++++++
 android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java        |  129 +++
 android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java          |   90 ++
 dev/null                                                                     |binary
 20 files changed, 911 insertions(+), 51 deletions(-)

New commits:
commit 14eeca49cd3c34b0a9caa6fa3a2070346935c514
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Tue Jul 24 11:46:48 2012 +0200

    Added cover flow.
    
    Change-Id: I7ffc47269a2e0b1fea4ec4dbcf6c03cdc37d4721

diff --git a/android/sdremote/res/layout/fragment_presentation.xml b/android/sdremote/res/layout/fragment_presentation.xml
index 3da7e09..fb50148 100644
--- a/android/sdremote/res/layout/fragment_presentation.xml
+++ b/android/sdremote/res/layout/fragment_presentation.xml
@@ -1,16 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/presentation_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:id="@+id/presentation_layout">
+    android:orientation="vertical" >
 
-    <ImageView
-        android:id="@+id/imageView1"
-        android:layout_width="wrap_content"
+    <pl.polidea.coverflow.CoverFlow
+        xmlns:coverflow="http://schemas.android.com/apk/res/org.libreoffice.impressremote"
+        android:id="@+id/presentation_coverflow"
+        android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:contentDescription="TODO"
-        android:src="@drawable/testimage" />
+        android:layout_marginTop="5dip"
+        coverflow:imageHeight="150dip"
+        coverflow:imageReflectionRatio="0.2"
+        coverflow:imageWidth="100dip"
+        coverflow:reflectionGap="2dip"
+        coverflow:withReflection="true" />
 
     <ImageView
         android:id="@+id/presentation_handle"
@@ -25,12 +30,12 @@
         android:src="@drawable/handle" />
 
     <ScrollView
-        android:id="@+id/scrollView1"
+        android:id="@+id/presentation_scrollview"
         android:layout_width="match_parent"
         android:layout_height="wrap_content" >
 
         <WebView
-            android:id="@+id/textView1"
+            android:id="@+id/presentation_notes"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content" />
     </ScrollView>
diff --git a/android/sdremote/res/values/attrs.xml b/android/sdremote/res/values/attrs.xml
new file mode 100644
index 0000000..43de3bc
--- /dev/null
+++ b/android/sdremote/res/values/attrs.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+     <declare-styleable name="CoverFlow">
+        <attr name="imageWidth" format="dimension" />
+        <attr name="imageHeight" format="dimension" />
+        <attr name="withReflection" format="boolean" />
+        <attr name="reflectionGap" format="dimension" />
+        <attr name="imageReflectionRatio" format="float" />
+    </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
index e06d2b5..8806610 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
@@ -69,8 +69,10 @@ public class PresentationActivity extends Activity {
 			mCommunicationService = ((CommunicationService.CBinder) aService)
 			                .getService();
 			mCommunicationService.setActivityMessenger(mMessenger);
+
+			mPresentationFragment
+			                .setCommunicationService(mCommunicationService);
 			mThumbnailFragment.setCommunicationService(mCommunicationService);
-			// TODO: add mCommunicationSercie to all fragments.
 
 		}
 
@@ -85,6 +87,7 @@ public class PresentationActivity extends Activity {
 	protected class MessageHandler extends Handler {
 		@Override
 		public void handleMessage(Message aMessage) {
+			mPresentationFragment.handleMessage(aMessage);
 			mThumbnailFragment.handleMessage(aMessage);
 			// Bundle aData = aMessage.getData();
 			// TODO: pass to fragments
diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
index c031986..28ba8d0 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
@@ -1,8 +1,15 @@
 package org.libreoffice.impressremote;
 
+import org.libreoffice.impressremote.communication.CommunicationService;
+import org.libreoffice.impressremote.communication.SlideShow;
+
+import pl.polidea.coverflow.AbstractCoverFlowImageAdapter;
+import pl.polidea.coverflow.CoverFlow;
 import android.app.Fragment;
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.os.Bundle;
+import android.os.Message;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -10,16 +17,20 @@ import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.webkit.WebView;
+import android.widget.AdapterView;
 import android.widget.ImageView;
 
 public class PresentationFragment extends Fragment {
 
-	private View mTopView;
+	private CoverFlow mTopView;
 	private ImageView mHandle;
 	private View mLayout;
-
+	private WebView mNotes;
 	private Context mContext;
 
+	private CommunicationService mCommunicationService;
+	private SlideShow mSlideShow;
+
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 	                Bundle savedInstanceState) {
 		mContext = container.getContext();
@@ -27,20 +38,25 @@ public class PresentationFragment extends Fragment {
 		View v = inflater.inflate(R.layout.fragment_presentation, container,
 		                false);
 
-		WebView mWebView = (WebView) v.findViewById(R.id.textView1);
+		mNotes = (WebView) v.findViewById(R.id.presentation_notes);
 
 		String summary = "<html><body>This is just a test<br/><ul><li>And item</li><li>And again</li></ul>More text<br/>Blabla<br/>Blabla<br/>blabla<br/>Blabla</body></html>";
-		mWebView.loadData(summary, "text/html", null);
+		mNotes.loadData(summary, "text/html", null);
 
-		mTopView = v.findViewById(R.id.imageView1);
+		mTopView = (CoverFlow) v.findViewById(R.id.presentation_coverflow);
 		mLayout = v.findViewById(R.id.presentation_layout);
 
 		mHandle = (ImageView) v.findViewById(R.id.presentation_handle);
 		mHandle.setOnTouchListener(new SizeListener());
 
+		if (mCommunicationService != null && mSlideShow != null) {
+			mTopView.setAdapter(new ThumbnailAdapter(mContext, mSlideShow));
+		}
+
 		return v;
 	}
 
+	// -------------------------------------------------- RESIZING LISTENER ----
 	private class SizeListener implements OnTouchListener {
 
 		@Override
@@ -75,4 +91,90 @@ public class PresentationFragment extends Fragment {
 			return true;
 		}
 	}
+
+	// ----------------------------------------------------- CLICK LISTENER ----
+	protected class ClickListener implements AdapterView.OnItemClickListener {
+		public void onItemClick(AdapterView<?> parent, View v, int position,
+		                long id) {
+			if (mCommunicationService != null)
+				mCommunicationService.getTransmitter().gotoSlide(position);
+		}
+	}
+
+	// ---------------------------------------------------- MESSAGE HANDLER ----
+	public void setCommunicationService(
+	                CommunicationService aCommunicationService) {
+		mCommunicationService = aCommunicationService;
+		mSlideShow = mCommunicationService.getSlideShow();
+		if (mTopView != null) {
+			mTopView.setAdapter(new ThumbnailAdapter(mContext, mSlideShow));
+		}
+	}
+
+	public void handleMessage(Message aMessage) {
+		Bundle aData = aMessage.getData();
+		switch (aMessage.what) {
+		case CommunicationService.MSG_SLIDE_CHANGED:
+			int aSlide = aData.getInt("slide_number");
+			mTopView.setSelection(aSlide, true);
+			break;
+		case CommunicationService.MSG_SLIDE_PREVIEW:
+			int aNSlide = aData.getInt("slide_number");
+			if (mTopView.getSelectedItemPosition() == aNSlide) {
+				// mTopView. // TODO: update the current item
+			}
+			break;
+
+		}
+	}
+
+	// ------------------------------------------------- THUMBNAIL ADAPTER ----
+	protected class ThumbnailAdapter extends AbstractCoverFlowImageAdapter {
+
+		private Context mContext;
+
+		private SlideShow mSlideShow;
+
+		public ThumbnailAdapter(Context aContext, SlideShow aSlideShow) {
+			mContext = aContext;
+			mSlideShow = aSlideShow;
+		}
+
+		@Override
+		public int getCount() {
+			return mSlideShow.getSize();
+		}
+
+		// @Override
+		// public View getView(int position, View convertView, ViewGroup parent)
+		// {
+		// LayoutInflater aInflater = (LayoutInflater) mContext
+		// .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+		// View v = aInflater.inflate(R.layout.slide_thumbnail, null);
+		//
+		// ImageView aImage = (ImageView) v.findViewById(R.id.sub_thumbnail);
+		// TextView aText = (TextView) v.findViewById(R.id.sub_number);
+		//
+		// // Do the image & number styling
+		// int aBorderWidth = getResources().getInteger(
+		// R.integer.thumbnail_border_width);
+		// aImage.setPadding(aBorderWidth, aBorderWidth, aBorderWidth,
+		// aBorderWidth);
+		//
+		// Bitmap aBitmap = mSlideShow.getImage(position);
+		// if (aBitmap != null) {
+		// aImage.setImageBitmap(aBitmap);
+		// }
+		//
+		// aText.setText(String.valueOf(position + 1));
+		//
+		// return v;
+		// }
+
+		@Override
+		protected Bitmap createBitmap(int position) {
+			Bitmap aBitmap = mSlideShow.getImage(position);
+			return aBitmap;
+		}
+	}
 }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java
index b1ed882..de07603 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java
@@ -101,8 +101,6 @@ public class ThumbnailFragment extends Fragment {
 		}
 	}
 
-	// ------------------------------------------------- SERVICE CONNECTION ----
-
 	// ----------------------------------------------------- CLICK LISTENER ----
 	protected class ClickListener implements AdapterView.OnItemClickListener {
 		public void onItemClick(AdapterView<?> parent, View v, int position,
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java
index b3209b8..bb76df9 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java
@@ -60,7 +60,6 @@ public abstract class Client {
 				String aTemp;
 				// read until empty line
 				while ((aTemp = aReader.readLine()).length() != 0) {
-					System.out.println("Read:" + aTemp);
 					aList.add(aTemp);
 				}
 				mReceiver.parseCommand(aList);
diff --git a/android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java b/android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java
new file mode 100644
index 0000000..f60975f
--- /dev/null
+++ b/android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java
@@ -0,0 +1,125 @@
+package pl.polidea.coverflow;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+
+/**
+ * This class is an adapter that provides base, abstract class for images
+ * adapter.
+ *
+ */
+public abstract class AbstractCoverFlowImageAdapter extends BaseAdapter {
+
+	/** The Constant TAG. */
+	private static final String TAG = AbstractCoverFlowImageAdapter.class
+	                .getSimpleName();
+
+	/** The width. */
+	private float width = 0;
+
+	/** The height. */
+	private float height = 0;
+
+	/** The bitmap map. */
+	private final Map<Integer, WeakReference<Bitmap>> bitmapMap = new HashMap<Integer, WeakReference<Bitmap>>();
+
+	public AbstractCoverFlowImageAdapter() {
+		super();
+	}
+
+	/**
+	 * Set width for all pictures.
+	 *
+	 * @param width
+	 *            picture height
+	 */
+	public synchronized void setWidth(final float width) {
+		this.width = width;
+	}
+
+	/**
+	 * Set height for all pictures.
+	 *
+	 * @param height
+	 *            picture height
+	 */
+	public synchronized void setHeight(final float height) {
+		this.height = height;
+	}
+
+	@Override
+	public final Bitmap getItem(final int position) {
+		final WeakReference<Bitmap> weakBitmapReference = bitmapMap
+		                .get(position);
+		if (weakBitmapReference != null) {
+			final Bitmap bitmap = weakBitmapReference.get();
+			if (bitmap == null) {
+				Log.v(TAG, "Empty bitmap reference at position: " + position
+				                + ":" + this);
+			} else {
+				Log.v(TAG, "Reusing bitmap item at position: " + position + ":"
+				                + this);
+				return bitmap;
+			}
+		}
+		Log.v(TAG, "Creating item at position: " + position + ":" + this);
+		final Bitmap bitmap = createBitmap(position);
+		bitmapMap.put(position, new WeakReference<Bitmap>(bitmap));
+		Log.v(TAG, "Created item at position: " + position + ":" + this);
+		return bitmap;
+	}
+
+	/**
+	 * Creates new bitmap for the position specified.
+	 *
+	 * @param position
+	 *            position
+	 * @return Bitmap created
+	 */
+	protected abstract Bitmap createBitmap(int position);
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see android.widget.Adapter#getItemId(int)
+	 */
+	@Override
+	public final synchronized long getItemId(final int position) {
+		return position;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see android.widget.Adapter#getView(int, android.view.View,
+	 * android.view.ViewGroup)
+	 */
+	@Override
+	public final synchronized ImageView getView(final int position,
+	                final View convertView, final ViewGroup parent) {
+		ImageView imageView;
+		if (convertView == null) {
+			final Context context = parent.getContext();
+			Log.v(TAG, "Creating Image view at position: " + position + ":"
+			                + this);
+			imageView = new ImageView(context);
+			imageView.setLayoutParams(new CoverFlow.LayoutParams((int) width,
+			                (int) height));
+		} else {
+			Log.v(TAG, "Reusing view at position: " + position + ":" + this);
+			imageView = (ImageView) convertView;
+		}
+		imageView.setImageBitmap(getItem(position));
+		return imageView;
+	}
+
+}
diff --git a/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java b/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java
new file mode 100644
index 0000000..09da2a0
--- /dev/null
+++ b/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2010 Neil Davies
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * This code is base on the Android Gallery widget and was Created
+ * by Neil Davies neild001 'at' gmail dot com to be a Coverflow widget
+ *
+ * @author Neil Davies
+ */
+package pl.polidea.coverflow;
+
+import org.libreoffice.impressremote.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Camera;
+import android.graphics.Matrix;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.Transformation;
+import android.widget.Gallery;
+import android.widget.ImageView;
+import android.widget.SpinnerAdapter;
+
+/**
+ * Cover Flow implementation.
+ *
+ */
+public class CoverFlow extends Gallery {
+
+	/**
+	 * Graphics Camera used for transforming the matrix of ImageViews.
+	 */
+	private final Camera mCamera = new Camera();
+
+	/**
+	 * The maximum angle the Child ImageView will be rotated by.
+	 */
+	private int mMaxRotationAngle = 60;
+
+	/**
+	 * The maximum zoom on the centre Child.
+	 */
+	private int mMaxZoom = -120;
+
+	/**
+	 * The Centre of the Coverflow.
+	 */
+	private int mCoveflowCenter;
+
+	/** The image height. */
+	private float imageHeight;
+
+	/** The image width. */
+	private float imageWidth;
+
+	/** The reflection gap. */
+	private float reflectionGap;
+
+	/** The with reflection. */
+	private boolean withReflection;
+
+	/** The image reflection ratio. */
+	private float imageReflectionRatio;
+
+	/**
+	 * Gets the image height.
+	 *
+	 * @return the image height
+	 */
+	public float getImageHeight() {
+		return imageHeight;
+	}
+
+	/**
+	 * Sets the image height.
+	 *
+	 * @param imageHeight
+	 *            the new image height
+	 */
+	public void setImageHeight(final float imageHeight) {
+		this.imageHeight = imageHeight;
+	}
+
+	/**
+	 * Gets the image width.
+	 *
+	 * @return the image width
+	 */
+	public float getImageWidth() {
+		return imageWidth;
+	}
+
+	/**
+	 * Sets the image width.
+	 *
+	 * @param imageWidth
+	 *            the new image width
+	 */
+	public void setImageWidth(final float imageWidth) {
+		this.imageWidth = imageWidth;
+	}
+
+	/**
+	 * Gets the reflection gap.
+	 *
+	 * @return the reflection gap
+	 */
+	public float getReflectionGap() {
+		return reflectionGap;
+	}
+
+	/**
+	 * Sets the reflection gap.
+	 *
+	 * @param reflectionGap
+	 *            the new reflection gap
+	 */
+	public void setReflectionGap(final float reflectionGap) {
+		this.reflectionGap = reflectionGap;
+	}
+
+	/**
+	 * Checks if is with reflection.
+	 *
+	 * @return true, if is with reflection
+	 */
+	public boolean isWithReflection() {
+		return withReflection;
+	}
+
+	/**
+	 * Sets the with reflection.
+	 *
+	 * @param withReflection
+	 *            the new with reflection
+	 */
+	public void setWithReflection(final boolean withReflection) {
+		this.withReflection = withReflection;
+	}
+
+	/**
+	 * Sets the image reflection ratio.
+	 *
+	 * @param imageReflectionRatio
+	 *            the new image reflection ratio
+	 */
+	public void setImageReflectionRatio(final float imageReflectionRatio) {
+		this.imageReflectionRatio = imageReflectionRatio;
+	}
+
+	/**
+	 * Gets the image reflection ratio.
+	 *
+	 * @return the image reflection ratio
+	 */
+	public float getImageReflectionRatio() {
+		return imageReflectionRatio;
+	}
+
+	public CoverFlow(final Context context) {
+		super(context);
+		this.setStaticTransformationsEnabled(true);
+	}
+
+	public CoverFlow(final Context context, final AttributeSet attrs) {
+		this(context, attrs, android.R.attr.galleryStyle);
+	}
+
+	public CoverFlow(final Context context, final AttributeSet attrs,
+	                final int defStyle) {
+		super(context, attrs, defStyle);
+		parseAttributes(context, attrs);
+		this.setStaticTransformationsEnabled(true);
+	}
+
+	/**
+	 * Get the max rotational angle of the image.
+	 *
+	 * @return the mMaxRotationAngle
+	 */
+	public int getMaxRotationAngle() {
+		return mMaxRotationAngle;
+	}
+
+	/**
+	 * Sets the.
+	 *
+	 * @param adapter
+	 *            the new adapter
+	 */
+	@Override
+	public void setAdapter(final SpinnerAdapter adapter) {
+		if (!(adapter instanceof AbstractCoverFlowImageAdapter)) {
+			throw new IllegalArgumentException(
+			                "The adapter should derive from "
+			                                + AbstractCoverFlowImageAdapter.class
+			                                                .getName());
+		}
+		final AbstractCoverFlowImageAdapter coverAdapter = (AbstractCoverFlowImageAdapter) adapter;
+		coverAdapter.setWidth(imageWidth);
+		coverAdapter.setHeight(imageHeight);
+		if (withReflection) {
+			final ReflectingImageAdapter reflectAdapter = new ReflectingImageAdapter(
+			                coverAdapter);
+			reflectAdapter.setReflectionGap(reflectionGap);
+			reflectAdapter.setWidthRatio(imageReflectionRatio);
+			reflectAdapter.setWidth(imageWidth);
+			reflectAdapter.setHeight(imageHeight * (1 + imageReflectionRatio));
+			super.setAdapter(reflectAdapter);
+		} else {
+			super.setAdapter(adapter);
+		}
+	}
+
+	/**
+	 * Set the max rotational angle of each image.
+	 *
+	 * @param maxRotationAngle
+	 *            the mMaxRotationAngle to set
+	 */
+	public void setMaxRotationAngle(final int maxRotationAngle) {
+		mMaxRotationAngle = maxRotationAngle;
+	}
+
+	/**
+	 * Get the Max zoom of the centre image.
+	 *
+	 * @return the mMaxZoom
+	 */
+	public int getMaxZoom() {
+		return mMaxZoom;
+	}
+
+	/**
+	 * Set the max zoom of the centre image.
+	 *
+	 * @param maxZoom
+	 *            the mMaxZoom to set
+	 */
+	public void setMaxZoom(final int maxZoom) {
+		mMaxZoom = maxZoom;
+	}
+
+	/**
+	 * Get the Centre of the Coverflow.
+	 *
+	 * @return The centre of this Coverflow.
+	 */
+	private int getCenterOfCoverflow() {
+		return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2
+		                + getPaddingLeft();
+	}
+
+	/**
+	 * Get the Centre of the View.
+	 *
+	 * @return The centre of the given view.
+	 */
+	private static int getCenterOfView(final View view) {
+		return view.getLeft() + view.getWidth() / 2;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see #setStaticTransformationsEnabled(boolean)
+	 */
+	@Override
+	protected boolean getChildStaticTransformation(final View child,
+	                final Transformation t) {
+
+		final int childCenter = getCenterOfView(child);
+		final int childWidth = child.getWidth();
+		int rotationAngle = 0;
+
+		t.clear();
+		t.setTransformationType(Transformation.TYPE_MATRIX);
+
+		if (childCenter == mCoveflowCenter) {
+			transformImageBitmap((ImageView) child, t, 0);
+		} else {
+			rotationAngle = (int) ((float) (mCoveflowCenter - childCenter)
+			                / childWidth * mMaxRotationAngle);
+			if (Math.abs(rotationAngle) > mMaxRotationAngle) {
+				rotationAngle = rotationAngle < 0 ? -mMaxRotationAngle
+				                : mMaxRotationAngle;
+			}
+			transformImageBitmap((ImageView) child, t, rotationAngle);
+		}
+
+		return true;
+	}
+
+	/**
+	 * This is called during layout when the size of this view has changed. If
+	 * you were just added to the view hierarchy, you're called with the old
+	 * values of 0.
+	 *
+	 * @param w
+	 *            Current width of this view.
+	 * @param h
+	 *            Current height of this view.
+	 * @param oldw
+	 *            Old width of this view.
+	 * @param oldh
+	 *            Old height of this view.
+	 */
+	@Override
+	protected void onSizeChanged(final int w, final int h, final int oldw,
+	                final int oldh) {
+		mCoveflowCenter = getCenterOfCoverflow();
+		super.onSizeChanged(w, h, oldw, oldh);
+	}
+
+	/**
+	 * Transform the Image Bitmap by the Angle passed.
+	 *
+	 * @param imageView
+	 *            ImageView the ImageView whose bitmap we want to rotate
+	 * @param t
+	 *            transformation
+	 * @param rotationAngle
+	 *            the Angle by which to rotate the Bitmap
+	 */
+	private void transformImageBitmap(final ImageView child,
+	                final Transformation t, final int rotationAngle) {
+		mCamera.save();
+		final Matrix imageMatrix = t.getMatrix();
+
+		final int height = child.getLayoutParams().height;
+
+		final int width = child.getLayoutParams().width;
+		final int rotation = Math.abs(rotationAngle);
+
+		mCamera.translate(0.0f, 0.0f, 100.0f);
+
+		// As the angle of the view gets less, zoom in
+		if (rotation < mMaxRotationAngle) {
+			final float zoomAmount = (float) (mMaxZoom + rotation * 1.5);
+			mCamera.translate(0.0f, 0.0f, zoomAmount);
+		}
+
+		mCamera.rotateY(rotationAngle);
+		mCamera.getMatrix(imageMatrix);
+		imageMatrix.preTranslate(-(width / 2.0f), -(height / 2.0f));
+		imageMatrix.postTranslate((width / 2.0f), (height / 2.0f));
+		mCamera.restore();
+	}
+
+	/**
+	 * Parses the attributes.
+	 *
+	 * @param context
+	 *            the context
+	 * @param attrs
+	 *            the attrs
+	 */
+	private void parseAttributes(final Context context, final AttributeSet attrs) {
+		final TypedArray a = context.obtainStyledAttributes(attrs,
+		                R.styleable.CoverFlow);
+		try {
+			imageWidth = a.getDimension(R.styleable.CoverFlow_imageWidth, 480);
+			imageHeight = a.getDimension(R.styleable.CoverFlow_imageHeight, 320);
+			withReflection = a.getBoolean(R.styleable.CoverFlow_withReflection,
+			                false);
+			imageReflectionRatio = a.getFloat(
+			                R.styleable.CoverFlow_imageReflectionRatio, 0.2f);
+			reflectionGap = a.getDimension(R.styleable.CoverFlow_reflectionGap,
+			                4);
+			setSpacing(-15);
+		} finally {
+			a.recycle();
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java b/android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java
new file mode 100644
index 0000000..ff04475
--- /dev/null
+++ b/android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java
@@ -0,0 +1,129 @@
+package pl.polidea.coverflow;
+
+import android.R.color;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Shader.TileMode;
+
+/**
+ * This adapter provides reflected images from linked adapter.
+ *
+ * @author potiuk
+ *
+ */
+public class ReflectingImageAdapter extends AbstractCoverFlowImageAdapter {
+
+	/** The linked adapter. */
+	private final AbstractCoverFlowImageAdapter linkedAdapter;
+	/**
+	 * Gap between the image and its reflection.
+	 */
+	private float reflectionGap;
+
+	/** The image reflection ratio. */
+	private float imageReflectionRatio;
+
+	/**
+	 * Sets the width ratio.
+	 *
+	 * @param imageReflectionRatio
+	 *            the new width ratio
+	 */
+	public void setWidthRatio(final float imageReflectionRatio) {
+		this.imageReflectionRatio = imageReflectionRatio;
+	}
+
+	/**
+	 * Creates reflecting adapter.
+	 *
+	 * @param linkedAdapter
+	 *            adapter that provides images to get reflections
+	 */
+	public ReflectingImageAdapter(
+	                final AbstractCoverFlowImageAdapter linkedAdapter) {
+		super();
+		this.linkedAdapter = linkedAdapter;
+	}
+
+	/**
+	 * Sets the reflection gap.
+	 *
+	 * @param reflectionGap
+	 *            the new reflection gap
+	 */
+	public void setReflectionGap(final float reflectionGap) {
+		this.reflectionGap = reflectionGap;
+	}
+
+	/**
+	 * Gets the reflection gap.
+	 *
+	 * @return the reflection gap
+	 */
+	public float getReflectionGap() {
+		return reflectionGap;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see pl.polidea.coverflow.AbstractCoverFlowImageAdapter#createBitmap(int)
+	 */
+	@Override
+	protected Bitmap createBitmap(final int position) {
+		return createReflectedImages(linkedAdapter.getItem(position));
+	}
+
+	/**
+	 * Creates the reflected images.
+	 *
+	 * @param originalImage
+	 *            the original image
+	 * @return true, if successful
+	 */
+	public Bitmap createReflectedImages(final Bitmap originalImage) {
+		final int width = originalImage.getWidth();
+		final int height = originalImage.getHeight();
+		final Matrix matrix = new Matrix();
+		matrix.preScale(1, -1);
+		final Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0,
+		                (int) (height * imageReflectionRatio), width,
+		                (int) (height - height * imageReflectionRatio), matrix,
+		                false);
+		final Bitmap bitmapWithReflection = Bitmap.createBitmap(width,
+		                (int) (height + height * imageReflectionRatio),
+		                Config.ARGB_8888);
+		final Canvas canvas = new Canvas(bitmapWithReflection);
+		canvas.drawBitmap(originalImage, 0, 0, null);
+		final Paint deafaultPaint = new Paint();
+		deafaultPaint.setColor(color.transparent);
+		canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
+		final Paint paint = new Paint();
+		final LinearGradient shader = new LinearGradient(0,
+		                originalImage.getHeight(), 0,
+		                bitmapWithReflection.getHeight() + reflectionGap,
+		                0x70ffffff, 0x00ffffff, TileMode.CLAMP);
+		paint.setShader(shader);
+		paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
+		canvas.drawRect(0, height, width, bitmapWithReflection.getHeight()
+		                + reflectionGap, paint);
+		return bitmapWithReflection;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see android.widget.Adapter#getCount()
+	 */
+	@Override
+	public int getCount() {
+		return linkedAdapter.getCount();
+	}
+
+}
diff --git a/android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java b/android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java
new file mode 100644
index 0000000..469d0d1
--- /dev/null
+++ b/android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java
@@ -0,0 +1,90 @@
+package pl.polidea.coverflow;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.util.Log;
+
+/**
+ * This class is an adapter that provides images from a fixed set of resource
+ * ids. Bitmaps and ImageViews are kept as weak references so that they can be
+ * cleared by garbage collection when not needed.
+ *
+ */
+public class ResourceImageAdapter extends AbstractCoverFlowImageAdapter {
+
+	/** The Constant TAG. */
+	private static final String TAG = ResourceImageAdapter.class
+	                .getSimpleName();
+
+	/** The Constant DEFAULT_LIST_SIZE. */
+	private static final int DEFAULT_LIST_SIZE = 20;
+
+	/** The Constant IMAGE_RESOURCE_IDS. */
+	private static final List<Integer> IMAGE_RESOURCE_IDS = new ArrayList<Integer>(
+	                DEFAULT_LIST_SIZE);
+
+	/** The Constant DEFAULT_RESOURCE_LIST. */
+	private static final int[] DEFAULT_RESOURCE_LIST = {};
+	/** The bitmap map. */
+	private final Map<Integer, WeakReference<Bitmap>> bitmapMap = new HashMap<Integer, WeakReference<Bitmap>>();
+
+	private final Context context;
+
+	/**
+	 * Creates the adapter with default set of resource images.
+	 *
+	 * @param context
+	 *            context
+	 */
+	public ResourceImageAdapter(final Context context) {
+		super();
+		this.context = context;
+		setResources(DEFAULT_RESOURCE_LIST);
+	}
+
+	/**
+	 * Replaces resources with those specified.
+	 *
+	 * @param resourceIds
+	 *            array of ids of resources.
+	 */
+	public final synchronized void setResources(final int[] resourceIds) {
+		IMAGE_RESOURCE_IDS.clear();
+		for (final int resourceId : resourceIds) {
+			IMAGE_RESOURCE_IDS.add(resourceId);
+		}
+		notifyDataSetChanged();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see android.widget.Adapter#getCount()
+	 */
+	@Override
+	public synchronized int getCount() {
+		return IMAGE_RESOURCE_IDS.size();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 *
+	 * @see pl.polidea.coverflow.AbstractCoverFlowImageAdapter#createBitmap(int)
+	 */
+	@Override
+	protected Bitmap createBitmap(final int position) {
+		Log.v(TAG, "creating item " + position);
+		final Bitmap bitmap = ((BitmapDrawable) context.getResources()
+		                .getDrawable(IMAGE_RESOURCE_IDS.get(position)))
+		                .getBitmap();
+		bitmapMap.put(position, new WeakReference<Bitmap>(bitmap));
+		return bitmap;
+	}
+}
\ No newline at end of file
commit 037fdae69e0be56b4470e7a21df4a3b9d36af01f
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Tue Jul 24 11:05:12 2012 +0200

    Improved resizing handle, added visual feedback, limits.
    
    Change-Id: I6f1f9168dd53f660b676bf5050848ce509e11ae1

diff --git a/android/sdremote/res/drawable-hdpi/handle_default.9.png b/android/sdremote/res/drawable-hdpi/handle_default.9.png
new file mode 100644
index 0000000..d978f95
Binary files /dev/null and b/android/sdremote/res/drawable-hdpi/handle_default.9.png differ
diff --git a/android/sdremote/res/drawable-hdpi/handle_light.9.png b/android/sdremote/res/drawable-hdpi/handle_light.9.png
new file mode 100644
index 0000000..b0d7bef
Binary files /dev/null and b/android/sdremote/res/drawable-hdpi/handle_light.9.png differ
diff --git a/android/sdremote/res/drawable-ldpi/handle_default.9.png b/android/sdremote/res/drawable-ldpi/handle_default.9.png
new file mode 100644
index 0000000..d978f95
Binary files /dev/null and b/android/sdremote/res/drawable-ldpi/handle_default.9.png differ
diff --git a/android/sdremote/res/drawable-ldpi/handle_light.9.png b/android/sdremote/res/drawable-ldpi/handle_light.9.png
new file mode 100644
index 0000000..b0d7bef
Binary files /dev/null and b/android/sdremote/res/drawable-ldpi/handle_light.9.png differ
diff --git a/android/sdremote/res/drawable-mdpi/handle_default.9.png b/android/sdremote/res/drawable-mdpi/handle_default.9.png
new file mode 100644
index 0000000..d978f95
Binary files /dev/null and b/android/sdremote/res/drawable-mdpi/handle_default.9.png differ
diff --git a/android/sdremote/res/drawable-mdpi/handle_light.9.png b/android/sdremote/res/drawable-mdpi/handle_light.9.png
new file mode 100644
index 0000000..b0d7bef
Binary files /dev/null and b/android/sdremote/res/drawable-mdpi/handle_light.9.png differ
diff --git a/android/sdremote/res/drawable-xhdpi/handle_default.9.png b/android/sdremote/res/drawable-xhdpi/handle_default.9.png
new file mode 100644
index 0000000..d978f95
Binary files /dev/null and b/android/sdremote/res/drawable-xhdpi/handle_default.9.png differ
diff --git a/android/sdremote/res/drawable-xhdpi/handle_light.9.png b/android/sdremote/res/drawable-xhdpi/handle_light.9.png
new file mode 100644
index 0000000..b0d7bef
Binary files /dev/null and b/android/sdremote/res/drawable-xhdpi/handle_light.9.png differ
diff --git a/android/sdremote/res/drawable/handle.xml b/android/sdremote/res/drawable/handle.xml
new file mode 100644
index 0000000..9fda3d8
--- /dev/null
+++ b/android/sdremote/res/drawable/handle.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:drawable="@drawable/handle_light" android:state_activated="true"/>
+    <item android:drawable="@drawable/handle_light" android:state_pressed="true"/>
+    <item android:drawable="@drawable/handle_light" android:state_focused="true"/>
+    <item android:drawable="@drawable/handle_default"/>
+
+</selector>
\ No newline at end of file
diff --git a/android/sdremote/res/drawable/handle_center.png b/android/sdremote/res/drawable/handle_center.png
deleted file mode 100644
index b591d35..0000000
Binary files a/android/sdremote/res/drawable/handle_center.png and /dev/null differ
diff --git a/android/sdremote/res/drawable/handle_line.png b/android/sdremote/res/drawable/handle_line.png
deleted file mode 100644
index ede5d81..0000000
Binary files a/android/sdremote/res/drawable/handle_line.png and /dev/null differ
diff --git a/android/sdremote/res/layout/fragment_presentation.xml b/android/sdremote/res/layout/fragment_presentation.xml
index 9331dc5..3da7e09 100644
--- a/android/sdremote/res/layout/fragment_presentation.xml
+++ b/android/sdremote/res/layout/fragment_presentation.xml
@@ -2,7 +2,8 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical" >
+    android:orientation="vertical"
+    android:id="@+id/presentation_layout">
 
     <ImageView
         android:id="@+id/imageView1"
@@ -11,40 +12,17 @@
         android:contentDescription="TODO"
         android:src="@drawable/testimage" />
 
-    <LinearLayout
-        android:layout_width="match_parent"
+    <ImageView
+        android:id="@+id/presentation_handle"
+        android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:id="@+id/presentation_handle" >
-
-        <ImageView
-            android:id="@+id/imageView4"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="0.5"
-            android:contentDescription="TODO"
-            android:paddingLeft="6dp"
-            android:scaleType="fitXY"
-            android:src="@drawable/handle_line" />
-
-        <ImageView
-            android:id="@+id/imageView3"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:contentDescription="TODO"
-            android:src="@drawable/handle_center" />
-
-        <ImageView
-            android:id="@+id/imageView2"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_weight="0.5"
-            android:maxWidth="500dp"
-            android:paddingRight="6dp"
-            android:scaleType="fitXY"
-            android:src="@drawable/handle_line"
-            android:contentDescription="TODO"/>
-    </LinearLayout>
+        android:layout_marginLeft="6dp"
+        android:layout_marginRight="6dp"
+        android:contentDescription="TODO"
+        android:paddingBottom="5dp"
+        android:paddingTop="5dp"
+        android:scaleType="fitXY"
+        android:src="@drawable/handle" />
 
     <ScrollView
         android:id="@+id/scrollView1"
diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
index 5ae47b3..c031986 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
@@ -1,6 +1,7 @@
 package org.libreoffice.impressremote;
 
 import android.app.Fragment;
+import android.content.Context;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -9,14 +10,20 @@ import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.webkit.WebView;
+import android.widget.ImageView;
 
 public class PresentationFragment extends Fragment {
 
 	private View mTopView;
+	private ImageView mHandle;
+	private View mLayout;
+
+	private Context mContext;
 
 	public View onCreateView(LayoutInflater inflater, ViewGroup container,
 	                Bundle savedInstanceState) {
-		// Inflate the layout for this fragment
+		mContext = container.getContext();
+
 		View v = inflater.inflate(R.layout.fragment_presentation, container,
 		                false);
 
@@ -26,9 +33,10 @@ public class PresentationFragment extends Fragment {
 		mWebView.loadData(summary, "text/html", null);
 
 		mTopView = v.findViewById(R.id.imageView1);
+		mLayout = v.findViewById(R.id.presentation_layout);
 
-		v.findViewById(R.id.presentation_handle).setOnTouchListener(
-		                new SizeListener());
+		mHandle = (ImageView) v.findViewById(R.id.presentation_handle);
+		mHandle.setOnTouchListener(new SizeListener());
 
 		return v;
 	}
@@ -41,9 +49,25 @@ public class PresentationFragment extends Fragment {
 			LayoutParams aParams = mTopView.getLayoutParams();
 
 			switch (aEvent.getAction()) {
+			case MotionEvent.ACTION_DOWN:
+				mHandle.setImageResource(R.drawable.handle_light);
+				break;
+			case MotionEvent.ACTION_UP:
+				mHandle.setImageResource(R.drawable.handle_default);
+				break;
 			case MotionEvent.ACTION_MOVE:
 				int aHeight = mTopView.getHeight();
 				aParams.height = aHeight + (int) (aEvent.getY());
+
+				final int DRAG_MARGIN = 120;
+
+				int aSize = mLayout.getHeight();
+				if (aParams.height < DRAG_MARGIN) {
+					aParams.height = DRAG_MARGIN;
+				} else if (aParams.height > aSize - DRAG_MARGIN) {
+					aParams.height = aSize - DRAG_MARGIN;
+				}
+
 				mTopView.setLayoutParams(aParams);
 				break;
 			}


More information about the Libreoffice-commits mailing list