refactor ListenableFutureTask and make saves async

// FREEBIE
This commit is contained in:
Jake McGinty 2014-10-28 02:23:00 -05:00
parent 53da1f849a
commit ff2ac8a66e
8 changed files with 107 additions and 54 deletions

View File

@ -1,32 +1,30 @@
package org.whispersystems.textsecure.util; package org.whispersystems.textsecure.util;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask; import java.util.concurrent.FutureTask;
public class ListenableFutureTask<V> extends FutureTask<V> { public class ListenableFutureTask<V> extends FutureTask<V> {
// private WeakReference<FutureTaskListener<V>> listener; private final List<FutureTaskListener<V>> listeners;
private FutureTaskListener<V> listener;
public ListenableFutureTask(Callable<V> callable, FutureTaskListener<V> listener) { public ListenableFutureTask(Callable<V> callable) {
super(callable); super(callable);
this.listener = listener; this.listeners = new LinkedList<>();
// if (listener == null) {
// this.listener = null;
// } else {
// this.listener = new WeakReference<FutureTaskListener<V>>(listener);
// }
} }
public synchronized void setListener(FutureTaskListener<V> listener) { public synchronized void addListener(FutureTaskListener<V> listener) {
// if (listener != null) this.listener = new WeakReference<FutureTaskListener<V>>(listener);
// else this.listener = null;
this.listener = listener;
if (this.isDone()) { if (this.isDone()) {
callback(); callback(listener);
return;
} }
listeners.add(listener);
}
public synchronized boolean removeListener(FutureTaskListener<V> listener) {
return listeners.remove(listener);
} }
@Override @Override
@ -35,17 +33,19 @@ public class ListenableFutureTask<V> extends FutureTask<V> {
} }
private void callback() { private void callback() {
if (this.listener != null) { for (FutureTaskListener<V> listener : listeners) {
FutureTaskListener<V> nestedListener = this.listener; callback(listener);
// FutureTaskListener<V> nestedListener = this.listener.get(); }
if (nestedListener != null) { }
try {
nestedListener.onSuccess(get()); private void callback(FutureTaskListener<V> listener) {
} catch (ExecutionException ee) { if (listener != null) {
nestedListener.onFailure(ee); try {
} catch (InterruptedException e) { listener.onSuccess(get());
throw new AssertionError(e); } catch (ExecutionException ee) {
} listener.onFailure(ee);
} catch (InterruptedException e) {
throw new AssertionError(e);
} }
} }
} }

View File

@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.SaveAttachmentTask; import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment; import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import org.whispersystems.textsecure.crypto.MasterSecret; import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.util.FutureTaskListener;
import java.sql.Date; import java.sql.Date;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
@ -242,14 +243,20 @@ public class ConversationFragment extends SherlockListFragment
SaveAttachmentTask.showWarningDialog(getActivity(), new DialogInterface.OnClickListener() { SaveAttachmentTask.showWarningDialog(getActivity(), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
final Slide slide = message.getMediaSlideSync(); message.fetchMediaSlide(new FutureTaskListener<Slide>() {
if (slide == null) { @Override
Log.w(TAG, "No slide with attachable media found, failing nicely."); public void onSuccess(Slide slide) {
Toast.makeText(getActivity(), R.string.ConversationFragment_error_while_saving_attachment_to_sd_card, Toast.LENGTH_LONG).show(); SaveAttachmentTask saveTask = new SaveAttachmentTask(getActivity(), masterSecret);
return; saveTask.execute(new Attachment(slide.getUri(), slide.getContentType(), message.getDateReceived()));
} }
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();
}
});
} }
}); });
} }

View File

