diff options
author | Andrzej J.R. Hunt <andrzej@ahunt.org> | 2012-08-21 14:35:39 +0200 |
---|---|---|
committer | Andrzej J.R. Hunt <andrzej@ahunt.org> | 2012-08-21 14:36:25 +0200 |
commit | fa3a32a8dad94378c46e98bc46ae5216959f7bdd (patch) | |
tree | e8debb977614f456b01a52c1d66f49f55f15193f /android/sdremote | |
parent | 15d272dfccc0e0f961fdcb190a322ad4a2e33432 (diff) |
Fix losing communication service on screen rotation.
Change-Id: I8ae72857ce65783fe79cd3b911b83b4c70deece6
Diffstat (limited to 'android/sdremote')
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 |