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"
}
def canonicalVersionCode = 72
def canonicalVersionName = "1.4.4"
def canonicalVersionCode = 73
def canonicalVersionName = "1.4.5"
def postFixSize = 10
def abiPostFix = ['armeabi-v7a' : 1,

View File

@ -25,15 +25,15 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Process;
import android.provider.OpenableColumns;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
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.conversation.ConversationActivity;
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.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FileUtils;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -337,12 +336,13 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity
private InputStream openFileUri(Uri uri) throws IOException {
FileInputStream fin = new FileInputStream(uri.getPath());
int owner = FileUtils.getFileDescriptorOwner(fin.getFD());
if (owner == -1 || owner == Process.myUid()) {
fin.close();
throw new IOException("File owned by application");
}
// 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()) {
// fin.close();
// throw new IOException("File owned by application");
// }
return fin;
}

View File

@ -426,7 +426,9 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder, int 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) {

View File

@ -20,11 +20,12 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd;
@ -816,7 +817,8 @@ public class MmsDatabase extends MessagingDatabase {
private Optional<InsertResult> insertMessageInbox(IncomingMediaMessage retrieved,
String contentLocation,
long threadId, long mailbox)
long threadId, long mailbox,
long serverTimestamp)
throws MmsException
{
if (threadId == -1 || retrieved.isGroupMessage()) {
@ -839,7 +841,10 @@ public class MmsDatabase extends MessagingDatabase {
contentValues.put(THREAD_ID, threadId);
contentValues.put(CONTENT_LOCATION, contentLocation);
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(SUBSCRIPTION_ID, retrieved.getSubscriptionId());
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
@ -893,11 +898,11 @@ public class MmsDatabase extends MessagingDatabase {
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)
throws MmsException
public Optional<InsertResult> insertSecureDecryptedMessageInbox(IncomingMediaMessage retrieved, long threadId, long serverTimestamp)
throws MmsException
{
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;
}
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) {

View File

@ -20,10 +20,11 @@ package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Pair;
import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase;
@ -580,7 +581,7 @@ public class SmsDatabase extends MessagingDatabase {
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()) {
type = (type & (Types.TOTAL_MASK - Types.BASE_TYPE_MASK)) | Types.JOINED_TYPE;
} else if (message.isPreKeyBundle()) {
@ -625,7 +626,10 @@ public class SmsDatabase extends MessagingDatabase {
ContentValues values = new ContentValues(6);
values.put(ADDRESS, message.getSender().serialize());
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(PROTOCOL, message.getProtocol());
values.put(READ, unread ? 0 : 1);
@ -672,7 +676,11 @@ public class SmsDatabase extends MessagingDatabase {
}
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,

View File

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

View File

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

View File

@ -755,7 +755,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
Optional<InsertResult> insertResult;
try {
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
if (message.isGroupMessage()) {
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1, content.getTimestamp());
} else {
insertResult = database.insertSecureDecryptedMessageInbox(mediaMessage, -1);
}
if (insertResult.isPresent()) {
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; }
// 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()) {
threadId = insertResult.get().getThreadId();

View File

@ -1,17 +1,15 @@
package org.thoughtcrime.securesms.loki.activities
import android.Manifest
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
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.View
import android.view.ViewGroup
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.fragment_view_my_qr_code.*
import network.loki.messenger.R
@ -106,8 +104,8 @@ class ViewMyQRCodeFragment : Fragment() {
private val hexEncodedPublicKey: String
get() {
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(context!!)
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(context!!)
val masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(requireContext())
val userHexEncodedPublicKey = TextSecurePreferences.getLocalNumber(requireContext())
return masterHexEncodedPublicKey ?: userHexEncodedPublicKey
}
@ -127,33 +125,22 @@ class ViewMyQRCodeFragment : Fragment() {
}
private fun shareQRCode() {
fun proceed() {
val directory = File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES)
val fileName = "$hexEncodedPublicKey.png"
val file = File(directory, fileName)
file.createNewFile()
val fos = FileOutputStream(file)
val size = toPx(280, resources)
val qrCode = QRCodeUtilities.encode(hexEncodedPublicKey, size, false, false)
qrCode.compress(Bitmap.CompressFormat.PNG, 100, fos)
fos.flush()
fos.close()
val intent = Intent(Intent.ACTION_SEND)
intent.putExtra(Intent.EXTRA_STREAM, FileProviderUtil.getUriFor(activity!!, file))
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = "image/png"
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()
}
}
}
val directory = requireContext().externalCacheDir
val fileName = "$hexEncodedPublicKey.png"
val file = File(directory, fileName)
file.createNewFile()
val fos = FileOutputStream(file)
val size = toPx(280, resources)
val qrCode = QRCodeUtilities.encode(hexEncodedPublicKey, size, false, false)
qrCode.compress(Bitmap.CompressFormat.PNG, 100, fos)
fos.flush()
fos.close()
val intent = Intent(Intent.ACTION_SEND)
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.type = "image/png"
startActivity(Intent.createChooser(intent, resources.getString(R.string.fragment_view_my_qr_code_share_title)))
}
}
// endregion

View File

@ -166,7 +166,7 @@ class PublicChatPoller(private val context: Context, private val group: PublicCh
}
val senderHexEncodedPublicKey = masterHexEncodedPublicKey ?: message.senderPublicKey
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) {
PushDecryptJob(context).handleMediaMessage(serviceContent, serviceDataMessage, Optional.absent(), Optional.of(message.serverID))
} else {

View File

@ -22,13 +22,14 @@ import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import androidx.annotation.ArrayRes;
import androidx.annotation.AttrRes;
import androidx.annotation.DimenRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import android.util.TypedValue;
import org.thoughtcrime.securesms.logging.Log;
@ -57,7 +58,7 @@ public class ResUtil {
int drawableRes = getDrawableRes(c, attr);
if (drawableRes == 0) {
Log.e(TAG, "Cannot find a drawable resource associated with the attribute: " + attr,
new Resources.NotFoundException());
new Resources.NotFoundException());
return null;
}
return ContextCompat.getDrawable(c, drawableRes);