summaryrefslogtreecommitdiff
path: root/android
diff options
context:
space:
mode:
authorAndrzej J.R. Hunt <andrzej@ahunt.org>2012-08-21 14:35:39 +0200
committerAndrzej J.R. Hunt <andrzej@ahunt.org>2012-08-21 14:36:25 +0200
commitfa3a32a8dad94378c46e98bc46ae5216959f7bdd (patch)
treee8debb977614f456b01a52c1d66f49f55f15193f /android
parent15d272dfccc0e0f961fdcb190a322ad4a2e33432 (diff)
Fix losing communication service on screen rotation.
Change-Id: I8ae72857ce65783fe79cd3b911b83b4c70deece6
Diffstat (limited to 'android')
-rw-r--r--android/sdremote/res/layout-land/fragment_presentation.xml10
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java2
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java62
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/communication/TestClient.java197
-rw-r--r--android/sdremote/src/pl/polidea/coverflow/CoverFlow.java690
5 files changed, 391 insertions, 570 deletions
diff --git a/android/sdremote/res/layout-land/fragment_presentation.xml b/android/sdremote/res/layout-land/fragment_presentation.xml
index 66de90528808..2f04f0e5cc98 100644
--- a/android/sdremote/res/layout-land/fragment_presentation.xml
+++ b/android/sdremote/res/layout-land/fragment_presentation.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res/org.libreoffice.impressremote"
android:id="@+id/presentation_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -15,9 +16,10 @@
android:id="@+id/presentation_coverflow"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_marginTop="5dip"
- coverflow:imageHeight="150dip"
- coverflow:imageWidth="180dip"
+ android:layout_margin="5dp"
+ android:layout_marginLeft="10dp"
+ coverflow:imageHeight="200dip"
+ coverflow:imageWidth="240dip"
coverflow:withReflection="false" />
<TextView
@@ -36,6 +38,8 @@
android:layout_marginRight="6dp"
android:contentDescription="@string/presentation_ui_resizehandle"
android:paddingBottom="5dp"
+ android:paddingLeft="5dp"
+ android:paddingRight="10dp"
android:paddingTop="5dp"
android:scaleType="fitXY"
android:src="@drawable/handle" />
diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
index 73325bc9607c..4d21d4035027 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
@@ -112,8 +112,6 @@ public class PresentationActivity extends SherlockFragmentActivity {
mCommunicationService = ((CommunicationService.CBinder) aService)
.getService();
- mPresentationFragment
- .setCommunicationService(mCommunicationService);
mThumbnailFragment.setCommunicationService(mCommunicationService);
}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
index 3b7bdca25517..4e90ee09594b 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
@@ -6,9 +6,11 @@ import org.libreoffice.impressremote.communication.SlideShow;
import pl.polidea.coverflow.AbstractCoverFlowImageAdapter;
import pl.polidea.coverflow.CoverFlow;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -16,6 +18,7 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
+import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -39,7 +42,6 @@ public class PresentationFragment extends SherlockFragment {
private TextView mNumberText;
private CommunicationService mCommunicationService;
- private SlideShow mSlideShow;
private float mOriginalCoverflowWidth;
private float mOriginalCoverflowHeight;
@@ -47,8 +49,37 @@ public class PresentationFragment extends SherlockFragment {
private float mNewCoverflowWidth = 0;
private float mNewCoverflowHeight = 0;
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName aClassName,
+ IBinder aService) {
+ mCommunicationService = ((CommunicationService.CBinder) aService)
+ .getService();
+
+ if (mTopView != null) {
+ mTopView.setAdapter(new ThumbnailAdapter(mContext,
+ mCommunicationService.getSlideShow()));
+ mTopView.setSelection(mCommunicationService.getSlideShow()
+ .getCurrentSlide(), true);
+ mTopView.setOnItemSelectedListener(new ClickListener());
+ }
+
+ updateSlideNumberDisplay();
+
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName aClassName) {
+ mCommunicationService = null;
+ }
+ };
+
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+ getActivity().bindService(
+ new Intent(getActivity().getApplicationContext(),
+ CommunicationService.class),
+ mConnection, Context.BIND_IMPORTANT);
mContext = getActivity().getApplicationContext();
container.removeAllViews();
View v = inflater.inflate(R.layout.fragment_presentation, container,
@@ -69,9 +100,6 @@ public class PresentationFragment extends SherlockFragment {
mHandle = (ImageView) v.findViewById(R.id.presentation_handle);
mHandle.setOnTouchListener(new SizeListener());
- // Call again to set things up if necessary.
- setCommunicationService(mCommunicationService);
-
// Save the height/width for future reference
mOriginalCoverflowHeight = mTopView.getImageHeight();
mOriginalCoverflowWidth = mTopView.getImageWidth();
@@ -95,11 +123,13 @@ public class PresentationFragment extends SherlockFragment {
LocalBroadcastManager
.getInstance(getActivity().getApplicationContext())
.registerReceiver(mListener, aFilter);
+
return v;
}
@Override
public void onDestroyView() {
+ getActivity().unbindService(mConnection);
super.onDestroyView();
LocalBroadcastManager
.getInstance(getActivity().getApplicationContext())
@@ -108,9 +138,11 @@ public class PresentationFragment extends SherlockFragment {
}
private void updateSlideNumberDisplay() {
- int aSlide = mSlideShow.getCurrentSlide();
- mNumberText.setText((aSlide + 1) + "/" + mSlideShow.getSize());
- mNotes.loadData(mSlideShow.getNotes(aSlide), "text/html", null);
+ int aSlide = mCommunicationService.getSlideShow().getCurrentSlide();
+ mNumberText.setText((aSlide + 1) + "/"
+ + mCommunicationService.getSlideShow().getSize());
+ mNotes.loadData(mCommunicationService.getSlideShow().getNotes(aSlide),
+ "text/html", null);
}
// -------------------------------------------------- RESIZING LISTENER ----
@@ -207,22 +239,6 @@ public class PresentationFragment extends SherlockFragment {
}
// ---------------------------------------------------- MESSAGE HANDLER ----
- public void setCommunicationService(
- CommunicationService aCommunicationService) {
- mCommunicationService = aCommunicationService;
- if (mCommunicationService == null)
- return;
-
- mSlideShow = mCommunicationService.getSlideShow();
- if (mTopView != null && mSlideShow != null) {
- mTopView.setAdapter(new ThumbnailAdapter(mContext, mSlideShow));
- mTopView.setSelection(mSlideShow.getCurrentSlide(), true);
- mTopView.setOnItemSelectedListener(new ClickListener());
- }
-
- updateSlideNumberDisplay();
- }
-
private BroadcastReceiver mListener = new BroadcastReceiver() {
@Override
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/TestClient.java b/android/sdremote/src/org/libreoffice/impressremote/communication/TestClient.java
deleted file mode 100644
index a63472f32e0b..000000000000
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/TestClient.java
+++ /dev/null
@@ -1,197 +0,0 @@
-///* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-///*
-// * This file is part of the LibreOffice project.
-// *
-// * This Source Code Form is subject to the terms of the Mozilla Public
-// * License, v. 2.0. If a copy of the MPL was not distributed with this
-// * file, You can obtain one at http://mozilla.org/MPL/2.0/.
-// */
-//package org.libreoffice.impressremote.communication;
-//
-//import org.libreoffice.impressremote.PresentationActivity;
-//import org.libreoffice.impressremote.R;
-//import org.libreoffice.impressremote.communication.Server.Protocol;
-//
-//import android.app.Activity;
-//import android.content.ComponentName;
-//import android.content.Context;
-//import android.content.Intent;
-//import android.content.ServiceConnection;
-//import android.graphics.Bitmap;
-//import android.os.Bundle;
-//import android.os.Handler;
-//import android.os.IBinder;
-//import android.os.Message;
-//import android.os.Messenger;
-//import android.view.View;
-//import android.view.View.OnClickListener;
-//import android.widget.Button;
-//import android.widget.ImageView;
-//import android.widget.TextView;
-//
-//public class TestClient extends Activity {
-//
-// private boolean mCurrentPreviewImageMissing = false;
-//
-// private boolean mIsBound = false;
-//
-// private CommunicationService mCommunicationService;
-//
-// final Messenger mMessenger = new Messenger(new MessageHandler());
-//
-// /** Called when the activity is first created. */
-// @Override
-// public void onCreate(Bundle savedInstanceState) {
-// super.onCreate(savedInstanceState);
-// setContentView(R.layout.testlayout);
-// setupUI();
-//
-// }
-//
-// @Override
-// protected void onResume() {
-// super.onResume();
-// doBindService();
-//
-// }
-//
-// // FIXME: move all necessary code to CommunicationService.onUnbind
-//
-// @Override
-// protected void onPause() {
-// super.onPause();
-// }
-//
-// @Override
-// public void onBackPressed() {
-// // TODO Auto-generated method stub
-// mCommunicationService.disconnect();
-// stopService(new Intent(this, CommunicationService.class));
-// doUnbindService();
-// finish();
-// super.onBackPressed();
-// }
-//
-// @Override
-// protected void onStop() {
-// // TODO Auto-generated method stub
-// super.onStop();
-// // mCommunicationService.disconnect();
-// // stopService(new Intent(this, CommunicationService.class));
-// }
-//
-// private ServiceConnection mConnection = new ServiceConnection() {
-// @Override
-// public void onServiceConnected(ComponentName aClassName,
-// IBinder aService) {
-// mCommunicationService = ((CommunicationService.CBinder) aService)
-// .getService();
-// mCommunicationService.connectTo(new Server(Protocol.NETWORK,
-// "10.0.2.2", "TestServer", 0l));
-// mCommunicationService.setActivityMessenger(mMessenger);
-// enableButtons(true);
-// }
-//
-// @Override
-// public void onServiceDisconnected(ComponentName aClassName) {
-// mCommunicationService = null;
-// enableButtons(false);
-// }
-// };
-//
-// void doBindService() {
-// Intent aIntent = new Intent(this, CommunicationService.class);
-// startService(aIntent);
-// bindService(aIntent, mConnection, Context.BIND_IMPORTANT);
-// mIsBound = true;
-// }
-//
-// void doUnbindService() {
-// mCommunicationService.setActivityMessenger(null);
-// if (mIsBound) {
-// unbindService(mConnection);
-// mIsBound = false;
-// }
-// }
-//
-// private Button mButtonNext;
-//
-// private Button mButtonPrevious;
-//
-// private ImageView mImageView;
-//
-// private TextView mSlideLabel;
-//
-// private void setupUI() {
-// mButtonNext = (Button) findViewById(R.id.button_next);
-// mButtonPrevious = (Button) findViewById(R.id.button_previous);
-// mImageView = (ImageView) findViewById(R.id.image_preview);
-// mSlideLabel = (TextView) findViewById(R.id.label_curSlide);
-//
-// enableButtons(false);
-//
-// mButtonNext.setOnClickListener(new OnClickListener() {
-//
-// @Override
-// public void onClick(View v) {
-// mCommunicationService.getTransmitter().nextTransition();
-//
-// }
-//
-// });
-//
-// mButtonPrevious.setOnClickListener(new OnClickListener() {
-//
-// @Override
-// public void onClick(View v) {
-// mCommunicationService.getTransmitter().previousTransition();
-//
-// }
-//
-// });
-//
-// Button mThumbnailButton = (Button) findViewById(R.id.button_thumbnail);
-//
-// mThumbnailButton.setOnClickListener(new OnClickListener() {
-// @Override
-// public void onClick(View v) {
-// Intent aIntent = new Intent(TestClient.this,
-// PresentationActivity.class);
-// startActivity(aIntent);
-// }
-// });
-//
-// }
-//
-// private void enableButtons(boolean aEnabled) {
-// mButtonNext.setEnabled(aEnabled);
-// mButtonPrevious.setEnabled(aEnabled);
-// }
-//
-// class MessageHandler extends Handler {
-// @Override
-// public void handleMessage(Message aMessage) {
-// Bundle aData = aMessage.getData();
-// switch (aMessage.what) {
-// case CommunicationService.MSG_SLIDE_CHANGED:
-// int newSlide = aData.getInt("slide_number");
-// mSlideLabel.setText("Slide " + newSlide);
-// mCurrentPreviewImageMissing = true;
-// // We continue on to try and update the image.
-// case CommunicationService.MSG_SLIDE_PREVIEW:
-// int aSlideNumber = aData.getInt("slide_number");
-// if (mCurrentPreviewImageMissing) {
-// Bitmap aImage = mCommunicationService.getSlideShow()
-// .getImage(aSlideNumber);
-// if (aImage != null) {
-// mImageView.setImageBitmap(aImage);
-// mCurrentPreviewImageMissing = false;
-// }
-// }
-// break;
-//
-// }
-// }
-// }
-//}
-///* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file
diff --git a/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java b/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java
index 148d31c1baf8..88f0da6d3623 100644
--- a/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java
+++ b/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java
@@ -39,350 +39,350 @@ import android.widget.SpinnerAdapter;
*/
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 = -160;
-
- /**
- * 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();
- }
- }
+ /**
+ * 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 = 30;
+
+ /**
+ * The maximum zoom on the centre Child.
+ */
+ private int mMaxZoom = -100;
+
+ /**
+ * 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