Compare commits

...

7 Commits

Author SHA1 Message Date
Moxie Marlinspike
f450b37cfd Bump version to 2.5.2
// FREEBIE
2015-02-11 23:24:10 -08:00
Jake McGinty
b88e470594 prevent recipient listener Activity context leak
Resolves #2372
Resolves #2425
// FREEBIE
2015-02-11 12:50:20 -08:00
Jake McGinty
f38677794a stop giving long-living static objects Activity contexts
// FREEBIE
2015-02-11 12:50:19 -08:00
Jake McGinty
ac4db41435 lower memory consumption from previews
// FREEBIE
2015-02-11 12:50:19 -08:00
Jake McGinty
3a9d521ffe Workaround LG-related menu issues, pt. 2
fixes #2444
// FREEBIE
2015-02-11 12:44:40 -08:00
Jake McGinty
b1bf33b13b Fix SaveAttachmentTask NPE
resolves #2454
// FREEBIE
2015-02-11 11:42:36 -08:00
Moxie Marlinspike
352418d2d7 Don't notify on MMS delivery failure if message has been deleted.
// FREEBIE

Fixes #2453
2015-02-11 10:29:05 -08:00
9 changed files with 132 additions and 58 deletions

View File

@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="org.thoughtcrime.securesms"
android:versionCode="92"
android:versionName="2.5.1">
android:versionCode="93"
android:versionName="2.5.2">
<permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"
android:label="Access to TextSecure Secrets"
@@ -206,6 +206,7 @@
<activity android:name=".MediaPreviewActivity"
android:label="@string/AndroidManifest__media_preview"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DummyActivity"

View File

@@ -1,22 +1,53 @@
package org.thoughtcrime.securesms;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.ViewConfiguration;
import java.lang.reflect.Field;
public abstract class BaseActionBarActivity extends ActionBarActivity {
private static final String TAG = BaseActionBarActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
if (BaseActivity.isMenuWorkaroundRequired()) {
forceOverflowMenu();
}
super.onCreate(savedInstanceState);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return BaseActivity.isKeyCodeWorkaroundRequired(keyCode) || super.onKeyDown(keyCode, event);
return (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (BaseActivity.isKeyCodeWorkaroundRequired(keyCode)) {
if (keyCode == KeyEvent.KEYCODE_MENU && BaseActivity.isMenuWorkaroundRequired()) {
openOptionsMenu();
return true;
}
return super.onKeyUp(keyCode, event);
}
/**
* Modified from: http://stackoverflow.com/a/13098824
*/
private void forceOverflowMenu() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if(menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.w(TAG, "Failed to force overflow menu.");
}
}
}

View File

@@ -1,6 +1,8 @@
package org.thoughtcrime.securesms;
import android.os.Build;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.view.KeyEvent;
@@ -8,21 +10,21 @@ import android.view.KeyEvent;
public abstract class BaseActivity extends FragmentActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return isKeyCodeWorkaroundRequired(keyCode) || super.onKeyDown(keyCode, event);
return (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) || super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (isKeyCodeWorkaroundRequired(keyCode)) {
if (keyCode == KeyEvent.KEYCODE_MENU && isMenuWorkaroundRequired()) {
openOptionsMenu();
return true;
}
return super.onKeyUp(keyCode, event);
}
public static boolean isKeyCodeWorkaroundRequired(int keyCode) {
return (keyCode == KeyEvent.KEYCODE_MENU) &&
(Build.VERSION.SDK_INT == 16) &&
("LGE".equalsIgnoreCase(Build.MANUFACTURER));
public static boolean isMenuWorkaroundRequired() {
return VERSION.SDK_INT <= VERSION_CODES.JELLY_BEAN &&
VERSION.SDK_INT > VERSION_CODES.GINGERBREAD_MR1 &&
("LGE".equalsIgnoreCase(Build.MANUFACTURER) || "E6710".equalsIgnoreCase(Build.DEVICE));
}
}

View File

