From a4c17e5325827f4c44e29148adcaf10862dff33d Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Sun, 11 Dec 2016 13:37:27 -0800 Subject: [PATCH] Support for generating video thumbnails // FREEBIE --- build.gradle | 38 +++++------ .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 1023 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 699 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 1379 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 2145 bytes .../ic_play_circle_outline_white_48dp.png | Bin 0 -> 2836 bytes res/layout/thumbnail_view.xml | 12 ++++ .../securesms/ConversationActivity.java | 8 +-- .../securesms/ConversationFragment.java | 2 +- .../securesms/ConversationItem.java | 2 +- .../securesms/ImageMediaAdapter.java | 25 +++---- .../securesms/attachments/Attachment.java | 14 ---- .../attachments/DatabaseAttachment.java | 27 ++++++-- .../securesms/attachments/UriAttachment.java | 17 ++--- .../securesms/components/ThumbnailView.java | 12 +++- .../database/AttachmentDatabase.java | 63 ++++++++++++++--- .../securesms/database/ImageDatabase.java | 9 ++- .../securesms/database/MmsDatabase.java | 2 + .../securesms/database/MmsSmsDatabase.java | 6 ++ .../securesms/mms/AttachmentManager.java | 2 +- .../securesms/mms/AudioSlide.java | 4 +- .../thoughtcrime/securesms/mms/GifSlide.java | 2 +- .../securesms/mms/ImageSlide.java | 8 +-- src/org/thoughtcrime/securesms/mms/Slide.java | 9 ++- .../securesms/mms/VideoSlide.java | 16 ++--- .../securesms/util/MediaUtil.java | 2 +- .../securesms/util/SaveAttachmentTask.java | 3 +- src/org/thoughtcrime/securesms/util/Util.java | 8 +++ .../video/EncryptedMediaDataSource.java | 64 ++++++++++++++++++ .../securesms/video/VideoPlayer.java | 21 +++++- 30 files changed, 268 insertions(+), 108 deletions(-) create mode 100644 res/drawable-hdpi/ic_play_circle_outline_white_48dp.png create mode 100644 res/drawable-mdpi/ic_play_circle_outline_white_48dp.png create mode 100644 res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png create mode 100644 res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png create mode 100644 res/drawable-xxxhdpi/ic_play_circle_outline_white_48dp.png create mode 100644 src/org/thoughtcrime/securesms/video/EncryptedMediaDataSource.java diff --git a/build.gradle b/build.gradle index 1d5da530a6..060bda4eb8 100644 --- a/build.gradle +++ b/build.gradle @@ -50,10 +50,10 @@ dependencies { compile 'de.greenrobot:eventbus:2.4.0' compile 'pl.tajchert:waitingdots:0.1.0' compile 'com.soundcloud.android:android-crop:0.9.10@aar' - compile 'com.android.support:appcompat-v7:25.0.1' - compile 'com.android.support:recyclerview-v7:25.0.1' - compile 'com.android.support:design:25.0.1' - compile 'com.android.support:cardview-v7:25.0.1' + compile 'com.android.support:appcompat-v7:24.2.1' + compile 'com.android.support:recyclerview-v7:24.2.1' + compile 'com.android.support:design:24.2.1' + compile 'com.android.support:cardview-v7:24.2.1' compile 'com.melnykov:floatingactionbutton:1.3.0' compile 'com.google.zxing:android-integration:3.1.0' compile ('com.android.support:support-v4-preferencefragment:1.0.0@aar'){ @@ -117,10 +117,10 @@ dependencyVerification { 'de.greenrobot:eventbus:61d743a748156a372024d083de763b9e91ac2dcb3f6a1cbc74995c7ddab6e968', 'pl.tajchert:waitingdots:2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c', 'com.soundcloud.android:android-crop:ffd4b973cf6e97f7d64118a0dc088df50e9066fd5634fe6911dd0c0c5d346177', - 'com.android.support:appcompat-v7:7fead560a22ea4b15848ce3000f312ef611fac0953bf90ca8710a72a1f6e36ea', - 'com.android.support:recyclerview-v7:803baba7be537ace8c5cb8a775e37547c22a04c4b028833796c45c26ec1deca2', - 'com.android.support:design:07a72eb68c888b38d7b78e450e1af8a84e571406e0cf911889e0645d5a41f1e4', - 'com.android.support:cardview-v7:50d88fae8cd1076cb90504d36ca5ee9df4018555c8f041bd28f43274c0fc9e1f', + 'com.android.support:appcompat-v7:ead7ac8011fb40676df8adc2856cae934edab55fc4444654c0ac6ea443736088', + 'com.android.support:recyclerview-v7:9077766a1a0f4e89528fbf9dcdf6d5880a8686f0266fa852d58d803beeef18fa', + 'com.android.support:design:89842bb1243507fe3079066ea4ea58795effe69cdf9a819e05274d21760adfc2', + 'com.android.support:cardview-v7:2303b351686d1db060b5fcf1a9c709c79b4a54a85bfda0fb3c4849e244606ee1', 'com.melnykov:floatingactionbutton:15d58d4fac0f7a288d0e5301bbaf501a146f5b3f5921277811bf99bd3b397263', 'com.google.zxing:android-integration:89e56aadf1164bd71e57949163c53abf90af368b51669c0d4a47a163335f95c4', 'com.android.support:support-v4-preferencefragment:5470f5872514a6226fa1fc6f4e000991f38805691c534cf0bd2778911fc773ad', @@ -136,10 +136,9 @@ dependencyVerification { 'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259', 'cn.carbswang.android:NumberPickerView:18b3c316d62c7c277978a8d4ed57a5b8f4e943762264960f579a8a549c756729', 'com.google.android.gms:play-services-base:ef36e50fa5c0415ed41f74dd399a889efd2fa327c449036e140c7c3786aa0e1f', - 'com.android.support:support-annotations:bd94ab42c841db16fb480f4c65d33d297e544655ecc498b37c5cf33a0c5f1968', - 'com.android.support:support-compat:d04f15aa5f2ae9e8cb7d025bf02dfd4fd6f6800628ceb107e0589634c9e4e537', - 'com.android.support:support-core-ui:29205ac978a1839d92be3d32db2385dac10f8688bba649e51650023c76de2f00', - 'com.android.support:transition:9fd1e6d27cb70b3c5cd19f842b48bbb05cb4e5c93a22372769c342523393e8ea', + 'com.android.support:support-annotations:1e4d471c5378b283d95abfb128e7ed3c6b3cb19bb6f0c317a9b75e48e99365ff', + 'com.android.support:support-compat:8e4fe0078b68073e8f5bcb52aa5b6407fd456d47c51aa0f8e8d1e23c69da06c1', + 'com.android.support:support-core-ui:ecc9184b7f438980e1c4a08b089d62dbc53ff90091f442d91fec27322a02c73c', 'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a', 'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f', @@ -156,18 +155,17 @@ dependencyVerification { 'com.squareup.okio:okio:5e1098bd3fdee4c3347f5ab815b40ba851e4ab1b348c5e49a5b0362f0ce6e978', 'com.fasterxml.jackson.core:jackson-annotations:0ca408c24202a7626ec8b861e99d85eca5e38b73311dd6dd12e3e9deecc3fe94', 'com.fasterxml.jackson.core:jackson-core:cbf4604784b4de226262845447a1ad3bb38a6728cebe86562e2c5afada8be2c0', - 'com.android.support:support-v4:50da261acc4ca3d2dea9a43106bf65488711ca97b20a4daa095dba381c205c98', - 'com.android.support:support-media-compat:01cac57af687bed9a6cb4ce803bebd1b7e6b8469c14f1f9ac6b4596637ff73d6', - 'com.android.support:support-core-utils:632c3750bd991da8b591f24a8916e74ca6063ae7f525f005c96981725c9bf491', - 'com.android.support:support-fragment:da47261a1d7c3d33e6e911335a7f4ce01135923bb221d3ab84625d005fa1969f', - 'com.android.support:support-vector-drawable:071ae3695bf8427d3cbfc8791492a3d9c804a4b111aa2a72fbfe7790ea268e5d', - 'com.android.support:animated-vector-drawable:70443a2857f9968c4e2c27c107657ce2291d774f8a50f03444e12ab637451175', + 'com.android.support:support-v4:cac2956f5c4bb363cc0ba824ac16ea2a687d1c305d434416a34772a5f9375ed7', + 'com.android.support:support-media-compat:fa29a23eadd685631584b2c0c624a36e3bb79a33e257b00304501ad682fa2be3', + 'com.android.support:support-core-utils:0fbc508e41dd6e8c634f310ee88452aaf8f48b6a843a369b115130b80d2fc05f', + 'com.android.support:support-fragment:d8030f0bf0f64214a29dc4e14d5ccd225e59f66ed15eb37f3a5022e773dd1fda', + 'com.android.support:support-vector-drawable:6ee37a7f7b93c1df1294e6f6f97df3724ac989fcda0549faf677001085330548', + 'com.android.support:animated-vector-drawable:5aa30f578e1daefb26bef0ce06414266fbb4cdf5d4259f42a92c7bd83dcd81b4', ] } - android { - compileSdkVersion 25 + compileSdkVersion 24 buildToolsVersion '23.0.3' useLibrary 'org.apache.http.legacy' diff --git a/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png b/res/drawable-hdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..6e1b578c54d13ceabffc2d6f49a383bc73605988 GIT binary patch literal 1023 zcmV0zV6u|K(L}#j#NlM5x;x=T{UGWVyM6uO@Y=mavGW`M?Mv;Vk1VIByAc4}n(2A*U z3=>39h#Cx`NLT5qBxa@2VKTTVm^*|2F3)|K+?O-=N$FyK=L`Jd+ugiT!=ubL>nt$F6^>#W8-sqjxydRXVfJ`Mfo~2z=pxJ1h^tDG{(}p;#A_O{ z$_4j9$N8Nk?sLp#&^11hRE0q|L1|{#-wqELCQlEYq)5?84|#@JdAN#x|i1x`yp%S}_Uc5VP2R)C3*p6LyYqFm_Uf z?)X8A*vo2l64Xi&zhC19UBbSUvlvIy!6ttF@q%6>ywE%ATXoV&YKWI{f-d5B2NN>? z@RK@e9KXKkpk>6nh{qtnyz=cZ%MM~GDyW+pqJW7Eg1?ljyN#%l3lF-9D3gg5gmQIl z>>_T22dyF|F)@R*tD8o=2n)*KAx^1+G^;y{_{@>upgdv+qYF~3u7wifa&XWX;(w^yq^WtLsH<1qYQ8o%$ff>bel6 z;2;l?(g!J4mqzUUmqA0xg50ibBl*f)Uet5RFKU;!{ZNA2-uZ)ZL-}BwjrY^Bs1J%< zmCPf=NN~^<#0OQ7tV;jm`a^KgQ9Q(HWzdHE*AK%h#FQ#1dQ~zrh!sp&Pyw;4c!eEO zz2;XC*P~wYtB6}sL5fw$j37L^!h;M&#QX5?U5Zu7wDS@17!wuLkKbKP@F-R#GlAc^ z=pe%?qRI)Ue@dUBW?#^8f-c~N^RHaXc)&Kcffd&*&b zkRi((Y*og|Dj$Or)Uf?Qrs1Q7x+K`)Hf=F~vqt#{bva#04qvi7r`|5poTVk?jylH- z73w`Dlk|8h#U%SH@sI)o^wLF|G+p#EK!Hb;*xx-4yE(ucq(V|DvGR literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png b/res/drawable-mdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..615b80d08543f8285c7ac5ffd66435bf0da1b7ff GIT binary patch literal 699 zcmV;s0!00ZP)9ER~}Ocb>nNr>2151>$#LL?rDP#4l7hMYi)F$bWnTZ;s2>AO;FAR7@pi(*JO z#wdzz)U=@XHOb~`;O1G)$1@Y!MZw>_4PNj!84~BgzknDs6sb_7NvFFeH7YEVC5B_0 z?FAF8ae<$6-ZS2NAk8KnY}%Aa^%9up2Vpgtixx=m8Ic>dSR_M|{_av_$g#~WA|>Ks z14Ha%z#$6^;{Ccs>KL%cP?$i1eT@HkOB^R)36{7AlOS#ne8Q;n0>?fkX<(FWfq9H? zq;W!Slmm=cL4hCF$h139M7D5( z0+v(lAO&}zf-D9HET_sNWp|*4WP$^hQ)Q8=JJ3Xu!2!#u(#VxN&_Vix1C~<_AniXD zcpW~_L{gyxwP+`b`cM86^`Bfpa`u2u6ZLJnjBHy2I*s?fB1`T-7P<9)6j)B9J?0L{ zcs=aSgFefy(*zyp)azmA@Byil@CpQ+M(gJoS;6rNjMD*gLDzy#qZN@BPuu~mgxoWU z6LBwTA?rAPffP-o!6;6Ijd6lpGU6T3<}eN-B*v&>%-X(ql`tAig*?s)#z!1mAkH4f zJp~e$cTSNO#x8x~zWgd7N8}jx`B>#S28>+>!+w2_Q$pmH9r9#JGtga{EP2Y@Vdyx0 z(SCr;aZOm4%=YpVD#-?IY+9@{()*9VXRLCDpHo)!skHK+2t{RV2URfJy|Ab$V=002ovPDHLkV1oZnH8lVL literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png b/res/drawable-xhdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..516f6432693ac6d89901a2c9a0e76baa01045808 GIT binary patch literal 1379 zcmV-p1)TbcP)y%WEavn41Afhq;gFm$1qB5K1qI<@ z9`ziggS+%G$_J*H;sc}fafeGBq@F5Fm}dy*N@?H%0|e1eJ6lQ2lz<}Y>Eb=ECh257 zMbjHlPLd%s25F{jdIAz0;Vof!O)K$y2Q=}FFb&g~zko&DCJNmw%tyd3CWuOkrf36V z{1IRbowTxm||j7vx+SoqLZiixj;!&0rU8q?9$w0549MdTg*Os_>#YMY}V#CI6|v4+Q4hEy3wKrG9T?qw2~kgkktcr}I*2yX{zY~8sAG?A$p6Y(7& zQ)4ax37%oQjLF0OiEWs;d%$6Ak4WStpqv40`&|Rdd4n_+@YmLF#MKGklSX<)sarr2 zTN@_O!9$j-6WX!ubqOeD26U*$AJR%ifPPA=?RfuyQKV``fPPBzkzV=- zd_amR0`yagBTf1TOd%C30`yZVM*2L{0)9~hO#6f$1ej35PM$eG#2r!n5ceUiau3i? zNAody2Wd;_0S^?v$Zq-vTtYhJ7NDPwxMN7?BY&9FPe;f&Ziw*N)WV7NDDsxcf+L!2-4-rCmm(n~u0; z*fs$|Lo>E>K?9W2@qVCz-58gEGF~I4S%dMvT&E*$Ew)h- zZUKf?Y>z3!-+5!P#$wLHg5ns(+YpLsg)_Kcb^ zUwmDbB>_?#XHJd}%qJMf+f$Z?{pxWoPatc=X})#*YwHZ-WYbSg6fb{Q(aV?gk__-1 zx`Gz&^Cdl0MD_Z8377Emf-a8Iz-s0brJ{_QMkc^{Cx?ikzv9#$hLfc4J*z8UJ-^-lEkLxi*Tjv?SeYUq!6rD(`SL z!4-aB)=c>_Xq-))+*+~&F lGp`V!zd}GEpb$_9_#bazb~6%eta1PV002ovPDHLkV1nTeaFqZ6 literal 0 HcmV?d00001 diff --git a/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png b/res/drawable-xxhdpi/ic_play_circle_outline_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..0311f899dd60c1856b10b4af459409309444aad9 GIT binary patch literal 2145 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 literal 0 HcmV?d00001 diff --git a/res/layout/thumbnail_view.xml b/res/layout/thumbnail_view.xml index 1e446b0552..24851538c3 100644 --- a/res/layout/thumbnail_view.xml +++ b/res/layout/thumbnail_view.xml @@ -10,6 +10,18 @@ android:scaleType="fitCenter" android:contentDescription="@string/conversation_item__mms_image_description" /> + + { @Override public void onClick(View v) { - Intent intent = new Intent(getContext(), MediaPreviewActivity.class); - intent.putExtra(MediaPreviewActivity.DATE_EXTRA, imageRecord.getDate()); - intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, threadId); + if (imageRecord.getAttachment().getDataUri() != null) { + Intent intent = new Intent(getContext(), MediaPreviewActivity.class); + intent.putExtra(MediaPreviewActivity.DATE_EXTRA, imageRecord.getDate()); + intent.putExtra(MediaPreviewActivity.THREAD_ID_EXTRA, threadId); - if (!TextUtils.isEmpty(imageRecord.getAddress())) { - Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(), - imageRecord.getAddress(), - true); - if (recipients != null && recipients.getPrimaryRecipient() != null) { - intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipients.getPrimaryRecipient().getRecipientId()); + if (!TextUtils.isEmpty(imageRecord.getAddress())) { + Recipients recipients = RecipientFactory.getRecipientsFromString(getContext(), + imageRecord.getAddress(), + true); + if (recipients != null && recipients.getPrimaryRecipient() != null) { + intent.putExtra(MediaPreviewActivity.RECIPIENT_EXTRA, recipients.getPrimaryRecipient().getRecipientId()); + } } + intent.setDataAndType(imageRecord.getAttachment().getDataUri(), imageRecord.getContentType()); + getContext().startActivity(intent); } - intent.setDataAndType(imageRecord.getAttachment().getDataUri(), imageRecord.getContentType()); - getContext().startActivity(intent); - } } } diff --git a/src/org/thoughtcrime/securesms/attachments/Attachment.java b/src/org/thoughtcrime/securesms/attachments/Attachment.java index ce579d81e8..c872cc1b25 100644 --- a/src/org/thoughtcrime/securesms/attachments/Attachment.java +++ b/src/org/thoughtcrime/securesms/attachments/Attachment.java @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms.attachments; -import android.graphics.Bitmap; import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -23,10 +22,6 @@ public abstract class Attachment { @Nullable private final String relay; - // XXX - This shouldn't be here. - @Nullable - private Bitmap thumbnail; - public Attachment(@NonNull String contentType, int transferState, long size, @Nullable String location, @Nullable String key, @Nullable String relay) { @@ -76,13 +71,4 @@ public abstract class Attachment { public String getRelay() { return relay; } - - public void setThumbnail(@Nullable Bitmap thumbnail) { - this.thumbnail = thumbnail; - } - - @Nullable - public Bitmap getThumbnail() { - return thumbnail; - } } diff --git a/src/org/thoughtcrime/securesms/attachments/DatabaseAttachment.java b/src/org/thoughtcrime/securesms/attachments/DatabaseAttachment.java index a8f47be164..84412c66b5 100644 --- a/src/org/thoughtcrime/securesms/attachments/DatabaseAttachment.java +++ b/src/org/thoughtcrime/securesms/attachments/DatabaseAttachment.java @@ -1,7 +1,7 @@ package org.thoughtcrime.securesms.attachments; import android.net.Uri; -import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import org.thoughtcrime.securesms.mms.PartAuthority; @@ -10,27 +10,38 @@ public class DatabaseAttachment extends Attachment { private final AttachmentId attachmentId; private final long mmsId; private final boolean hasData; + private final boolean hasThumbnail; - public DatabaseAttachment(AttachmentId attachmentId, long mmsId, boolean hasData, + public DatabaseAttachment(AttachmentId attachmentId, long mmsId, + boolean hasData, boolean hasThumbnail, String contentType, int transferProgress, long size, String location, String key, String relay) { super(contentType, transferProgress, size, location, key, relay); this.attachmentId = attachmentId; this.hasData = hasData; + this.hasThumbnail = hasThumbnail; this.mmsId = mmsId; } @Override - @NonNull + @Nullable public Uri getDataUri() { - return PartAuthority.getAttachmentDataUri(attachmentId); + if (hasData) { + return PartAuthority.getAttachmentDataUri(attachmentId); + } else { + return null; + } } @Override - @NonNull + @Nullable public Uri getThumbnailUri() { - return PartAuthority.getAttachmentThumbnailUri(attachmentId); + if (hasThumbnail) { + return PartAuthority.getAttachmentThumbnailUri(attachmentId); + } else { + return null; + } } public AttachmentId getAttachmentId() { @@ -56,4 +67,8 @@ public class DatabaseAttachment extends Attachment { public boolean hasData() { return hasData; } + + public boolean hasThumbnail() { + return hasThumbnail; + } } diff --git a/src/org/thoughtcrime/securesms/attachments/UriAttachment.java b/src/org/thoughtcrime/securesms/attachments/UriAttachment.java index ea6828bc76..fdef4178b1 100644 --- a/src/org/thoughtcrime/securesms/attachments/UriAttachment.java +++ b/src/org/thoughtcrime/securesms/attachments/UriAttachment.java @@ -1,26 +1,19 @@ package org.thoughtcrime.securesms.attachments; -import android.content.Context; import android.net.Uri; import android.support.annotation.NonNull; - -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.util.MediaUtil; -import org.whispersystems.libsignal.util.guava.Optional; - -import java.io.IOException; -import java.io.InputStream; +import android.support.annotation.Nullable; public class UriAttachment extends Attachment { - private final @NonNull Uri dataUri; - private final @NonNull Uri thumbnailUri; + private final @NonNull Uri dataUri; + private final @Nullable Uri thumbnailUri; public UriAttachment(@NonNull Uri uri, @NonNull String contentType, int transferState, long size) { this(uri, uri, contentType, transferState, size); } - public UriAttachment(@NonNull Uri dataUri, @NonNull Uri thumbnailUri, + public UriAttachment(@NonNull Uri dataUri, @Nullable Uri thumbnailUri, @NonNull String contentType, int transferState, long size) { super(contentType, transferState, size, null, null, null); @@ -35,7 +28,7 @@ public class UriAttachment extends Attachment { } @Override - @NonNull + @Nullable public Uri getThumbnailUri() { return thumbnailUri; } diff --git a/src/org/thoughtcrime/securesms/components/ThumbnailView.java b/src/org/thoughtcrime/securesms/components/ThumbnailView.java index 29799b548e..ec30896f0c 100644 --- a/src/org/thoughtcrime/securesms/components/ThumbnailView.java +++ b/src/org/thoughtcrime/securesms/components/ThumbnailView.java @@ -36,6 +36,7 @@ public class ThumbnailView extends FrameLayout { private static final String TAG = ThumbnailView.class.getSimpleName(); private ImageView image; + private ImageView playOverlay; private int backgroundColorHint; private int radius; private OnClickListener parentClickListener; @@ -58,8 +59,9 @@ public class ThumbnailView extends FrameLayout { inflate(context, R.layout.thumbnail_view, this); - this.radius = getResources().getDimensionPixelSize(R.dimen.message_bubble_corner_radius); - this.image = (ImageView) findViewById(R.id.thumbnail_image); + this.radius = getResources().getDimensionPixelSize(R.dimen.message_bubble_corner_radius); + this.image = (ImageView) findViewById(R.id.thumbnail_image); + this.playOverlay = (ImageView) findViewById(R.id.play_overlay); super.setOnClickListener(new ThumbnailClickDispatcher()); if (attrs != null) { @@ -105,6 +107,12 @@ public class ThumbnailView extends FrameLayout { getTransferControls().setVisibility(View.GONE); } + if (slide.getThumbnailUri() != null && slide.hasPlayOverlay() && slide.getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_DONE) { + this.playOverlay.setVisibility(View.VISIBLE); + } else { + this.playOverlay.setVisibility(View.GONE); + } + if (Util.equals(slide, this.slide)) { Log.w(TAG, "Not re-loading slide " + slide.asAttachment().getDataUri()); return; diff --git a/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java index f591765d1e..b78abc6031 100644 --- a/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java +++ b/src/org/thoughtcrime/securesms/database/AttachmentDatabase.java @@ -21,7 +21,10 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; +import android.graphics.Bitmap; +import android.media.MediaMetadataRetriever; import android.net.Uri; +import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; @@ -42,6 +45,7 @@ import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil.ThumbnailData; import org.thoughtcrime.securesms.util.Util; +import org.thoughtcrime.securesms.video.EncryptedMediaDataSource; import java.io.File; import java.io.FileNotFoundException; @@ -54,6 +58,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import ws.com.google.android.mms.ContentType; import ws.com.google.android.mms.MmsException; public class AttachmentDatabase extends Database { @@ -71,7 +76,7 @@ public class AttachmentDatabase extends Database { static final String DATA = "_data"; static final String TRANSFER_STATE = "pending_push"; static final String SIZE = "data_size"; - private static final String THUMBNAIL = "thumbnail"; + static final String THUMBNAIL = "thumbnail"; static final String THUMBNAIL_ASPECT_RATIO = "aspect_ratio"; static final String UNIQUE_ID = "unique_id"; @@ -84,7 +89,7 @@ public class AttachmentDatabase extends Database { private static final String[] PROJECTION = new String[] {ROW_ID + " AS " + ATTACHMENT_ID_ALIAS, MMS_ID, CONTENT_TYPE, NAME, CONTENT_DISPOSITION, - CONTENT_LOCATION, DATA, TRANSFER_STATE, + CONTENT_LOCATION, DATA, THUMBNAIL, TRANSFER_STATE, SIZE, THUMBNAIL, THUMBNAIL_ASPECT_RATIO, UNIQUE_ID}; @@ -313,6 +318,7 @@ public class AttachmentDatabase extends Database { return new DatabaseAttachment(databaseAttachment.getAttachmentId(), databaseAttachment.getMmsId(), databaseAttachment.hasData(), + databaseAttachment.hasThumbnail(), mediaStream.getMimeType(), databaseAttachment.getTransferState(), dataSize, @@ -434,6 +440,7 @@ public class AttachmentDatabase extends Database { cursor.getLong(cursor.getColumnIndexOrThrow(UNIQUE_ID))), cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)), !cursor.isNull(cursor.getColumnIndexOrThrow(DATA)), + !cursor.isNull(cursor.getColumnIndexOrThrow(THUMBNAIL)), cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_TYPE)), cursor.getInt(cursor.getColumnIndexOrThrow(TRANSFER_STATE)), cursor.getLong(cursor.getColumnIndexOrThrow(SIZE)), @@ -474,11 +481,8 @@ public class AttachmentDatabase extends Database { long rowId = database.insert(TABLE_NAME, null, contentValues); AttachmentId attachmentId = new AttachmentId(rowId, uniqueId); - if (attachment.getThumbnail() != null && masterSecret.getMasterSecret().isPresent()) { - Log.w(TAG, "inserting pre-generated thumbnail"); - ThumbnailData data = new ThumbnailData(attachment.getThumbnail()); - updateAttachmentThumbnail(masterSecret.getMasterSecret().get(), attachmentId, data.toDataStream(), data.getAspectRatio()); - } else if (!attachment.isInProgress()) { + if (partData != null) { + Log.w(TAG, "Submitting thumbnail generation job..."); thumbnailExecutor.submit(new ThumbnailFetchCallable(masterSecret.getMasterSecret().get(), attachmentId)); } @@ -501,21 +505,33 @@ public class AttachmentDatabase extends Database { values.put(THUMBNAIL_ASPECT_RATIO, aspectRatio); database.update(TABLE_NAME, values, PART_ID_WHERE, attachmentId.toStrings()); + + Cursor cursor = database.query(TABLE_NAME, new String[] {MMS_ID}, PART_ID_WHERE, attachmentId.toStrings(), null, null, null); + + try { + if (cursor != null && cursor.moveToFirst()) { + notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(cursor.getLong(cursor.getColumnIndexOrThrow(MMS_ID)))); + } + } finally { + if (cursor != null) cursor.close(); + } } @VisibleForTesting class ThumbnailFetchCallable implements Callable { + private final MasterSecret masterSecret; private final AttachmentId attachmentId; - public ThumbnailFetchCallable(MasterSecret masterSecret, AttachmentId attachmentId) { + ThumbnailFetchCallable(MasterSecret masterSecret, AttachmentId attachmentId) { this.masterSecret = masterSecret; this.attachmentId = attachmentId; } @Override public @Nullable InputStream call() throws Exception { + Log.w(TAG, "Executing thumbnail job..."); final InputStream stream = getDataStream(masterSecret, attachmentId, THUMBNAIL); if (stream != null) { @@ -528,7 +544,13 @@ public class AttachmentDatabase extends Database { return null; } - ThumbnailData data = MediaUtil.generateThumbnail(context, masterSecret, attachment.getContentType(), attachment.getDataUri()); + ThumbnailData data; + + if (ContentType.isVideoType(attachment.getContentType())) { + data = generateVideoThumbnail(masterSecret, attachmentId); + } else{ + data = MediaUtil.generateThumbnail(context, masterSecret, attachment.getContentType(), attachment.getDataUri()); + } if (data == null) { return null; @@ -538,5 +560,28 @@ public class AttachmentDatabase extends Database { return getDataStream(masterSecret, attachmentId, THUMBNAIL); } + + private ThumbnailData generateVideoThumbnail(MasterSecret masterSecret, AttachmentId attachmentId) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + Log.w(TAG, "Video thumbnails not supported..."); + return null; + } + + File mediaFile = getAttachmentDataFile(attachmentId, DATA); + + if (mediaFile == null) { + Log.w(TAG, "No data file found for video thumbnail..."); + return null; + } + + EncryptedMediaDataSource dataSource = new EncryptedMediaDataSource(masterSecret, mediaFile); + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(dataSource); + + Bitmap bitmap = retriever.getFrameAtTime(1000); + + Log.w(TAG, "Generated video thumbnail..."); + return new ThumbnailData(bitmap); + } } } diff --git a/src/org/thoughtcrime/securesms/database/ImageDatabase.java b/src/org/thoughtcrime/securesms/database/ImageDatabase.java index 5e7bb25179..6532501a8d 100644 --- a/src/org/thoughtcrime/securesms/database/ImageDatabase.java +++ b/src/org/thoughtcrime/securesms/database/ImageDatabase.java @@ -19,6 +19,7 @@ public class ImageDatabase extends Database { + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.TRANSFER_STATE + ", " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.SIZE + ", " + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.DATA + ", " + + AttachmentDatabase.TABLE_NAME + "." + AttachmentDatabase.THUMBNAIL + ", " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.MESSAGE_BOX + ", " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_SENT + ", " + MmsDatabase.TABLE_NAME + "." + MmsDatabase.DATE_RECEIVED + ", " @@ -47,19 +48,22 @@ public class ImageDatabase extends Database { private final AttachmentId attachmentId; private final long mmsId; private final boolean hasData; + private final boolean hasThumbnail; private final String contentType; private final String address; private final long date; private final int transferState; private final long size; - private ImageRecord(AttachmentId attachmentId, long mmsId, boolean hasData, + private ImageRecord(AttachmentId attachmentId, long mmsId, + boolean hasData, boolean hasThumbnail, String contentType, String address, long date, int transferState, long size) { this.attachmentId = attachmentId; this.mmsId = mmsId; this.hasData = hasData; + this.hasThumbnail = hasThumbnail; this.contentType = contentType; this.address = address; this.date = date; @@ -82,6 +86,7 @@ public class ImageDatabase extends Database { return new ImageRecord(attachmentId, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID)), !cursor.isNull(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA)), + !cursor.isNull(cursor.getColumnIndexOrThrow(AttachmentDatabase.THUMBNAIL)), cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.CONTENT_TYPE)), cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.ADDRESS)), date, @@ -90,7 +95,7 @@ public class ImageDatabase extends Database { } public Attachment getAttachment() { - return new DatabaseAttachment(attachmentId, mmsId, hasData, contentType, transferState, size, null, null, null); + return new DatabaseAttachment(attachmentId, mmsId, hasData, hasThumbnail, contentType, transferState, size, null, null, null); } public String getContentType() { diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 0bcd958759..fdb5e5bb67 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -138,6 +138,7 @@ public class MmsDatabase extends MessagingDatabase { AttachmentDatabase.MMS_ID, AttachmentDatabase.SIZE, AttachmentDatabase.DATA, + AttachmentDatabase.THUMBNAIL, AttachmentDatabase.CONTENT_TYPE, AttachmentDatabase.CONTENT_LOCATION, AttachmentDatabase.CONTENT_DISPOSITION, @@ -672,6 +673,7 @@ public class MmsDatabase extends MessagingDatabase { attachments.add(new DatabaseAttachment(databaseAttachment.getAttachmentId(), databaseAttachment.getMmsId(), databaseAttachment.hasData(), + databaseAttachment.hasThumbnail(), databaseAttachment.getContentType(), AttachmentDatabase.TRANSFER_PROGRESS_DONE, databaseAttachment.getSize(), diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java index 3ad42dec9f..106fd94093 100644 --- a/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsSmsDatabase.java @@ -62,6 +62,7 @@ public class MmsSmsDatabase extends Database { AttachmentDatabase.MMS_ID, AttachmentDatabase.SIZE, AttachmentDatabase.DATA, + AttachmentDatabase.THUMBNAIL, AttachmentDatabase.CONTENT_TYPE, AttachmentDatabase.CONTENT_LOCATION, AttachmentDatabase.CONTENT_DISPOSITION, @@ -153,6 +154,7 @@ public class MmsSmsDatabase extends Database { AttachmentDatabase.MMS_ID, AttachmentDatabase.SIZE, AttachmentDatabase.DATA, + AttachmentDatabase.THUMBNAIL, AttachmentDatabase.CONTENT_TYPE, AttachmentDatabase.CONTENT_LOCATION, AttachmentDatabase.CONTENT_DISPOSITION, @@ -178,6 +180,7 @@ public class MmsSmsDatabase extends Database { AttachmentDatabase.MMS_ID, AttachmentDatabase.SIZE, AttachmentDatabase.DATA, + AttachmentDatabase.THUMBNAIL, AttachmentDatabase.CONTENT_TYPE, AttachmentDatabase.CONTENT_LOCATION, AttachmentDatabase.CONTENT_DISPOSITION, @@ -226,7 +229,10 @@ public class MmsSmsDatabase extends Database { mmsColumnsPresent.add(AttachmentDatabase.ROW_ID); mmsColumnsPresent.add(AttachmentDatabase.UNIQUE_ID); + mmsColumnsPresent.add(AttachmentDatabase.MMS_ID); mmsColumnsPresent.add(AttachmentDatabase.SIZE); + mmsColumnsPresent.add(AttachmentDatabase.DATA); + mmsColumnsPresent.add(AttachmentDatabase.THUMBNAIL); mmsColumnsPresent.add(AttachmentDatabase.CONTENT_TYPE); mmsColumnsPresent.add(AttachmentDatabase.CONTENT_LOCATION); mmsColumnsPresent.add(AttachmentDatabase.CONTENT_DISPOSITION); diff --git a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java index a26e782ded..bb5941e14b 100644 --- a/src/org/thoughtcrime/securesms/mms/AttachmentManager.java +++ b/src/org/thoughtcrime/securesms/mms/AttachmentManager.java @@ -328,7 +328,7 @@ public class AttachmentManager { } private void previewImageDraft(final @NonNull Slide slide) { - if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getThumbnailUri() != null) { + if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) { Intent intent = new Intent(context, MediaPreviewActivity.class); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setDataAndType(slide.getUri(), slide.getContentType()); diff --git a/src/org/thoughtcrime/securesms/mms/AudioSlide.java b/src/org/thoughtcrime/securesms/mms/AudioSlide.java index 46cb231079..805a61ec3c 100644 --- a/src/org/thoughtcrime/securesms/mms/AudioSlide.java +++ b/src/org/thoughtcrime/securesms/mms/AudioSlide.java @@ -37,11 +37,11 @@ import ws.com.google.android.mms.pdu.PduPart; public class AudioSlide extends Slide { public AudioSlide(Context context, Uri uri, long dataSize) { - super(context, constructAttachmentFromUri(context, uri, ContentType.AUDIO_UNSPECIFIED, dataSize)); + super(context, constructAttachmentFromUri(context, uri, ContentType.AUDIO_UNSPECIFIED, dataSize, false)); } public AudioSlide(Context context, Uri uri, long dataSize, String contentType) { - super(context, new UriAttachment(uri, contentType, AttachmentDatabase.TRANSFER_PROGRESS_STARTED, dataSize)); + super(context, new UriAttachment(uri, null, contentType, AttachmentDatabase.TRANSFER_PROGRESS_STARTED, dataSize)); } public AudioSlide(Context context, Attachment attachment) { diff --git a/src/org/thoughtcrime/securesms/mms/GifSlide.java b/src/org/thoughtcrime/securesms/mms/GifSlide.java index 614e5ad557..5a2c614b8d 100644 --- a/src/org/thoughtcrime/securesms/mms/GifSlide.java +++ b/src/org/thoughtcrime/securesms/mms/GifSlide.java @@ -20,7 +20,7 @@ public class GifSlide extends ImageSlide { } public GifSlide(Context context, Uri uri, long size) { - super(context, constructAttachmentFromUri(context, uri, ContentType.IMAGE_GIF, size)); + super(context, constructAttachmentFromUri(context, uri, ContentType.IMAGE_GIF, size, true)); } @Override diff --git a/src/org/thoughtcrime/securesms/mms/ImageSlide.java b/src/org/thoughtcrime/securesms/mms/ImageSlide.java index 2971086f39..2324309306 100644 --- a/src/org/thoughtcrime/securesms/mms/ImageSlide.java +++ b/src/org/thoughtcrime/securesms/mms/ImageSlide.java @@ -25,8 +25,6 @@ import android.support.annotation.NonNull; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.Attachment; -import java.io.IOException; - import ws.com.google.android.mms.ContentType; public class ImageSlide extends Slide { @@ -38,7 +36,7 @@ public class ImageSlide extends Slide { } public ImageSlide(Context context, Uri uri, long size) { - super(context, constructAttachmentFromUri(context, uri, ContentType.IMAGE_JPEG, size)); + super(context, constructAttachmentFromUri(context, uri, ContentType.IMAGE_JPEG, size, true)); } @Override @@ -51,7 +49,9 @@ public class ImageSlide extends Slide { return true; } - @NonNull @Override public String getContentDescription() { + @NonNull + @Override + public String getContentDescription() { return context.getString(R.string.Slide_image); } } diff --git a/src/org/thoughtcrime/securesms/mms/Slide.java b/src/org/thoughtcrime/securesms/mms/Slide.java index ba85a3d0a1..71550bee5f 100644 --- a/src/org/thoughtcrime/securesms/mms/Slide.java +++ b/src/org/thoughtcrime/securesms/mms/Slide.java @@ -103,13 +103,18 @@ public abstract class Slide { return false; } + public boolean hasPlayOverlay() { + return false; + } + protected static Attachment constructAttachmentFromUri(@NonNull Context context, @NonNull Uri uri, @NonNull String defaultMime, - long size) + long size, + boolean hasThumbnail) { Optional resolvedType = Optional.fromNullable(MediaUtil.getMimeType(context, uri)); - return new UriAttachment(uri, resolvedType.or(defaultMime), AttachmentDatabase.TRANSFER_PROGRESS_STARTED, size); + return new UriAttachment(uri, hasThumbnail ? uri : null, resolvedType.or(defaultMime), AttachmentDatabase.TRANSFER_PROGRESS_STARTED, size); } @Override diff --git a/src/org/thoughtcrime/securesms/mms/VideoSlide.java b/src/org/thoughtcrime/securesms/mms/VideoSlide.java index 8c2000b42e..465e91ff34 100644 --- a/src/org/thoughtcrime/securesms/mms/VideoSlide.java +++ b/src/org/thoughtcrime/securesms/mms/VideoSlide.java @@ -21,21 +21,17 @@ import android.content.res.Resources.Theme; import android.net.Uri; import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.util.ResUtil; -import java.io.IOException; - import ws.com.google.android.mms.ContentType; -import ws.com.google.android.mms.pdu.PduPart; public class VideoSlide extends Slide { public VideoSlide(Context context, Uri uri, long dataSize) { - super(context, constructAttachmentFromUri(context, uri, ContentType.VIDEO_UNSPECIFIED, dataSize)); + super(context, constructAttachmentFromUri(context, uri, ContentType.VIDEO_UNSPECIFIED, dataSize, false)); } public VideoSlide(Context context, Attachment attachment) { @@ -43,13 +39,12 @@ public class VideoSlide extends Slide { } @Override - @Nullable - public Uri getThumbnailUri() { - return null; + public boolean hasPlaceholder() { + return true; } @Override - public boolean hasPlaceholder() { + public boolean hasPlayOverlay() { return true; } @@ -68,7 +63,8 @@ public class VideoSlide extends Slide { return true; } - @NonNull @Override public String getContentDescription() { + @NonNull @Override + public String getContentDescription() { return context.getString(R.string.Slide_video); } } diff --git a/src/org/thoughtcrime/securesms/util/MediaUtil.java b/src/org/thoughtcrime/securesms/util/MediaUtil.java index 0d04f0b533..a9adbec6f3 100644 --- a/src/org/thoughtcrime/securesms/util/MediaUtil.java +++ b/src/org/thoughtcrime/securesms/util/MediaUtil.java @@ -23,11 +23,11 @@ import org.thoughtcrime.securesms.providers.PersistentBlobProvider; import java.io.IOException; import java.io.InputStream; -import java.util.concurrent.ExecutionException; import ws.com.google.android.mms.ContentType; public class MediaUtil { + private static final String TAG = MediaUtil.class.getSimpleName(); public static @Nullable ThumbnailData generateThumbnail(Context context, MasterSecret masterSecret, String contentType, Uri uri) diff --git a/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java b/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java index 38500086bf..85bfa6f063 100644 --- a/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java +++ b/src/org/thoughtcrime/securesms/util/SaveAttachmentTask.java @@ -5,6 +5,7 @@ import android.content.DialogInterface.OnClickListener; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Environment; +import android.support.annotation.NonNull; import android.support.v7.app.AlertDialog; import android.util.Log; import android.webkit.MimeTypeMap; @@ -158,7 +159,7 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask 0) { + int read = inputStream.read(buffer, 0, Util.toIntExact(Math.min((long)buffer.length, headerRemaining))); + + if (read == -1) return -1; + + headerRemaining -= read; + } + + int returnValue = inputStream.read(bytes, offset, length); + inputStream.close(); + return returnValue; + } + + @Override + public long getSize() throws IOException { + DecryptingPartInputStream inputStream = new DecryptingPartInputStream(mediaFile, masterSecret); + byte[] buffer = new byte[4096]; + long size = 0; + + int read; + + while ((read = inputStream.read(buffer)) != -1) { + size += read; + } + + return size; + } + + @Override + public void close() throws IOException { + + } +} diff --git a/src/org/thoughtcrime/securesms/video/VideoPlayer.java b/src/org/thoughtcrime/securesms/video/VideoPlayer.java index 6cb3bbeddd..47135bb5cb 100644 --- a/src/org/thoughtcrime/securesms/video/VideoPlayer.java +++ b/src/org/thoughtcrime/securesms/video/VideoPlayer.java @@ -5,13 +5,16 @@ import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; +import android.util.Log; import android.widget.FrameLayout; import android.widget.MediaController; +import android.widget.Toast; import android.widget.VideoView; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.AttachmentServer; import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.mms.VideoSlide; import org.thoughtcrime.securesms.util.ViewUtil; @@ -19,6 +22,8 @@ import java.io.IOException; public class VideoPlayer extends FrameLayout { + private static final String TAG = VideoPlayer.class.getName(); + @NonNull private final VideoView videoView; @Nullable private AttachmentServer attachmentServer; @@ -45,10 +50,20 @@ public class VideoPlayer extends FrameLayout { this.attachmentServer.stop(); } - this.attachmentServer = new AttachmentServer(getContext(), masterSecret, videoSource.asAttachment()); - this.attachmentServer.start(); + if (videoSource.getUri() != null && PartAuthority.isLocalUri(videoSource.getUri())) { + Log.w(TAG, "Starting video attachment server for part provider Uri..."); + this.attachmentServer = new AttachmentServer(getContext(), masterSecret, videoSource.asAttachment()); + this.attachmentServer.start(); + + this.videoView.setVideoURI(this.attachmentServer.getUri()); + } else if (videoSource.getUri() != null) { + Log.w(TAG, "Playing video directly from non-local Uri..."); + this.videoView.setVideoURI(videoSource.getUri()); + } else { + Toast.makeText(getContext(), "Error playing video...", Toast.LENGTH_LONG).show(); + return; + } - this.videoView.setVideoURI(this.attachmentServer.getUri()); this.videoView.start(); }