summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtur Dryomov <artur.dryomov@gmail.com>2013-07-27 16:30:17 +0300
committerArtur Dryomov <artur.dryomov@gmail.com>2013-07-29 04:13:10 +0300
commita92fa984ae24dc25283d4b6805cff01bf00117e5 (patch)
tree93cd1e8f5768255107cd4c03d7fa49de1570e67b
parentff5c113531ce9819927ecacbbb5853393eff501d (diff)
Add async slide previews loading.
* The previews storage contains bytes arrays instead of Bitmaps which should decrease memory footprint. * All previews processing moved to the background thread. This change should solve out of memory errors. Change-Id: Idd4046020c8fe8f977858f1911e04c0ec095380a
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/activity/SlideShowActivity.java14
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesGridAdapter.java31
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesPagerAdapter.java19
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java2
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java2
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java19
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/fragment/SlidesGridFragment.java24
-rw-r--r--android/sdremote/src/org/libreoffice/impressremote/util/ImageLoader.java154
8 files changed, 235 insertions, 30 deletions
diff --git a/android/sdremote/src/org/libreoffice/impressremote/activity/SlideShowActivity.java b/android/sdremote/src/org/libreoffice/impressremote/activity/SlideShowActivity.java
index 7de2ee4049af..4b91a6af8f65 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/activity/SlideShowActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/activity/SlideShowActivity.java
@@ -245,21 +245,31 @@ public class SlideShowActivity extends SherlockFragmentActivity implements Servi
protected void onDestroy() {
super.onDestroy();
+ disconnectComputer();
+
unbindService();
}
- private void unbindService() {
+ private void disconnectComputer() {
if (!isServiceBound()) {
return;
}
- unbindService(this);
+ mCommunicationService.disconnect();
}
private boolean isServiceBound() {
return mCommunicationService != null;
}
+ private void unbindService() {
+ if (!isServiceBound()) {
+ return;
+ }
+
+ unbindService(this);
+ }
+
@Override
public void onServiceDisconnected(ComponentName aComponentName) {
mCommunicationService = null;
diff --git a/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesGridAdapter.java b/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesGridAdapter.java
index f7f7a010b8ab..846226fa50e0 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesGridAdapter.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesGridAdapter.java
@@ -18,14 +18,17 @@ import android.widget.TextView;
import org.libreoffice.impressremote.R;
import org.libreoffice.impressremote.communication.SlideShow;
+import org.libreoffice.impressremote.util.ImageLoader;
public class SlidesGridAdapter extends BaseAdapter {
private final LayoutInflater mLayoutInflater;
+ private final ImageLoader mImageLoader;
private final SlideShow mSlideShow;
public SlidesGridAdapter(Context aContext, SlideShow aSlideShow) {
mLayoutInflater = LayoutInflater.from(aContext);
+ mImageLoader = new ImageLoader(aContext.getResources(), R.drawable.slide_unknown);
mSlideShow = aSlideShow;
}
@@ -37,7 +40,7 @@ public class SlidesGridAdapter extends BaseAdapter {
@Override
public Object getItem(int aPosition) {
- return mSlideShow.getSlidePreview(aPosition);
+ return mSlideShow.getSlidePreviewBytes(aPosition);
}
@Override
@@ -51,12 +54,12 @@ public class SlidesGridAdapter extends BaseAdapter {
ViewHolder aSlideViewHolder = getViewHolder(aSlideView);
if (isSlidePreviewAvailable(aPosition)) {
- aSlideViewHolder.aSlidePreview.setImageBitmap(mSlideShow.getSlidePreview(aPosition));
+ setUpSlidePreview(aSlideViewHolder, aPosition);
} else {
- aSlideViewHolder.aSlidePreview.setImageResource(R.drawable.slide_unknown);
+ setUpUnknownSlidePreview(aSlideViewHolder);
}
- aSlideViewHolder.aSlideIndex.setText(buildSlideIndex(aPosition));
+ aSlideViewHolder.mSlideIndex.setText(buildSlideIndex(aPosition));
return aSlideView;
}
@@ -78,21 +81,31 @@ public class SlidesGridAdapter extends BaseAdapter {
}
private static final class ViewHolder {
- public ImageView aSlidePreview;
- public TextView aSlideIndex;
+ public ImageView mSlidePreview;
+ public TextView mSlideIndex;
}
private ViewHolder buildViewHolder(View aView) {
ViewHolder aViewHolder = new ViewHolder();
- aViewHolder.aSlidePreview = (ImageView) aView.findViewById(R.id.image_slide_preview);
- aViewHolder.aSlideIndex = (TextView) aView.findViewById(R.id.text_slide_index);
+ aViewHolder.mSlidePreview = (ImageView) aView.findViewById(R.id.image_slide_preview);
+ aViewHolder.mSlideIndex = (TextView) aView.findViewById(R.id.text_slide_index);
return aViewHolder;
}
private boolean isSlidePreviewAvailable(int aSlideIndex) {
- return mSlideShow.getSlidePreview(aSlideIndex) != null;
+ return mSlideShow.getSlidePreviewBytes(aSlideIndex) != null;
+ }
+
+ private void setUpSlidePreview(ViewHolder aSlideViewHolder, int aPosition) {
+ byte[] aSlidePreviewBytes = mSlideShow.getSlidePreviewBytes(aPosition);
+
+ mImageLoader.loadImage(aSlideViewHolder.mSlidePreview, aSlidePreviewBytes);
+ }
+
+ private void setUpUnknownSlidePreview(ViewHolder aSlideViewHolder) {
+ aSlideViewHolder.mSlidePreview.setImageResource(R.drawable.slide_unknown);
}
private String buildSlideIndex(int aPosition) {
diff --git a/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesPagerAdapter.java b/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesPagerAdapter.java
index 352e7a89f849..02097d27a743 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesPagerAdapter.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/adapter/SlidesPagerAdapter.java
@@ -17,14 +17,17 @@ import android.widget.ImageView;
import org.libreoffice.impressremote.R;
import org.libreoffice.impressremote.communication.SlideShow;
+import org.libreoffice.impressremote.util.ImageLoader;
public class SlidesPagerAdapter extends PagerAdapter {
private final LayoutInflater mLayoutInflater;
+ private final ImageLoader mImageLoader;
private final SlideShow mSlideShow;
public SlidesPagerAdapter(Context aContext, SlideShow aSlideShow) {
mLayoutInflater = LayoutInflater.from(aContext);
+ mImageLoader = new ImageLoader(aContext.getResources(), R.drawable.slide_unknown);
mSlideShow = aSlideShow;
}
@@ -39,10 +42,10 @@ public class SlidesPagerAdapter extends PagerAdapter {
ImageView aSlideView = (ImageView) getView(aViewGroup);
if (isSlidePreviewAvailable(aPosition)) {
- aSlideView.setImageBitmap(mSlideShow.getSlidePreview(aPosition));
+ setUpSlidePreview(aSlideView, aPosition);
}
else {
- aSlideView.setImageResource(R.drawable.slide_unknown);
+ setUpUnknownSlidePreview(aSlideView);
}
aViewGroup.addView(aSlideView);
@@ -55,7 +58,17 @@ public class SlidesPagerAdapter extends PagerAdapter {
}
private boolean isSlidePreviewAvailable(int aSlideIndex) {
- return mSlideShow.getSlidePreview(aSlideIndex) != null;
+ return mSlideShow.getSlidePreviewBytes(aSlideIndex) != null;
+ }
+
+ private void setUpSlidePreview(ImageView aSlideView, int aPosition) {
+ byte[] aSlidePreviewBytes = mSlideShow.getSlidePreviewBytes(aPosition);
+
+ mImageLoader.loadImage(aSlideView, aSlidePreviewBytes);
+ }
+
+ private void setUpUnknownSlidePreview(ImageView aSlideView) {
+ aSlideView.setImageResource(R.drawable.slide_unknown);
}
@Override
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index 2e32813fbba0..2977921f25a9 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -264,7 +264,7 @@ public class CommunicationService extends Service implements Runnable, MessagesL
@Override
public void onSlidePreview(int aSlideIndex, byte[] aPreview) {
- mSlideShow.setSlidePreview(aSlideIndex, aPreview);
+ mSlideShow.setSlidePreviewBytes(aSlideIndex, aPreview);
Intent aIntent = Intents.buildSlidePreviewIntent(aSlideIndex);
LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java b/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java
index 4d226d868183..bb6de8fc8742 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java
@@ -14,10 +14,12 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import android.text.TextUtils;
import android.util.Base64;
+import android.util.Log;
class MessagesReceiver implements Runnable {
private final BufferedReader mMessagesReader;
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
index 79852c507b68..a216dfc8f0eb 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
@@ -8,8 +8,6 @@
*/
package org.libreoffice.impressremote.communication;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.util.SparseArray;
@@ -17,7 +15,7 @@ public class SlideShow {
private int mSlidesCount;
private int mCurrentSlideIndex;
- private final SparseArray<Bitmap> mSlidePreviews;
+ private final SparseArray<byte[]> mSlidePreviewsBytes;
private final SparseArray<String> mSlideNotes;
private final Timer mTimer;
@@ -26,7 +24,7 @@ public class SlideShow {
this.mSlidesCount = 0;
this.mCurrentSlideIndex = 0;
- this.mSlidePreviews = new SparseArray<Bitmap>();
+ this.mSlidePreviewsBytes = new SparseArray<byte[]>();
this.mSlideNotes = new SparseArray<String>();
this.mTimer = new Timer();
@@ -52,15 +50,12 @@ public class SlideShow {
return getCurrentSlideIndex() + 1;
}
- public void setSlidePreview(int aSlideIndex, byte[] aSlidePreviewBytes) {
- Bitmap aSlidePreview = BitmapFactory
- .decodeByteArray(aSlidePreviewBytes, 0, aSlidePreviewBytes.length);
-
- mSlidePreviews.put(aSlideIndex, aSlidePreview);
+ public void setSlidePreviewBytes(int aSlideIndex, byte[] aSlidePreviewBytes) {
+ mSlidePreviewsBytes.put(aSlideIndex, aSlidePreviewBytes);
}
- public Bitmap getSlidePreview(int aSlideIndex) {
- return mSlidePreviews.get(aSlideIndex);
+ public byte[] getSlidePreviewBytes(int aSlideIndex) {
+ return mSlidePreviewsBytes.get(aSlideIndex);
}
public void setSlideNotes(int aSlideIndex, String aSlideNotes) {
@@ -85,7 +80,7 @@ public class SlideShow {
mSlidesCount = 0;
mCurrentSlideIndex = 0;
- mSlidePreviews.clear();
+ mSlidePreviewsBytes.clear();
mSlideNotes.clear();
}
}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/fragment/SlidesGridFragment.java b/android/sdremote/src/org/libreoffice/impressremote/fragment/SlidesGridFragment.java
index ebc9a24d02ef..25e2819a7c4c 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/fragment/SlidesGridFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/fragment/SlidesGridFragment.java
@@ -51,14 +51,12 @@ public class SlidesGridFragment extends SherlockFragment implements ServiceConne
private void bindService() {
Intent aServiceIntent = new Intent(getActivity(), CommunicationService.class);
-
getActivity().bindService(aServiceIntent, this, Context.BIND_AUTO_CREATE);
}
@Override
public void onServiceConnected(ComponentName aComponentName, IBinder aBinder) {
CommunicationService.CBinder aServiceBinder = (CommunicationService.CBinder) aBinder;
-
mCommunicationService = aServiceBinder.getService();
setUpSlidesGrid();
@@ -109,14 +107,23 @@ public class SlidesGridFragment extends SherlockFragment implements ServiceConne
@Override
public void onReceive(Context aContext, Intent aIntent) {
- if (Intents.Actions.SLIDE_PREVIEW.equals(aIntent.getAction())) {
+ if (Intents.Actions.SLIDE_SHOW_RUNNING.equals(aIntent.getAction())) {
mSlidesGridFragment.refreshSlidesGrid();
+
+ return;
+ }
+
+ if (Intents.Actions.SLIDE_PREVIEW.equals(aIntent.getAction())) {
+ int aSlideIndex = aIntent.getIntExtra(Intents.Extras.SLIDE_INDEX, 0);
+
+ mSlidesGridFragment.refreshSlidePreview(aSlideIndex);
}
}
}
private IntentFilter buildIntentsReceiverFilter() {
IntentFilter aIntentFilter = new IntentFilter();
+ aIntentFilter.addAction(Intents.Actions.SLIDE_SHOW_RUNNING);
aIntentFilter.addAction(Intents.Actions.SLIDE_PREVIEW);
return aIntentFilter;
@@ -132,6 +139,17 @@ public class SlidesGridFragment extends SherlockFragment implements ServiceConne
getSlidesGrid().invalidateViews();
}
+ private void refreshSlidePreview(int aSlideIndex) {
+ GridView aSlidesGrid = getSlidesGrid();
+ View aSlideView = aSlidesGrid.getChildAt(aSlideIndex);
+
+ if (aSlideView == null) {
+ return;
+ }
+
+ aSlidesGrid.getAdapter().getView(aSlideIndex, aSlideView, aSlidesGrid);
+ }
+
@Override
public void onPause() {
super.onPause();
diff --git a/android/sdremote/src/org/libreoffice/impressremote/util/ImageLoader.java b/android/sdremote/src/org/libreoffice/impressremote/util/ImageLoader.java
new file mode 100644
index 000000000000..1bd2f4f326df
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/util/ImageLoader.java
@@ -0,0 +1,154 @@
+/* -*- Mode: Java; 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.util;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.widget.ImageView;
+
+public final class ImageLoader {
+ private final Resources mResources;
+ private final Bitmap mLoadingImage;
+
+ public ImageLoader(Resources aResources, int aLoadingImageResourceId) {
+ mResources = aResources;
+ mLoadingImage = BitmapFactory.decodeResource(mResources, aLoadingImageResourceId);
+ }
+
+ public void loadImage(ImageView aImageView, byte[] aImageBytes) {
+ if (isSameImageLoading(aImageView, aImageBytes)) {
+ return;
+ }
+
+ if (isImageLoadingCancellationRequired(aImageView, aImageBytes)) {
+ cancelImageLoading(aImageView);
+ }
+
+ startImageLoading(aImageView, aImageBytes);
+ }
+
+ private boolean isSameImageLoading(ImageView aImageView, byte[] aImageBytes) {
+ if (!isImageLoading(aImageView)) {
+ return false;
+ }
+
+ ImageLoadingTask aImageLoadingTask = getImageLoadingTask(aImageView);
+
+ return Arrays.equals(aImageBytes, aImageLoadingTask.getImageBytes());
+ }
+
+ private boolean isImageLoading(ImageView aImageView) {
+ ImageLoadingTask aImageLoadingTask = getImageLoadingTask(aImageView);
+
+ return aImageLoadingTask != null;
+ }
+
+ private ImageLoadingTask getImageLoadingTask(ImageView aImageView) {
+ if (aImageView == null) {
+ return null;
+ }
+
+ Drawable aImageDrawable = aImageView.getDrawable();
+
+ if (!(aImageDrawable instanceof AsyncDrawable)) {
+ return null;
+ }
+
+ AsyncDrawable aAsyncImageDrawable = (AsyncDrawable) aImageDrawable;
+
+ return aAsyncImageDrawable.getImageLoadingTask();
+ }
+
+ private boolean isImageLoadingCancellationRequired(ImageView aImageView, byte[] aImageBytes) {
+ return isImageLoading(aImageView) && !isSameImageLoading(aImageView, aImageBytes);
+ }
+
+ private void cancelImageLoading(ImageView aImageView) {
+ ImageLoadingTask aImageLoadingTask = getImageLoadingTask(aImageView);
+
+ aImageLoadingTask.cancel(true);
+ }
+
+ private void startImageLoading(ImageView aImageView, byte[] aImageBytes) {
+ ImageLoadingTask aImageLoadingTask = new ImageLoadingTask(aImageView, aImageBytes);
+ AsyncDrawable aAsyncDrawable = new AsyncDrawable(mResources, mLoadingImage, aImageLoadingTask);
+
+ aImageView.setImageDrawable(aAsyncDrawable);
+ aImageLoadingTask.execute();
+ }
+
+ private static class ImageLoadingTask extends AsyncTask<Void, Void, Bitmap> {
+ private final WeakReference<ImageView> mImageViewReference;
+ private final byte[] mImageBytes;
+
+ public ImageLoadingTask(ImageView aImageView, byte[] aImageBytes) {
+ mImageViewReference = new WeakReference<ImageView>(aImageView);
+ mImageBytes = aImageBytes;
+ }
+
+ public byte[] getImageBytes() {
+ return mImageBytes;
+ }
+
+ @Override
+ protected Bitmap doInBackground(Void... aParameters) {
+ return BitmapFactory.decodeByteArray(mImageBytes, 0, mImageBytes.length);
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap aBitmap) {
+ super.onPostExecute(aBitmap);
+
+ if (isCancelled()) {
+ return;
+ }
+
+ if (aBitmap == null) {
+ return;
+ }
+
+ if (mImageViewReference == null) {
+ return;
+ }
+
+ if (getImageView() == null) {
+ return;
+ }
+
+ getImageView().setImageBitmap(aBitmap);
+ }
+
+ private ImageView getImageView() {
+ return mImageViewReference.get();
+ }
+ }
+
+ private static class AsyncDrawable extends BitmapDrawable {
+ private final WeakReference<ImageLoadingTask> mImageLoadingTaskReference;
+
+ public AsyncDrawable(Resources aResources, Bitmap aBitmap, ImageLoadingTask aImageLoadingTask) {
+ super(aResources, aBitmap);
+
+ mImageLoadingTaskReference = new WeakReference<ImageLoadingTask>(aImageLoadingTask);
+ }
+
+ public ImageLoadingTask getImageLoadingTask() {
+ return mImageLoadingTaskReference.get();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */