@ -79,6 +79,7 @@ dependencies {
|
||||
compile 'org.whispersystems:libpastelog:1.0.6'
|
||||
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||
compile 'org.whispersystems:textsecure-android:1.6.2'
|
||||
compile 'com.h6ah4i.android.compat:mulsellistprefcompat:1.0.0'
|
||||
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
|
||||
|
BIN
res/drawable-hdpi/ic_file_download_white_36dp.png
Normal file
After Width: | Height: | Size: 656 B |
BIN
res/drawable-hdpi/ic_forum_black_32dp.png
Normal file
After Width: | Height: | Size: 495 B |
BIN
res/drawable-hdpi/ic_forum_grey_32dp.png
Normal file
After Width: | Height: | Size: 512 B |
BIN
res/drawable-hdpi/ic_textsms_black_32dp.png
Normal file
After Width: | Height: | Size: 583 B |
BIN
res/drawable-hdpi/ic_textsms_grey_32dp.png
Normal file
After Width: | Height: | Size: 687 B |
BIN
res/drawable-mdpi/ic_file_download_white_36dp.png
Normal file
After Width: | Height: | Size: 479 B |
BIN
res/drawable-mdpi/ic_forum_black_32dp.png
Normal file
After Width: | Height: | Size: 422 B |
BIN
res/drawable-mdpi/ic_forum_grey_32dp.png
Normal file
After Width: | Height: | Size: 437 B |
BIN
res/drawable-mdpi/ic_textsms_black_32dp.png
Normal file
After Width: | Height: | Size: 435 B |
BIN
res/drawable-mdpi/ic_textsms_grey_32dp.png
Normal file
After Width: | Height: | Size: 517 B |
BIN
res/drawable-xhdpi/ic_file_download_white_36dp.png
Normal file
After Width: | Height: | Size: 653 B |
BIN
res/drawable-xhdpi/ic_forum_black_32dp.png
Normal file
After Width: | Height: | Size: 620 B |
BIN
res/drawable-xhdpi/ic_forum_grey_32dp.png
Normal file
After Width: | Height: | Size: 640 B |
BIN
res/drawable-xhdpi/ic_textsms_black_32dp.png
Normal file
After Width: | Height: | Size: 636 B |
BIN
res/drawable-xhdpi/ic_textsms_grey_32dp.png
Normal file
After Width: | Height: | Size: 751 B |
BIN
res/drawable-xxhdpi/ic_file_download_white_36dp.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
res/drawable-xxhdpi/ic_forum_black_32dp.png
Normal file
After Width: | Height: | Size: 759 B |
BIN
res/drawable-xxhdpi/ic_forum_grey_32dp.png
Normal file
After Width: | Height: | Size: 782 B |
BIN
res/drawable-xxhdpi/ic_textsms_black_32dp.png
Normal file
After Width: | Height: | Size: 805 B |
BIN
res/drawable-xxhdpi/ic_textsms_grey_32dp.png
Normal file
After Width: | Height: | Size: 958 B |
BIN
res/drawable-xxxhdpi/ic_file_download_white_36dp.png
Normal file
After Width: | Height: | Size: 615 B |
BIN
res/drawable-xxxhdpi/ic_forum_black_32dp.png
Normal file
After Width: | Height: | Size: 551 B |
BIN
res/drawable-xxxhdpi/ic_forum_grey_32dp.png
Normal file
After Width: | Height: | Size: 579 B |
BIN
res/drawable-xxxhdpi/ic_textsms_black_32dp.png
Normal file
After Width: | Height: | Size: 431 B |
BIN
res/drawable-xxxhdpi/ic_textsms_grey_32dp.png
Normal file
After Width: | Height: | Size: 461 B |
@ -20,4 +20,12 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top|right"
|
||||
android:layout="@layout/thumbnail_view_remove_button" />
|
||||
|
||||
<ImageButton android:id="@+id/download_button"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="70dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@drawable/progress_background"
|
||||
android:src="@drawable/ic_file_download_white_36dp"
|
||||
android:visibility="gone" />
|
||||
</merge>
|
||||
|
@ -193,4 +193,29 @@
|
||||
<item>contact</item>
|
||||
<item>none</item>
|
||||
</string-array>
|
||||
|
||||
<!-- discrete MIME type (the part before the "/") -->
|
||||
<string-array name="pref_media_download_entries">
|
||||
<item>image</item>
|
||||
<item>audio</item>
|
||||
<item>video</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_media_download_values">
|
||||
<item>@string/arrays__images</item>
|
||||
<item>@string/arrays__audio</item>
|
||||
<item>@string/arrays__video</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_media_download_mobile_data_default">
|
||||
<item>image</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_media_download_wifi_default">
|
||||
<item>image</item>
|
||||
<item>audio</item>
|
||||
<item>video</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pref_media_download_roaming_default" />
|
||||
</resources>
|
||||
|
@ -106,6 +106,7 @@
|
||||
<attr name="pref_ic_app_protection" format="reference" />
|
||||
<attr name="pref_ic_appearance" format="reference" />
|
||||
<attr name="pref_ic_storage" format="reference" />
|
||||
<attr name="pref_ic_chats" format="reference" />
|
||||
<attr name="pref_ic_devices" format="reference" />
|
||||
<attr name="pref_ic_advanced" format="reference" />
|
||||
|
||||
|
@ -762,6 +762,10 @@
|
||||
<string name="arrays__name_only">Name only</string>
|
||||
<string name="arrays__neither">Neither</string>
|
||||
|
||||
<string name="arrays__images">Images</string>
|
||||
<string name="arrays__audio">Audio</string>
|
||||
<string name="arrays__video">Video</string>
|
||||
|
||||
<!-- plurals.xml -->
|
||||
<plurals name="hours_ago">
|
||||
<item quantity="one">%d hour</item>
|
||||
@ -847,6 +851,7 @@
|
||||
<string name="preferences__request_a_delivery_report_for_each_sms_message_you_send">Request a delivery report for each SMS message you send</string>
|
||||
<string name="preferences__automatically_delete_older_messages_once_a_conversation_thread_exceeds_a_specified_length">Automatically delete older messages once a conversation thread exceeds a specified length</string>
|
||||
<string name="preferences__delete_old_messages">Delete old messages</string>
|
||||
<string name="preferences__chats">Chats and media</string>
|
||||
<string name="preferences__conversation_length_limit">Conversation length limit</string>
|
||||
<string name="preferences__trim_all_threads_now">Trim all threads now</string>
|
||||
<string name="preferences__scan_through_all_conversation_threads_and_enforce_conversation_length_limits">Scan through all conversation threads and enforce conversation length limits</string>
|
||||
|
@ -169,11 +169,11 @@
|
||||
|
||||
<item name="reminder_header_background">#ff1d85d7</item>
|
||||
|
||||
<item name="pref_ic_sms_mms">@drawable/ic_message_black</item>
|
||||
<item name="pref_ic_sms_mms">@drawable/ic_textsms_black_32dp</item>
|
||||
<item name="pref_ic_notifications">@drawable/ic_notifications_black</item>
|
||||
<item name="pref_ic_app_protection">@drawable/ic_app_protection_black</item>
|
||||
<item name="pref_ic_appearance">@drawable/ic_brightness_6_black</item>
|
||||
<item name="pref_ic_storage">@drawable/ic_delete_black</item>
|
||||
<item name="pref_ic_chats">@drawable/ic_forum_black_32dp</item>
|
||||
<item name="pref_ic_devices">@drawable/ic_devices_black_48dp</item>
|
||||
<item name="pref_ic_advanced">@drawable/ic_advanced_black</item>
|
||||
|
||||
@ -281,11 +281,11 @@
|
||||
|
||||
<item name="reminder_header_background">@color/textsecure_primary_dark</item>
|
||||
|
||||
<item name="pref_ic_sms_mms">@drawable/ic_message_gray</item>
|
||||
<item name="pref_ic_sms_mms">@drawable/ic_textsms_grey_32dp</item>
|
||||
<item name="pref_ic_notifications">@drawable/ic_notifications_gray</item>
|
||||
<item name="pref_ic_app_protection">@drawable/ic_app_protection_gray</item>
|
||||
<item name="pref_ic_appearance">@drawable/ic_brightness_6_gray</item>
|
||||
<item name="pref_ic_storage">@drawable/ic_delete_gray</item>
|
||||
<item name="pref_ic_chats">@drawable/ic_forum_grey_32dp</item>
|
||||
<item name="pref_ic_devices">@drawable/ic_devices_grey600_48dp</item>
|
||||
<item name="pref_ic_advanced">@drawable/ic_advanced_gray</item>
|
||||
|
||||
|
@ -17,9 +17,9 @@
|
||||
android:title="@string/preferences__appearance"
|
||||
android:icon="?pref_ic_appearance"/>
|
||||
|
||||
<Preference android:key="preference_category_storage"
|
||||
android:title="@string/preferences__delete_old_messages"
|
||||
android:icon="?pref_ic_storage"/>
|
||||
<Preference android:key="preference_category_chats"
|
||||
android:title="@string/preferences__chats"
|
||||
android:icon="?pref_ic_chats"/>
|
||||
|
||||
<!--<Preference android:key="preference_category_devices"-->
|
||||
<!--android:title="Devices"-->
|
||||
|
48
res/xml/preferences_chats.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:key="media_download" android:title="Media auto-download">
|
||||
<com.h6ah4i.android.compat.preference.MultiSelectListPreferenceCompat
|
||||
android:title="When using mobile data"
|
||||
android:key="pref_media_download_mobile"
|
||||
android:defaultValue="@array/pref_media_download_mobile_data_default"
|
||||
android:persistent="true"
|
||||
android:entries="@array/pref_media_download_values"
|
||||
android:entryValues="@array/pref_media_download_entries" />
|
||||
|
||||
<com.h6ah4i.android.compat.preference.MultiSelectListPreferenceCompat
|
||||
android:title="When using Wi-Fi"
|
||||
android:key="pref_media_download_wifi"
|
||||
android:defaultValue="@array/pref_media_download_wifi_default"
|
||||
android:persistent="true"
|
||||
android:entries="@array/pref_media_download_values"
|
||||
android:entryValues="@array/pref_media_download_entries" />
|
||||
|
||||
<com.h6ah4i.android.compat.preference.MultiSelectListPreferenceCompat
|
||||
android:title="When roaming"
|
||||
android:key="pref_media_download_roaming"
|
||||
android:defaultValue="@array/pref_media_download_roaming_default"
|
||||
android:persistent="true"
|
||||
android:entries="@array/pref_media_download_values"
|
||||
android:entryValues="@array/pref_media_download_entries" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:key="message_trimming" android:title="Message trimming">
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="pref_trim_threads"
|
||||
android:summary="@string/preferences__automatically_delete_older_messages_once_a_conversation_thread_exceeds_a_specified_length"
|
||||
android:title="@string/preferences__delete_old_messages" />
|
||||
|
||||
<EditTextPreference android:defaultValue="500"
|
||||
android:key="pref_trim_length"
|
||||
android:title="@string/preferences__conversation_length_limit"
|
||||
android:inputType="number"
|
||||
android:dependency="pref_trim_threads" />
|
||||
|
||||
<Preference android:key="pref_trim_now"
|
||||
android:title="@string/preferences__trim_all_threads_now"
|
||||
android:summary="@string/preferences__scan_through_all_conversation_threads_and_enforce_conversation_length_limits"
|
||||
android:dependency="pref_trim_threads" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="pref_trim_threads"
|
||||
android:summary="@string/preferences__automatically_delete_older_messages_once_a_conversation_thread_exceeds_a_specified_length"
|
||||
android:title="@string/preferences__delete_old_messages" />
|
||||
|
||||
<EditTextPreference android:defaultValue="500"
|
||||
android:key="pref_trim_length"
|
||||
android:title="@string/preferences__conversation_length_limit"
|
||||
android:inputType="number"
|
||||
android:dependency="pref_trim_threads" />
|
||||
|
||||
<Preference android:key="pref_trim_now"
|
||||
android:title="@string/preferences__trim_all_threads_now"
|
||||
android:summary="@string/preferences__scan_through_all_conversation_threads_and_enforce_conversation_length_limits"
|
||||
android:dependency="pref_trim_threads" />
|
||||
|
||||
</PreferenceScreen>
|
@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.dependencies.TextSecureCommunicationModule;
|
||||
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.persistence.EncryptingJobSerializer;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirementProvider;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MediaNetworkRequirementProvider;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirementProvider;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.JobManager;
|
||||
@ -49,9 +50,11 @@ import dagger.ObjectGraph;
|
||||
*/
|
||||
public class ApplicationContext extends Application implements DependencyInjector {
|
||||
|
||||
private JobManager jobManager;
|
||||
private JobManager jobManager;
|
||||
private ObjectGraph objectGraph;
|
||||
|
||||
private MediaNetworkRequirementProvider mediaNetworkRequirementProvider = new MediaNetworkRequirementProvider();
|
||||
|
||||
public static ApplicationContext getInstance(Context context) {
|
||||
return (ApplicationContext)context.getApplicationContext();
|
||||
}
|
||||
@ -103,11 +106,16 @@ public class ApplicationContext extends Application implements DependencyInjecto
|
||||
.withJobSerializer(new EncryptingJobSerializer())
|
||||
.withRequirementProviders(new MasterSecretRequirementProvider(this),
|
||||
new ServiceRequirementProvider(this),
|
||||
new NetworkRequirementProvider(this))
|
||||
new NetworkRequirementProvider(this),
|
||||
mediaNetworkRequirementProvider)
|
||||
.withConsumerThreads(5)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void notifyMediaControlEvent() {
|
||||
mediaNetworkRequirementProvider.notifyMediaControlEvent();
|
||||
}
|
||||
|
||||
private void initializeDependencyInjection() {
|
||||
this.objectGraph = ObjectGraph.create(new TextSecureCommunicationModule(this),
|
||||
new AxolotlStorageModule(this));
|
||||
|
@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.SmsMmsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.StoragePreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
@ -54,7 +54,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "preference_category_notifications";
|
||||
private static final String PREFERENCE_CATEGORY_APP_PROTECTION = "preference_category_app_protection";
|
||||
private static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance";
|
||||
private static final String PREFERENCE_CATEGORY_STORAGE = "preference_category_storage";
|
||||
private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats";
|
||||
private static final String PREFERENCE_CATEGORY_DEVICES = "preference_category_devices";
|
||||
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
|
||||
|
||||
@ -130,8 +130,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(masterSecret, PREFERENCE_CATEGORY_APP_PROTECTION));
|
||||
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(masterSecret, PREFERENCE_CATEGORY_APPEARANCE));
|
||||
this.findPreference(PREFERENCE_CATEGORY_STORAGE)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(masterSecret, PREFERENCE_CATEGORY_STORAGE));
|
||||
this.findPreference(PREFERENCE_CATEGORY_CHATS)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(masterSecret, PREFERENCE_CATEGORY_CHATS));
|
||||
// this.findPreference(PREFERENCE_CATEGORY_DEVICES)
|
||||
// .setOnPreferenceClickListener(new CategoryClickListener(masterSecret, PREFERENCE_CATEGORY_DEVICES));
|
||||
this.findPreference(PREFERENCE_CATEGORY_ADVANCED)
|
||||
@ -154,8 +154,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
.setSummary(AppProtectionPreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_APPEARANCE)
|
||||
.setSummary(AppearancePreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_STORAGE)
|
||||
.setSummary(StoragePreferenceFragment.getSummary(getActivity()));
|
||||
this.findPreference(PREFERENCE_CATEGORY_CHATS)
|
||||
.setSummary(ChatsPreferenceFragment.getSummary(getActivity()));
|
||||
}
|
||||
|
||||
private class CategoryClickListener implements Preference.OnPreferenceClickListener {
|
||||
@ -184,8 +184,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
case PREFERENCE_CATEGORY_APPEARANCE:
|
||||
fragment = new AppearancePreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_STORAGE:
|
||||
fragment = new StoragePreferenceFragment();
|
||||
case PREFERENCE_CATEGORY_CHATS:
|
||||
fragment = new ChatsPreferenceFragment();
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_DEVICES:
|
||||
Intent intent = new Intent(getActivity(), DeviceListActivity.class);
|
||||
|
@ -47,6 +47,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.PartDatabase;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||
@ -156,6 +157,7 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
if (mediaThumbnail != null) {
|
||||
mediaThumbnail.setThumbnailClickListener(new ThumbnailClickListener());
|
||||
mediaThumbnail.setOnLongClickListener(new MultiSelectLongClickListener());
|
||||
mediaThumbnail.setDownloadClickListener(new ThumbnailDownloadClickListener());
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,7 +277,7 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
mediaThumbnail.setImageResource(masterSecret, messageRecord.getId(),
|
||||
messageRecord.getDateReceived(),
|
||||
((MediaMmsMessageRecord)messageRecord).getSlideDeckFuture());
|
||||
mediaThumbnail.setShowProgress(!messageRecord.isFailed() && (!messageRecord.isOutgoing() || messageRecord.isPending()));
|
||||
mediaThumbnail.hideControls(messageRecord.isFailed() || (messageRecord.isOutgoing() && !messageRecord.isPending()));
|
||||
bodyText.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
||||
} else {
|
||||
mediaThumbnail.setVisibility(View.GONE);
|
||||
@ -409,6 +411,11 @@ public class ConversationItem extends LinearLayout implements Recipient.Recipien
|
||||
}
|
||||
}
|
||||
|
||||
private class ThumbnailDownloadClickListener implements ThumbnailView.ThumbnailClickListener {
|
||||
@Override public void onClick(View v, Slide slide) {
|
||||
DatabaseFactory.getPartDatabase(context).setTransferState(messageRecord.getId(), slide.getPart().getPartId(), PartDatabase.TRANSFER_PROGRESS_STARTED);
|
||||
}
|
||||
}
|
||||
private class ThumbnailClickListener implements ThumbnailView.ThumbnailClickListener {
|
||||
private void fireIntent(Slide slide) {
|
||||
Log.w(TAG, "Clicked: " + slide.getUri() + " , " + slide.getContentType());
|
||||
|
@ -32,7 +32,11 @@ import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecurePreKeyStore;
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase.Reader;
|
||||
import org.thoughtcrime.securesms.database.PushDatabase;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
|
||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.PushDecryptJob;
|
||||
@ -41,10 +45,14 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.VersionTracker;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
|
||||
public class DatabaseUpgradeActivity extends BaseActivity {
|
||||
private static final String TAG = DatabaseUpgradeActivity.class.getSimpleName();
|
||||
|
||||
public static final int NO_MORE_KEY_EXCHANGE_PREFIX_VERSION = 46;
|
||||
public static final int MMS_BODY_VERSION = 46;
|
||||
@ -57,6 +65,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
||||
public static final int PUSH_DECRYPT_SERIAL_ID_VERSION = 131;
|
||||
public static final int MIGRATE_SESSION_PLAINTEXT = 136;
|
||||
public static final int CONTACTS_ACCOUNT_VERSION = 136;
|
||||
public static final int MEDIA_DOWNLOAD_CONTROLS_VERSION = 146;
|
||||
|
||||
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
|
||||
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);
|
||||
@ -68,6 +77,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
||||
add(NO_DECRYPT_QUEUE_VERSION);
|
||||
add(PUSH_DECRYPT_SERIAL_ID_VERSION);
|
||||
add(MIGRATE_SESSION_PLAINTEXT);
|
||||
add(MEDIA_DOWNLOAD_CONTROLS_VERSION);
|
||||
}};
|
||||
|
||||
private MasterSecret masterSecret;
|
||||
@ -205,9 +215,32 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
||||
.add(new DirectoryRefreshJob(getApplicationContext()));
|
||||
}
|
||||
|
||||
if (params[0] < MEDIA_DOWNLOAD_CONTROLS_VERSION) {
|
||||
schedulePendingIncomingParts(context);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void schedulePendingIncomingParts(Context context) {
|
||||
MmsDatabase db = DatabaseFactory.getMmsDatabase(context);
|
||||
List<PduPart> pendingParts = DatabaseFactory.getPartDatabase(context).getPendingParts();
|
||||
|
||||
Log.w(TAG, pendingParts.size() + " pending parts.");
|
||||
for (PduPart part : pendingParts) {
|
||||
final Reader reader = db.readerFor(masterSecret, db.getMessage(part.getMmsId()));
|
||||
final MessageRecord record = reader.getNext();
|
||||
|
||||
if (record != null && !record.isOutgoing() && record.isPush()) {
|
||||
Log.w(TAG, "queuing new attachment download job for incoming push part.");
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, part.getMmsId(), part.getPartId()));
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void scheduleMessagesInPushDatabase(Context context) {
|
||||
PushDatabase pushDatabase = DatabaseFactory.getPushDatabase(context);
|
||||
Cursor pushReader = null;
|
||||
|
@ -31,6 +31,7 @@ import com.pnikosis.materialishprogress.ProgressWheel;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.PartDatabase;
|
||||
import org.thoughtcrime.securesms.jobs.PartProgressEvent;
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
|
||||
import org.thoughtcrime.securesms.mms.RoundedCorners;
|
||||
@ -47,16 +48,18 @@ import ws.com.google.android.mms.pdu.PduPart;
|
||||
public class ThumbnailView extends FrameLayout {
|
||||
private static final String TAG = ThumbnailView.class.getSimpleName();
|
||||
|
||||
private boolean showProgress = true;
|
||||
private boolean hideControls;
|
||||
private ImageView image;
|
||||
private ProgressWheel progress;
|
||||
private ImageView removeButton;
|
||||
private ImageButton downloadButton;
|
||||
private int backgroundColorHint;
|
||||
private int radius;
|
||||
|
||||
private ListenableFutureTask<SlideDeck> slideDeckFuture = null;
|
||||
private SlideDeckListener slideDeckListener = null;
|
||||
private ThumbnailClickListener thumbnailClickListener = null;
|
||||
private ThumbnailClickListener downloadClickListener = null;
|
||||
private String slideId = null;
|
||||
private Slide slide = null;
|
||||
|
||||
@ -68,11 +71,13 @@ public class ThumbnailView extends FrameLayout {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ThumbnailView(Context context, AttributeSet attrs, int defStyle) {
|
||||
public ThumbnailView(final Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
inflate(context, R.layout.thumbnail_view, this);
|
||||
radius = getResources().getDimensionPixelSize(R.dimen.message_bubble_corner_radius);
|
||||
image = (ImageView) findViewById(R.id.thumbnail_image);
|
||||
radius = getResources().getDimensionPixelSize(R.dimen.message_bubble_corner_radius);
|
||||
image = (ImageView) findViewById(R.id.thumbnail_image);
|
||||
progress = (ProgressWheel) findViewById(R.id.progress_wheel);
|
||||
downloadButton = (ImageButton) findViewById(R.id.download_button);
|
||||
|
||||
if (attrs != null) {
|
||||
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ThumbnailView, 0, 0);
|
||||
@ -162,15 +167,24 @@ public class ThumbnailView extends FrameLayout {
|
||||
return;
|
||||
}
|
||||
|
||||
this.slide = slide;
|
||||
if (slide.isInProgress() && showProgress) {
|
||||
if (!hideControls && slide.getTransferProgress() == PartDatabase.TRANSFER_PROGRESS_STARTED) {
|
||||
getProgressWheel().spin();
|
||||
getProgressWheel().setVisibility(VISIBLE);
|
||||
downloadButton.setVisibility(GONE);
|
||||
} else if (!hideControls && slide.getTransferProgress() == PartDatabase.TRANSFER_PROGRESS_AUTO_PENDING ||
|
||||
slide.getTransferProgress() == PartDatabase.TRANSFER_PROGRESS_FAILED)
|
||||
{
|
||||
hideProgressWheel();
|
||||
downloadButton.setVisibility(VISIBLE);
|
||||
} else {
|
||||
hideProgressWheel();
|
||||
downloadButton.setVisibility(GONE);
|
||||
}
|
||||
|
||||
this.slide = slide;
|
||||
buildGlideRequest(slide, masterSecret).into(image);
|
||||
setOnClickListener(new ThumbnailClickDispatcher(thumbnailClickListener, slide));
|
||||
downloadButton.setOnClickListener(new ThumbnailClickDispatcher(downloadClickListener, slide));
|
||||
}
|
||||
|
||||
public void setThumbnailClickListener(ThumbnailClickListener listener) {
|
||||
@ -181,15 +195,17 @@ public class ThumbnailView extends FrameLayout {
|
||||
getRemoveButton().setOnClickListener(listener);
|
||||
}
|
||||
|
||||
public void setDownloadClickListener(ThumbnailClickListener listener) {
|
||||
this.downloadClickListener = listener;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (isContextValid()) Glide.clear(this);
|
||||
}
|
||||
|
||||
public void setShowProgress(boolean showProgress) {
|
||||
this.showProgress = showProgress;
|
||||
if (progress != null && progress.getVisibility() == View.VISIBLE && !showProgress) {
|
||||
animateOutProgress();
|
||||
}
|
||||
public void hideControls(boolean hideControls) {
|
||||
this.hideControls = hideControls;
|
||||
if (hideControls) hideProgressWheel();
|
||||
}
|
||||
|
||||
@TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
|
||||
@ -202,7 +218,6 @@ public class ThumbnailView extends FrameLayout {
|
||||
private GenericRequestBuilder buildGlideRequest(@NonNull Slide slide,
|
||||
@Nullable MasterSecret masterSecret)
|
||||
{
|
||||
Log.w(TAG, "slide type " + slide.getContentType());
|
||||
final GenericRequestBuilder builder;
|
||||
if (slide.getThumbnailUri() != null) {
|
||||
builder = buildThumbnailGlideRequest(slide, masterSecret);
|
||||
@ -210,7 +225,7 @@ public class ThumbnailView extends FrameLayout {
|
||||
builder = buildPlaceholderGlideRequest(slide);
|
||||
}
|
||||
|
||||
if (slide.isInProgress() && showProgress) {
|
||||
if (slide.isInProgress() && !hideControls) {
|
||||
return builder;
|
||||
} else {
|
||||
return builder.error(R.drawable.ic_missing_thumbnail_picture);
|
||||
|
@ -752,7 +752,7 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
|
||||
if (sendRequest.getBody() != null) {
|
||||
for (int i = 0; i < sendRequest.getBody().getPartsNum(); i++) {
|
||||
sendRequest.getBody().getPart(i).setInProgress(true);
|
||||
sendRequest.getBody().getPart(i).setTransferProgress(PartDatabase.TRANSFER_PROGRESS_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,14 +23,18 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream;
|
||||
import org.thoughtcrime.securesms.crypto.EncryptingPartOutputStream;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MediaNetworkRequirement;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MediaNetworkRequirementProvider;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil.ThumbnailData;
|
||||
@ -43,12 +47,14 @@ import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import de.greenrobot.event.EventBus;
|
||||
import ws.com.google.android.mms.ContentType;
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.PduBody;
|
||||
@ -72,12 +78,17 @@ public class PartDatabase extends Database {
|
||||
private static final String CONTENT_TYPE_TYPE = "ctt_t";
|
||||
private static final String ENCRYPTED = "encrypted";
|
||||
private static final String DATA = "_data";
|
||||
private static final String IN_PROGRESS = "pending_push";
|
||||
private static final String TRANSFER_STATE = "pending_push";
|
||||
private static final String SIZE = "data_size";
|
||||
private static final String THUMBNAIL = "thumbnail";
|
||||
private static final String ASPECT_RATIO = "aspect_ratio";
|
||||
private static final String UNIQUE_ID = "unique_id";
|
||||
|
||||
public static final int TRANSFER_PROGRESS_DONE = 0;
|
||||
public static final int TRANSFER_PROGRESS_STARTED = 1;
|
||||
public static final int TRANSFER_PROGRESS_AUTO_PENDING = 2;
|
||||
public static final int TRANSFER_PROGRESS_FAILED = 3;
|
||||
|
||||
private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?";
|
||||
|
||||
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ROW_ID + " INTEGER PRIMARY KEY, " +
|
||||
@ -86,12 +97,12 @@ public class PartDatabase extends Database {
|
||||
CONTENT_DISPOSITION + " TEXT, " + FILENAME + " TEXT, " + CONTENT_ID + " TEXT, " +
|
||||
CONTENT_LOCATION + " TEXT, " + CONTENT_TYPE_START + " INTEGER, " +
|
||||
CONTENT_TYPE_TYPE + " TEXT, " + ENCRYPTED + " INTEGER, " +
|
||||
IN_PROGRESS + " INTEGER, "+ DATA + " TEXT, " + SIZE + " INTEGER, " +
|
||||
TRANSFER_STATE + " INTEGER, "+ DATA + " TEXT, " + SIZE + " INTEGER, " +
|
||||
THUMBNAIL + " TEXT, " + ASPECT_RATIO + " REAL, " + UNIQUE_ID + " INTEGER NOT NULL);";
|
||||
|
||||
public static final String[] CREATE_INDEXS = {
|
||||
"CREATE INDEX IF NOT EXISTS part_mms_id_index ON " + TABLE_NAME + " (" + MMS_ID + ");",
|
||||
"CREATE INDEX IF NOT EXISTS pending_push_index ON " + TABLE_NAME + " (" + IN_PROGRESS + ");",
|
||||
"CREATE INDEX IF NOT EXISTS pending_push_index ON " + TABLE_NAME + " (" + TRANSFER_STATE + ");",
|
||||
};
|
||||
|
||||
private final static String IMAGES_QUERY = "SELECT " + TABLE_NAME + "." + ROW_ID + ", "
|
||||
@ -127,7 +138,7 @@ public class PartDatabase extends Database {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
part.setContentDisposition(new byte[0]);
|
||||
part.setInProgress(false);
|
||||
part.setTransferProgress(TRANSFER_PROGRESS_FAILED);
|
||||
|
||||
ContentValues values = getContentValuesForPart(part);
|
||||
|
||||
@ -223,6 +234,7 @@ public class PartDatabase extends Database {
|
||||
}
|
||||
|
||||
void insertParts(MasterSecretUnion masterSecret, long mmsId, PduBody body) throws MmsException {
|
||||
Log.w(TAG, "insertParts(" + body.getPartsNum() + ")");
|
||||
for (int i=0;i<body.getPartsNum();i++) {
|
||||
PduPart part = body.getPart(i);
|
||||
PartId partId = insertPart(masterSecret, part, mmsId, part.getThumbnail());
|
||||
@ -234,6 +246,7 @@ public class PartDatabase extends Database {
|
||||
|
||||
part.setRowId(cursor.getLong(cursor.getColumnIndexOrThrow(ROW_ID)));
|
||||
part.setUniqueId(cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID)));
|
||||
part.setMmsId(cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)));
|
||||
|
||||
int charsetColumn = cursor.getColumnIndexOrThrow(CHARSET);
|
||||
|
||||
@ -275,16 +288,15 @@ public class PartDatabase extends Database {
|
||||
if (!cursor.isNull(encryptedColumn))
|
||||
part.setEncrypted(cursor.getInt(encryptedColumn) == 1);
|
||||
|
||||
int inProgressColumn = cursor.getColumnIndexOrThrow(IN_PROGRESS);
|
||||
int transferStateColumn = cursor.getColumnIndexOrThrow(TRANSFER_STATE);
|
||||
|
||||
if (!cursor.isNull(inProgressColumn))
|
||||
part.setInProgress(cursor.getInt(inProgressColumn) == 1);
|
||||
if (!cursor.isNull(transferStateColumn))
|
||||
part.setTransferProgress(cursor.getInt(transferStateColumn));
|
||||
|
||||
int sizeColumn = cursor.getColumnIndexOrThrow(SIZE);
|
||||
|
||||
if (!cursor.isNull(sizeColumn))
|
||||
part.setDataSize(cursor.getLong(cursor.getColumnIndexOrThrow(SIZE)));
|
||||
|
||||
}
|
||||
|
||||
private ContentValues getContentValuesForPart(PduPart part) throws MmsException {
|
||||
@ -325,7 +337,7 @@ public class PartDatabase extends Database {
|
||||
}
|
||||
|
||||
contentValues.put(ENCRYPTED, part.getEncrypted() ? 1 : 0);
|
||||
contentValues.put(IN_PROGRESS, part.isInProgress() ? 1 : 0);
|
||||
contentValues.put(TRANSFER_STATE, part.getTransferProgress());
|
||||
contentValues.put(UNIQUE_ID, part.getUniqueId());
|
||||
|
||||
return contentValues;
|
||||
@ -423,7 +435,7 @@ public class PartDatabase extends Database {
|
||||
}
|
||||
|
||||
private PduPart getPart(Cursor cursor) {
|
||||
PduPart part = new PduPart();
|
||||
PduPart part = new PduPart();
|
||||
|
||||
getPartValues(part, cursor);
|
||||
|
||||
@ -432,6 +444,23 @@ public class PartDatabase extends Database {
|
||||
return part;
|
||||
}
|
||||
|
||||
public List<PduPart> getPendingParts() {
|
||||
final SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
final List<PduPart> parts = new LinkedList<>();
|
||||
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, TRANSFER_STATE + " = ?", new String[] {String.valueOf(TRANSFER_PROGRESS_STARTED)}, null, null, null);
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
parts.add(getPart(cursor));
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
private PartId insertPart(MasterSecretUnion masterSecret, PduPart part, long mmsId, Bitmap thumbnail) throws MmsException {
|
||||
Log.w(TAG, "inserting part to mms " + mmsId);
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
@ -472,7 +501,7 @@ public class PartDatabase extends Database {
|
||||
Pair<File, Long> partData = writePartData(masterSecret, part, data);
|
||||
|
||||
part.setContentDisposition(new byte[0]);
|
||||
part.setInProgress(false);
|
||||
part.setTransferProgress(TRANSFER_PROGRESS_DONE);
|
||||
|
||||
ContentValues values = getContentValuesForPart(part);
|
||||
|
||||
@ -492,13 +521,23 @@ public class PartDatabase extends Database {
|
||||
ContentValues values = new ContentValues(1);
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
part.setInProgress(false);
|
||||
values.put(IN_PROGRESS, false);
|
||||
part.setTransferProgress(TRANSFER_PROGRESS_DONE);
|
||||
values.put(TRANSFER_STATE, TRANSFER_PROGRESS_DONE);
|
||||
database.update(TABLE_NAME, values, PART_ID_WHERE, part.getPartId().toStrings());
|
||||
|
||||
notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId));
|
||||
}
|
||||
|
||||
public void setTransferState(long messageId, @NonNull PartId partId, int transferState) {
|
||||
final ContentValues values = new ContentValues(1);
|
||||
final SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
values.put(TRANSFER_STATE, transferState);
|
||||
database.update(TABLE_NAME, values, PART_ID_WHERE, partId.toStrings());
|
||||
notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId));
|
||||
ApplicationContext.getInstance(context).notifyMediaControlEvent();
|
||||
}
|
||||
|
||||
public void updatePartData(MasterSecret masterSecret, PduPart part, InputStream data)
|
||||
throws MmsException
|
||||
{
|
||||
|
@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.database.PartDatabase;
|
||||
import org.thoughtcrime.securesms.database.PartDatabase.PartId;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
|
||||
import org.thoughtcrime.securesms.jobs.requirements.MediaNetworkRequirement;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.jobqueue.JobParameters;
|
||||
@ -26,7 +27,6 @@ import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@ -35,50 +35,49 @@ import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
|
||||
public class AttachmentDownloadJob extends MasterSecretJob implements InjectableType {
|
||||
|
||||
private static final String TAG = AttachmentDownloadJob.class.getSimpleName();
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TAG = AttachmentDownloadJob.class.getSimpleName();
|
||||
|
||||
@Inject transient TextSecureMessageReceiver messageReceiver;
|
||||
|
||||
private final long messageId;
|
||||
private final long partRowId;
|
||||
private final long partUniqueId;
|
||||
|
||||
public AttachmentDownloadJob(Context context, long messageId) {
|
||||
public AttachmentDownloadJob(Context context, long messageId, PartId partId) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withGroupId(AttachmentDownloadJob.class.getCanonicalName())
|
||||
.withRequirement(new MasterSecretRequirement(context))
|
||||
.withRequirement(new NetworkRequirement(context))
|
||||
.withRequirement(new MediaNetworkRequirement(context, messageId, partId))
|
||||
.withPersistence()
|
||||
.create());
|
||||
|
||||
this.messageId = messageId;
|
||||
this.messageId = messageId;
|
||||
this.partRowId = partId.getRowId();
|
||||
this.partUniqueId = partId.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdded() {}
|
||||
public void onAdded() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws IOException {
|
||||
PartDatabase database = DatabaseFactory.getPartDatabase(context);
|
||||
final PartId partId = new PartId(partRowId, partUniqueId);
|
||||
final PduPart part = DatabaseFactory.getPartDatabase(context).getPart(partId);
|
||||
|
||||
Log.w(TAG, "Downloading push parts for: " + messageId);
|
||||
|
||||
List<PduPart> parts = database.getParts(messageId);
|
||||
|
||||
for (PduPart part : parts) {
|
||||
retrievePart(masterSecret, part, messageId);
|
||||
Log.w(TAG, "Got part: " + part.getPartId());
|
||||
}
|
||||
Log.w(TAG, "Downloading push part " + partId);
|
||||
|
||||
retrievePart(masterSecret, part, messageId);
|
||||
MessageNotifier.updateNotification(context, masterSecret);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
PartDatabase database = DatabaseFactory.getPartDatabase(context);
|
||||
List<PduPart> parts = database.getParts(messageId);
|
||||
|
||||
for (PduPart part : parts) {
|
||||
markFailed(messageId, part, part.getPartId());
|
||||
}
|
||||
final PartId partId = new PartId(partRowId, partUniqueId);
|
||||
final PduPart part = DatabaseFactory.getPartDatabase(context).getPart(partId);
|
||||
markFailed(messageId, part, part.getPartId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,9 +58,11 @@ import org.whispersystems.textsecure.api.messages.multidevice.SentTranscriptMess
|
||||
import org.whispersystems.textsecure.api.messages.multidevice.TextSecureSyncMessage;
|
||||
import org.whispersystems.textsecure.api.push.TextSecureAddress;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
|
||||
public class PushDecryptJob extends ContextJob {
|
||||
|
||||
@ -252,11 +254,14 @@ public class PushDecryptJob extends ContextJob {
|
||||
message.getGroupInfo(),
|
||||
message.getAttachments());
|
||||
|
||||
Pair<Long, Long> messageAndThreadId = database.insertSecureDecryptedMessageInbox(masterSecret, mediaMessage, -1);
|
||||
Pair<Long, Long> messageAndThreadId = database.insertSecureDecryptedMessageInbox(masterSecret, mediaMessage, -1);
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, messageAndThreadId.first));
|
||||
List<PduPart> parts = DatabaseFactory.getPartDatabase(context).getParts(messageAndThreadId.first);
|
||||
for (PduPart part : parts) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, messageAndThreadId.first, part.getPartId()));
|
||||
}
|
||||
|
||||
if (smsMessageId.isPresent()) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||
@ -284,9 +289,11 @@ public class PushDecryptJob extends ContextJob {
|
||||
database.markAsSent(messageId, "push".getBytes(), 0);
|
||||
database.markAsPush(messageId);
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, messageId));
|
||||
for (PduPart part : DatabaseFactory.getPartDatabase(context).getParts(messageId)) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new AttachmentDownloadJob(context, messageId, part.getPartId()));
|
||||
}
|
||||
|
||||
if (smsMessageId.isPresent()) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteMessage(smsMessageId.get());
|
||||
|
@ -0,0 +1,99 @@
|
||||
package org.thoughtcrime.securesms.jobs.requirements;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.PartDatabase;
|
||||
import org.thoughtcrime.securesms.database.PartDatabase.PartId;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.jobqueue.dependencies.ContextDependent;
|
||||
import org.whispersystems.jobqueue.requirements.Requirement;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import ws.com.google.android.mms.pdu.PduPart;
|
||||
|
||||
public class MediaNetworkRequirement implements Requirement, ContextDependent {
|
||||
private static final long serialVersionUID = 0L;
|
||||
private static final String TAG = MediaNetworkRequirement.class.getSimpleName();
|
||||
|
||||
private transient Context context;
|
||||
|
||||
private final long messageId;
|
||||
private final long partRowId;
|
||||
private final long partUniqueId;
|
||||
|
||||
public MediaNetworkRequirement(Context context, long messageId, PartId partId) {
|
||||
this.context = context;
|
||||
this.messageId = messageId;
|
||||
this.partRowId = partId.getRowId();
|
||||
this.partUniqueId = partId.getUniqueId();
|
||||
}
|
||||
|
||||
@Override public void setContext(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private NetworkInfo getNetworkInfo() {
|
||||
return ServiceUtil.getConnectivityManager(context).getActiveNetworkInfo();
|
||||
}
|
||||
|
||||
public boolean isConnectedWifi() {
|
||||
final NetworkInfo info = getNetworkInfo();
|
||||
return info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_WIFI;
|
||||
}
|
||||
|
||||
public boolean isConnectedMobile() {
|
||||
final NetworkInfo info = getNetworkInfo();
|
||||
return info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_MOBILE;
|
||||
}
|
||||
|
||||
public boolean isConnectedRoaming() {
|
||||
final NetworkInfo info = getNetworkInfo();
|
||||
return info != null && info.isConnected() && info.isRoaming() && info.getType() == ConnectivityManager.TYPE_MOBILE;
|
||||
}
|
||||
|
||||
private @NonNull Set<String> getAllowedAutoDownloadTypes() {
|
||||
if (isConnectedWifi()) {
|
||||
return TextSecurePreferences.getWifiMediaDownloadAllowed(context);
|
||||
} else if (isConnectedRoaming()) {
|
||||
return TextSecurePreferences.getRoamingMediaDownloadAllowed(context);
|
||||
} else if (isConnectedMobile()) {
|
||||
return TextSecurePreferences.getMobileMediaDownloadAllowed(context);
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPresent() {
|
||||
final PartId partId = new PartId(partRowId, partUniqueId);
|
||||
final PartDatabase db = DatabaseFactory.getPartDatabase(context);
|
||||
final PduPart part = db.getPart(partId);
|
||||
if (part == null) {
|
||||
Log.w(TAG, "part was null");
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.w(TAG, "part transfer progress is " + part.getTransferProgress());
|
||||
switch (part.getTransferProgress()) {
|
||||
case PartDatabase.TRANSFER_PROGRESS_STARTED:
|
||||
return true;
|
||||
case PartDatabase.TRANSFER_PROGRESS_AUTO_PENDING:
|
||||
final Set<String> allowedTypes = getAllowedAutoDownloadTypes();
|
||||
final boolean isAllowed = allowedTypes.contains(MediaUtil.getDiscreteMimeType(part));
|
||||
|
||||
if (isAllowed) db.setTransferState(messageId, partId, PartDatabase.TRANSFER_PROGRESS_STARTED);
|
||||
return isAllowed;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.thoughtcrime.securesms.jobs.requirements;
|
||||
|
||||
import org.whispersystems.jobqueue.requirements.RequirementListener;
|
||||
import org.whispersystems.jobqueue.requirements.RequirementProvider;
|
||||
|
||||
public class MediaNetworkRequirementProvider implements RequirementProvider {
|
||||
|
||||
private RequirementListener listener;
|
||||
|
||||
public void notifyMediaControlEvent() {
|
||||
if (listener != null) listener.onRequirementStatusChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListener(RequirementListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
package org.thoughtcrime.securesms.mms;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.AsymmetricMasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterCipher;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUnion;
|
||||
import org.thoughtcrime.securesms.crypto.MediaKey;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.database.PartDatabase;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libaxolotl.util.guava.Optional;
|
||||
@ -83,7 +81,7 @@ public class IncomingMediaMessage {
|
||||
media.setName(Util.toIsoBytes(relay.get()));
|
||||
}
|
||||
|
||||
media.setInProgress(true);
|
||||
media.setTransferProgress(PartDatabase.TRANSFER_PROGRESS_AUTO_PENDING);
|
||||
|
||||
this.body.addPart(media);
|
||||
}
|
||||
|
@ -78,6 +78,10 @@ public abstract class Slide {
|
||||
return part.isInProgress();
|
||||
}
|
||||
|
||||
public long getTransferProgress() {
|
||||
return part.getTransferProgress();
|
||||
}
|
||||
|
||||
public @DrawableRes int getPlaceholderRes(Theme theme) {
|
||||
throw new AssertionError("getPlaceholderRes() called for non-drawable slide");
|
||||
}
|
||||
@ -111,7 +115,7 @@ public abstract class Slide {
|
||||
this.hasImage() == that.hasImage() &&
|
||||
this.hasVideo() == that.hasVideo() &&
|
||||
this.isDraft() == that.isDraft() &&
|
||||
this.isInProgress() == that.isInProgress() &&
|
||||
this.getTransferProgress() == that.getTransferProgress() &&
|
||||
Util.equals(this.getUri(), that.getUri()) &&
|
||||
Util.equals(this.getThumbnailUri(), that.getThumbnailUri());
|
||||
}
|
||||
@ -119,7 +123,7 @@ public abstract class Slide {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Util.hashCode(getContentType(), hasAudio(), hasImage(),
|
||||
hasVideo(), isDraft(), getUri(), getThumbnailUri());
|
||||
hasVideo(), isDraft(), getUri(), getThumbnailUri(), getTransferProgress());
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,143 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.MultiSelectListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.Preference.OnPreferenceChangeListener;
|
||||
import android.support.v4.preference.PreferenceFragment;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.afollestad.materialdialogs.AlertDialogWrapper;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Trimmer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ChatsPreferenceFragment extends PreferenceFragment {
|
||||
private static final String TAG = ChatsPreferenceFragment.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
addPreferencesFromResource(R.xml.preferences_chats);
|
||||
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF)
|
||||
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF)
|
||||
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF)
|
||||
.setOnPreferenceChangeListener(new MediaDownloadChangeListener());
|
||||
|
||||
findPreference(TextSecurePreferences.THREAD_TRIM_NOW)
|
||||
.setOnPreferenceClickListener(new TrimNowClickListener());
|
||||
findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH)
|
||||
.setOnPreferenceChangeListener(new TrimLengthValidationListener());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((ApplicationPreferencesActivity)getActivity()).getSupportActionBar().setTitle(R.string.preferences__chats);
|
||||
setMediaDownloadSummaries();
|
||||
}
|
||||
|
||||
private void setMediaDownloadSummaries() {
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_MOBILE_PREF)
|
||||
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getMobileMediaDownloadAllowed(getActivity())));
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_WIFI_PREF)
|
||||
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getWifiMediaDownloadAllowed(getActivity())));
|
||||
findPreference(TextSecurePreferences.MEDIA_DOWNLOAD_ROAMING_PREF)
|
||||
.setSummary(getSummaryForMediaPreference(TextSecurePreferences.getRoamingMediaDownloadAllowed(getActivity())));
|
||||
}
|
||||
|
||||
private CharSequence getSummaryForMediaPreference(Set<String> allowedNetworks) {
|
||||
String[] keys = getResources().getStringArray(R.array.pref_media_download_entries);
|
||||
String[] values = getResources().getStringArray(R.array.pref_media_download_values);
|
||||
List<String> outValues = new ArrayList<>(allowedNetworks.size());
|
||||
|
||||
for (int i=0; i < keys.length; i++) {
|
||||
if (allowedNetworks.contains(keys[i])) outValues.add(values[i]);
|
||||
}
|
||||
|
||||
return outValues.isEmpty() ? getResources().getString(R.string.preferences__none)
|
||||
: TextUtils.join(", ", outValues);
|
||||
}
|
||||
|
||||
private class TrimNowClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
final int threadLengthLimit = TextSecurePreferences.getThreadTrimLength(getActivity());
|
||||
AlertDialogWrapper.Builder builder = new AlertDialogWrapper.Builder(getActivity());
|
||||
builder.setTitle(R.string.ApplicationPreferencesActivity_delete_all_old_messages_now);
|
||||
builder.setMessage(getString(R.string.ApplicationPreferencesActivity_are_you_sure_you_would_like_to_immediately_trim_all_conversation_threads_to_the_s_most_recent_messages,
|
||||
threadLengthLimit));
|
||||
builder.setPositiveButton(R.string.ApplicationPreferencesActivity_delete,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Trimmer.trimAllThreads(getActivity(), threadLengthLimit);
|
||||
}
|
||||
});
|
||||
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class MediaDownloadChangeListener implements OnPreferenceChangeListener {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
Log.w(TAG, "onPreferenceChange");
|
||||
preference.setSummary(getSummaryForMediaPreference((Set<String>)newValue));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class TrimLengthValidationListener implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
public TrimLengthValidationListener() {
|
||||
EditTextPreference preference = (EditTextPreference)findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH);
|
||||
preference.setSummary(getString(R.string.ApplicationPreferencesActivity_messages_per_conversation, preference.getText()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue == null || ((String)newValue).trim().length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Integer.parseInt((String)newValue);
|
||||
} catch (NumberFormatException nfe) {
|
||||
Log.w(TAG, nfe);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Integer.parseInt((String)newValue) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
preference.setSummary(getString(R.string.ApplicationPreferencesActivity_messages_per_conversation, newValue));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static CharSequence getSummary(Context context) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
package org.thoughtcrime.securesms.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.Preference;
|
||||
import android.support.v4.preference.PreferenceFragment;
|
||||
import android.util.Log;
|
||||
|
||||
import com.afollestad.materialdialogs.AlertDialogWrapper;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationPreferencesActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Trimmer;
|
||||
|
||||
public class StoragePreferenceFragment extends PreferenceFragment {
|
||||
private static final String TAG = StoragePreferenceFragment.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle paramBundle) {
|
||||
super.onCreate(paramBundle);
|
||||
addPreferencesFromResource(R.xml.preferences_storage);
|
||||
|
||||
this.findPreference(TextSecurePreferences.THREAD_TRIM_NOW)
|
||||
.setOnPreferenceClickListener(new TrimNowClickListener());
|
||||
this.findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH)
|
||||
.setOnPreferenceChangeListener(new TrimLengthValidationListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
((ApplicationPreferencesActivity) getActivity()).getSupportActionBar().setTitle(R.string.preferences__delete_old_messages);
|
||||
}
|
||||
|
||||
private class TrimNowClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
final int threadLengthLimit = TextSecurePreferences.getThreadTrimLength(getActivity());
|
||||
AlertDialogWrapper.Builder builder = new AlertDialogWrapper.Builder(getActivity());
|
||||
builder.setTitle(R.string.ApplicationPreferencesActivity_delete_all_old_messages_now);
|
||||
builder.setMessage(getString(R.string.ApplicationPreferencesActivity_are_you_sure_you_would_like_to_immediately_trim_all_conversation_threads_to_the_s_most_recent_messages,
|
||||
threadLengthLimit));
|
||||
builder.setPositiveButton(R.string.ApplicationPreferencesActivity_delete,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Trimmer.trimAllThreads(getActivity(), threadLengthLimit);
|
||||
}
|
||||
});
|
||||
|
||||
builder.setNegativeButton(android.R.string.cancel, null);
|
||||
builder.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class TrimLengthValidationListener implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
public TrimLengthValidationListener() {
|
||||
EditTextPreference preference = (EditTextPreference)findPreference(TextSecurePreferences.THREAD_TRIM_LENGTH);
|
||||
preference.setSummary(getString(R.string.ApplicationPreferencesActivity_messages_per_conversation, preference.getText()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue == null || ((String)newValue).trim().length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
Integer.parseInt((String)newValue);
|
||||
} catch (NumberFormatException nfe) {
|
||||
Log.w(TAG, nfe);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Integer.parseInt((String)newValue) < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
preference.setSummary(getString(R.string.ApplicationPreferencesActivity_messages_per_conversation, newValue));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static CharSequence getSummary(Context context) {
|
||||
final int onCapsResId = R.string.ApplicationPreferencesActivity_On;
|
||||
final int offCapsResId = R.string.ApplicationPreferencesActivity_Off;
|
||||
|
||||
return context.getString(TextSecurePreferences.isThreadLengthTrimmingEnabled(context) ? onCapsResId : offCapsResId);
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.util;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.webkit.MimeTypeMap;
|
||||
@ -108,6 +110,11 @@ public class MediaUtil {
|
||||
return ContentType.isVideoType(Util.toIsoString(part.getContentType()));
|
||||
}
|
||||
|
||||
public static @Nullable String getDiscreteMimeType(@NonNull PduPart part) {
|
||||
final String[] sections = (Util.toIsoString(part.getContentType()).split("/", 2));
|
||||
return sections.length > 1 ? sections[0] : null;
|
||||
}
|
||||
|
||||
public static class ThumbnailData {
|
||||
Bitmap bitmap;
|
||||
float aspectRatio;
|
||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
@ -13,4 +14,8 @@ public class ServiceUtil {
|
||||
public static WindowManager getWindowManager(Context context) {
|
||||
return (WindowManager) context.getSystemService(Activity.WINDOW_SERVICE);
|
||||
}
|
||||
|
||||
public static ConnectivityManager getConnectivityManager(Context context) {
|
||||
return (ConnectivityManager) context.getSystemService(Activity.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,19 @@ import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.ArrayRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.preferences.NotificationPrivacyPreference;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class TextSecurePreferences {
|
||||
|
||||
@ -74,6 +82,10 @@ public class TextSecurePreferences {
|
||||
public static final String REPEAT_ALERTS_PREF = "pref_repeat_alerts";
|
||||
public static final String NOTIFICATION_PRIVACY_PREF = "pref_notification_privacy";
|
||||
|
||||
public static final String MEDIA_DOWNLOAD_MOBILE_PREF = "pref_media_download_mobile";
|
||||
public static final String MEDIA_DOWNLOAD_WIFI_PREF = "pref_media_download_wifi";
|
||||
public static final String MEDIA_DOWNLOAD_ROAMING_PREF = "pref_media_download_roaming";
|
||||
|
||||
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
|
||||
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
|
||||
}
|
||||
@ -433,6 +445,25 @@ public class TextSecurePreferences {
|
||||
return Integer.parseInt(getStringPreference(context, THREAD_TRIM_LENGTH, "500"));
|
||||
}
|
||||
|
||||
public static @NonNull Set<String> getMobileMediaDownloadAllowed(Context context) {
|
||||
return getMediaDownloadAllowed(context, MEDIA_DOWNLOAD_MOBILE_PREF, R.array.pref_media_download_mobile_data_default);
|
||||
}
|
||||
|
||||
public static @NonNull Set<String> getWifiMediaDownloadAllowed(Context context) {
|
||||
return getMediaDownloadAllowed(context, MEDIA_DOWNLOAD_WIFI_PREF, R.array.pref_media_download_wifi_default);
|
||||
}
|
||||
|
||||
public static @NonNull Set<String> getRoamingMediaDownloadAllowed(Context context) {
|
||||
return getMediaDownloadAllowed(context, MEDIA_DOWNLOAD_ROAMING_PREF, R.array.pref_media_download_roaming_default);
|
||||
}
|
||||
|
||||
private static @NonNull Set<String> getMediaDownloadAllowed(Context context, String key, @ArrayRes int defaultValuesRes) {
|
||||
return getStringSetPreference(context,
|
||||
key,
|
||||
new HashSet<>(Arrays.asList(context.getResources().getStringArray(defaultValuesRes))));
|
||||
}
|
||||
|
||||
|
||||
public static void setBooleanPreference(Context context, String key, boolean value) {
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putBoolean(key, value).apply();
|
||||
}
|
||||
@ -468,4 +499,8 @@ public class TextSecurePreferences {
|
||||
private static void setLongPreference(Context context, String key, long value) {
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putLong(key, value).apply();
|
||||
}
|
||||
|
||||
private static Set<String> getStringSetPreference(Context context, String key, Set<String> defaultValues) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getStringSet(key, defaultValues);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import android.os.Build.VERSION_CODES;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Telephony;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.Spannable;
|
||||
@ -119,7 +120,7 @@ public class Util {
|
||||
return spanned;
|
||||
}
|
||||
|
||||
public static String toIsoString(byte[] bytes) {
|
||||
public static @NonNull String toIsoString(byte[] bytes) {
|
||||
try {
|
||||
return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
|
@ -134,8 +134,9 @@ public class PduPart {
|
||||
|
||||
private long rowId = -1;
|
||||
private long uniqueId = -1;
|
||||
private long mmsId = -1;
|
||||
private boolean isEncrypted;
|
||||
private boolean isInProgress;
|
||||
private int transferProgress;
|
||||
private long dataSize;
|
||||
private Bitmap thumbnail;
|
||||
|
||||
@ -163,13 +164,17 @@ public class PduPart {
|
||||
return this.dataSize;
|
||||
}
|
||||
|
||||
|
||||
public void setInProgress(boolean isInProgress) {
|
||||
this.isInProgress = isInProgress;
|
||||
public boolean isInProgress() {
|
||||
return transferProgress != PartDatabase.TRANSFER_PROGRESS_DONE &&
|
||||
transferProgress != PartDatabase.TRANSFER_PROGRESS_FAILED;
|
||||
}
|
||||
|
||||
public boolean isInProgress() {
|
||||
return isInProgress;
|
||||
public void setTransferProgress(int transferProgress) {
|
||||
this.transferProgress = transferProgress;
|
||||
}
|
||||
|
||||
public int getTransferProgress() {
|
||||
return transferProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -475,5 +480,13 @@ public class PduPart {
|
||||
public void setUniqueId(long uniqueId) {
|
||||
this.uniqueId = uniqueId;
|
||||
}
|
||||
|
||||
public long getMmsId() {
|
||||
return mmsId;
|
||||
}
|
||||
|
||||
public void setMmsId(long mmsId) {
|
||||
this.mmsId = mmsId;
|
||||
}
|
||||
}
|
||||
|
||||
|