This commit is contained in:
Anton Chekulaev 2020-08-27 15:51:54 +10:00
commit f11478585d
11 changed files with 87 additions and 66 deletions

View File

@ -185,8 +185,8 @@ dependencies {
implementation "com.opencsv:opencsv:4.6" implementation "com.opencsv:opencsv:4.6"
} }
def canonicalVersionCode = 72 def canonicalVersionCode = 73
def canonicalVersionName = "1.4.4" def canonicalVersionName = "1.4.5"
def postFixSize = 10 def postFixSize = 10
def abiPostFix = ['armeabi-v7a' : 1, def abiPostFix = ['armeabi-v7a' : 1,

View File

@ -25,15 +25,15 @@ import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcel; import android.os.Parcel;
import android.os.Process;
import android.provider.OpenableColumns; import android.provider.OpenableColumns;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import org.thoughtcrime.securesms.components.SearchToolbar; import org.thoughtcrime.securesms.components.SearchToolbar;
import org.thoughtcrime.securesms.conversation.ConversationActivity; import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.database.Address; import org.thoughtcrime.securesms.database.Address;
@ -50,7 +50,6 @@ import org.thoughtcrime.securesms.stickers.StickerLocator;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FileUtils;
import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.ViewUtil;
@ -337,12 +336,13 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
private InputStream openFileUri(Uri uri) throws IOException { private InputStream openFileUri(Uri uri) throws IOException {
FileInputStream fin = new FileInputStream(uri.getPath()); FileInputStream fin = new FileInputStream(uri.getPath());
int owner = FileUtils.getFileDescriptorOwner(fin.getFD()); // TODO: Remove the commented code if there are no issues with reading shared files by October 2020
// int owner = FileUtils.getFileDescriptorOwner(fin.getFD());
if (owner == -1 || owner == Process.myUid()) { // if (owner == -1 || owner == Process.myUid()) {
fin.close(); // fin.close();
throw new IOException("File owned by application"); // throw new IOException("File owned by application");
} // }
return fin; return fin;
} }

View File

@ -426,7 +426,9 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override @Override
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) { public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int position) {
MessageRecord messageRecord = getRecordForPositionOrThrow(position); MessageRecord messageRecord = getRecordForPositionOrThrow(position);
viewHolder.setText(DateUtils.getRelativeDate(getContext(), locale, messageRecord.getDateReceived())); long timestamp = messageRecord.getDateReceived();
if (recipient.getAddress().isOpenGroup()) { timestamp = messageRecord.getTimestamp(); }
viewHolder.setText(DateUtils.getRelativeDate(getContext(), locale, timestamp));
} }
public void onBindLastSeenViewHolder(HeaderViewHolder viewHolder, int position) { public void onBindLastSeenViewHolder(HeaderViewHolder viewHolder, int position) {

View File

@ -20,11 +20,12 @@ import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Collectors; import com.annimon.stream.Collectors;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd; import com.google.android.mms.pdu_alt.NotificationInd;
@ -816,7 +817,8 @@ public class MmsDatabase extends MessagingDatabase {
private Optional<InsertResult> insertMessageInbox(IncomingMediaMessage retrieved, private Optional<InsertResult> insertMessageInbox(IncomingMediaMessage retrieved,
String contentLocation, String contentLocation,
long threadId, long mailbox) long threadId, long mailbox,
long serverTimestamp)
throws MmsException throws MmsException
{ {
if (threadId == -1 || retrieved.isGroupMessage()) { if (threadId == -1 || retrieved.isGroupMessage()) {
@ -839,7 +841,10 @@ public class MmsDatabase extends MessagingDatabase {
contentValues.put(THREAD_ID, threadId); contentValues.put(THREAD_ID, threadId);
contentValues.put(CONTENT_LOCATION, contentLocation); contentValues.put(CONTENT_LOCATION, contentLocation);
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED); contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
contentValues.put(DATE_RECEIVED, retrieved.getSentTimeMillis()); // Loki - This is important due to how we handle GIFs // In open groups messages should be sorted by their server timestamp
long receivedTimestamp = serverTimestamp;
if (serverTimestamp == 0) { receivedTimestamp = retrieved.getSentTimeMillis(); }
contentValues.put(DATE_RECEIVED, receivedTimestamp); // Loki - This is important due to how we handle GIFs
contentValues.put(PART_COUNT, retrieved.getAttachments().size()); contentValues.put(PART_COUNT, retrieved.getAttachments().size());
contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId()); contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId());
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn()); contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
@ -893,10 +898,10 @@ public class MmsDatabase extends MessagingDatabase {
type |= Types.EXPIRATION_TIMER_UPDATE_BIT; type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
} }
return insertMessageInbox(retrieved, contentLocation, threadId, type); return insertMessageInbox(retrieved, contentLocation, threadId, type, 0);
} }
public Optional<InsertResult> insertSecureDecryptedMessageInbox(IncomingMediaMessage retrieved, long threadId) public Optional<InsertResult> insertSecureDecryptedMessageInbox(IncomingMediaMessage retrieved, long threadId, long serverTimestamp)
throws MmsException throws MmsException
{ {
long type = Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT; long type = Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT;
@ -909,7 +914,13 @@ public class MmsDatabase extends MessagingDatabase {
type |= Types.EXPIRATION_TIMER_UPDATE_BIT; type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
} }
return insertMessageInbox(retrieved, "", threadId, type); return insertMessageInbox(retrieved, "", threadId, type, 0);
}
public Optional<InsertResult> insertSecureDecryptedMessageInbox(IncomingMediaMessage retrieved, long threadId)
throws MmsException
{
return insertSecureDecryptedMessageInbox(retrieved, threadId, 0);
} }
public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification, int subscriptionId) { public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification, int subscriptionId) {

View File

@ -20,10 +20,11 @@ package org.thoughtcrime.securesms.database;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import androidx.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.NonNull;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteDatabase;
@ -580,7 +581,7 @@ public class SmsDatabase extends MessagingDatabase {
return new Pair<>(messageId, threadId); return new Pair<>(messageId, threadId);
} }
protected Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long type) { protected Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long type, long serverTimestamp) {
if (message.isJoined()) { if (message.isJoined()) {
type = (type & (Types.TOTAL_MASK - Types.BASE_TYPE_MASK)) | Types.JOINED_TYPE; type = (type & (Types.TOTAL_MASK - Types.BASE_TYPE_MASK)) | Types.JOINED_TYPE;
} else if (message.isPreKeyBundle()) { } else if (message.isPreKeyBundle()) {
@ -625,7 +626,10 @@ public class SmsDatabase extends MessagingDatabase {
ContentValues values = new ContentValues(6); ContentValues values = new ContentValues(6);
values.put(ADDRESS, message.getSender().serialize()); values.put(ADDRESS, message.getSender().serialize());
values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId()); values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId());
values.put(DATE_RECEIVED, message.getSentTimestampMillis()); // Loki - This is important due to how we handle GIFs // In open groups messages should be sorted by their server timestamp
long receivedTimestamp = serverTimestamp;
if (serverTimestamp == 0) { receivedTimestamp = message.getSentTimestampMillis(); }
values.put(DATE_RECEIVED, receivedTimestamp); // Loki - This is important due to how we handle GIFs
values.put(DATE_SENT, message.getSentTimestampMillis()); values.put(DATE_SENT, message.getSentTimestampMillis());
values.put(PROTOCOL, message.getProtocol()); values.put(PROTOCOL, message.getProtocol());
values.put(READ, unread ? 0 : 1); values.put(READ, unread ? 0 : 1);
@ -672,7 +676,11 @@ public class SmsDatabase extends MessagingDatabase {
} }
public Optional<InsertResult> insertMessageInbox(IncomingTextMessage message) { public Optional<InsertResult> insertMessageInbox(IncomingTextMessage message) {
return insertMessageInbox(message, Types.BASE_INBOX_TYPE); return insertMessageInbox(message, Types.BASE_INBOX_TYPE, 0);
}
public Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long serverTimestamp) {
return insertMessageInbox(message, Types.BASE_INBOX_TYPE, serverTimestamp);
} }
public long insertMessageOutbox(long threadId, OutgoingTextMessage message, public long insertMessageOutbox(long threadId, OutgoingTextMessage message,

View File

@ -139,6 +139,9 @@ public abstract class MessageRecord extends DisplayRecord {
if (isPush() && getDateSent() < getDateReceived()) { if (isPush() && getDateSent() < getDateReceived()) {
return getDateSent(); return getDateSent();
} }
if (getRecipient().getAddress().isOpenGroup()) {
return getDateSent();
}
return getDateReceived(); return getDateReceived();
} }

View File

@ -52,7 +52,7 @@ public class AttachmentUploadJob extends BaseJob implements InjectableType {
this(new Job.Parameters.Builder() this(new Job.Parameters.Builder()
.addConstraint(NetworkConstraint.KEY) .addConstraint(NetworkConstraint.KEY)
.setLifespan(TimeUnit.DAYS.toMillis(1)) .setLifespan(TimeUnit.DAYS.toMillis(1))
.setMaxAttempts(1) .setMaxAttempts(5)
.build(), .build(),
attachmentId, destination); attachmentId, destination);
} }

