diff --git a/build.gradle b/build.gradle index b3072e0a4b..351d21faf2 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,8 @@ dependencies { compile 'com.github.chrisbanes.photoview:library:1.2.3' compile 'com.github.bumptech.glide:glide:3.6.0' compile 'com.makeramen:roundedimageview:2.1.0' + compile 'com.pnikosis:materialish-progress:1.5' + compile 'de.greenrobot:eventbus:2.4.0' compile ('com.afollestad:material-dialogs:0.7.3.1') { exclude module: 'appcompat-v7' exclude module: 'recyclerview-v7' @@ -72,7 +74,7 @@ dependencies { compile 'org.whispersystems:jobmanager:0.11.0' compile 'org.whispersystems:libpastelog:1.0.6' compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1' - compile 'org.whispersystems:textsecure-android:1.6.0' + compile 'org.whispersystems:textsecure-android:1.6.1' androidTestCompile 'com.google.dexmaker:dexmaker:1.2' androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2' @@ -104,6 +106,8 @@ dependencyVerification { 'com.github.chrisbanes.photoview:library:8b5344e206f125e7ba9d684008f36c4992d03853c57e5814125f88496126e3cc', 'com.github.bumptech.glide:glide:adf657e6bddccb168a29e18ab0954043af46a9b5c736d8c3193c9783fd83d69e', 'com.makeramen:roundedimageview:1f5a1865796b308c6cdd114acc6e78408b110f0a62fc63553278fbeacd489cd1', + 'com.pnikosis:materialish-progress:d71d80e00717a096784482aee21001a9d299fec3833e4ebd87739ed36cf77c54', + 'de.greenrobot:eventbus:61d743a748156a372024d083de763b9e91ac2dcb3f6a1cbc74995c7ddab6e968', 'com.afollestad:material-dialogs:c17205f0d300baa307599c428a5473a6659684c94a5f68ae3c2b84b5e4741172', 'pl.tajchert:waitingdots:2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c', 'com.soundcloud.android:android-crop:ffd4b973cf6e97f7d64118a0dc088df50e9066fd5634fe6911dd0c0c5d346177', @@ -119,11 +123,11 @@ dependencyVerification { 'org.whispersystems:jobmanager:ea9cb943c4892fb90c1eea1be30efeb85cefca213d52c788419553b58d0ed70d', 'org.whispersystems:libpastelog:550d33c565380d90f4c671e7b8ed5f3a6da55a9fda468373177106b2eb5220b2', 'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb', - 'org.whispersystems:textsecure-android:b5786690a2603ca78eed8a4f829737c41e2b5099695ce02bd44d0a9af3392318', + 'org.whispersystems:textsecure-android:843d4483e9c3b3414373ddd70df19895b3ee7ef559eeb15e60926e1b07fcecf3', 'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a', 'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f', - 'org.whispersystems:textsecure-java:dd32ab5fbb232116e7e533a78dce7b8be168bf561c5774772406aea54a677c0a', + 'org.whispersystems:textsecure-java:f161c5d5be5a0ba52ede273692ef17982b2af270c6af5c3666bc2adb289a3f61', 'org.whispersystems:axolotl-android:40d3db5004a84749a73f68d2f0d01b2ae35a73c54df96d8c6c6723b96efb6fc0', 'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab', 'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74', diff --git a/res/drawable-hdpi/ic_missing_thumbnail_picture.png b/res/drawable-hdpi/ic_missing_thumbnail_picture.png index 05cbe34d84..b79b403295 100644 Binary files a/res/drawable-hdpi/ic_missing_thumbnail_picture.png and b/res/drawable-hdpi/ic_missing_thumbnail_picture.png differ diff --git a/res/drawable-hdpi/stat_sys_download_anim0.png b/res/drawable-hdpi/stat_sys_download_anim0.png deleted file mode 100644 index 4dca0ecd84..0000000000 Binary files a/res/drawable-hdpi/stat_sys_download_anim0.png and /dev/null differ diff --git a/res/drawable-hdpi/stat_sys_download_anim1.png b/res/drawable-hdpi/stat_sys_download_anim1.png deleted file mode 100644 index cf1ac1db87..0000000000 Binary files a/res/drawable-hdpi/stat_sys_download_anim1.png and /dev/null differ diff --git a/res/drawable-hdpi/stat_sys_download_anim2.png b/res/drawable-hdpi/stat_sys_download_anim2.png deleted file mode 100644 index 449d2b1270..0000000000 Binary files a/res/drawable-hdpi/stat_sys_download_anim2.png and /dev/null differ diff --git a/res/drawable-hdpi/stat_sys_download_anim3.png b/res/drawable-hdpi/stat_sys_download_anim3.png deleted file mode 100644 index 260b2135c2..0000000000 Binary files a/res/drawable-hdpi/stat_sys_download_anim3.png and /dev/null differ diff --git a/res/drawable-hdpi/stat_sys_download_anim4.png b/res/drawable-hdpi/stat_sys_download_anim4.png deleted file mode 100644 index 1f5dca42d1..0000000000 Binary files a/res/drawable-hdpi/stat_sys_download_anim4.png and /dev/null differ diff --git a/res/drawable-hdpi/stat_sys_download_anim5.png b/res/drawable-hdpi/stat_sys_download_anim5.png deleted file mode 100644 index 98719839c0..0000000000 Binary files a/res/drawable-hdpi/stat_sys_download_anim5.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_missing_thumbnail_picture.png b/res/drawable-mdpi/ic_missing_thumbnail_picture.png index e8c712c14b..50e615333b 100644 Binary files a/res/drawable-mdpi/ic_missing_thumbnail_picture.png and b/res/drawable-mdpi/ic_missing_thumbnail_picture.png differ diff --git a/res/drawable-mdpi/stat_sys_download_anim0.png b/res/drawable-mdpi/stat_sys_download_anim0.png deleted file mode 100644 index e6fd9d46ab..0000000000 Binary files a/res/drawable-mdpi/stat_sys_download_anim0.png and /dev/null differ diff --git a/res/drawable-mdpi/stat_sys_download_anim1.png b/res/drawable-mdpi/stat_sys_download_anim1.png deleted file mode 100644 index 1c445d7d34..0000000000 Binary files a/res/drawable-mdpi/stat_sys_download_anim1.png and /dev/null differ diff --git a/res/drawable-mdpi/stat_sys_download_anim2.png b/res/drawable-mdpi/stat_sys_download_anim2.png deleted file mode 100644 index 8efbe910b4..0000000000 Binary files a/res/drawable-mdpi/stat_sys_download_anim2.png and /dev/null differ diff --git a/res/drawable-mdpi/stat_sys_download_anim3.png b/res/drawable-mdpi/stat_sys_download_anim3.png deleted file mode 100644 index 8698c6acf3..0000000000 Binary files a/res/drawable-mdpi/stat_sys_download_anim3.png and /dev/null differ diff --git a/res/drawable-mdpi/stat_sys_download_anim4.png b/res/drawable-mdpi/stat_sys_download_anim4.png deleted file mode 100644 index 174836814e..0000000000 Binary files a/res/drawable-mdpi/stat_sys_download_anim4.png and /dev/null differ diff --git a/res/drawable-mdpi/stat_sys_download_anim5.png b/res/drawable-mdpi/stat_sys_download_anim5.png deleted file mode 100644 index 27b0617b72..0000000000 Binary files a/res/drawable-mdpi/stat_sys_download_anim5.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_missing_thumbnail_picture.png b/res/drawable-xhdpi/ic_missing_thumbnail_picture.png index 1ace7424cb..e4aaf33a4b 100644 Binary files a/res/drawable-xhdpi/ic_missing_thumbnail_picture.png and b/res/drawable-xhdpi/ic_missing_thumbnail_picture.png differ diff --git a/res/drawable-xhdpi/stat_sys_download_anim0.png b/res/drawable-xhdpi/stat_sys_download_anim0.png deleted file mode 100644 index 4c2fdbd17e..0000000000 Binary files a/res/drawable-xhdpi/stat_sys_download_anim0.png and /dev/null differ diff --git a/res/drawable-xhdpi/stat_sys_download_anim1.png b/res/drawable-xhdpi/stat_sys_download_anim1.png deleted file mode 100644 index 06cb66648d..0000000000 Binary files a/res/drawable-xhdpi/stat_sys_download_anim1.png and /dev/null differ diff --git a/res/drawable-xhdpi/stat_sys_download_anim2.png b/res/drawable-xhdpi/stat_sys_download_anim2.png deleted file mode 100644 index 75945787b0..0000000000 Binary files a/res/drawable-xhdpi/stat_sys_download_anim2.png and /dev/null differ diff --git a/res/drawable-xhdpi/stat_sys_download_anim3.png b/res/drawable-xhdpi/stat_sys_download_anim3.png deleted file mode 100644 index 6c715f60a0..0000000000 Binary files a/res/drawable-xhdpi/stat_sys_download_anim3.png and /dev/null differ diff --git a/res/drawable-xhdpi/stat_sys_download_anim4.png b/res/drawable-xhdpi/stat_sys_download_anim4.png deleted file mode 100644 index e5cfd95ccf..0000000000 Binary files a/res/drawable-xhdpi/stat_sys_download_anim4.png and /dev/null differ diff --git a/res/drawable-xhdpi/stat_sys_download_anim5.png b/res/drawable-xhdpi/stat_sys_download_anim5.png deleted file mode 100644 index 7756933054..0000000000 Binary files a/res/drawable-xhdpi/stat_sys_download_anim5.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_missing_thumbnail_picture.png b/res/drawable-xxhdpi/ic_missing_thumbnail_picture.png index 2e2e32e80a..8a04517020 100644 Binary files a/res/drawable-xxhdpi/ic_missing_thumbnail_picture.png and b/res/drawable-xxhdpi/ic_missing_thumbnail_picture.png differ diff --git a/res/drawable/progress_background.xml b/res/drawable/progress_background.xml new file mode 100644 index 0000000000..5f2e8b64c9 --- /dev/null +++ b/res/drawable/progress_background.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/res/drawable/stat_sys_download.xml b/res/drawable/stat_sys_download.xml deleted file mode 100644 index 77ecf8588b..0000000000 --- a/res/drawable/stat_sys_download.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - diff --git a/res/layout/conversation_activity.xml b/res/layout/conversation_activity.xml index 99be48928d..2444b62c7c 100644 --- a/res/layout/conversation_activity.xml +++ b/res/layout/conversation_activity.xml @@ -46,8 +46,8 @@ diff --git a/res/layout/media_overview_item.xml b/res/layout/media_overview_item.xml index 8b37e0f125..f02d942140 100644 --- a/res/layout/media_overview_item.xml +++ b/res/layout/media_overview_item.xml @@ -1,8 +1,6 @@ - @@ -10,8 +8,6 @@ android:id="@+id/image" android:layout_width="match_parent" android:layout_height="match_parent" - android:scaleType="centerCrop" - android:background="#11ffffff" android:contentDescription="@string/media_preview_activity__image_content_description" /> - + diff --git a/res/layout/thumbnail_view.xml b/res/layout/thumbnail_view.xml index 7884ac040c..75017775b7 100644 --- a/res/layout/thumbnail_view.xml +++ b/res/layout/thumbnail_view.xml @@ -1,22 +1,25 @@ - + - + - \ No newline at end of file + + + diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 6c139548eb..6d25609aa4 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -100,12 +100,6 @@ - - - - - - diff --git a/src/org/thoughtcrime/securesms/BaseActionBarActivity.java b/src/org/thoughtcrime/securesms/BaseActionBarActivity.java index a3dc4c52e5..565bd46f85 100644 --- a/src/org/thoughtcrime/securesms/BaseActionBarActivity.java +++ b/src/org/thoughtcrime/securesms/BaseActionBarActivity.java @@ -5,11 +5,14 @@ import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.ActivityOptionsCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.ViewConfiguration; +import android.view.animation.AnimationUtils; import java.lang.reflect.Field; @@ -58,10 +61,8 @@ public abstract class BaseActionBarActivity extends AppCompatActivity { } protected void startActivitySceneTransition(Intent intent, View sharedView, String transitionName) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, sharedView, transitionName).toBundle()); - } else { - startActivity(intent); - } + Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(this, sharedView, transitionName) + .toBundle(); + ActivityCompat.startActivity(this, intent, bundle); } } diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java index c2b6cd1e86..300911ce47 100644 --- a/src/org/thoughtcrime/securesms/ConversationItem.java +++ b/src/org/thoughtcrime/securesms/ConversationItem.java @@ -263,6 +263,7 @@ public class ConversationItem extends LinearLayout { mediaThumbnail.setImageResource(masterSecret, messageRecord.getId(), messageRecord.getDateReceived(), ((MediaMmsMessageRecord)messageRecord).getSlideDeckFuture()); + mediaThumbnail.setShowProgress(!messageRecord.isFailed()); bodyText.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); } else { mediaThumbnail.setVisibility(View.GONE); @@ -374,7 +375,7 @@ public class ConversationItem extends LinearLayout { contactPhoto.setAvatar(recipient, true); contactPhoto.setVisibility(View.VISIBLE); } - + /// Event handlers private void handleApproveIdentity() { diff --git a/src/org/thoughtcrime/securesms/components/ForegroundImageView.java b/src/org/thoughtcrime/securesms/components/ForegroundImageView.java deleted file mode 100644 index 0139774ff6..0000000000 --- a/src/org/thoughtcrime/securesms/components/ForegroundImageView.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.thoughtcrime.securesms.components; - -import android.annotation.TargetApi; -import android.app.ActivityOptions; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Build.VERSION_CODES; -import android.support.annotation.NonNull; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.View; - -import com.makeramen.roundedimageview.RoundedImageView; - -import org.thoughtcrime.securesms.R; - -/** - * https://gist.github.com/chrisbanes/9091754 - */ -public class ForegroundImageView extends RoundedImageView { - - private Drawable mForeground; - - private final Rect mSelfBounds = new Rect(); - private final Rect mOverlayBounds = new Rect(); - - private int mForegroundGravity = Gravity.FILL; - - private boolean mForegroundInPadding = true; - - private boolean mForegroundBoundsChanged = false; - - public ForegroundImageView(Context context) { - super(context); - } - - public ForegroundImageView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ForegroundImageView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundImageView, - defStyle, 0); - - mForegroundGravity = a.getInt( - R.styleable.ForegroundImageView_android_foregroundGravity, mForegroundGravity); - - final Drawable d = a.getDrawable(R.styleable.ForegroundImageView_android_foreground); - if (d != null) { - setForeground(d); - } - - mForegroundInPadding = a.getBoolean( - R.styleable.ForegroundImageView_android_foregroundInsidePadding, true); - - a.recycle(); - } - - /** - * Describes how the foreground is positioned. - * - * @return foreground gravity. - * - * @see #setForegroundGravity(int) - */ - public int getForegroundGravity() { - return mForegroundGravity; - } - - /** - * Describes how the foreground is positioned. Defaults to START and TOP. - * - * @param foregroundGravity See {@link android.view.Gravity} - * - * @see #getForegroundGravity() - */ - public void setForegroundGravity(int foregroundGravity) { - if (mForegroundGravity != foregroundGravity) { - if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { - foregroundGravity |= Gravity.START; - } - - if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { - foregroundGravity |= Gravity.TOP; - } - - mForegroundGravity = foregroundGravity; - - - if (mForegroundGravity == Gravity.FILL && mForeground != null) { - Rect padding = new Rect(); - mForeground.getPadding(padding); - } - - requestLayout(); - } - } - - @TargetApi(VERSION_CODES.JELLY_BEAN) - public ActivityOptions getThumbnailTransition() { - return ActivityOptions.makeScaleUpAnimation(this, 0, 0, getWidth(), getHeight()); - } - - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || (who == mForeground); - } - - @Override - @TargetApi(VERSION_CODES.HONEYCOMB) - public void jumpDrawablesToCurrentState() { - super.jumpDrawablesToCurrentState(); - if (mForeground != null) mForeground.jumpToCurrentState(); - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - if (mForeground != null && mForeground.isStateful()) { - mForeground.setState(getDrawableState()); - } - } - - /** - * Supply a Drawable that is to be rendered on top of all of the child - * views in the frame layout. Any padding in the Drawable will be taken - * into account by ensuring that the children are inset to be placed - * inside of the padding area. - * - * @param drawable The Drawable to be drawn on top of the children. - */ - public void setForeground(Drawable drawable) { - if (mForeground != drawable) { - if (mForeground != null) { - mForeground.setCallback(null); - unscheduleDrawable(mForeground); - } - - mForeground = drawable; - - if (drawable != null) { - setWillNotDraw(false); - drawable.setCallback(this); - if (drawable.isStateful()) { - drawable.setState(getDrawableState()); - } - if (mForegroundGravity == Gravity.FILL) { - Rect padding = new Rect(); - drawable.getPadding(padding); - } - } else { - setWillNotDraw(true); - } - requestLayout(); - invalidate(); - } - } - - /** - * Returns the drawable used as the foreground of this FrameLayout. The - * foreground drawable, if non-null, is always drawn on top of the children. - * - * @return A Drawable or null if no foreground was set. - */ - public Drawable getForeground() { - return mForeground; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - mForegroundBoundsChanged = changed; - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mForegroundBoundsChanged = true; - } - - @Override - public void draw(@NonNull Canvas canvas) { - super.draw(canvas); - - if (mForeground != null) { - final Drawable foreground = mForeground; - - if (mForegroundBoundsChanged) { - mForegroundBoundsChanged = false; - final Rect selfBounds = mSelfBounds; - final Rect overlayBounds = mOverlayBounds; - - final int w = getRight() - getLeft(); - final int h = getBottom() - getTop(); - - if (mForegroundInPadding) { - selfBounds.set(0, 0, w, h); - } else { - selfBounds.set(getPaddingLeft(), getPaddingTop(), - w - getPaddingRight(), h - getPaddingBottom()); - } - - Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(), - foreground.getIntrinsicHeight(), selfBounds, overlayBounds); - foreground.setBounds(overlayBounds); - } - - foreground.draw(canvas); - } - } -} \ No newline at end of file diff --git a/src/org/thoughtcrime/securesms/components/SquareFrameLayout.java b/src/org/thoughtcrime/securesms/components/SquareFrameLayout.java new file mode 100644 index 0000000000..b4028febf1 --- /dev/null +++ b/src/org/thoughtcrime/securesms/components/SquareFrameLayout.java @@ -0,0 +1,35 @@ +package org.thoughtcrime.securesms.components; + +import android.annotation.TargetApi; +import android.content.Context; +import android.os.Build.VERSION_CODES; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +public class SquareFrameLayout extends FrameLayout { + @SuppressWarnings("unused") + public SquareFrameLayout(Context context) { + super(context); + } + + @SuppressWarnings("unused") + public SquareFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @TargetApi(VERSION_CODES.HONEYCOMB) @SuppressWarnings("unused") + public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @TargetApi(VERSION_CODES.LOLLIPOP) @SuppressWarnings("unused") + public SquareFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + //noinspection SuspiciousNameCombination + super.onMeasure(widthMeasureSpec, widthMeasureSpec); + } +} diff --git a/src/org/thoughtcrime/securesms/components/ThumbnailView.java b/src/org/thoughtcrime/securesms/components/ThumbnailView.java index 3f58cf7ac4..4d580995bd 100644 --- a/src/org/thoughtcrime/securesms/components/ThumbnailView.java +++ b/src/org/thoughtcrime/securesms/components/ThumbnailView.java @@ -4,56 +4,87 @@ import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; -import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.Animation.AnimationListener; +import android.widget.FrameLayout; import com.bumptech.glide.GenericRequestBuilder; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.target.Target; import com.makeramen.roundedimageview.RoundedImageView; +import com.pnikosis.materialishprogress.ProgressWheel; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.jobs.PartProgressEvent; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; import org.thoughtcrime.securesms.mms.Slide; import org.thoughtcrime.securesms.mms.SlideDeck; -import org.thoughtcrime.securesms.mms.ThumbnailTransform; import org.thoughtcrime.securesms.util.FutureTaskListener; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.Util; +import de.greenrobot.event.EventBus; import ws.com.google.android.mms.pdu.PduPart; -public class ThumbnailView extends RoundedImageView { +public class ThumbnailView extends FrameLayout { + private static final String TAG = ThumbnailView.class.getSimpleName(); + + private boolean showProgress = true; + private RoundedImageView image; + private ProgressWheel progress; private ListenableFutureTask slideDeckFuture = null; private SlideDeckListener slideDeckListener = null; private ThumbnailClickListener thumbnailClickListener = null; private String slideId = null; private Slide slide = null; - private Handler handler = new Handler(); public ThumbnailView(Context context) { - super(context); + this(context, null); } public ThumbnailView(Context context, AttributeSet attrs) { - super(context, attrs); + this(context, attrs, 0); } public ThumbnailView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + inflate(context, R.layout.thumbnail_view, this); + image = (RoundedImageView) findViewById(R.id.thumbnail_image); + progress = (ProgressWheel) findViewById(R.id.progress_wheel); + } + + @Override protected void onAttachedToWindow() { + super.onAttachedToWindow(); + EventBus.getDefault().registerSticky(this); + } + + @Override protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + EventBus.getDefault().unregister(this); + } + + @SuppressWarnings("unused") + public void onEventAsync(final PartProgressEvent event) { + if (this.slide != null && event.partId.equals(this.slide.getPart().getPartId())) { + Util.runOnMain(new Runnable() { + @Override public void run() { + progress.setInstantProgress(((float) event.progress) / event.total); + if (event.progress >= event.total) animateOutProgress(); + } + }); + } } public void setImageResource(@Nullable MasterSecret masterSecret, @@ -67,7 +98,7 @@ public class ThumbnailView extends RoundedImageView { String slideId = id + "::" + timestamp; if (!slideId.equals(this.slideId)) { - setImageDrawable(null); + image.setImageDrawable(null); this.slide = null; this.slideId = slideId; } @@ -82,13 +113,24 @@ public class ThumbnailView extends RoundedImageView { } public void setImageResource(@NonNull Slide slide, @Nullable MasterSecret masterSecret) { - if (isContextValid()) { - if (!Util.equals(slide, this.slide)) buildGlideRequest(slide, masterSecret).into(this); - this.slide = slide; - setOnClickListener(new ThumbnailClickDispatcher(thumbnailClickListener, slide)); - } else { - Log.w(TAG, "Not going to load resource, context is invalid"); + if (Util.equals(slide, this.slide)) { + Log.w(TAG, "Not loading resource, slide was identical"); + return; } + if (!isContextValid()) { + Log.w(TAG, "Not loading resource, context is invalid"); + return; + } + + this.slide = slide; + if (slide.isInProgress() && showProgress) { + progress.spin(); + progress.setVisibility(VISIBLE); + } else { + progress.setVisibility(GONE); + } + buildGlideRequest(slide, masterSecret).into(image); + setOnClickListener(new ThumbnailClickDispatcher(thumbnailClickListener, slide)); } public void setThumbnailClickListener(ThumbnailClickListener listener) { @@ -99,6 +141,13 @@ public class ThumbnailView extends RoundedImageView { if (isContextValid()) Glide.clear(this); } + public void setShowProgress(boolean showProgress) { + this.showProgress = showProgress; + if (progress.getVisibility() == View.VISIBLE && !showProgress) { + animateOutProgress(); + } + } + @TargetApi(VERSION_CODES.JELLY_BEAN_MR1) private boolean isContextValid() { return !(getContext() instanceof Activity) || @@ -110,22 +159,17 @@ public class ThumbnailView extends RoundedImageView { @Nullable MasterSecret masterSecret) { final GenericRequestBuilder builder; - if (slide.getPart().isPendingPush()) { - builder = buildPendingGlideRequest(slide); - } else if (slide.getThumbnailUri() != null) { + if (slide.getThumbnailUri() != null) { builder = buildThumbnailGlideRequest(slide, masterSecret); } else { builder = buildPlaceholderGlideRequest(slide); } - return builder.error(R.drawable.ic_missing_thumbnail_picture); - } - - private GenericRequestBuilder buildPendingGlideRequest(Slide slide) { - return Glide.with(getContext()).load(R.drawable.stat_sys_download_anim0) - .dontTransform() - .skipMemoryCache(true) - .crossFade(); + if (slide.isInProgress() && showProgress) { + return builder; + } else { + return builder.error(R.drawable.ic_missing_thumbnail_picture); + } } private GenericRequestBuilder buildThumbnailGlideRequest(Slide slide, MasterSecret masterSecret) { @@ -148,7 +192,7 @@ public class ThumbnailView extends RoundedImageView { } return Glide.with(getContext()).load(new DecryptableUri(masterSecret, slide.getThumbnailUri())) - .transform(new ThumbnailTransform(getContext())); + .centerCrop(); } private GenericRequestBuilder buildPlaceholderGlideRequest(Slide slide) { @@ -157,6 +201,19 @@ public class ThumbnailView extends RoundedImageView { .crossFade(); } + private void animateOutProgress() { + AlphaAnimation animation = new AlphaAnimation(1f, 0f); + animation.setDuration(200); + animation.setAnimationListener(new AnimationListener() { + @Override public void onAnimationStart(Animation animation) { } + @Override public void onAnimationRepeat(Animation animation) { } + @Override public void onAnimationEnd(Animation animation) { + progress.setVisibility(View.GONE); + } + }); + progress.startAnimation(animation); + } + private class SlideDeckListener implements FutureTaskListener { private final MasterSecret masterSecret; @@ -170,14 +227,14 @@ public class ThumbnailView extends RoundedImageView { final Slide slide = slideDeck.getThumbnailSlide(getContext()); if (slide != null) { - handler.post(new Runnable() { + Util.runOnMain(new Runnable() { @Override public void run() { setImageResource(slide, masterSecret); } }); } else { - handler.post(new Runnable() { + Util.runOnMain(new Runnable() { @Override public void run() { Log.w(TAG, "Resolved slide was null!"); @@ -190,7 +247,7 @@ public class ThumbnailView extends RoundedImageView { @Override public void onFailure(Throwable error) { Log.w(TAG, error); - handler.post(new Runnable() { + Util.runOnMain(new Runnable() { @Override public void run() { Log.w(TAG, "onFailure!"); diff --git a/src/org/thoughtcrime/securesms/database/MmsDatabase.java b/src/org/thoughtcrime/securesms/database/MmsDatabase.java index 7b8a091003..8ec2419a63 100644 --- a/src/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -721,6 +721,12 @@ public class MmsDatabase extends MessagingDatabase { contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT)); contentValues.remove(ADDRESS); + if (sendRequest.getBody() != null) { + for (int i = 0; i < sendRequest.getBody().getPartsNum(); i++) { + sendRequest.getBody().getPart(i).setInProgress(true); + } + } + long messageId = insertMediaMessage(masterSecret, sendRequest.getPduHeaders(), sendRequest.getBody(), contentValues); jobManager.add(new TrimThreadJob(context, threadId)); diff --git a/src/org/thoughtcrime/securesms/database/PartDatabase.java b/src/org/thoughtcrime/securesms/database/PartDatabase.java index 938f2036e4..5207ed8eb2 100644 --- a/src/org/thoughtcrime/securesms/database/PartDatabase.java +++ b/src/org/thoughtcrime/securesms/database/PartDatabase.java @@ -57,26 +57,26 @@ import ws.com.google.android.mms.pdu.PduPart; public class PartDatabase extends Database { private static final String TAG = PartDatabase.class.getSimpleName(); - private static final String TABLE_NAME = "part"; - private static final String ROW_ID = "_id"; - private static final String MMS_ID = "mid"; - private static final String SEQUENCE = "seq"; - private static final String CONTENT_TYPE = "ct"; - private static final String NAME = "name"; - private static final String CHARSET = "chset"; - private static final String CONTENT_DISPOSITION = "cd"; - private static final String FILENAME = "fn"; - private static final String CONTENT_ID = "cid"; - private static final String CONTENT_LOCATION = "cl"; - private static final String CONTENT_TYPE_START = "ctt_s"; - 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 PENDING_PUSH_ATTACHMENT = "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"; + private static final String TABLE_NAME = "part"; + private static final String ROW_ID = "_id"; + private static final String MMS_ID = "mid"; + private static final String SEQUENCE = "seq"; + private static final String CONTENT_TYPE = "ct"; + private static final String NAME = "name"; + private static final String CHARSET = "chset"; + private static final String CONTENT_DISPOSITION = "cd"; + private static final String FILENAME = "fn"; + private static final String CONTENT_ID = "cid"; + private static final String CONTENT_LOCATION = "cl"; + private static final String CONTENT_TYPE_START = "ctt_s"; + 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 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"; private static final String PART_ID_WHERE = ROW_ID + " = ? AND " + UNIQUE_ID + " = ?"; @@ -86,12 +86,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, " + - PENDING_PUSH_ATTACHMENT + " INTEGER, "+ DATA + " TEXT, " + SIZE + " INTEGER, " + + IN_PROGRESS + " 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 + " (" + PENDING_PUSH_ATTACHMENT + ");", + "CREATE INDEX IF NOT EXISTS pending_push_index ON " + TABLE_NAME + " (" + IN_PROGRESS + ");", }; private final static String IMAGES_QUERY = "SELECT " + TABLE_NAME + "." + ROW_ID + ", " @@ -127,7 +127,7 @@ public class PartDatabase extends Database { SQLiteDatabase database = databaseHelper.getWritableDatabase(); part.setContentDisposition(new byte[0]); - part.setPendingPush(false); + part.setInProgress(false); ContentValues values = getContentValuesForPart(part); @@ -275,10 +275,10 @@ public class PartDatabase extends Database { if (!cursor.isNull(encryptedColumn)) part.setEncrypted(cursor.getInt(encryptedColumn) == 1); - int pendingPushColumn = cursor.getColumnIndexOrThrow(PENDING_PUSH_ATTACHMENT); + int inProgressColumn = cursor.getColumnIndexOrThrow(IN_PROGRESS); - if (!cursor.isNull(pendingPushColumn)) - part.setPendingPush(cursor.getInt(pendingPushColumn) == 1); + if (!cursor.isNull(inProgressColumn)) + part.setInProgress(cursor.getInt(inProgressColumn) == 1); int sizeColumn = cursor.getColumnIndexOrThrow(SIZE); @@ -325,7 +325,7 @@ public class PartDatabase extends Database { } contentValues.put(ENCRYPTED, part.getEncrypted() ? 1 : 0); - contentValues.put(PENDING_PUSH_ATTACHMENT, part.isPendingPush() ? 1 : 0); + contentValues.put(IN_PROGRESS, part.isInProgress() ? 1 : 0); contentValues.put(UNIQUE_ID, part.getUniqueId()); return contentValues; @@ -437,7 +437,7 @@ public class PartDatabase extends Database { SQLiteDatabase database = databaseHelper.getWritableDatabase(); Pair partData = null; - if (!part.isPendingPush()) { + if (part.getData() != null || part.getDataUri() != null) { partData = writePartData(masterSecret, part); Log.w(TAG, "Wrote part to file: " + partData.first.getAbsolutePath()); } @@ -457,7 +457,7 @@ public class PartDatabase extends Database { Log.w(TAG, "inserting pre-generated thumbnail"); ThumbnailData data = new ThumbnailData(thumbnail); updatePartThumbnail(masterSecret, partId, part, data.toDataStream(), data.getAspectRatio()); - } else if (!part.isPendingPush()) { + } else if (!part.isInProgress()) { thumbnailExecutor.submit(new ThumbnailFetchCallable(masterSecret, partId)); } @@ -472,7 +472,7 @@ public class PartDatabase extends Database { Pair partData = writePartData(masterSecret, part, data); part.setContentDisposition(new byte[0]); - part.setPendingPush(false); + part.setInProgress(false); ContentValues values = getContentValuesForPart(part); @@ -488,6 +488,17 @@ public class PartDatabase extends Database { notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId)); } + public void markPartUploaded(long messageId, PduPart part) { + ContentValues values = new ContentValues(1); + SQLiteDatabase database = databaseHelper.getWritableDatabase(); + + part.setInProgress(false); + values.put(IN_PROGRESS, false); + database.update(TABLE_NAME, values, PART_ID_WHERE, part.getPartId().toStrings()); + + notifyConversationListeners(DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId)); + } + public void updatePartData(MasterSecret masterSecret, PduPart part, InputStream data) throws MmsException { @@ -640,5 +651,20 @@ public class PartDatabase extends Database { public boolean isValid() { return rowId >= 0 && uniqueId >= 0; } + + @Override public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + PartId partId = (PartId)o; + + if (rowId != partId.rowId) return false; + return uniqueId == partId.uniqueId; + + } + + @Override public int hashCode() { + return Util.hashCode(rowId, uniqueId); + } } } diff --git a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java index 4402aa4a17..85bce1f142 100644 --- a/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.java @@ -3,10 +3,12 @@ package org.thoughtcrime.securesms.jobs; import android.content.Context; import android.util.Log; + import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; 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.util.Base64; @@ -15,6 +17,7 @@ import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; import org.whispersystems.libaxolotl.InvalidMessageException; import org.whispersystems.textsecure.api.TextSecureMessageReceiver; +import org.whispersystems.textsecure.api.messages.TextSecureAttachment.ProgressListener; import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer; import org.whispersystems.textsecure.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.textsecure.api.push.exceptions.PushNetworkException; @@ -26,6 +29,7 @@ import java.util.List; import javax.inject.Inject; +import de.greenrobot.event.EventBus; import ws.com.google.android.mms.MmsException; import ws.com.google.android.mms.pdu.PduPart; @@ -82,15 +86,19 @@ public class AttachmentDownloadJob extends MasterSecretJob implements Injectable private void retrievePart(MasterSecret masterSecret, PduPart part, long messageId) throws IOException { - PartDatabase database = DatabaseFactory.getPartDatabase(context); - File attachmentFile = null; - PartDatabase.PartId partId = part.getPartId(); + PartDatabase database = DatabaseFactory.getPartDatabase(context); + File attachmentFile = null; + final PartId partId = part.getPartId(); try { attachmentFile = createTempFile(); TextSecureAttachmentPointer pointer = createAttachmentPointer(masterSecret, part); - InputStream attachment = messageReceiver.retrieveAttachment(pointer, attachmentFile); + InputStream attachment = messageReceiver.retrieveAttachment(pointer, attachmentFile, new ProgressListener() { + @Override public void onAttachmentProgress(long total, long progress) { + EventBus.getDefault().postSticky(new PartProgressEvent(partId, total, progress)); + } + }); database.updateDownloadedPart(masterSecret, messageId, partId, part, attachment); } catch (InvalidPartException | NonSuccessfulResponseCodeException | InvalidMessageException | MmsException e) { @@ -145,4 +153,5 @@ public class AttachmentDownloadJob extends MasterSecretJob implements Injectable private class InvalidPartException extends Exception { public InvalidPartException(Exception e) {super(e);} } + } diff --git a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java index c85d1fe1bd..f3a5b14670 100644 --- a/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java +++ b/src/org/thoughtcrime/securesms/jobs/AvatarDownloadJob.java @@ -96,7 +96,7 @@ public class AvatarDownloadJob extends MasterSecretJob { destination.deleteOnExit(); - socket.retrieveAttachment(relay, contentLocation, destination); + socket.retrieveAttachment(relay, contentLocation, destination, null); return destination; } diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java index 3b36e6d48d..90b78b906d 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceContactUpdateJob.java @@ -103,7 +103,8 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje FileInputStream contactsFileStream = new FileInputStream(contactsFile); TextSecureAttachmentStream attachmentStream = new TextSecureAttachmentStream(contactsFileStream, "application/octet-stream", - contactsFile.length()); + contactsFile.length(), + null); try { messageSender.sendMessage(TextSecureSyncMessage.forContacts(attachmentStream)); @@ -117,7 +118,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje try { Uri displayPhotoUri = Uri.withAppendedPath(uri, ContactsContract.Contacts.Photo.DISPLAY_PHOTO); AssetFileDescriptor fd = context.getContentResolver().openAssetFileDescriptor(displayPhotoUri, "r"); - return Optional.of(new TextSecureAttachmentStream(fd.createInputStream(), "image/*", fd.getLength())); + return Optional.of(new TextSecureAttachmentStream(fd.createInputStream(), "image/*", fd.getLength(), null)); } catch (IOException e) { Log.w(TAG, e); } @@ -140,7 +141,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje byte[] data = cursor.getBlob(0); if (data != null) { - return Optional.of(new TextSecureAttachmentStream(new ByteArrayInputStream(data), "image/*", data.length)); + return Optional.of(new TextSecureAttachmentStream(new ByteArrayInputStream(data), "image/*", data.length, null)); } } diff --git a/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java b/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java index 7f8b1e9cd5..5fdaf13f92 100644 --- a/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java +++ b/src/org/thoughtcrime/securesms/jobs/MultiDeviceGroupUpdateJob.java @@ -95,7 +95,8 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject FileInputStream contactsFileStream = new FileInputStream(contactsFile); TextSecureAttachmentStream attachmentStream = new TextSecureAttachmentStream(contactsFileStream, "application/octet-stream", - contactsFile.length()); + contactsFile.length(), + null); messageSender.sendMessage(TextSecureSyncMessage.forGroups(attachmentStream)); } @@ -105,7 +106,7 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject if (avatar == null) return Optional.absent(); return Optional.of(new TextSecureAttachmentStream(new ByteArrayInputStream(avatar), - "image/*", avatar.length)); + "image/*", avatar.length, null)); } private File createTempFile(String prefix) throws IOException { diff --git a/src/org/thoughtcrime/securesms/jobs/PartProgressEvent.java b/src/org/thoughtcrime/securesms/jobs/PartProgressEvent.java new file mode 100644 index 0000000000..7a22aaef6b --- /dev/null +++ b/src/org/thoughtcrime/securesms/jobs/PartProgressEvent.java @@ -0,0 +1,15 @@ +package org.thoughtcrime.securesms.jobs; + +import org.thoughtcrime.securesms.database.PartDatabase.PartId; + +public class PartProgressEvent { + public PartId partId; + public long total; + public long progress; + + public PartProgressEvent(PartId partId, long total, long progress) { + this.partId = partId; + this.total = total; + this.progress = progress; + } +} diff --git a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index ead5f892c2..1fbe8d51a1 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MmsDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; +import org.thoughtcrime.securesms.database.PartDatabase; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.mms.MediaConstraints; import org.thoughtcrime.securesms.mms.PartParser; @@ -30,6 +31,7 @@ import java.util.List; import javax.inject.Inject; import ws.com.google.android.mms.MmsException; +import ws.com.google.android.mms.pdu.PduBody; import ws.com.google.android.mms.pdu.SendReq; import static org.thoughtcrime.securesms.dependencies.TextSecureCommunicationModule.TextSecureMessageSenderFactory; @@ -69,6 +71,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { database.markAsPush(messageId); database.markAsSecure(messageId); database.markAsSent(messageId, "push".getBytes(), 0); + updatePartsStatus(message.getBody()); } catch (InsecureFallbackApprovalException ifae) { Log.w(TAG, ifae); database.markAsPendingInsecureSmsFallback(messageId); @@ -97,6 +100,13 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { notifyMediaMessageDeliveryFailed(context, messageId); } + private void updatePartsStatus(PduBody body) { + if (body == null) return; + PartDatabase database = DatabaseFactory.getPartDatabase(context); + for (int i = 0; i < body.getPartsNum(); i++) { + database.markPartUploaded(messageId, body.getPart(i)); + } + } private void deliver(MasterSecret masterSecret, SendReq message) throws RetryLaterException, InsecureFallbackApprovalException, UntrustedIdentityException, diff --git a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java index 027148092f..bddae1c39d 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushSendJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushSendJob.java @@ -10,13 +10,12 @@ import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.notifications.MessageNotifier; import org.thoughtcrime.securesms.recipients.Recipients; -import org.thoughtcrime.securesms.util.GroupUtil; -import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.jobqueue.requirements.NetworkRequirement; import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; +import org.whispersystems.textsecure.api.messages.TextSecureAttachment.ProgressListener; import org.whispersystems.textsecure.api.messages.TextSecureAttachmentStream; import org.whispersystems.textsecure.api.push.TextSecureAddress; import org.whispersystems.textsecure.api.util.InvalidNumberException; @@ -26,6 +25,7 @@ import java.io.InputStream; import java.util.LinkedList; import java.util.List; +import de.greenrobot.event.EventBus; import ws.com.google.android.mms.ContentType; import ws.com.google.android.mms.pdu.PduPart; import ws.com.google.android.mms.pdu.SendReq; @@ -59,16 +59,19 @@ public abstract class PushSendJob extends SendJob { List attachments = new LinkedList<>(); for (int i=0;i