@@ -126,7 +126,8 @@ import static org.whispersystems.textsecure.internal.push.PushMessageProtos.Push
*/
public class ConversationActivity extends PassphraseRequiredActionBarActivity
implements ConversationFragment.ConversationFragmentListener,
AttachmentManager.AttachmentListener
AttachmentManager.AttachmentListener,
RecipientModifiedListener
{
private static final String TAG = ConversationActivity.class.getSimpleName();
@@ -232,6 +233,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onDestroy() {
saveDraft();
recipients.removeListener(this);
unregisterReceiver(securityUpdateReceiver);
unregisterReceiver(groupUpdateReceiver);
MemoryCleaner.clean(masterSecret);
@@ -764,12 +766,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
distributionType = getIntent().getIntExtra(DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA);
recipients.addListener(new RecipientModifiedListener() {
@Override
public void onModified(Recipient recipient) {
initializeTitleBar();
}
});
recipients.addListener(this);
}
@Override
public void onModified(Recipient recipient) {
initializeTitleBar();
}
private void initializeReceivers() {

View File

@@ -18,6 +18,7 @@ package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.opengl.GLES20;
@@ -36,7 +37,6 @@ import android.widget.TextView;
import android.widget.Toast;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.Recipient.RecipientModifiedListener;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
@@ -48,14 +48,13 @@ import org.thoughtcrime.securesms.util.SaveAttachmentTask;
import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
import java.io.IOException;
import java.io.InputStream;
import uk.co.senab.photoview.PhotoViewAttacher;
/**
* Activity for displaying media attachments in-app
*/
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity implements RecipientModifiedListener {
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
public final static String MASTER_SECRET_EXTRA = "master_secret";
@@ -65,9 +64,11 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private MasterSecret masterSecret;
private boolean paused;
private View loadingView;
private TextView errorText;
private Bitmap bitmap;
private ImageView image;
private PhotoViewAttacher imageAttacher;
private Uri mediaUri;
@@ -88,7 +89,9 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.media_preview_activity);
initializeViews();
initializeResources();
initializeActionBar();
}
@TargetApi(VERSION_CODES.JELLY_BEAN)
@@ -98,11 +101,58 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
}
}
@Override
public void onModified(Recipient recipient) {
initializeActionBar();
}
private void initializeActionBar() {
final CharSequence relativeTimeSpan;
if (date > 0) {
relativeTimeSpan = DateUtils.getRelativeTimeSpanString(date,
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS);
} else {
relativeTimeSpan = null;
}
getSupportActionBar().setTitle(recipient == null ? getString(R.string.MediaPreviewActivity_you) : recipient.toShortString());
getSupportActionBar().setSubtitle(relativeTimeSpan);
}
@Override
public void onResume() {
super.onResume();
paused = false;
dynamicLanguage.onResume(this);
if (recipient != null) recipient.addListener(this);
initializeMedia();
}
@Override
public void onPause() {
super.onPause();
paused = true;
if (recipient != null) recipient.removeListener(this);
cleanupMedia();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (recipient != null) recipient.removeListener(this);
setIntent(intent);
initializeResources();
initializeActionBar();
}
private void initializeViews() {
loadingView = findViewById(R.id.loading_indicator);
errorText = (TextView) findViewById(R.id.error);
image = (ImageView) findViewById(R.id.image);
imageAttacher = new PhotoViewAttacher(image);
}
private void initializeResources() {
final long recipientId = getIntent().getLongExtra(RECIPIENT_EXTRA, -1);
masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA);
@@ -112,18 +162,13 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
if (recipientId > -1) {
recipient = RecipientFactory.getRecipientForId(this, recipientId, true);
recipient.addListener(new RecipientModifiedListener() {
@Override
public void onModified(Recipient recipient) {
initializeActionBar();
}
});
recipient.addListener(this);
} else {
recipient = null;
}
}
initializeActionBar();
private void initializeMedia() {
if (!isContentTypeSupported(mediaType)) {
Log.w(TAG, "Unsupported media type sent to MediaPreviewActivity, finishing.");
Toast.makeText(getApplicationContext(), R.string.MediaPreviewActivity_unssuported_media_type, Toast.LENGTH_LONG).show();
@@ -137,32 +182,14 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
}
}
private void initializeActionBar() {
final CharSequence relativeTimeSpan;
if (date > 0) {
relativeTimeSpan = DateUtils.getRelativeTimeSpanString(date,
System.currentTimeMillis(),
DateUtils.MINUTE_IN_MILLIS);
} else {
relativeTimeSpan = null;
private void cleanupMedia() {
image.setImageDrawable(null);
if (bitmap != null) {
bitmap.recycle();
bitmap = null;
}
getSupportActionBar().setTitle(recipient == null ? getString(R.string.MediaPreviewActivity_you) : recipient.getName());
getSupportActionBar().setSubtitle(relativeTimeSpan);
}
@Override
public void onPause() {
super.onPause();
}
private void initializeResources() {
loadingView = findViewById(R.id.loading_indicator);
errorText = (TextView) findViewById(R.id.error);
image = (ImageView) findViewById(R.id.image);
imageAttacher = new PhotoViewAttacher(image);
}
private void displayImage() {
new AsyncTask<Void,Void,Bitmap>() {
@Override
@@ -186,12 +213,17 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
@Override
protected void onPostExecute(Bitmap bitmap) {
loadingView.setVisibility(View.GONE);
if (paused) {
if (bitmap != null) bitmap.recycle();
return;
}
loadingView.setVisibility(View.GONE);
if (bitmap == null) {
errorText.setText(R.string.MediaPreviewActivity_cant_display);
errorText.setVisibility(View.VISIBLE);
} else {
MediaPreviewActivity.this.bitmap = bitmap;
image.setImageBitmap(bitmap);
image.setVisibility(View.VISIBLE);
imageAttacher.update();

View File

@@ -73,7 +73,7 @@ public class ApnDatabase {
private static ApnDatabase instance = null;
public synchronized static ApnDatabase getInstance(Context context) throws IOException {
if (instance == null) instance = new ApnDatabase(context);
if (instance == null) instance = new ApnDatabase(context.getApplicationContext());
return instance;
}

View File

@@ -47,7 +47,7 @@ public class TextSecureDirectory {
if (instance == null) {
synchronized (instanceLock) {
if (instance == null) {
instance = new TextSecureDirectory(context);
instance = new TextSecureDirectory(context.getApplicationContext());
}
}
}

View File

@@ -244,7 +244,9 @@ public class MmsSendJob extends SendJob {
long threadId = DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
Recipients recipients = DatabaseFactory.getThreadDatabase(context).getRecipientsForThreadId(threadId);
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
if (recipients != null) {
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
}
}

View File

@@ -59,10 +59,14 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask<SaveAttachmentTa
return FAILURE;
}
File mediaFile = constructOutputFile(attachment.contentType, attachment.date);
InputStream inputStream = PartAuthority.getPartStream(context, masterSecret, attachment.uri);
OutputStream outputStream = new FileOutputStream(mediaFile);
File mediaFile = constructOutputFile(attachment.contentType, attachment.date);
InputStream inputStream = PartAuthority.getPartStream(context, masterSecret, attachment.uri);
if (inputStream == null) {
return FAILURE;
}
OutputStream outputStream = new FileOutputStream(mediaFile);
Util.copy(inputStream, outputStream);
MediaScannerConnection.scanFile(context, new String[]{mediaFile.getAbsolutePath()},