@ -107,6 +107,7 @@ public class ConversationItem extends LinearLayout {
private Button mmsDownloadButton; private Button mmsDownloadButton;
private TextView mmsDownloadingLabel; private TextView mmsDownloadingLabel;
private ListenableFutureTask<SlideDeck> slideDeck; private ListenableFutureTask<SlideDeck> slideDeck;
private FutureTaskListener<SlideDeck> slideDeckListener;
private TypedArray backgroundDrawables; private TypedArray backgroundDrawables;
private final FailedIconClickListener failedIconClickListener = new FailedIconClickListener(); private final FailedIconClickListener failedIconClickListener = new FailedIconClickListener();
@ -181,8 +182,8 @@ public class ConversationItem extends LinearLayout {
} }
public void unbind() { public void unbind() {
if (slideDeck != null) if (slideDeck != null && slideDeckListener != null)
slideDeck.setListener(null); slideDeck.removeListener(slideDeckListener);
} }
public MessageRecord getMessageRecord() { public MessageRecord getMessageRecord() {
@ -345,7 +346,7 @@ public class ConversationItem extends LinearLayout {
} }
slideDeck = messageRecord.getSlideDeckFuture(); slideDeck = messageRecord.getSlideDeckFuture();
slideDeck.setListener(new FutureTaskListener<SlideDeck>() { slideDeckListener = new FutureTaskListener<SlideDeck>() {
@Override @Override
public void onSuccess(final SlideDeck result) { public void onSuccess(final SlideDeck result) {
if (result == null) if (result == null)
@ -376,7 +377,8 @@ public class ConversationItem extends LinearLayout {
@Override @Override
public void onFailure(Throwable error) {} public void onFailure(Throwable error) {}
}); };
slideDeck.addListener(slideDeckListener);
} }
/// Helper Methods /// Helper Methods

View File

@ -1064,7 +1064,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
} }
}; };
future = new ListenableFutureTask<SlideDeck>(task, null); future = new ListenableFutureTask<SlideDeck>(task);
slideResolver.execute(future); slideResolver.execute(future);
return future; return future;
@ -1084,7 +1084,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
} }
}; };
ListenableFutureTask<SlideDeck> future = new ListenableFutureTask<SlideDeck>(task, null); ListenableFutureTask<SlideDeck> future = new ListenableFutureTask<SlideDeck>(task);
future.run(); future.run();
return future; return future;

View File

@ -22,10 +22,13 @@ import android.util.Log;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.mms.MediaNotFoundException;
import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipients; 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 org.whispersystems.textsecure.util.ListenableFutureTask;
import java.util.List; import java.util.List;
@ -82,21 +85,26 @@ public class MediaMmsMessageRecord extends MessageRecord {
return deck != null && deck.containsMediaSlide(); return deck != null && deck.containsMediaSlide();
} }
public Slide getMediaSlideSync() {
SlideDeck deck = getSlideDeckSync();
if (deck == null) {
return null;
}
List<Slide> slides = deck.getSlides();
for (Slide slide : slides) { public void fetchMediaSlide(final FutureTaskListener<Slide> listener) {
if (slide.hasImage() || slide.hasVideo() || slide.hasAudio()) { slideDeckFutureTask.addListener(new FutureTaskListener<SlideDeck>() {
return slide; @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() { public int getPartCount() {
return partCount; return partCount;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

@ -67,7 +67,7 @@ public class Recipient implements Parcelable, CanonicalRecipient {
this.contactPhoto = contactPhoto; this.contactPhoto = contactPhoto;
this.recipientId = recipientId; this.recipientId = recipientId;
future.setListener(new FutureTaskListener<RecipientDetails>() { future.addListener(new FutureTaskListener<RecipientDetails>() {
@Override @Override
public void onSuccess(RecipientDetails result) { public void onSuccess(RecipientDetails result) {
if (result != null) { if (result != null) {

View File

@ -105,7 +105,7 @@ public class RecipientProvider {
} }
}; };
ListenableFutureTask<RecipientDetails> future = new ListenableFutureTask<RecipientDetails>(task, null); ListenableFutureTask<RecipientDetails> future = new ListenableFutureTask<RecipientDetails>(task);
asyncRecipientResolver.submit(future); asyncRecipientResolver.submit(future);