View File

@ -755,7 +755,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
Optional<InsertResult> insertResult; Optional<InsertResult> insertResult;
try { try {
if (message.isGroupMessage()) {
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1, content.getTimestamp());
} else {
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1); insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
}
if (insertResult.isPresent()) { if (insertResult.isPresent()) {
List<DatabaseAttachment> allAttachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(insertResult.get().getMessageId()); List<DatabaseAttachment> allAttachments = DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(insertResult.get().getMessageId());
@ -952,7 +956,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
if (textMessage.getMessageBody().length() == 0) { return; } if (textMessage.getMessageBody().length() == 0) { return; }
// Insert the message into the database // Insert the message into the database
Optional<InsertResult> insertResult = database.insertMessageInbox(textMessage); Optional<InsertResult> insertResult;
if (message.isGroupMessage()) {
insertResult = database.insertMessageInbox(textMessage, content.getTimestamp());
} else {
insertResult = database.insertMessageInbox(textMessage);
}
if (insertResult.isPresent()) { if (insertResult.isPresent()) {
threadId = insertResult.get().getThreadId(); threadId = insertResult.get().getThreadId();

View File

@ -1,17 +1,15 @@
package org.thoughtcrime.securesms.loki.activities package org.thoughtcrime.securesms.loki.activities
import android.Manifest
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentPagerAdapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import com.tbruyelle.rxpermissions2.RxPermissions import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentPagerAdapter
import kotlinx.android.synthetic.main.activity_qr_code.* import kotlinx.android.synthetic.main.activity_qr_code.*
import kotlinx.android.synthetic.main.fragment_view_my_qr_code.* import kotlinx.android.synthetic.main.fragment_view_my_qr_code.*
import network.loki.messenger.R import network.loki.messenger.R
@ -106,8 +104,8 @@ class ViewMyQRCodeFragment : Fragment() {
private val hexEncodedPublicKey: String private val hexEncodedPublicKey: String
get() { get() {
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context!!) val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(requireContext())
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context!!) val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(requireContext())
return masterHexEncodedPublicKey ?: userHexEncodedPublicKey return masterHexEncodedPublicKey ?: userHexEncodedPublicKey
} }
@ -127,8 +125,7 @@ class ViewMyQRCodeFragment : Fragment() {
} }
private fun shareQRCode() { private fun shareQRCode() {
fun proceed() { val directory = requireContext().externalCacheDir
val directory = File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES)
val fileName = "$hexEncodedPublicKey.png" val fileName = "$hexEncodedPublicKey.png"
val file = File(directory, fileName) val file = File(directory, fileName)
file.createNewFile() file.createNewFile()
@ -139,21 +136,11 @@ class ViewMyQRCodeFragment : Fragment() {
fos.flush() fos.flush()
fos.close() fos.close()
val intent = Intent(Intent.ACTION_SEND) val intent = Intent(Intent.ACTION_SEND)
intent.putExtra(Intent.EXTRA_STREAM, FileProviderUtil.getUriFor(activity!!, file)) intent.putExtra(Intent.EXTRA_STREAM, FileProviderUtil.getUriFor(requireActivity(), file))
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file))
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = "image/png" intent.type = "image/png"
startActivity(Intent.createChooser(intent, resources.getString(R.string.fragment_view_my_qr_code_share_title))) startActivity(Intent.createChooser(intent, resources.getString(R.string.fragment_view_my_qr_code_share_title)))
} }
if (RxPermissions(this).isGranted(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
proceed()
} else {
@SuppressWarnings("unused")
val unused = RxPermissions(this).request(Manifest.permission.WRITE_EXTERNAL_STORAGE).subscribe { isGranted ->
if (isGranted) {
proceed()
}
}
}
}
} }
// endregion // endregion

View File

@ -166,7 +166,7 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
} }
val senderHexEncodedPublicKey = masterHexEncodedPublicKey ?: message.senderPublicKey val senderHexEncodedPublicKey = masterHexEncodedPublicKey ?: message.senderPublicKey
val serviceDataMessage = getDataMessage(message) val serviceDataMessage = getDataMessage(message)
val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.timestamp, false, false) val serviceContent = SignalServiceContent(serviceDataMessage, senderHexEncodedPublicKey, SignalServiceAddress.DEFAULT_DEVICE_ID, message.serverTimestamp, false, false)
if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) { if (serviceDataMessage.quote.isPresent || (serviceDataMessage.attachments.isPresent && serviceDataMessage.attachments.get().size > 0) || serviceDataMessage.previews.isPresent) {
PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID)) PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
} else { } else {

View File

@ -22,13 +22,14 @@ import android.content.res.Resources;
import android.content.res.Resources.Theme; import android.content.res.Resources.Theme;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import androidx.annotation.ArrayRes; import androidx.annotation.ArrayRes;
import androidx.annotation.AttrRes; import androidx.annotation.AttrRes;
import androidx.annotation.DimenRes; import androidx.annotation.DimenRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import android.util.TypedValue;
import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.logging.Log;