pull/305/head
Anton Chekulaev 4 years ago
commit f11478585d

@ -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,

@ -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;
}

@ -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) {

@ -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) {

@ -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,

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

@ -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);
}

@ -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();

@ -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

@ -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 {

@ -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);

Loading…
Cancel
Save