diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 46549e07ce..fe0ea8e29e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -97,6 +97,10 @@ android:allowBackup="false" android:theme="@style/TextSecure.LightTheme"> + + diff --git a/build.gradle b/build.gradle index f316abfed3..da041195fa 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,9 @@ repositories { dependencies { compile 'me.leolin:ShortcutBadger:1.1.0-WS1' compile 'se.emilsjolander:stickylistheaders:2.7.0' - compile 'com.google.android.gms:play-services-base:6.5.87' + compile 'com.google.android.gms:play-services-gcm:8.1.0' + compile 'com.google.android.gms:play-services-maps:8.1.0' + compile 'com.google.android.gms:play-services-location:8.1.0' compile 'com.jpardogo.materialtabstrip:library:1.0.9' compile 'org.w3c:smil:1.0.0' compile 'org.apache.httpcomponents:httpclient-android:4.3.5' @@ -97,7 +99,9 @@ dependencyVerification { verify = [ 'me.leolin:ShortcutBadger:3142d017234bfa0cdd69ccded7cc5ea63f13b97574803c8c616c9bbeaad33ad9', 'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb', - 'com.google.android.gms:play-services-base:832cb6b3130e871db6a412c4ab585656dbcc5e7948101f190186757785703f75', + 'com.google.android.gms:play-services-gcm:757ecd2c837ac81c98f4cc7dc783e7454c6d0506f6cc66b10417126b675248c9', + 'com.google.android.gms:play-services-maps:c58a9d98a98889fb0b27f78100f2d9341ed7722db24ccf832df62b6e8ce1b42e', + 'com.google.android.gms:play-services-location:8226f778aa86bd15b9143f62425262cc53d64021990f62eb1aaec108d4e25f35', 'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa', 'org.w3c:smil:085dc40f2bb249651578bfa07499fd08b16ad0886dbe2c4078586a408da62f9b', 'org.apache.httpcomponents:httpclient-android:6f56466a9bd0d42934b90bfbfe9977a8b654c058bf44a12bdc2877c4e1f033f1', @@ -125,12 +129,14 @@ dependencyVerification { 'org.whispersystems:textsecure-android:aec5fc59952d9f5482491091091687816f46be1144342a0244f48fd55d6ab393', 'com.h6ah4i.android.compat:mulsellistprefcompat:47167c5cb796de1a854788e9ff318358e36c8fb88123baaa6e38fb78511dfabe', 'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259', + 'com.google.android.gms:play-services-base:ef36e50fa5c0415ed41f74dd399a889efd2fa327c449036e140c7c3786aa0e1f', 'com.android.support:support-annotations:104f353b53d5dd8d64b2f77eece4b37f6b961de9732eb6b706395e91033ec70a', 'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a', 'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f', 'org.whispersystems:textsecure-java:b407ca6d1430204dfabf38e27db22d5177409072a9668238bd1877de7676ad3f', 'org.whispersystems:axolotl-android:40d3db5004a84749a73f68d2f0d01b2ae35a73c54df96d8c6c6723b96efb6fc0', + 'com.google.android.gms:play-services-basement:e1d29b21e02fd2a63e5a31807415cbb17a59568e27e3254181c01ffae10659bf', 'com.googlecode.libphonenumber:libphonenumber:9625de9d2270e9a280ff4e6d9ef3106573fb4828773fd32c9b7614f4e17d2811', 'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74', 'com.squareup.okhttp:okhttp:89b7f63e2e5b6c410266abc14f50fe52ea8d2d8a57260829e499b1cd9f0e61af', diff --git a/res/drawable-hdpi/ic_location_on_white_36dp.png b/res/drawable-hdpi/ic_location_on_white_36dp.png new file mode 100644 index 0000000000..b345cffca4 Binary files /dev/null and b/res/drawable-hdpi/ic_location_on_white_36dp.png differ diff --git a/res/drawable-mdpi/ic_location_on_white_36dp.png b/res/drawable-mdpi/ic_location_on_white_36dp.png new file mode 100644 index 0000000000..7c281c3f52 Binary files /dev/null and b/res/drawable-mdpi/ic_location_on_white_36dp.png differ diff --git a/res/drawable-xhdpi/ic_location_on_white_36dp.png b/res/drawable-xhdpi/ic_location_on_white_36dp.png new file mode 100644 index 0000000000..078b10d4fb Binary files /dev/null and b/res/drawable-xhdpi/ic_location_on_white_36dp.png differ diff --git a/res/drawable-xxhdpi/ic_location_on_white_36dp.png b/res/drawable-xxhdpi/ic_location_on_white_36dp.png new file mode 100644 index 0000000000..633bc56957 Binary files /dev/null and b/res/drawable-xxhdpi/ic_location_on_white_36dp.png differ diff --git a/res/drawable-xxxhdpi/ic_location_on_white_36dp.png b/res/drawable-xxxhdpi/ic_location_on_white_36dp.png new file mode 100644 index 0000000000..42ab08cf74 Binary files /dev/null and b/res/drawable-xxxhdpi/ic_location_on_white_36dp.png differ diff --git a/res/layout/attachment_type_selector.xml b/res/layout/attachment_type_selector.xml index a3780d8894..23df762566 100644 --- a/res/layout/attachment_type_selector.xml +++ b/res/layout/attachment_type_selector.xml @@ -143,6 +143,29 @@ android:gravity="center" android:orientation="vertical"> + + + + + + + + diff --git a/res/layout/conversation_activity.xml b/res/layout/conversation_activity.xml index c43f3a788e..ca51f733cf 100644 --- a/res/layout/conversation_activity.xml +++ b/res/layout/conversation_activity.xml @@ -46,6 +46,13 @@ android:layout_height="wrap_content" android:layout_gravity="center"> + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 040df4bb7e..e76234b5a8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -617,6 +617,7 @@ Video Contact Camera + Location Old passphrase diff --git a/src/org/thoughtcrime/securesms/ConversationActivity.java b/src/org/thoughtcrime/securesms/ConversationActivity.java index 0f7d7f77b5..8cddd77e63 100644 --- a/src/org/thoughtcrime/securesms/ConversationActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationActivity.java @@ -56,6 +56,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import com.google.android.gms.location.places.Place; +import com.google.android.gms.location.places.ui.PlacePicker; import com.google.protobuf.ByteString; import org.thoughtcrime.redphone.RedPhone; @@ -174,6 +176,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity private static final int GROUP_EDIT = 5; private static final int TAKE_PHOTO = 6; private static final int ADD_CONTACT = 7; + private static final int PICK_LOCATION = 8; private MasterSecret masterSecret; protected ComposeText composeText; @@ -312,7 +315,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity } @Override - public void onActivityResult(int reqCode, int resultCode, Intent data) { + public void onActivityResult(final int reqCode, int resultCode, Intent data) { Log.w(TAG, "onActivityResult called: " + reqCode + ", " + resultCode + " , " + data); super.onActivityResult(reqCode, resultCode, data); @@ -349,6 +352,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity recipients.addListener(this); fragment.reloadList(); break; + case PICK_LOCATION: + attachmentManager.setLocation(masterSecret, PlacePicker.getPlace(data, this), getCurrentMediaConstraints()); + break; } } @@ -998,6 +1004,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity AttachmentManager.selectAudio(this, PICK_AUDIO); break; case AttachmentTypeSelectorAdapter.ADD_CONTACT_INFO: AttachmentManager.selectContactInfo(this, PICK_CONTACT_INFO); break; + case AttachmentTypeSelector.ADD_LOCATION: + AttachmentManager.selectLocation(this, PICK_LOCATION); break; case AttachmentTypeSelectorAdapter.TAKE_PHOTO: attachmentManager.capturePhoto(this, TAKE_PHOTO); break; } diff --git a/src/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java b/src/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java index 9415c5c48f..e37605d7a5 100644 --- a/src/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java +++ b/src/org/thoughtcrime/securesms/components/AttachmentTypeSelector.java @@ -33,6 +33,7 @@ public class AttachmentTypeSelector extends PopupWindow { public static final int ADD_SOUND = 3; public static final int ADD_CONTACT_INFO = 4; public static final int TAKE_PHOTO = 5; + public static final int ADD_LOCATION = 6; private static final int ANIMATION_DURATION = 300; @@ -43,6 +44,7 @@ public class AttachmentTypeSelector extends PopupWindow { private final @NonNull ImageView videoButton; private final @NonNull ImageView contactButton; private final @NonNull ImageView cameraButton; + private final @NonNull ImageView locationButton; private final @NonNull ImageView closeButton; private @Nullable View currentAnchor; @@ -54,21 +56,27 @@ public class AttachmentTypeSelector extends PopupWindow { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.attachment_type_selector, null, true); - this.listener = listener; - this.imageButton = ViewUtil.findById(layout, R.id.gallery_button); - this.audioButton = ViewUtil.findById(layout, R.id.audio_button); - this.videoButton = ViewUtil.findById(layout, R.id.video_button); - this.contactButton = ViewUtil.findById(layout, R.id.contact_button); - this.cameraButton = ViewUtil.findById(layout, R.id.camera_button); - this.closeButton = ViewUtil.findById(layout, R.id.close_button); + this.listener = listener; + this.imageButton = ViewUtil.findById(layout, R.id.gallery_button); + this.audioButton = ViewUtil.findById(layout, R.id.audio_button); + this.videoButton = ViewUtil.findById(layout, R.id.video_button); + this.contactButton = ViewUtil.findById(layout, R.id.contact_button); + this.cameraButton = ViewUtil.findById(layout, R.id.camera_button); + this.closeButton = ViewUtil.findById(layout, R.id.close_button); + this.locationButton = ViewUtil.findById(layout, R.id.location_button); this.imageButton.setOnClickListener(new PropagatingClickListener(ADD_IMAGE)); this.audioButton.setOnClickListener(new PropagatingClickListener(ADD_SOUND)); this.videoButton.setOnClickListener(new PropagatingClickListener(ADD_VIDEO)); this.contactButton.setOnClickListener(new PropagatingClickListener(ADD_CONTACT_INFO)); this.cameraButton.setOnClickListener(new PropagatingClickListener(TAKE_PHOTO)); + this.locationButton.setOnClickListener(new PropagatingClickListener(ADD_LOCATION)); this.closeButton.setOnClickListener(new CloseClickListener()); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { + this.locationButton.setVisibility(View.INVISIBLE); + } + setContentView(layout); setWidth(LinearLayout.LayoutParams.MATCH_PARENT); setHeight(LinearLayout.LayoutParams.WRAP_CONTENT); diff --git a/src/org/thoughtcrime/securesms/components/location/SignalMapView.java b/src/org/thoughtcrime/securesms/components/location/SignalMapView.java new file mode 100644 index 0000000000..067af7bb85 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/location/SignalMapView.java @@ -0,0 +1,98 @@ +package org.thoughtcrime.securesms.components.location; + +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Build; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.android.gms.location.places.Place; +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.MapView; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.model.MarkerOptions; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.ViewUtil; +import org.thoughtcrime.securesms.util.concurrent.ListenableFuture; +import org.thoughtcrime.securesms.util.concurrent.SettableFuture; + +public class SignalMapView extends LinearLayout { + + private MapView mapView; + private ImageView imageView; + private TextView textView; + + public SignalMapView(Context context) { + this(context, null); + } + + public SignalMapView(Context context, AttributeSet attrs) { + super(context, attrs); + initialize(context); + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public SignalMapView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(context); + } + + private void initialize(Context context) { + setOrientation(LinearLayout.VERTICAL); + LayoutInflater.from(context).inflate(R.layout.signal_map_view, this, true); + + this.mapView = ViewUtil.findById(this, R.id.map_view); + this.imageView = ViewUtil.findById(this, R.id.image_view); + this.textView = ViewUtil.findById(this, R.id.address_view); + } + + public ListenableFuture display(final SignalPlace place) { + final SettableFuture future = new SettableFuture<>(); + + this.mapView.onCreate(null); + this.mapView.onResume(); + + this.mapView.setVisibility(View.VISIBLE); + this.imageView.setVisibility(View.GONE); + + this.mapView.getMapAsync(new OnMapReadyCallback() { + @Override + public void onMapReady(final GoogleMap googleMap) { + googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(place.getLatLong(), 13)); + googleMap.addMarker(new MarkerOptions().position(place.getLatLong())); + googleMap.setBuildingsEnabled(true); + googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); + googleMap.getUiSettings().setAllGesturesEnabled(false); + googleMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { + @Override + public void onMapLoaded() { + googleMap.snapshot(new GoogleMap.SnapshotReadyCallback() { + @Override + public void onSnapshotReady(Bitmap bitmap) { + future.set(bitmap); + imageView.setImageBitmap(bitmap); + imageView.setVisibility(View.VISIBLE); + mapView.setVisibility(View.GONE); + mapView.onPause(); + mapView.onDestroy(); + } + }); + } + }); + } + }); + + this.textView.setText(place.getDescription()); + + return future; + } + +} diff --git a/src/org/thoughtcrime/securesms/components/location/SignalPlace.java b/src/org/thoughtcrime/securesms/components/location/SignalPlace.java new file mode 100644 index 0000000000..c83a3c8bd7 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/location/SignalPlace.java @@ -0,0 +1,37 @@ +package org.thoughtcrime.securesms.components.location; + +import android.text.TextUtils; + +import com.google.android.gms.location.places.Place; +import com.google.android.gms.maps.model.LatLng; + +public class SignalPlace { + + private static final String URL = "https://maps.google.com/maps?q=%s,%s"; + + private final Place place; + + public SignalPlace(Place place) { + this.place = place; + } + + public LatLng getLatLong() { + return place.getLatLng(); + } + + public String getDescription() { + String description = ""; + + if (!TextUtils.isEmpty(place.getName())) { + description += (place.getName() + "\n"); + } + + if (!TextUtils.isEmpty(place.getAddress())) { + description += (place.getAddress() + "\n"); + } + + description += String.format(URL, place.getLatLng().latitude, place.getLatLng().longitude); + + return description; + } +} diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java index a75ac3eb40..55a89a3a34 100644 --- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -20,6 +20,7 @@ import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -32,15 +33,25 @@ import android.util.Log; import android.view.View; import android.widget.Toast; +import com.google.android.gms.common.GooglePlayServicesNotAvailableException; +import com.google.android.gms.common.GooglePlayServicesRepairableException; +import com.google.android.gms.location.places.Place; +import com.google.android.gms.location.places.ui.PlacePicker; + import org.thoughtcrime.securesms.MediaPreviewActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.AudioView; import org.thoughtcrime.securesms.components.RemovableMediaView; +import org.thoughtcrime.securesms.components.location.SignalMapView; import org.thoughtcrime.securesms.components.ThumbnailView; +import org.thoughtcrime.securesms.components.location.SignalPlace; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.providers.PersistentBlobProvider; +import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.MediaUtil; 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.ListenableFuture.Listener; import org.whispersystems.libaxolotl.util.guava.Optional; @@ -61,6 +72,7 @@ public class AttachmentManager { private final @NonNull RemovableMediaView removableMediaView; private final @NonNull ThumbnailView thumbnail; private final @NonNull AudioView audioView; + private final @NonNull SignalMapView mapView; private final @NonNull AttachmentListener attachmentListener; private @NonNull List garbage = new LinkedList<>(); @@ -71,6 +83,7 @@ public class AttachmentManager { this.attachmentView = ViewUtil.findById(activity, R.id.attachment_editor); this.thumbnail = ViewUtil.findById(activity, R.id.attachment_thumbnail); this.audioView = ViewUtil.findById(activity, R.id.attachment_audio); + this.mapView = ViewUtil.findById(activity, R.id.attachment_location); this.removableMediaView = ViewUtil.findById(activity, R.id.removable_media_view); this.context = activity; this.attachmentListener = listener; @@ -134,6 +147,29 @@ public class AttachmentManager { this.slide = Optional.of(slide); } + public void setLocation(@NonNull final MasterSecret masterSecret, + @NonNull final Place place, + @NonNull final MediaConstraints constraints) + { + final SignalPlace signalPlace = new SignalPlace(place); + ListenableFuture future = mapView.display(signalPlace); + + attachmentView.setVisibility(View.VISIBLE); + removableMediaView.display(mapView); + + future.addListener(new AssertedSuccessListener() { + @Override + public void onSuccess(@NonNull Bitmap result) { + byte[] blob = BitmapUtil.toByteArray(result); + Uri uri = PersistentBlobProvider.getInstance(context).create(masterSecret, blob); + LocationSlide locationSlide = new LocationSlide(context, uri, blob.length, signalPlace.getDescription()); + + setSlide(locationSlide); + attachmentListener.onAttachmentChanged(); + } + }); + } + public void setMedia(@NonNull final MasterSecret masterSecret, @NonNull final Uri uri, @NonNull final MediaType mediaType, @@ -218,6 +254,14 @@ public class AttachmentManager { activity.startActivityForResult(intent, requestCode); } + public static void selectLocation(Activity activity, int requestCode) { + try { + activity.startActivityForResult(new PlacePicker.IntentBuilder().build(activity), requestCode); + } catch (GooglePlayServicesRepairableException | GooglePlayServicesNotAvailableException e) { + Log.w(TAG, e); + } + } + private @Nullable Uri getSlideUri() { return slide.isPresent() ? slide.get().getUri() : null; } @@ -310,7 +354,6 @@ public class AttachmentManager { public @NonNull Slide createSlide(@NonNull Context context, @NonNull Uri uri, long dataSize) - throws IOException { switch (this) { case IMAGE: return new ImageSlide(context, uri, dataSize); diff --git a/src/org/thoughtcrime/securesms/mms/AudioSlide.java b/src/org/thoughtcrime/securesms/mms/AudioSlide.java index ab76fee39f..46cb231079 100644 --- a/src/org/thoughtcrime/securesms/mms/AudioSlide.java +++ b/src/org/thoughtcrime/securesms/mms/AudioSlide.java @@ -36,7 +36,7 @@ import ws.com.google.android.mms.pdu.PduPart; public class AudioSlide extends Slide { - public AudioSlide(Context context, Uri uri, long dataSize) throws IOException { + public AudioSlide(Context context, Uri uri, long dataSize) { super(context, constructAttachmentFromUri(context, uri, ContentType.AUDIO_UNSPECIFIED, dataSize)); } diff --git a/src/org/thoughtcrime/securesms/mms/GifSlide.java b/src/org/thoughtcrime/securesms/mms/GifSlide.java index 22b4b410da..614e5ad557 100644 --- a/src/org/thoughtcrime/securesms/mms/GifSlide.java +++ b/src/org/thoughtcrime/securesms/mms/GifSlide.java @@ -19,7 +19,7 @@ public class GifSlide extends ImageSlide { super(context, attachment); } - public GifSlide(Context context, Uri uri, long size) throws IOException { + public GifSlide(Context context, Uri uri, long size) { super(context, constructAttachmentFromUri(context, uri, ContentType.IMAGE_GIF, size)); } diff --git a/src/org/thoughtcrime/securesms/mms/ImageSlide.java b/src/org/thoughtcrime/securesms/mms/ImageSlide.java index e7d8eb46a1..2971086f39 100644 --- a/src/org/thoughtcrime/securesms/mms/ImageSlide.java +++ b/src/org/thoughtcrime/securesms/mms/ImageSlide.java @@ -37,7 +37,7 @@ public class ImageSlide extends Slide { super(context, attachment); } - public ImageSlide(Context context, Uri uri, long size) throws IOException { + public ImageSlide(Context context, Uri uri, long size) { super(context, constructAttachmentFromUri(context, uri, ContentType.IMAGE_JPEG, size)); } diff --git a/src/org/thoughtcrime/securesms/mms/LocationSlide.java b/src/org/thoughtcrime/securesms/mms/LocationSlide.java new file mode 100644 index 0000000000..fc6b113f02 --- /dev/null +++ b/src/org/thoughtcrime/securesms/mms/LocationSlide.java @@ -0,0 +1,25 @@ +package org.thoughtcrime.securesms.mms; + +import android.content.Context; +import android.net.Uri; +import android.support.annotation.NonNull; + +import org.whispersystems.libaxolotl.util.guava.Optional; + +public class LocationSlide extends ImageSlide { + + @NonNull + private final String description; + + public LocationSlide(@NonNull Context context, @NonNull Uri uri, long size, @NonNull String description) + { + super(context, uri, size); + this.description = description; + } + + @Override + @NonNull + public Optional getBody() { + return Optional.of(description); + } +} diff --git a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java index c10850e662..af07384638 100644 --- a/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/OutgoingMediaMessage.java @@ -1,5 +1,7 @@ package org.thoughtcrime.securesms.mms; +import android.text.TextUtils; + import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.recipients.Recipients; @@ -26,7 +28,11 @@ public class OutgoingMediaMessage { public OutgoingMediaMessage(Recipients recipients, SlideDeck slideDeck, String message, long sentTimeMillis, int distributionType) { - this(recipients, message, slideDeck.asAttachments(), sentTimeMillis, distributionType); + this(recipients, + TextUtils.isEmpty(message) ? slideDeck.getBody() : slideDeck.getBody() + "\n\n" + message, + slideDeck.asAttachments(), + sentTimeMillis, + distributionType); } public OutgoingMediaMessage(OutgoingMediaMessage that) { diff --git a/src/org/thoughtcrime/securesms/mms/Slide.java b/src/org/thoughtcrime/securesms/mms/Slide.java index f68e8b4b3d..c0bf65105d 100644 --- a/src/org/thoughtcrime/securesms/mms/Slide.java +++ b/src/org/thoughtcrime/securesms/mms/Slide.java @@ -30,8 +30,6 @@ import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libaxolotl.util.guava.Optional; -import java.io.IOException; - public abstract class Slide { protected final Attachment attachment; @@ -57,6 +55,11 @@ public abstract class Slide { return attachment.getThumbnailUri(); } + @NonNull + public Optional getBody() { + return Optional.absent(); + } + public boolean hasImage() { return false; } @@ -100,7 +103,6 @@ public abstract class Slide { @NonNull Uri uri, @NonNull String defaultMime, long size) - throws IOException { Optional resolvedType = Optional.fromNullable(MediaUtil.getMimeType(context, uri)); return new UriAttachment(uri, resolvedType.or(defaultMime), AttachmentDatabase.TRANSFER_PROGRESS_STARTED, size); diff --git a/src/org/thoughtcrime/securesms/mms/SlideDeck.java b/src/org/thoughtcrime/securesms/mms/SlideDeck.java index 8709494587..65bfefb2df 100644 --- a/src/org/thoughtcrime/securesms/mms/SlideDeck.java +++ b/src/org/thoughtcrime/securesms/mms/SlideDeck.java @@ -17,10 +17,12 @@ package org.thoughtcrime.securesms.mms; import android.content.Context; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.util.MediaUtil; +import org.whispersystems.libaxolotl.util.guava.Optional; import java.util.LinkedList; import java.util.List; @@ -48,6 +50,22 @@ public class SlideDeck { slides.clear(); } + @NonNull + public String getBody() { + String body = ""; + + for (Slide slide : slides) { + Optional slideBody = slide.getBody(); + + if (slideBody.isPresent()) { + body = slideBody.get(); + } + } + + return body; + } + + @NonNull public List asAttachments() { List attachments = new LinkedList<>(); diff --git a/src/org/thoughtcrime/securesms/mms/VideoSlide.java b/src/org/thoughtcrime/securesms/mms/VideoSlide.java index 63be2dcc79..8c2000b42e 100644 --- a/src/org/thoughtcrime/securesms/mms/VideoSlide.java +++ b/src/org/thoughtcrime/securesms/mms/VideoSlide.java @@ -34,7 +34,7 @@ import ws.com.google.android.mms.pdu.PduPart; public class VideoSlide extends Slide { - public VideoSlide(Context context, Uri uri, long dataSize) throws IOException { + public VideoSlide(Context context, Uri uri, long dataSize) { super(context, constructAttachmentFromUri(context, uri, ContentType.VIDEO_UNSPECIFIED, dataSize)); }