diff --git a/src/org/thoughtcrime/securesms/ApplicationContext.java b/src/org/thoughtcrime/securesms/ApplicationContext.java index 73871aeae..6cb3f95c2 100644 --- a/src/org/thoughtcrime/securesms/ApplicationContext.java +++ b/src/org/thoughtcrime/securesms/ApplicationContext.java @@ -42,7 +42,7 @@ import org.webrtc.PeerConnectionFactory.InitializationOptions; import org.webrtc.voiceengine.WebRtcAudioManager; import org.webrtc.voiceengine.WebRtcAudioUtils; import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider; -import org.whispersystems.libsignal.util.AndroidSignalProtocolLogger; +import org.thoughtcrime.securesms.util.AndroidSignalProtocolLogger; import java.util.HashSet; import java.util.Set; diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index a49e88e25..629677a1b 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -134,8 +134,7 @@ import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.concurrent.SettableFuture; import org.thoughtcrime.securesms.util.views.Stub; -import org.whispersystems.libsignal.InvalidMessageException; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.File; import java.io.FileOutputStream; diff --git a/src/org/thoughtcrime/securesms/ConversationListFragment.java b/src/org/thoughtcrime/securesms/ConversationListFragment.java index a8821c7ab..2d9d337a4 100644 --- a/src/org/thoughtcrime/securesms/ConversationListFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationListFragment.java @@ -71,7 +71,7 @@ import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.task.SnackbarAsyncTask; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.HashSet; import java.util.Locale; diff --git a/src/org/thoughtcrime/securesms/GroupCreateActivity.java b/src/org/thoughtcrime/securesms/GroupCreateActivity.java index a250b92fc..f1baaea67 100644 --- a/src/org/thoughtcrime/securesms/GroupCreateActivity.java +++ b/src/org/thoughtcrime/securesms/GroupCreateActivity.java @@ -60,7 +60,7 @@ import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter; import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter.OnRecipientDeletedListener; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.File; import java.util.LinkedList; diff --git a/src/org/thoughtcrime/securesms/InvalidMessageException.java b/src/org/thoughtcrime/securesms/InvalidMessageException.java new file mode 100644 index 000000000..23badd44b --- /dev/null +++ b/src/org/thoughtcrime/securesms/InvalidMessageException.java @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +package org.thoughtcrime.securesms; + +import java.util.List; + +public class InvalidMessageException extends Exception { + + public InvalidMessageException() {} + + public InvalidMessageException(String detailMessage) { + super(detailMessage); + } + + public InvalidMessageException(Throwable throwable) { + super(throwable); + } + + public InvalidMessageException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } + + public InvalidMessageException(String detailMessage, List exceptions) { + super(detailMessage, exceptions.get(0)); + } +} diff --git a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java index 778fc4dd5..541018461 100644 --- a/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java +++ b/src/org/thoughtcrime/securesms/RecipientPreferenceActivity.java @@ -64,7 +64,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.concurrent.ExecutionException; diff --git a/src/org/thoughtcrime/securesms/TransportOption.java b/src/org/thoughtcrime/securesms/TransportOption.java index 22ba41d62..35d047fa7 100644 --- a/src/org/thoughtcrime/securesms/TransportOption.java +++ b/src/org/thoughtcrime/securesms/TransportOption.java @@ -5,7 +5,7 @@ import android.support.annotation.NonNull; import org.thoughtcrime.securesms.util.CharacterCalculator; import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; public class TransportOption { diff --git a/src/org/thoughtcrime/securesms/TransportOptions.java b/src/org/thoughtcrime/securesms/TransportOptions.java index e2ae76282..641254030 100644 --- a/src/org/thoughtcrime/securesms/TransportOptions.java +++ b/src/org/thoughtcrime/securesms/TransportOptions.java @@ -5,7 +5,7 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import org.thoughtcrime.securesms.util.PushCharacterCalculator; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.LinkedList; import java.util.List; diff --git a/src/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java b/src/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java index d641f7f51..7c3414dd4 100644 --- a/src/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java +++ b/src/org/thoughtcrime/securesms/audio/AudioSlidePlayer.java @@ -24,7 +24,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.mms.AudioSlide; import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.IOException; import java.lang.ref.WeakReference; diff --git a/src/org/thoughtcrime/securesms/components/DocumentView.java b/src/org/thoughtcrime/securesms/components/DocumentView.java index 2b4da4da9..dbeea112e 100644 --- a/src/org/thoughtcrime/securesms/components/DocumentView.java +++ b/src/org/thoughtcrime/securesms/components/DocumentView.java @@ -18,7 +18,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.mms.DocumentSlide; import org.thoughtcrime.securesms.mms.SlideClickListener; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; public class DocumentView extends FrameLayout { diff --git a/src/org/thoughtcrime/securesms/components/InputPanel.java b/src/org/thoughtcrime/securesms/components/InputPanel.java index 05fd5ed94..3fda9ea83 100644 --- a/src/org/thoughtcrime/securesms/components/InputPanel.java +++ b/src/org/thoughtcrime/securesms/components/InputPanel.java @@ -33,7 +33,7 @@ import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.concurrent.SettableFuture; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; diff --git a/src/org/thoughtcrime/securesms/components/SendButton.java b/src/org/thoughtcrime/securesms/components/SendButton.java index 8d4bffbe4..ef9c1a1e2 100644 --- a/src/org/thoughtcrime/securesms/components/SendButton.java +++ b/src/org/thoughtcrime/securesms/components/SendButton.java @@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.TransportOptions; import org.thoughtcrime.securesms.TransportOptions.OnTransportChangedListener; import org.thoughtcrime.securesms.TransportOptionsPopup; import org.thoughtcrime.securesms.util.ViewUtil; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; public class SendButton extends ImageButton implements TransportOptions.OnTransportChangedListener, diff --git a/src/org/thoughtcrime/securesms/components/ThumbnailView.java b/src/org/thoughtcrime/securesms/components/ThumbnailView.java index 5fe13a0d0..ffd769b61 100644 --- a/src/org/thoughtcrime/securesms/components/ThumbnailView.java +++ b/src/org/thoughtcrime/securesms/components/ThumbnailView.java @@ -31,7 +31,7 @@ import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.concurrent.SettableFuture; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.Locale; diff --git a/src/org/thoughtcrime/securesms/components/camera/CameraView.java b/src/org/thoughtcrime/securesms/components/camera/CameraView.java index de84e3fbd..52241e251 100644 --- a/src/org/thoughtcrime/securesms/components/camera/CameraView.java +++ b/src/org/thoughtcrime/securesms/components/camera/CameraView.java @@ -43,7 +43,7 @@ import org.thoughtcrime.securesms.jobmanager.JobParameters; import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.IOException; import java.util.Collections; diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java index 05c6d20bc..226c91a0d 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiPages.java @@ -1,7 +1,7 @@ package org.thoughtcrime.securesms.components.emoji; import org.thoughtcrime.securesms.R; -import org.whispersystems.libsignal.util.Pair; +import org.thoughtcrime.securesms.util.Pair; import java.util.Arrays; import java.util.LinkedList; diff --git a/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java b/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java index 1291794ba..79f1ed9a7 100644 --- a/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java +++ b/src/org/thoughtcrime/securesms/components/emoji/EmojiProvider.java @@ -25,7 +25,7 @@ import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser; import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.Pair; +import org.thoughtcrime.securesms.util.Pair; import java.util.concurrent.ExecutionException; diff --git a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java index 72d00c143..b87808732 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactsDatabase.java @@ -41,7 +41,7 @@ import org.thoughtcrime.securesms.ContactSelectionListFragment; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/org/thoughtcrime/securesms/database/GroupDatabase.java b/src/org/thoughtcrime/securesms/database/GroupDatabase.java index 933692fa7..326eda24a 100644 --- a/src/org/thoughtcrime/securesms/database/GroupDatabase.java +++ b/src/org/thoughtcrime/securesms/database/GroupDatabase.java @@ -16,7 +16,7 @@ import net.sqlcipher.database.SQLiteDatabase; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import org.thoughtcrime.securesms.util.GroupUtil; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.Closeable; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/database/IdentityDatabase.java b/src/org/thoughtcrime/securesms/database/IdentityDatabase.java index c4121a63c..53500d4e3 100644 --- a/src/org/thoughtcrime/securesms/database/IdentityDatabase.java +++ b/src/org/thoughtcrime/securesms/database/IdentityDatabase.java @@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import org.thoughtcrime.securesms.util.Base64; import org.whispersystems.libsignal.IdentityKey; import org.whispersystems.libsignal.InvalidKeyException; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 7921f1c53..e0c43f01a 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -49,7 +49,7 @@ import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.JsonUtils; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.Closeable; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java index 2ee6a381e..dae7f2e7c 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientDatabase.java @@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.Base64; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.IOException; import java.util.HashMap; diff --git a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java index 312829bf8..d82900525 100644 --- a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -45,8 +45,8 @@ import org.thoughtcrime.securesms.mms.SlideDeck; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DelimiterUtil; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.Pair; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.Pair; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.Closeable; import java.util.LinkedList; diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java index 6e86bb140..2b8255675 100644 --- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -65,7 +65,7 @@ import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener; import org.thoughtcrime.securesms.util.concurrent.SettableFuture; import org.thoughtcrime.securesms.util.views.Stub; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.IOException; import java.util.Iterator; diff --git a/src/org/thoughtcrime/securesms/mms/LocationSlide.java b/src/org/thoughtcrime/securesms/mms/LocationSlide.java index e5f613d2f..c07c4b3da 100644 --- a/src/org/thoughtcrime/securesms/mms/LocationSlide.java +++ b/src/org/thoughtcrime/securesms/mms/LocationSlide.java @@ -5,7 +5,7 @@ import android.net.Uri; import android.support.annotation.NonNull; import org.thoughtcrime.securesms.components.location.SignalPlace; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; public class LocationSlide extends ImageSlide { diff --git a/src/org/thoughtcrime/securesms/mms/Slide.java b/src/org/thoughtcrime/securesms/mms/Slide.java index 1dabb0d72..9fad9c4e2 100644 --- a/src/org/thoughtcrime/securesms/mms/Slide.java +++ b/src/org/thoughtcrime/securesms/mms/Slide.java @@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.attachments.UriAttachment; import org.thoughtcrime.securesms.database.AttachmentDatabase; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; diff --git a/src/org/thoughtcrime/securesms/mms/SlideDeck.java b/src/org/thoughtcrime/securesms/mms/SlideDeck.java index e6604d351..7d7129cb1 100644 --- a/src/org/thoughtcrime/securesms/mms/SlideDeck.java +++ b/src/org/thoughtcrime/securesms/mms/SlideDeck.java @@ -24,7 +24,7 @@ import com.b44t.messenger.DcMsg; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.util.MediaUtil; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.LinkedList; import java.util.List; diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index 3abc0935b..0f33169af 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -47,7 +47,7 @@ import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.Arrays; import java.util.Collections; diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index 2cc1d2de3..016857879 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -33,7 +33,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.SoftHashMap; import org.thoughtcrime.securesms.util.Util; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.HashMap; import java.util.LinkedList; diff --git a/src/org/thoughtcrime/securesms/util/AndroidSignalProtocolLogger.java b/src/org/thoughtcrime/securesms/util/AndroidSignalProtocolLogger.java new file mode 100644 index 000000000..f1a2690a4 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/AndroidSignalProtocolLogger.java @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +package org.thoughtcrime.securesms.util; + +import android.util.Log; +import android.util.SparseIntArray; + +import org.whispersystems.libsignal.logging.SignalProtocolLogger; + +public class AndroidSignalProtocolLogger implements SignalProtocolLogger { + + private static final SparseIntArray PRIORITY_MAP = new SparseIntArray(5) {{ + put(SignalProtocolLogger.INFO, Log.INFO); + put(SignalProtocolLogger.ASSERT, Log.ASSERT); + put(SignalProtocolLogger.DEBUG, Log.DEBUG); + put(SignalProtocolLogger.VERBOSE, Log.VERBOSE); + put(SignalProtocolLogger.WARN, Log.WARN); + + }}; + + @Override + public void log(int priority, String tag, String message) { + int androidPriority = PRIORITY_MAP.get(priority, Log.WARN); + Log.println(androidPriority, tag, message); + } +} diff --git a/src/org/thoughtcrime/securesms/util/Medium.java b/src/org/thoughtcrime/securesms/util/Medium.java new file mode 100644 index 000000000..200166919 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/Medium.java @@ -0,0 +1,10 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +package org.thoughtcrime.securesms.util; + +public class Medium { + public static int MAX_VALUE = 0xFFFFFF; +} diff --git a/src/org/thoughtcrime/securesms/util/Pair.java b/src/org/thoughtcrime/securesms/util/Pair.java new file mode 100644 index 000000000..2492b1722 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/Pair.java @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2014-2016 Open Whisper Systems + * + * Licensed according to the LICENSE file in this repository. + */ +package org.thoughtcrime.securesms.util; + +public class Pair { + private final T1 v1; + private final T2 v2; + + public Pair(T1 v1, T2 v2) { + this.v1 = v1; + this.v2 = v2; + } + + public T1 first(){ + return v1; + } + + public T2 second(){ + return v2; + } + + public boolean equals(Object o) { + return o instanceof Pair && + equal(((Pair) o).first(), first()) && + equal(((Pair) o).second(), second()); + } + + public int hashCode() { + return first().hashCode() ^ second().hashCode(); + } + + private boolean equal(Object first, Object second) { + if (first == null && second == null) return true; + if (first == null || second == null) return false; + return first.equals(second); + } +} diff --git a/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java b/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java index ea46fe2b5..894e5327b 100644 --- a/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java +++ b/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java @@ -15,7 +15,6 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.NoExternalStorageException; import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; -import org.whispersystems.libsignal.util.Pair; import java.io.File; import java.io.FileOutputStream; diff --git a/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java b/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java index 926ae05c7..cc98a85e4 100644 --- a/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java +++ b/src/org/thoughtcrime/securesms/util/SelectedRecipientsAdapter.java @@ -16,7 +16,7 @@ import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.ApplicationDcContext; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.recipients.Recipient; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.Collection; import java.util.Collections; diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java index 8d517e233..6efa637ed 100644 --- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java +++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java @@ -16,7 +16,7 @@ import android.support.v4.app.NotificationCompat; import android.util.Log; import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference; -import org.whispersystems.libsignal.util.Medium; +import org.thoughtcrime.securesms.util.Medium; import java.io.IOException; import java.security.SecureRandom; diff --git a/src/org/thoughtcrime/securesms/util/Util.java b/src/org/thoughtcrime/securesms/util/Util.java index 03dd389d2..5d2e8fb8a 100644 --- a/src/org/thoughtcrime/securesms/util/Util.java +++ b/src/org/thoughtcrime/securesms/util/Util.java @@ -47,7 +47,7 @@ import com.google.android.mms.pdu_alt.EncodedStringValue; import org.thoughtcrime.securesms.BuildConfig; import org.thoughtcrime.securesms.components.ComposeText; import org.thoughtcrime.securesms.database.Address; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/org/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat.java b/src/org/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat.java index 3d358afee..b6f9735a5 100644 --- a/src/org/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat.java +++ b/src/org/thoughtcrime/securesms/util/dualsim/SubscriptionManagerCompat.java @@ -6,7 +6,7 @@ import android.support.annotation.NonNull; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; -import org.whispersystems.libsignal.util.guava.Optional; +import org.thoughtcrime.securesms.util.guava.Optional; import java.util.LinkedList; import java.util.List; diff --git a/src/org/thoughtcrime/securesms/util/guava/Absent.java b/src/org/thoughtcrime/securesms/util/guava/Absent.java new file mode 100644 index 000000000..469c05792 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/guava/Absent.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thoughtcrime.securesms.util.guava; + +import static org.thoughtcrime.securesms.util.guava.Preconditions.checkNotNull; + + + +import java.util.Collections; +import java.util.Set; + + +/** + * Implementation of an {@link Optional} not containing a reference. + */ + +final class Absent extends Optional { + static final Absent INSTANCE = new Absent(); + + @Override public boolean isPresent() { + return false; + } + + @Override public Object get() { + throw new IllegalStateException("value is absent"); + } + + @Override public Object or(Object defaultValue) { + return checkNotNull(defaultValue, "use orNull() instead of or(null)"); + } + + @SuppressWarnings("unchecked") // safe covariant cast + @Override public Optional or(Optional secondChoice) { + return (Optional) checkNotNull(secondChoice); + } + + @Override public Object or(Supplier supplier) { + return checkNotNull(supplier.get(), + "use orNull() instead of a Supplier that returns null"); + } + + @Override public Object orNull() { + return null; + } + + @Override public Set asSet() { + return Collections.emptySet(); + } + + @Override + public Optional transform(Function function) { + checkNotNull(function); + return Optional.absent(); + } + + @Override public boolean equals(Object object) { + return object == this; + } + + @Override public int hashCode() { + return 0x598df91c; + } + + @Override public String toString() { + return "Optional.absent()"; + } + + private Object readResolve() { + return INSTANCE; + } + + private static final long serialVersionUID = 0; +} diff --git a/src/org/thoughtcrime/securesms/util/guava/Function.java b/src/org/thoughtcrime/securesms/util/guava/Function.java new file mode 100644 index 000000000..bd1d4c598 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/guava/Function.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thoughtcrime.securesms.util.guava; + + + +/** + * Determines an output value based on an input value. + * + *

See the Guava User Guide article on the use of {@code + * Function}. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ + +public interface Function { + /** + * Returns the result of applying this function to {@code input}. This method is generally + * expected, but not absolutely required, to have the following properties: + * + *

    + *
  • Its execution does not cause any observable side effects. + *
  • The computation is consistent with equals; that is, {@link Objects#equal + * Objects.equal}{@code (a, b)} implies that {@code Objects.equal(function.apply(a), + * function.apply(b))}. + *
+ * + * @throws NullPointerException if {@code input} is null and this function does not accept null + * arguments + */ + T apply(F input); + + /** + * Indicates whether another object is equal to this function. + * + *

Most implementations will have no reason to override the behavior of {@link Object#equals}. + * However, an implementation may also choose to return {@code true} whenever {@code object} is a + * {@link Function} that it considers interchangeable with this one. "Interchangeable" + * typically means that {@code Objects.equal(this.apply(f), that.apply(f))} is true for all + * {@code f} of type {@code F}. Note that a {@code false} result from this method does not imply + * that the functions are known not to be interchangeable. + */ + @Override + boolean equals(Object object); +} diff --git a/src/org/thoughtcrime/securesms/util/guava/Optional.java b/src/org/thoughtcrime/securesms/util/guava/Optional.java new file mode 100644 index 000000000..bde8b04a5 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/guava/Optional.java @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thoughtcrime.securesms.util.guava; + +import static org.thoughtcrime.securesms.util.guava.Preconditions.checkNotNull; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.Set; + + +/** + * An immutable object that may contain a non-null reference to another object. Each + * instance of this type either contains a non-null reference, or contains nothing (in + * which case we say that the reference is "absent"); it is never said to "contain {@code + * null}". + * + *

A non-null {@code Optional} reference can be used as a replacement for a nullable + * {@code T} reference. It allows you to represent "a {@code T} that must be present" and + * a "a {@code T} that might be absent" as two distinct types in your program, which can + * aid clarity. + * + *

Some uses of this class include + * + *

    + *
  • As a method return type, as an alternative to returning {@code null} to indicate + * that no value was available + *
  • To distinguish between "unknown" (for example, not present in a map) and "known to + * have no value" (present in the map, with value {@code Optional.absent()}) + *
  • To wrap nullable references for storage in a collection that does not support + * {@code null} (though there are + * + * several other approaches to this that should be considered first) + *
+ * + *

A common alternative to using this class is to find or create a suitable + * null object for the + * type in question. + * + *

This class is not intended as a direct analogue of any existing "option" or "maybe" + * construct from other programming environments, though it may bear some similarities. + * + *

See the Guava User Guide article on + * using {@code Optional}. + * + * @param the type of instance that can be contained. {@code Optional} is naturally + * covariant on this type, so it is safe to cast an {@code Optional} to {@code + * Optional} for any supertype {@code S} of {@code T}. + * @author Kurt Alfred Kluever + * @author Kevin Bourrillion + * @since 10.0 + */ +public abstract class Optional implements Serializable { + /** + * Returns an {@code Optional} instance with no contained reference. + */ + @SuppressWarnings("unchecked") + public static Optional absent() { + return (Optional) Absent.INSTANCE; + } + + /** + * Returns an {@code Optional} instance containing the given non-null reference. + */ + public static Optional of(T reference) { + return new Present(checkNotNull(reference)); + } + + /** + * If {@code nullableReference} is non-null, returns an {@code Optional} instance containing that + * reference; otherwise returns {@link Optional#absent}. + */ + public static Optional fromNullable(T nullableReference) { + return (nullableReference == null) + ? Optional.absent() + : new Present(nullableReference); + } + + Optional() {} + + /** + * Returns {@code true} if this holder contains a (non-null) instance. + */ + public abstract boolean isPresent(); + + /** + * Returns the contained instance, which must be present. If the instance might be + * absent, use {@link #or(Object)} or {@link #orNull} instead. + * + * @throws IllegalStateException if the instance is absent ({@link #isPresent} returns + * {@code false}) + */ + public abstract T get(); + + /** + * Returns the contained instance if it is present; {@code defaultValue} otherwise. If + * no default value should be required because the instance is known to be present, use + * {@link #get()} instead. For a default value of {@code null}, use {@link #orNull}. + * + *

Note about generics: The signature {@code public T or(T defaultValue)} is overly + * restrictive. However, the ideal signature, {@code public S or(S)}, is not legal + * Java. As a result, some sensible operations involving subtypes are compile errors: + *

   {@code
+   *
+   *   Optional optionalInt = getSomeOptionalInt();
+   *   Number value = optionalInt.or(0.5); // error
+   *
+   *   FluentIterable numbers = getSomeNumbers();
+   *   Optional first = numbers.first();
+   *   Number value = first.or(0.5); // error}
+ * + * As a workaround, it is always safe to cast an {@code Optional} to {@code + * Optional}. Casting either of the above example {@code Optional} instances to {@code + * Optional} (where {@code Number} is the desired output type) solves the problem: + *
   {@code
+   *
+   *   Optional optionalInt = (Optional) getSomeOptionalInt();
+   *   Number value = optionalInt.or(0.5); // fine
+   *
+   *   FluentIterable numbers = getSomeNumbers();
+   *   Optional first = (Optional) numbers.first();
+   *   Number value = first.or(0.5); // fine}
+ */ + public abstract T or(T defaultValue); + + /** + * Returns this {@code Optional} if it has a value present; {@code secondChoice} + * otherwise. + */ + public abstract Optional or(Optional secondChoice); + + /** + * Returns the contained instance if it is present; {@code supplier.get()} otherwise. If the + * supplier returns {@code null}, a {@link NullPointerException} is thrown. + * + * @throws NullPointerException if the supplier returns {@code null} + */ + public abstract T or(Supplier supplier); + + /** + * Returns the contained instance if it is present; {@code null} otherwise. If the + * instance is known to be present, use {@link #get()} instead. + */ + public abstract T orNull(); + + /** + * Returns an immutable singleton {@link Set} whose only element is the contained instance + * if it is present; an empty immutable {@link Set} otherwise. + * + * @since 11.0 + */ + public abstract Set asSet(); + + /** + * If the instance is present, it is transformed with the given {@link Function}; otherwise, + * {@link Optional#absent} is returned. If the function returns {@code null}, a + * {@link NullPointerException} is thrown. + * + * @throws NullPointerException if the function returns {@code null} + * + * @since 12.0 + */ + + public abstract Optional transform(Function function); + + /** + * Returns {@code true} if {@code object} is an {@code Optional} instance, and either + * the contained references are {@linkplain Object#equals equal} to each other or both + * are absent. Note that {@code Optional} instances of differing parameterized types can + * be equal. + */ + @Override public abstract boolean equals(Object object); + + /** + * Returns a hash code for this instance. + */ + @Override public abstract int hashCode(); + + /** + * Returns a string representation for this instance. The form of this string + * representation is unspecified. + */ + @Override public abstract String toString(); + + /** + * Returns the value of each present instance from the supplied {@code optionals}, in order, + * skipping over occurrences of {@link Optional#absent}. Iterators are unmodifiable and are + * evaluated lazily. + * + * @since 11.0 (generics widened in 13.0) + */ + +// public static Iterable presentInstances( +// final Iterable> optionals) { +// checkNotNull(optionals); +// return new Iterable() { +// @Override public Iterator iterator() { +// return new AbstractIterator() { +// private final Iterator> iterator = +// checkNotNull(optionals.iterator()); +// +// @Override protected T computeNext() { +// while (iterator.hasNext()) { +// Optional optional = iterator.next(); +// if (optional.isPresent()) { +// return optional.get(); +// } +// } +// return endOfData(); +// } +// }; +// }; +// }; +// } + + private static final long serialVersionUID = 0; +} diff --git a/src/org/thoughtcrime/securesms/util/guava/Preconditions.java b/src/org/thoughtcrime/securesms/util/guava/Preconditions.java new file mode 100644 index 000000000..1c32bb54c --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/guava/Preconditions.java @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thoughtcrime.securesms.util.guava; + + +import java.util.NoSuchElementException; + + + +/** + * Simple static methods to be called at the start of your own methods to verify + * correct arguments and state. This allows constructs such as + *
+ *     if (count <= 0) {
+ *       throw new IllegalArgumentException("must be positive: " + count);
+ *     }
+ * + * to be replaced with the more compact + *
+ *     checkArgument(count > 0, "must be positive: %s", count);
+ * + * Note that the sense of the expression is inverted; with {@code Preconditions} + * you declare what you expect to be true, just as you do with an + * + * {@code assert} or a JUnit {@code assertTrue} call. + * + *

Warning: only the {@code "%s"} specifier is recognized as a + * placeholder in these messages, not the full range of {@link + * String#format(String, Object[])} specifiers. + * + *

Take care not to confuse precondition checking with other similar types + * of checks! Precondition exceptions -- including those provided here, but also + * {@link IndexOutOfBoundsException}, {@link NoSuchElementException}, {@link + * UnsupportedOperationException} and others -- are used to signal that the + * calling method has made an error. This tells the caller that it should + * not have invoked the method when it did, with the arguments it did, or + * perhaps ever. Postcondition or other invariant failures should not throw + * these types of exceptions. + * + *

See the Guava User Guide on + * using {@code Preconditions}. + * + * @author Kevin Bourrillion + * @since 2.0 (imported from Google Collections Library) + */ + +public final class Preconditions { + private Preconditions() {} + + /** + * Ensures the truth of an expression involving one or more parameters to the + * calling method. + * + * @param expression a boolean expression + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument(boolean expression) { + if (!expression) { + throw new IllegalArgumentException(); + } + } + + /** + * Ensures the truth of an expression involving one or more parameters to the + * calling method. + * + * @param expression a boolean expression + * @param errorMessage the exception message to use if the check fails; will + * be converted to a string using {@link String#valueOf(Object)} + * @throws IllegalArgumentException if {@code expression} is false + */ + public static void checkArgument( + boolean expression, Object errorMessage) { + if (!expression) { + throw new IllegalArgumentException(String.valueOf(errorMessage)); + } + } + + /** + * Ensures the truth of an expression involving one or more parameters to the + * calling method. + * + * @param expression a boolean expression + * @param errorMessageTemplate a template for the exception message should the + * check fail. The message is formed by replacing each {@code %s} + * placeholder in the template with an argument. These are matched by + * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. + * Unmatched arguments will be appended to the formatted message in square + * braces. Unmatched placeholders will be left as-is. + * @param errorMessageArgs the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. + * @throws IllegalArgumentException if {@code expression} is false + * @throws NullPointerException if the check fails and either {@code + * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let + * this happen) + */ + public static void checkArgument(boolean expression, + String errorMessageTemplate, + Object... errorMessageArgs) { + if (!expression) { + throw new IllegalArgumentException( + format(errorMessageTemplate, errorMessageArgs)); + } + } + + /** + * Ensures the truth of an expression involving the state of the calling + * instance, but not involving any parameters to the calling method. + * + * @param expression a boolean expression + * @throws IllegalStateException if {@code expression} is false + */ + public static void checkState(boolean expression) { + if (!expression) { + throw new IllegalStateException(); + } + } + + /** + * Ensures the truth of an expression involving the state of the calling + * instance, but not involving any parameters to the calling method. + * + * @param expression a boolean expression + * @param errorMessage the exception message to use if the check fails; will + * be converted to a string using {@link String#valueOf(Object)} + * @throws IllegalStateException if {@code expression} is false + */ + public static void checkState( + boolean expression, Object errorMessage) { + if (!expression) { + throw new IllegalStateException(String.valueOf(errorMessage)); + } + } + + /** + * Ensures the truth of an expression involving the state of the calling + * instance, but not involving any parameters to the calling method. + * + * @param expression a boolean expression + * @param errorMessageTemplate a template for the exception message should the + * check fail. The message is formed by replacing each {@code %s} + * placeholder in the template with an argument. These are matched by + * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. + * Unmatched arguments will be appended to the formatted message in square + * braces. Unmatched placeholders will be left as-is. + * @param errorMessageArgs the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. + * @throws IllegalStateException if {@code expression} is false + * @throws NullPointerException if the check fails and either {@code + * errorMessageTemplate} or {@code errorMessageArgs} is null (don't let + * this happen) + */ + public static void checkState(boolean expression, + String errorMessageTemplate, + Object... errorMessageArgs) { + if (!expression) { + throw new IllegalStateException( + format(errorMessageTemplate, errorMessageArgs)); + } + } + + /** + * Ensures that an object reference passed as a parameter to the calling + * method is not null. + * + * @param reference an object reference + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static T checkNotNull(T reference) { + if (reference == null) { + throw new NullPointerException(); + } + return reference; + } + + /** + * Ensures that an object reference passed as a parameter to the calling + * method is not null. + * + * @param reference an object reference + * @param errorMessage the exception message to use if the check fails; will + * be converted to a string using {@link String#valueOf(Object)} + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static T checkNotNull(T reference, Object errorMessage) { + if (reference == null) { + throw new NullPointerException(String.valueOf(errorMessage)); + } + return reference; + } + + /** + * Ensures that an object reference passed as a parameter to the calling + * method is not null. + * + * @param reference an object reference + * @param errorMessageTemplate a template for the exception message should the + * check fail. The message is formed by replacing each {@code %s} + * placeholder in the template with an argument. These are matched by + * position - the first {@code %s} gets {@code errorMessageArgs[0]}, etc. + * Unmatched arguments will be appended to the formatted message in square + * braces. Unmatched placeholders will be left as-is. + * @param errorMessageArgs the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. + * @return the non-null reference that was validated + * @throws NullPointerException if {@code reference} is null + */ + public static T checkNotNull(T reference, + String errorMessageTemplate, + Object... errorMessageArgs) { + if (reference == null) { + // If either of these parameters is null, the right thing happens anyway + throw new NullPointerException( + format(errorMessageTemplate, errorMessageArgs)); + } + return reference; + } + + /* + * All recent hotspots (as of 2009) *really* like to have the natural code + * + * if (guardExpression) { + * throw new BadException(messageExpression); + * } + * + * refactored so that messageExpression is moved to a separate + * String-returning method. + * + * if (guardExpression) { + * throw new BadException(badMsg(...)); + * } + * + * The alternative natural refactorings into void or Exception-returning + * methods are much slower. This is a big deal - we're talking factors of + * 2-8 in microbenchmarks, not just 10-20%. (This is a hotspot optimizer + * bug, which should be fixed, but that's a separate, big project). + * + * The coding pattern above is heavily used in java.util, e.g. in ArrayList. + * There is a RangeCheckMicroBenchmark in the JDK that was used to test this. + * + * But the methods in this class want to throw different exceptions, + * depending on the args, so it appears that this pattern is not directly + * applicable. But we can use the ridiculous, devious trick of throwing an + * exception in the middle of the construction of another exception. + * Hotspot is fine with that. + */ + + /** + * Ensures that {@code index} specifies a valid element in an array, + * list or string of size {@code size}. An element index may range from zero, + * inclusive, to {@code size}, exclusive. + * + * @param index a user-supplied index identifying an element of an array, list + * or string + * @param size the size of that array, list or string + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is not + * less than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkElementIndex(int index, int size) { + return checkElementIndex(index, size, "index"); + } + + /** + * Ensures that {@code index} specifies a valid element in an array, + * list or string of size {@code size}. An element index may range from zero, + * inclusive, to {@code size}, exclusive. + * + * @param index a user-supplied index identifying an element of an array, list + * or string + * @param size the size of that array, list or string + * @param desc the text to use to describe this index in an error message + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is not + * less than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkElementIndex( + int index, int size, String desc) { + // Carefully optimized for execution by hotspot (explanatory comment above) + if (index < 0 || index >= size) { + throw new IndexOutOfBoundsException(badElementIndex(index, size, desc)); + } + return index; + } + + private static String badElementIndex(int index, int size, String desc) { + if (index < 0) { + return format("%s (%s) must not be negative", desc, index); + } else if (size < 0) { + throw new IllegalArgumentException("negative size: " + size); + } else { // index >= size + return format("%s (%s) must be less than size (%s)", desc, index, size); + } + } + + /** + * Ensures that {@code index} specifies a valid position in an array, + * list or string of size {@code size}. A position index may range from zero + * to {@code size}, inclusive. + * + * @param index a user-supplied index identifying a position in an array, list + * or string + * @param size the size of that array, list or string + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is + * greater than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkPositionIndex(int index, int size) { + return checkPositionIndex(index, size, "index"); + } + + /** + * Ensures that {@code index} specifies a valid position in an array, + * list or string of size {@code size}. A position index may range from zero + * to {@code size}, inclusive. + * + * @param index a user-supplied index identifying a position in an array, list + * or string + * @param size the size of that array, list or string + * @param desc the text to use to describe this index in an error message + * @return the value of {@code index} + * @throws IndexOutOfBoundsException if {@code index} is negative or is + * greater than {@code size} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static int checkPositionIndex( + int index, int size, String desc) { + // Carefully optimized for execution by hotspot (explanatory comment above) + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc)); + } + return index; + } + + private static String badPositionIndex(int index, int size, String desc) { + if (index < 0) { + return format("%s (%s) must not be negative", desc, index); + } else if (size < 0) { + throw new IllegalArgumentException("negative size: " + size); + } else { // index > size + return format("%s (%s) must not be greater than size (%s)", + desc, index, size); + } + } + + /** + * Ensures that {@code start} and {@code end} specify a valid positions + * in an array, list or string of size {@code size}, and are in order. A + * position index may range from zero to {@code size}, inclusive. + * + * @param start a user-supplied index identifying a starting position in an + * array, list or string + * @param end a user-supplied index identifying a ending position in an array, + * list or string + * @param size the size of that array, list or string + * @throws IndexOutOfBoundsException if either index is negative or is + * greater than {@code size}, or if {@code end} is less than {@code start} + * @throws IllegalArgumentException if {@code size} is negative + */ + public static void checkPositionIndexes(int start, int end, int size) { + // Carefully optimized for execution by hotspot (explanatory comment above) + if (start < 0 || end < start || end > size) { + throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size)); + } + } + + private static String badPositionIndexes(int start, int end, int size) { + if (start < 0 || start > size) { + return badPositionIndex(start, size, "start index"); + } + if (end < 0 || end > size) { + return badPositionIndex(end, size, "end index"); + } + // end < start + return format("end index (%s) must not be less than start index (%s)", + end, start); + } + + /** + * Substitutes each {@code %s} in {@code template} with an argument. These + * are matched by position - the first {@code %s} gets {@code args[0]}, etc. + * If there are more arguments than placeholders, the unmatched arguments will + * be appended to the end of the formatted message in square braces. + * + * @param template a non-null string containing 0 or more {@code %s} + * placeholders. + * @param args the arguments to be substituted into the message + * template. Arguments are converted to strings using + * {@link String#valueOf(Object)}. Arguments can be null. + */ + static String format(String template, + Object... args) { + template = String.valueOf(template); // null -> "null" + + // start substituting the arguments into the '%s' placeholders + StringBuilder builder = new StringBuilder( + template.length() + 16 * args.length); + int templateStart = 0; + int i = 0; + while (i < args.length) { + int placeholderStart = template.indexOf("%s", templateStart); + if (placeholderStart == -1) { + break; + } + builder.append(template.substring(templateStart, placeholderStart)); + builder.append(args[i++]); + templateStart = placeholderStart + 2; + } + builder.append(template.substring(templateStart)); + + // if we run out of placeholders, append the extra args in square braces + if (i < args.length) { + builder.append(" ["); + builder.append(args[i++]); + while (i < args.length) { + builder.append(", "); + builder.append(args[i++]); + } + builder.append(']'); + } + + return builder.toString(); + } +} diff --git a/src/org/thoughtcrime/securesms/util/guava/Present.java b/src/org/thoughtcrime/securesms/util/guava/Present.java new file mode 100644 index 000000000..4bf3d1548 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/guava/Present.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thoughtcrime.securesms.util.guava; + +import static org.thoughtcrime.securesms.util.guava.Preconditions.checkNotNull; + +import java.util.Collections; +import java.util.Set; + +/** + * Implementation of an {@link Optional} containing a reference. + */ + +final class Present extends Optional { + private final T reference; + + Present(T reference) { + this.reference = reference; + } + + @Override public boolean isPresent() { + return true; + } + + @Override public T get() { + return reference; + } + + @Override public T or(T defaultValue) { + checkNotNull(defaultValue, "use orNull() instead of or(null)"); + return reference; + } + + @Override public Optional or(Optional secondChoice) { + checkNotNull(secondChoice); + return this; + } + + @Override public T or(Supplier supplier) { + checkNotNull(supplier); + return reference; + } + + @Override public T orNull() { + return reference; + } + + @Override public Set asSet() { + return Collections.singleton(reference); + } + + @Override public Optional transform(Function function) { + return new Present(checkNotNull(function.apply(reference), + "Transformation function cannot return null.")); + } + + @Override public boolean equals(Object object) { + if (object instanceof Present) { + Present other = (Present) object; + return reference.equals(other.reference); + } + return false; + } + + @Override public int hashCode() { + return 0x598df91c + reference.hashCode(); + } + + @Override public String toString() { + return "Optional.of(" + reference + ")"; + } + + private static final long serialVersionUID = 0; +} diff --git a/src/org/thoughtcrime/securesms/util/guava/Supplier.java b/src/org/thoughtcrime/securesms/util/guava/Supplier.java new file mode 100644 index 000000000..8a3683c42 --- /dev/null +++ b/src/org/thoughtcrime/securesms/util/guava/Supplier.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thoughtcrime.securesms.util.guava; + + +/** + * A class that can supply objects of a single type. Semantically, this could + * be a factory, generator, builder, closure, or something else entirely. No + * guarantees are implied by this interface. + * + * @author Harry Heymann + * @since 2.0 (imported from Google Collections Library) + */ +public interface Supplier { + /** + * Retrieves an instance of the appropriate type. The returned object may or + * may not be a new instance, depending on the implementation. + * + * @return an instance of the appropriate type + */ + T get(); +}