From ff2ac8a66ed11bd4dd45eb5d4361fafb8586d936 Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Tue, 28 Oct 2014 02:23:00 -0500 Subject: [PATCH] refactor ListenableFutureTask and make saves async // FREEBIE --- .../textsecure/util/ListenableFutureTask.java | 52 +++++++++---------- .../securesms/ConversationFragment.java | 23 +++++--- .../securesms/ConversationItem.java | 10 ++-- .../securesms/database/MmsDatabase.java | 4 +- .../database/model/MediaMmsMessageRecord.java | 32 +++++++----- .../securesms/mms/MediaNotFoundException.java | 36 +++++++++++++ .../securesms/recipients/Recipient.java | 2 +- .../recipients/RecipientProvider.java | 2 +- 8 files changed, 107 insertions(+), 54 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/mms/MediaNotFoundException.java diff --git a/library/src/org/whispersystems/textsecure/util/ListenableFutureTask.java b/library/src/org/whispersystems/textsecure/util/ListenableFutureTask.java index 0bb9d681e6..d478d5b8c1 100644 --- a/library/src/org/whispersystems/textsecure/util/ListenableFutureTask.java +++ b/library/src/org/whispersystems/textsecure/util/ListenableFutureTask.java @@ -1,32 +1,30 @@ package org.whispersystems.textsecure.util; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class ListenableFutureTask extends FutureTask { -// private WeakReference> listener; - private FutureTaskListener listener; + private final List> listeners; - public ListenableFutureTask(Callable callable, FutureTaskListener listener) { + public ListenableFutureTask(Callable callable) { super(callable); - this.listener = listener; -// if (listener == null) { -// this.listener = null; -// } else { -// this.listener = new WeakReference>(listener); -// } + this.listeners = new LinkedList<>(); } - public synchronized void setListener(FutureTaskListener listener) { -// if (listener != null) this.listener = new WeakReference>(listener); -// else this.listener = null; - this.listener = listener; - + public synchronized void addListener(FutureTaskListener listener) { if (this.isDone()) { - callback(); + callback(listener); + return; } + listeners.add(listener); + } + + public synchronized boolean removeListener(FutureTaskListener listener) { + return listeners.remove(listener); } @Override @@ -35,17 +33,19 @@ public class ListenableFutureTask extends FutureTask { } private void callback() { - if (this.listener != null) { - FutureTaskListener nestedListener = this.listener; -// FutureTaskListener nestedListener = this.listener.get(); - if (nestedListener != null) { - try { - nestedListener.onSuccess(get()); - } catch (ExecutionException ee) { - nestedListener.onFailure(ee); - } catch (InterruptedException e) { - throw new AssertionError(e); - } + for (FutureTaskListener listener : listeners) { + callback(listener); + } + } + + private void callback(FutureTaskListener listener) { + if (listener != null) { + try { + listener.onSuccess(get()); + } catch (ExecutionException ee) { + listener.onFailure(ee); + } catch (InterruptedException e) { + throw new AssertionError(e); } } } diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java index 38c7e41d0a..635a8d3e0f 100644 --- a/src/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationFragment.java @@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.util.DirectoryHelper; import org.thoughtcrime.securesms.util.SaveAttachmentTask; import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment; import org.whispersystems.textsecure.crypto.MasterSecret; +import org.whispersystems.textsecure.util.FutureTaskListener; import java.sql.Date; import java.text.SimpleDateFormat; @@ -242,14 +243,20 @@ public class ConversationFragment extends SherlockListFragment SaveAttachmentTask.showWarningDialog(getActivity(), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - final Slide slide = message.getMediaSlideSync(); - if (slide == null) { - Log.w(TAG, "No slide with attachable media found, failing nicely."); - Toast.makeText(getActivity(), R.string.ConversationFragment_error_while_saving_attachment_to_sd_card, Toast.LENGTH_LONG).show(); - return; - } - SaveAttachmentTask saveTask = new SaveAttachmentTask(getActivity(), masterSecret); - saveTask.execute(new Attachment(slide.getUri(), slide.getContentType(), message.getDateReceived())); + message.fetchMediaSlide(new FutureTaskListener() { + @Override + public void onSuccess(Slide slide) { + SaveAttachmentTask saveTask = new SaveAttachmentTask(getActivity(), masterSecret); + saveTask.execute(new Attachment(slide.getUri(), slide.getContentType(), message.getDateReceived())); + } + + @Override + public void onFailure(Throwable error) { + Log.w(TAG, "No slide with attachable media found, failing nicely."); + Log.w(TAG, error); + Toast.makeText(getActivity(), R.string.ConversationFragment_error_while_saving_attachment_to_sd_card, Toast.LENGTH_LONG).show(); + } + }); } }); } diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index 6d7c51623c..fe0aed0263 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -107,6 +107,7 @@ public class ConversationItem extends LinearLayout { private Button mmsDownloadButton; private TextView mmsDownloadingLabel; private ListenableFutureTask slideDeck; + private FutureTaskListener slideDeckListener; private TypedArray backgroundDrawables; private final FailedIconClickListener failedIconClickListener = new FailedIconClickListener(); @@ -181,8 +182,8 @@ public class ConversationItem extends LinearLayout { } public void unbind() { - if (slideDeck != null) - slideDeck.setListener(null); + if (slideDeck != null && slideDeckListener != null) + slideDeck.removeListener(slideDeckListener); } public MessageRecord getMessageRecord() { @@ -345,7 +346,7 @@ public class ConversationItem extends LinearLayout { } slideDeck = messageRecord.getSlideDeckFuture(); - slideDeck.setListener(new FutureTaskListener() { + slideDeckListener = new FutureTaskListener() { @Override public void onSuccess(final SlideDeck result) { if (result == null) @@ -376,7 +377,8 @@ public class ConversationItem extends LinearLayout { @Override public void onFailure(Throwable error) {} - }); + }; + slideDeck.addListener(slideDeckListener); } /// Helper Methods diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 216a31b76e..7fe6d0a241 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -1064,7 +1064,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns { } }; - future = new ListenableFutureTask(task, null); + future = new ListenableFutureTask(task); slideResolver.execute(future); return future; @@ -1084,7 +1084,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns { } }; - ListenableFutureTask future = new ListenableFutureTask(task, null); + ListenableFutureTask future = new ListenableFutureTask(task); future.run(); return future; diff --git a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java index 5940142174..0b4cd6a9ab 100644 --- a/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java @@ -22,10 +22,13 @@ import android.util.Log; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.MmsDatabase; +import org.thoughtcrime.securesms.mms.MediaNotFoundException; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipients; +import org.whispersystems.textsecure.push.exceptions.NotFoundException; +import org.whispersystems.textsecure.util.FutureTaskListener; import org.whispersystems.textsecure.util.ListenableFutureTask; import java.util.List; @@ -82,21 +85,26 @@ public class MediaMmsMessageRecord extends MessageRecord { return deck != null && deck.containsMediaSlide(); } - public Slide getMediaSlideSync() { - SlideDeck deck = getSlideDeckSync(); - if (deck == null) { - return null; - } - List slides = deck.getSlides(); - for (Slide slide : slides) { - if (slide.hasImage() || slide.hasVideo() || slide.hasAudio()) { - return slide; + public void fetchMediaSlide(final FutureTaskListener listener) { + slideDeckFutureTask.addListener(new FutureTaskListener() { + @Override + public void onSuccess(SlideDeck deck) { + for (Slide slide : deck.getSlides()) { + if (slide.hasImage() || slide.hasVideo() || slide.hasAudio()) { + listener.onSuccess(slide); + return; + } + } + listener.onFailure(new MediaNotFoundException("no media slide found")); } - } - return null; - } + @Override + public void onFailure(Throwable error) { + listener.onFailure(error); + } + }); + } public int getPartCount() { return partCount; diff --git a/src/org/thoughtcrime/securesms/mms/MediaNotFoundException.java b/src/org/thoughtcrime/securesms/mms/MediaNotFoundException.java new file mode 100644 index 0000000000..1215dda94d --- /dev/null +++ b/src/org/thoughtcrime/securesms/mms/MediaNotFoundException.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2014 Open Whisper Systems + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.thoughtcrime.securesms.mms; + +public class MediaNotFoundException extends Exception { + + public MediaNotFoundException() { + } + + public MediaNotFoundException(String detailMessage) { + super(detailMessage); + } + + public MediaNotFoundException(Throwable throwable) { + super(throwable); + } + + public MediaNotFoundException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } + +} diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index 7b8cf05ced..6545f28796 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -67,7 +67,7 @@ public class Recipient implements Parcelable, CanonicalRecipient { this.contactPhoto = contactPhoto; this.recipientId = recipientId; - future.setListener(new FutureTaskListener() { + future.addListener(new FutureTaskListener() { @Override public void onSuccess(RecipientDetails result) { if (result != null) { diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index f72aa4e43f..21b508fdff 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -105,7 +105,7 @@ public class RecipientProvider { } }; - ListenableFutureTask future = new ListenableFutureTask(task, null); + ListenableFutureTask future = new ListenableFutureTask(task); asyncRecipientResolver.submit(future);