Compare commits

...

16 Commits

Author SHA1 Message Date
Moxie Marlinspike
5e61161767 Bump version to 2.3.2
// FREEBIE
2014-11-24 23:44:50 -08:00
Jake McGinty
83d281de71 compat actionbar bg for dark theme
// FREEBIE
2014-11-25 09:28:22 +02:00
Jake McGinty
28f63cf335 Revert "Try to fix LGE menu button NPEs"
This reverts commit f3a3aaca60.
2014-11-25 09:23:57 +02:00
Jake McGinty
f3a3aaca60 Try to fix LGE menu button NPEs
fix based on https://code.google.com/p/android/issues/detail?id=78154

// FREEBIE
2014-11-25 09:17:27 +02:00
agrajaghh
908e8b8746 fix for ringtone selection with android-support-v4-preferencefragment 2014-11-25 09:08:30 +02:00
Jake McGinty
4573f3cb77 reorder window feature requests in MediaPreviewActivity
ActionBar is initialized in a different way by AppCompat v20 compared to
ABS or v21 even...
// FREEBIE
2014-11-25 08:55:40 +02:00
Moxie Marlinspike
d72a3ec669 Do thread trimming as JobManager job rather than AsyncTask.
// FREEBIE
2014-11-24 22:50:32 -08:00
Moxie Marlinspike
3439657bba Guard against fragment disappearing before callback.
// FREEBIE
2014-11-24 22:48:50 -08:00
Moxie Marlinspike
1ad7912e75 Add callback method parameter to axolotl decrypt functions.
// FREEBIE
2014-11-24 12:17:15 -08:00
Moxie Marlinspike
30aff82341 The future is the other direction.
// FREEBIE
2014-11-24 11:37:28 -08:00
Moxie Marlinspike
c54a5b613b Bump version to 2.3.1
// FREEBIE
2014-11-24 11:15:29 -08:00
Moxie Marlinspike
31ad30b3a5 Updated translations.
// FREEBIE
2014-11-24 10:59:03 -08:00
Moxie Marlinspike
4ccb7ebab6 Don't completely disable GCM.
// FREEBIE
2014-11-24 10:48:33 -08:00
Jake McGinty
bf69a90b69 rollback to appcompat v20
v21 appears to just not be ready for production given the bugs.
// FREEBIE
2014-11-24 19:09:33 +02:00
Moxie Marlinspike
bf19307916 Make GCM re-registration failure notification based.
// FREEBIE
2014-11-23 17:12:35 -08:00
Moxie Marlinspike
d42c4229fd Update to latest zxing QR code scanner.
Closes #2078

// FREEBIE
2014-11-22 09:47:02 -08:00
25 changed files with 384 additions and 433 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="84"
android:versionName="2.3.0">
android:versionCode="86"
android:versionName="2.3.2">
<permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"
android:label="Access to TextSecure Secrets"
@@ -208,13 +208,14 @@
android:clearTaskOnLaunch="true"
android:finishOnTaskLaunch="true" />
<service android:enabled="true" android:name=".service.GcmRegistrationService"/>
<activity android:name=".PlayServicesProblemActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
<service android:enabled="true" android:name=".service.KeyCachingService"/>
<service android:enabled="true" android:name=".service.SendReceiveService"/>
<service android:enabled="true" android:name=".service.RegistrationService"/>
<service android:enabled="true" android:name=".service.DirectoryRefreshService"/>
<service android:enabled="true" android:name=".service.PreKeyService"/>
<service android:name=".service.QuickResponseService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"

View File

@@ -36,8 +36,9 @@ dependencies {
compile 'org.w3c:smil:1.0.0'
compile 'org.apache.httpcomponents:httpclient-android:4.3.5'
compile 'com.github.chrisbanes.photoview:library:1.2.3'
compile 'com.android.support:appcompat-v7:21.0.2'
compile 'com.android.support:appcompat-v7:20.0.0'
compile 'com.madgag.spongycastle:prov:1.51.0.0'
compile 'com.google.zxing:android-integration:3.1.0'
compile ('com.android.support:support-v4-preferencefragment:1.0.0@aar'){
exclude module: 'support-v4'
}
@@ -60,17 +61,18 @@ dependencyVerification {
'org.w3c:smil:085dc40f2bb249651578bfa07499fd08b16ad0886dbe2c4078586a408da62f9b',
'org.apache.httpcomponents:httpclient-android:6f56466a9bd0d42934b90bfbfe9977a8b654c058bf44a12bdc2877c4e1f033f1',
'com.github.chrisbanes.photoview:library:8b5344e206f125e7ba9d684008f36c4992d03853c57e5814125f88496126e3cc',
'com.android.support:appcompat-v7:b760fd3d0b0b0547a1bcef9031b40939f31049ba955f04c8fdc5aa09a25d19e9',
'com.android.support:appcompat-v7:736f576ab0b68d27bdf18b1e7931566e6d8254b73965175313e87f8866b91547',
'com.madgag.spongycastle:prov:b8c3fec3a59aac1aa04ccf4dad7179351e54ef7672f53f508151b614c131398a',
'com.google.zxing:android-integration:89e56aadf1164bd71e57949163c53abf90af368b51669c0d4a47a163335f95c4',
'com.android.support:support-v4-preferencefragment:5470f5872514a6226fa1fc6f4e000991f38805691c534cf0bd2778911fc773ad',
'com.squareup.dagger:dagger:789aca24537022e49f91fc6444078d9de8f1dd99e1bfb090f18491b186967883',
'com.android.support:support-v4:81f2b1c2c94efd5a4ec7fcd97b6cdcd00e87a933905c5c86103c7319eb024572',
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
'com.googlecode.libphonenumber:libphonenumber:eba17eae81dd622ea89a00a3a8c025b2f25d342e0d9644c5b62e16f15687c3ab',
'org.whispersystems:gson:08f4f7498455d1539c9233e5aac18e9b1805815ef29221572996508eb512fe51',
'com.android.support:support-v4:126a4c291f41f75f3fff4968e9d397bc8454cdff4d8f994cbe0524e3bad76e72',
'com.android.support:support-annotations:7e37f00e3d932c4d9a6dd84604a99133bb5ae7d81cbd1aee69861fcf2f91e5e9',
'com.android.support:support-annotations:1aa96ef0cc4a445bfc2f93ccf762305bc57fa107b12afe9d11f3863ae8a11036',
]
}

View File

@@ -3,7 +3,6 @@ package org.whispersystems.test;
import android.test.AndroidTestCase;
import org.whispersystems.libaxolotl.DuplicateMessageException;
import org.whispersystems.libaxolotl.IdentityKey;
import org.whispersystems.libaxolotl.InvalidKeyException;
import org.whispersystems.libaxolotl.InvalidKeyIdException;
import org.whispersystems.libaxolotl.InvalidMessageException;
@@ -24,10 +23,7 @@ import org.whispersystems.libaxolotl.state.AxolotlStore;
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
import org.whispersystems.libaxolotl.state.PreKeyBundle;
import org.whispersystems.libaxolotl.state.PreKeyRecord;
import org.whispersystems.libaxolotl.state.PreKeyStore;
import org.whispersystems.libaxolotl.state.SessionStore;
import org.whispersystems.libaxolotl.state.SignedPreKeyRecord;
import org.whispersystems.libaxolotl.state.SignedPreKeyStore;
import org.whispersystems.libaxolotl.util.Pair;
import java.util.HashSet;
@@ -122,11 +118,11 @@ public class SessionBuilderTest extends AndroidTestCase {
AxolotlStore aliceStore = new InMemoryAxolotlStore();
SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_RECIPIENT_ID, 1);
AxolotlStore bobStore = new InMemoryAxolotlStore();
ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();
byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.getIdentityKeyPair().getPrivateKey(),
bobSignedPreKeyPair.getPublicKey().serialize());
final AxolotlStore bobStore = new InMemoryAxolotlStore();
ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();
byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.getIdentityKeyPair().getPrivateKey(),
bobSignedPreKeyPair.getPublicKey().serialize());
PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.getLocalRegistrationId(), 1,
31337, bobPreKeyPair.getPublicKey(),
@@ -139,9 +135,9 @@ public class SessionBuilderTest extends AndroidTestCase {
assertTrue(aliceStore.containsSession(BOB_RECIPIENT_ID, 1));
assertTrue(aliceStore.loadSession(BOB_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3);
String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1);
CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes());
final String originalMessage = "L'homme est condamné à être libre";
SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_RECIPIENT_ID, 1);
CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(originalMessage.getBytes());
assertTrue(outgoingMessage.getType() == CiphertextMessage.PREKEY_TYPE);
@@ -150,8 +146,13 @@ public class SessionBuilderTest extends AndroidTestCase {
bobStore.storeSignedPreKey(22, new SignedPreKeyRecord(22, System.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));
SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_RECIPIENT_ID, 1);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
byte[] plaintext = bobSessionCipher.decrypt(incomingMessage, new SessionCipher.DecryptionCallback() {
@Override
public void handlePlaintext(byte[] plaintext) {
assertTrue(originalMessage.equals(new String(plaintext)));
assertFalse(bobStore.containsSession(ALICE_RECIPIENT_ID, 1));
}
});
assertTrue(bobStore.containsSession(ALICE_RECIPIENT_ID, 1));
assertTrue(bobStore.loadSession(ALICE_RECIPIENT_ID, 1).getSessionState().getSessionVersion() == 3);

View File

@@ -19,12 +19,8 @@ import org.whispersystems.libaxolotl.ratchet.AliceAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.BobAxolotlParameters;
import org.whispersystems.libaxolotl.ratchet.RatchetingSession;
import org.whispersystems.libaxolotl.state.AxolotlStore;
import org.whispersystems.libaxolotl.state.IdentityKeyStore;
import org.whispersystems.libaxolotl.state.PreKeyStore;
import org.whispersystems.libaxolotl.state.SessionRecord;
import org.whispersystems.libaxolotl.state.SessionState;
import org.whispersystems.libaxolotl.state.SessionStore;
import org.whispersystems.libaxolotl.state.SignedPreKeyStore;
import org.whispersystems.libaxolotl.util.guava.Optional;
import java.security.NoSuchAlgorithmException;

View File

@@ -138,6 +138,7 @@ public class SessionCipher {
* Decrypt a message.
*
* @param ciphertext The {@link PreKeyWhisperMessage} to decrypt.
*
* @return The plaintext.
* @throws InvalidMessageException if the input is not valid ciphertext.
* @throws DuplicateMessageException if the input is a message that has already been received.
@@ -147,17 +148,46 @@ public class SessionCipher {
* that corresponds to the PreKey ID in the message.
* @throws InvalidKeyException when the message is formatted incorrectly.
* @throws UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
*/
public byte[] decrypt(PreKeyWhisperMessage ciphertext)
throws DuplicateMessageException, LegacyMessageException, InvalidMessageException,
InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException
{
return decrypt(ciphertext, new NullDecryptionCallback());
}
/**
* Decrypt a message.
*
* @param ciphertext The {@link PreKeyWhisperMessage} to decrypt.
* @param callback A callback that is triggered after decryption is complete,
* but before the updated session state has been committed to the session
* DB. This allows some implementations to store the committed plaintext
* to a DB first, in case they are concerned with a crash happening between
* the time the session state is updated but before they're able to store
* the plaintext to disk.
*
* @return The plaintext.
* @throws InvalidMessageException if the input is not valid ciphertext.
* @throws DuplicateMessageException if the input is a message that has already been received.
* @throws LegacyMessageException if the input is a message formatted by a protocol version that
* is no longer supported.
* @throws InvalidKeyIdException when there is no local {@link org.whispersystems.libaxolotl.state.PreKeyRecord}
* that corresponds to the PreKey ID in the message.
* @throws InvalidKeyException when the message is formatted incorrectly.
* @throws UntrustedIdentityException when the {@link IdentityKey} of the sender is untrusted.
*/
public byte[] decrypt(PreKeyWhisperMessage ciphertext, DecryptionCallback callback)
throws DuplicateMessageException, LegacyMessageException, InvalidMessageException,
InvalidKeyIdException, InvalidKeyException, UntrustedIdentityException
{
synchronized (SESSION_LOCK) {
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
Optional<Integer> unsignedPreKeyId = sessionBuilder.process(sessionRecord, ciphertext);
byte[] plaintext = decrypt(sessionRecord, ciphertext.getWhisperMessage());
callback.handlePlaintext(plaintext);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
if (unsignedPreKeyId.isPresent()) {
@@ -168,7 +198,6 @@ public class SessionCipher {
}
}
/**
* Decrypt a message.
*
@@ -182,6 +211,31 @@ public class SessionCipher {
* @throws NoSessionException if there is no established session for this contact.
*/
public byte[] decrypt(WhisperMessage ciphertext)
throws InvalidMessageException, DuplicateMessageException, LegacyMessageException,
NoSessionException
{
return decrypt(ciphertext, new NullDecryptionCallback());
}
/**
* Decrypt a message.
*
* @param ciphertext The {@link WhisperMessage} to decrypt.
* @param callback A callback that is triggered after decryption is complete,
* but before the updated session state has been committed to the session
* DB. This allows some implementations to store the committed plaintext
* to a DB first, in case they are concerned with a crash happening between
* the time the session state is updated but before they're able to store
* the plaintext to disk.
*
* @return The plaintext.
* @throws InvalidMessageException if the input is not valid ciphertext.
* @throws DuplicateMessageException if the input is a message that has already been received.
* @throws LegacyMessageException if the input is a message formatted by a protocol version that
* is no longer supported.
* @throws NoSessionException if there is no established session for this contact.
*/
public byte[] decrypt(WhisperMessage ciphertext, DecryptionCallback callback)
throws InvalidMessageException, DuplicateMessageException, LegacyMessageException,
NoSessionException
{
@@ -194,6 +248,8 @@ public class SessionCipher {
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
byte[] plaintext = decrypt(sessionRecord, ciphertext);
callback.handlePlaintext(plaintext);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
return plaintext;
@@ -324,7 +380,7 @@ public class SessionCipher {
}
}
if (chainKey.getIndex() - counter > 2000) {
if (counter - chainKey.getIndex() > 2000) {
throw new InvalidMessageException("Over 2000 messages into the future!");
}
@@ -401,4 +457,13 @@ public class SessionCipher {
throw new AssertionError(e);
}
}
public static interface DecryptionCallback {
public void handlePlaintext(byte[] plaintext);
}
private static class NullDecryptionCallback implements DecryptionCallback {
@Override
public void handlePlaintext(byte[] plaintext) {}
}
}

View File

@@ -1,285 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* 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.whispersystems.textsecure.zxing.integration;
import android.app.AlertDialog;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
/**
* <p>A utility class which helps ease integration with Barcode Scanner via {@link Intent}s. This is a simple
* way to invoke barcode scanning and receive the result, without any need to integrate, modify, or learn the
* project's source code.</p>
*
* <h2>Initiating a barcode scan</h2>
*
* <p>Integration is essentially as easy as calling {@link #initiateScan(Activity)} and waiting
* for the result in your app.</p>
*
* <p>It does require that the Barcode Scanner application is installed. The
* {@link #initiateScan(Activity)} method will prompt the user to download the application, if needed.</p>
*
* <p>There are a few steps to using this integration. First, your {@link Activity} must implement
* the method {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:</p>
*
* <p>{@code
* public void onActivityResult(int requestCode, int resultCode, Intent intent) {
* IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
* if (scanResult != null) {
* // handle scan result
* }
* // else continue with any other code you need in the method
* ...
* }
* }</p>
*
* <p>This is where you will handle a scan result.
* Second, just call this in response to a user action somewhere to begin the scan process:</p>
*
* <p>{@code IntentIntegrator.initiateScan(yourActivity);}</p>
*
* <p>You can use {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} or
* {@link #initiateScan(Activity, int, int, int, int)} to customize the download prompt with
* different text labels.</p>
*
* <p>Note that {@link #initiateScan(Activity)} returns an {@link AlertDialog} which is non-null if the
* user was prompted to download the application. This lets the calling app potentially manage the dialog.
* In particular, ideally, the app dismisses the dialog if it's still active in its {@link Activity#onPause()}
* method.</p>
*
* <h2>Sharing text via barcode</h2>
*
* <p>To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(Activity, CharSequence)}.</p>
*
* <p>Some code, particularly download integration, was contributed from the Anobiit application.</p>
*
* @author Sean Owen
* @author Fred Lin
* @author Isaac Potoczny-Jones
* @author Brad Drehmer
*/
public final class IntentIntegrator {
public static final int REQUEST_CODE = 0x0ba7c0de; // get it?
public static final String DEFAULT_TITLE = "Install Barcode Scanner?";
public static final String DEFAULT_MESSAGE =
"This application requires Barcode Scanner. Would you like to install it?";
public static final String DEFAULT_YES = "Yes";
public static final String DEFAULT_NO = "No";
// supported barcode formats
public static final String PRODUCT_CODE_TYPES = "UPC_A,UPC_E,EAN_8,EAN_13";
public static final String ONE_D_CODE_TYPES = PRODUCT_CODE_TYPES + ",CODE_39,CODE_93,CODE_128";
public static final String QR_CODE_TYPES = "QR_CODE";
public static final String ALL_CODE_TYPES = null;
private IntentIntegrator() {
}
/**
* See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} --
* same, but uses default English labels.
*/
public static AlertDialog initiateScan(Activity activity) {
return initiateScan(activity, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO);
}
/**
* See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} --
* same, but takes string IDs which refer
* to the {@link Activity}'s resource bundle entries.
*/
public static AlertDialog initiateScan(Activity activity,
int stringTitle,
int stringMessage,
int stringButtonYes,
int stringButtonNo) {
return initiateScan(activity,
activity.getString(stringTitle),
activity.getString(stringMessage),
activity.getString(stringButtonYes),
activity.getString(stringButtonNo));
}
/**
* See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
* same, but scans for all supported barcode types.
* @param stringTitle title of dialog prompting user to download Barcode Scanner
* @param stringMessage text of dialog prompting user to download Barcode Scanner
* @param stringButtonYes text of button user clicks when agreeing to download
* Barcode Scanner (e.g. "Yes")
* @param stringButtonNo text of button user clicks when declining to download
* Barcode Scanner (e.g. "No")
* @return an {@link AlertDialog} if the user was prompted to download the app,
* null otherwise
*/
public static AlertDialog initiateScan(Activity activity,
CharSequence stringTitle,
CharSequence stringMessage,
CharSequence stringButtonYes,
CharSequence stringButtonNo) {
return initiateScan(activity,
stringTitle,
stringMessage,
stringButtonYes,
stringButtonNo,
ALL_CODE_TYPES);
}
/**
* Invokes scanning.
*
* @param stringTitle title of dialog prompting user to download Barcode Scanner
* @param stringMessage text of dialog prompting user to download Barcode Scanner
* @param stringButtonYes text of button user clicks when agreeing to download
* Barcode Scanner (e.g. "Yes")
* @param stringButtonNo text of button user clicks when declining to download
* Barcode Scanner (e.g. "No")
* @param stringDesiredBarcodeFormats a comma separated list of codes you would
* like to scan for.
* @return an {@link AlertDialog} if the user was prompted to download the app,
* null otherwise
* @throws InterruptedException if timeout expires before a scan completes
*/
public static AlertDialog initiateScan(Activity activity,
CharSequence stringTitle,
CharSequence stringMessage,
CharSequence stringButtonYes,
CharSequence stringButtonNo,
CharSequence stringDesiredBarcodeFormats) {
Intent intentScan = new Intent("com.google.zxing.client.android.SCAN");
intentScan.addCategory(Intent.CATEGORY_DEFAULT);
// check which types of codes to scan for
if (stringDesiredBarcodeFormats != null) {
// set the desired barcode types
intentScan.putExtra("SCAN_FORMATS", stringDesiredBarcodeFormats);
}
try {
activity.startActivityForResult(intentScan, REQUEST_CODE);
return null;
} catch (ActivityNotFoundException e) {
return showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo);
}
}
private static AlertDialog showDownloadDialog(final Activity activity,
CharSequence stringTitle,
CharSequence stringMessage,
CharSequence stringButtonYes,
CharSequence stringButtonNo) {
AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity);
downloadDialog.setTitle(stringTitle);
downloadDialog.setMessage(stringMessage);
downloadDialog.setPositiveButton(stringButtonYes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {
Uri uri = Uri.parse("market://search?q=pname:com.google.zxing.client.android");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
activity.startActivity(intent);
}
});
downloadDialog.setNegativeButton(stringButtonNo, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialogInterface, int i) {}
});
return downloadDialog.show();
}
/**
* <p>Call this from your {@link Activity}'s
* {@link Activity#onActivityResult(int, int, Intent)} method.</p>
*
* @return null if the event handled here was not related to {@link IntentIntegrator}, or
* else an {@link IntentResult} containing the result of the scan. If the user cancelled scanning,
* the fields will be null.
*/
public static IntentResult parseActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
String contents = intent.getStringExtra("SCAN_RESULT");
String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT");
return new IntentResult(contents, formatName);
} else {
return new IntentResult(null, null);
}
}
return null;
}
/**
* See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
* same, but uses default English labels.
*/
public static void shareText(Activity activity, CharSequence text) {
shareText(activity, text, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO);
}
/**
* See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} --
* same, but takes string IDs which refer to the {@link Activity}'s resource bundle entries.
*/
public static void shareText(Activity activity,
CharSequence text,
int stringTitle,
int stringMessage,
int stringButtonYes,
int stringButtonNo) {
shareText(activity,
text,
activity.getString(stringTitle),
activity.getString(stringMessage),
activity.getString(stringButtonYes),
activity.getString(stringButtonNo));
}
/**
* Shares the given text by encoding it as a barcode, such that another user can
* scan the text off the screen of the device.
*
* @param text the text string to encode as a barcode
* @param stringTitle title of dialog prompting user to download Barcode Scanner
* @param stringMessage text of dialog prompting user to download Barcode Scanner
* @param stringButtonYes text of button user clicks when agreeing to download
* Barcode Scanner (e.g. "Yes")
* @param stringButtonNo text of button user clicks when declining to download
* Barcode Scanner (e.g. "No")
*/
public static void shareText(Activity activity,
CharSequence text,
CharSequence stringTitle,
CharSequence stringMessage,
CharSequence stringButtonYes,
CharSequence stringButtonNo) {
Intent intent = new Intent();
intent.setAction("com.google.zxing.client.android.ENCODE");
intent.putExtra("ENCODE_TYPE", "TEXT_TYPE");
intent.putExtra("ENCODE_DATA", text);
try {
activity.startActivity(intent);
} catch (ActivityNotFoundException e) {
showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo);
}
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2009 ZXing authors
*
* 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.whispersystems.textsecure.zxing.integration;
/**
* <p>Encapsulates the result of a barcode scan invoked through {@link IntentIntegrator}.</p>
*
* @author Sean Owen
*/
public final class IntentResult {
private final String contents;
private final String formatName;
IntentResult(String contents, String formatName) {
this.contents = contents;
this.formatName = formatName;
}
/**
* @return raw content of barcode
*/
public String getContents() {
return contents;
}
/**
* @return name of format, like "QR_CODE", "UPC_A". See <code>BarcodeFormat</code> for more format names.
*/
public String getFormatName() {
return formatName;
}
}

View File

@@ -93,8 +93,13 @@ Trebat ćete ponovno registrirati vaš broj telefona kako biste koristili instan
<string name="ConversationFragment_sender_s_transport_s_sent_s_received_s">Pošiljatelj: %1$s\nTransport: %2$s\nPoslano: %3$s\nPrimljeno: %4$s</string>
<string name="ConversationFragment_confirm_message_delete">Potvrda brisanja poruke</string>
<string name="ConversationFragment_are_you_sure_you_want_to_permanently_delete_this_message">Jeste li sigurni da želite trajno obrisati ovu poruku?</string>
<string name="ConversationFragment_save_to_sd_card">Spremi na disk?</string>
<string name="ConversationFragment_this_media_has_been_stored_in_an_encrypted_database_warning">Spremanje ovog medija na disk će omogućiti pristup mediju iz drugih aplikacija na vašem telefonu.\n\nNastavi?</string>
<string name="ConversationFragment_error_while_saving_attachment_to_sd_card">Greška prilikom spremanja privitka na disk!</string>
<string name="ConversationFragment_success_exclamation">Uspješno!</string>
<string name="ConversationFragment_unable_to_write_to_sd_card_exclamation">Nije moguće pisati na disk!</string>
<string name="ConversationFragment_saving_attachment">Spremanje privitka</string>
<string name="ConversationFragment_saving_attachment_to_sd_card">Spremanje privitka na disk...</string>
<!--ConversationListAdapter-->
<string name="ConversationListAdapter_key_exchange_message">Poruka za razmjenu ključa...</string>
<!--ConversationListFragment-->
@@ -458,11 +463,14 @@ Uvezi nekriptiranu kopiju kompatibilnu s \'SMSBackup And Restore\'.</string>
<!--receive_key_activity-->
<string name="receive_key_activity__complete">Završeno</string>
<!--registration_activity-->
<string name="registration_activity__textsecure_can_use_instant_messages_to_avoid_sms_charges_when_communicating_with_other_textsecure_users">
Registracija je besplatna i povećava privatnost prilikom slanja poruka drugim TextSecure korisnicima. Provjerite svoj broj telefona.</string>
<string name="registration_activity__your_country">VAŠA ZEMLJA</string>
<string name="registration_activity__your_country_code_and_phone_number">POZIVNI BROJ ZEMLJE I
TELEFONSKI BROJ</string>
<string name="registration_activity__phone_number">TELEFONSKI BROJ</string>
<string name="registration_activity__register">Registriraj</string>
<string name="registration_activity__registration_will_transmit_some_contact_information_to_the_server_temporariliy">Registracija šalje neke informacije o kontaktima na poslužitelj. Podaci se ne pohranjuju trajno.</string>
<string name="registration_activity__skip">Preskoči</string>
<!--registration_problems-->
<string name="registration_problems__some_possible_problems_include">Neki mogući problemi
@@ -542,6 +550,7 @@ neuspješno.</string>
<string name="AndroidManifest__manage_identity_keys">Upravljajte ključevima identiteta</string>
<string name="AndroidManifest__complete_key_exchange">Završite razmjenu ključeva</string>
<string name="AndroidManifest__log_submit">Pošaljite debug zapise</string>
<string name="AndroidManifest__media_preview">Prikaz medija</string>
<!--arrays.xml-->
<string name="arrays__import_export">Uvoz / izvoz</string>
<string name="arrays__my_identity_key">Moj ključ identiteta</string>
@@ -718,7 +727,10 @@ Povećajte privatnost i izbjegnite SMS troškove koristeći podatkovni kanal za
<string name="reminder_header_push_title">Omogući TextSecure poruke?</string>
<string name="reminder_header_push_text">Instant isporuka, pojačana privatnost i bez SMS troškova.</string>
<!--MediaPreviewActivity-->
<string name="MediaPreviewActivity_you">Vi</string>
<!--media_preview-->
<string name="media_preview__save_title">Spremi</string>
<!--media_preview_activity-->
<string name="media_preview_activity__image_content_description">Prikaz slike</string>
<!--EOF-->
</resources>

View File

@@ -28,7 +28,7 @@ U zal uw telefoonnummer opnieuw moeten registreren als u push berichten weer wil
<string name="ApplicationPreferencesActivity_updating_directory">Contactpersonen updaten</string>
<string name="ApplicationPreferencesActivity_updating_push_directory">Pushcontactpersonen updaten...</string>
<string name="ApplicationPreferencesActivity_sms_enabled">Inkomende SMS geactiveerd</string>
<string name="ApplicationPreferencesActivity_touch_to_change_your_default_sms_app">Raak aan om uw standaard SMS applicatie te veranderen</string>
<string name="ApplicationPreferencesActivity_touch_to_change_your_default_sms_app">Aanraken om uw standaard SMS applicatie te veranderen</string>
<string name="ApplicationPreferencesActivity_sms_disabled">Inkomende SMS uitgeschakeld</string>
<string name="ApplicationPreferencesActivity_touch_to_make_textsecure_your_default_sms_app">Raak aan om TextSecure uw standaard SMS applicatie te maken</string>
<!--AttchmentManager-->
@@ -516,7 +516,7 @@ TextSecure heeft te lang moeten wachten op het binnenkomen van de verificatie-SM
<string name="AndroidManifest__select_contact">Selecteer contact</string>
<string name="AndroidManifest__textsecure_detected">TextSecure gedetecteerd</string>
<string name="AndroidManifest__public_identity_key">Publieke identiteitssleutel</string>
<string name="AndroidManifest__change_passphrase">Verander wachtwoord</string>
<string name="AndroidManifest__change_passphrase">Wachtwoord veranderen</string>
<string name="AndroidManifest__verify_session">Sessie verifiëren</string>
<string name="AndroidManifest__verify_identity">Identiteit verifiëren</string>
<string name="AndroidManifest__manage_identity_keys">Beheer identiteitssleutels</string>
@@ -541,9 +541,9 @@ TextSecure heeft te lang moeten wachten op het binnenkomen van de verificatie-SM
<string name="preferences__display_settings">Beeldscherminstellingen</string>
<string name="preferences__choose_identity">Identiteit kiezen</string>
<string name="preferences__choose_your_contact_entry_from_the_contacts_list">Kies uw contactinformatie uit de contactpersonenlijst.</string>
<string name="preferences__change_passphrase">Verander wachtwoord</string>
<string name="preferences__change_passphrase">Wachtwoord veranderen</string>
<string name="preferences__change_my_passphrase">Mijn wachtwoord veranderen</string>
<string name="preferences__complete_key_exchanges">Voltooi sleuteluitwisselingen</string>
<string name="preferences__complete_key_exchanges">Sleuteluitwisselingen voltooien</string>
<string name="preferences__disable_passphrase">Wachtwoord uitschakelen</string>
<string name="preferences__disable_local_encryption_of_messages_and_keys">Lokale versleuteling van berichten en sleutels uitschakelen</string>
<string name="preferences__screen_security">Schermbeveiliging</string>
@@ -595,12 +595,12 @@ TextSecure heeft te lang moeten wachten op het binnenkomen van de verificatie-SM
<string name="preferences__mms_proxy_host_optional">MMS Proxy Host (Optioneel)</string>
<string name="preferences__mms_proxy_port_optional">MMS Proxy Poort (Optioneel)</string>
<string name="preferences__sms_delivery_reports">SMS ontvangstbevestigingen</string>
<string name="preferences__request_a_delivery_report_for_each_sms_message_you_send">Verzoek om een ontvangstbevestiging voor ieder verzonden SMS bericht</string>
<string name="preferences__request_a_delivery_report_for_each_sms_message_you_send">Verzoeken om een ontvangstbevestiging voor ieder verzonden SMS bericht</string>
<string name="preferences__automatically_delete_older_messages_once_a_conversation_thread_exceeds_a_specified_length">Automatisch oudere berichten verwijderen wanneer een gesprek meer dan een bepaald aantal berichten bevat</string>
<string name="preferences__delete_old_messages">Verwijder oude berichten</string>
<string name="preferences__storage">Opslag</string>
<string name="preferences__conversation_length_limit">Gesprekslengte limiet</string>
<string name="preferences__trim_all_threads_now">Oudere gespreksberichten nu verwijderen</string>
<string name="preferences__trim_all_threads_now">Oude berichten nu verwijderen</string>
<string name="preferences__scan_through_all_conversation_threads_and_enforce_conversation_length_limits">Alle gesprekken scannen en de maximale gesprekslengte toepassen</string>
<string name="preferences__light_theme">Licht thema</string>
<string name="preferences__dark_theme">Donker thema</string>
@@ -611,7 +611,8 @@ TextSecure heeft te lang moeten wachten op het binnenkomen van de verificatie-SM
<string name="preferences__make_default_sms_app">Stel in als standaard SMS-app</string>
<string name="preferences__make_textsecure_the_default_sms_mms_app">Stel TextSecure in als standaard SMS/MMS-applicatie voor uw systeem.</string>
<string name="preferences__use_data_channel">Pushberichten</string>
<string name="preferences__use_the_data_channel_for_communication_with_other_textsecure_users">Privacy verbeteren en SMS-kosten vermijden door het datakanaal te gebruiken om te communiceren met andere TextSecure gebruikers</string>
<string name="preferences__use_the_data_channel_for_communication_with_other_textsecure_users">
Privacy verbeteren en SMS-kosten vermijden door het datakanaal te gebruiken voor communicatie met andere TextSecure gebruikers</string>
<string name="preferences__allow_sms_fallback">SMS versturen naar</string>
<string name="preferences__allow_sms_fallback_disabled_reason">TextSecure is momenteel uw standaard SMS applicatie. Selecteer alstublieft een andere SMS applicatie om deze voorkeur te veranderen.</string>
<string name="preferences__refresh_push_directory">Pushcontacten verversen</string>

View File

@@ -31,6 +31,7 @@ Za ponovno uporabo potisnih sporočil se boste morali zopet prijaviti s svojo te
<string name="ApplicationPreferencesActivity_sms_disabled">Dohodna SMS sporočila izklopljena</string>
<string name="ApplicationPreferencesActivity_touch_to_make_textsecure_your_default_sms_app">Z dotikom nastavi TexteScure za privzeto aplikacijo SMS</string>
<!--AttchmentManager-->
<string name="AttachmentManager_cant_open_media_selection">Ne najdem aplikacije za izbor datotek.</string>
<!--AttachmentTypeSelectorAdapter-->
<string name="AttachmentTypeSelectorAdapter_picture">Slika</string>
<string name="AttachmentTypeSelectorAdapter_video">Video</string>
@@ -56,6 +57,7 @@ Za ponovno uporabo potisnih sporočil se boste morali zopet prijaviti s svojo te
<string name="ConversationItem_click_to_approve_unencrypted_sms_dialog_title">Preklopim na nešifriran SMS?</string>
<string name="ConversationItem_click_to_approve_unencrypted_mms_dialog_title">Preklopim na nešifriran MMS?</string>
<string name="ConversationItem_click_to_approve_unencrypted_dialog_message">To sporočilo <b>ne bo</b> šifrirano, ker varna seja ne more biti vzpostavljena.\n\nPošljem nešifrirano sporočilo?</string>
<string name="ConversationItem_unable_to_open_media">Ne najdem aplikacije za odpiranje te vrste datotek.</string>
<!--ConversationActivity-->
<string name="ConversationActivity_initiate_secure_session_question">Začnem varno sejo?</string>
<string name="ConversationActivity_initiate_secure_session_with_s_question">Začnem varno sejo z %s?</string>
@@ -88,8 +90,13 @@ Za ponovno uporabo potisnih sporočil se boste morali zopet prijaviti s svojo te
<string name="ConversationFragment_sender_s_transport_s_sent_s_received_s">Pošiljatelj: %1$s\nNačin prenosa: %2$s\nPoslano: %3$s\nPrejeto: %4$s</string>
<string name="ConversationFragment_confirm_message_delete">Potrdite izbris sporočila</string>
<string name="ConversationFragment_are_you_sure_you_want_to_permanently_delete_this_message">Ste prepričani, da želite dokonćno izbrisati sporočilo?</string>
<string name="ConversationFragment_save_to_sd_card">Spravim v sistemsko shrambo?</string>
<string name="ConversationFragment_this_media_has_been_stored_in_an_encrypted_database_warning">S shranitvijo datoteke v sistemsko shrambo bo ta dostopna tudi drugim aplikacijam.\n\nNadaljujem?</string>
<string name="ConversationFragment_error_while_saving_attachment_to_sd_card">Napaka pri shranjevanju priponke v sistemsko shrambo!</string>
<string name="ConversationFragment_success_exclamation">Uspešno opravljeno!</string>
<string name="ConversationFragment_unable_to_write_to_sd_card_exclamation">Ne morem shranjevati v sistemsko shrambo!</string>
<string name="ConversationFragment_saving_attachment">Shranjujem priponko</string>
<string name="ConversationFragment_saving_attachment_to_sd_card">Shranjujem v sistemsko shrambo...</string>
<!--ConversationListAdapter-->
<string name="ConversationListAdapter_key_exchange_message">Sporočilo za izmenjavo ključev...</string>
<!--ConversationListFragment-->
@@ -302,7 +309,7 @@ Prejeto sporočilo z neznanim identifikacijskim ključem. Kliknite za obdelavo i
<string name="MessageNotifier_message_delivery_failed">Dostava sporočila ni uspela.</string>
<string name="MessageNotifier_failed_to_deliver_message">Neuspešna dostava sporočila.</string>
<string name="MessageNotifier_error_delivering_message">Napaka pri dostavi sporočila.</string>
<string name="MessageNotifier_mark_all_as_read">Označi vsa kot prebrana</string>
<string name="MessageNotifier_mark_all_as_read">Označi vse kot prebrano</string>
<string name="MessageNotifier_mark_as_read">Označi kot prebrano</string>
<!--ViewLocalIdentityActivity-->
<string name="ViewLocalIdentityActivity_regenerating">Ustvarjam nov ključ...</string>
@@ -423,11 +430,14 @@ Prejeto sporočilo z neznanim identifikacijskim ključem. Kliknite za obdelavo i
<!--receive_key_activity-->
<string name="receive_key_activity__complete">Dokončaj</string>
<!--registration_activity-->
<string name="registration_activity__textsecure_can_use_instant_messages_to_avoid_sms_charges_when_communicating_with_other_textsecure_users">
Registracija je brezplačna in izboljša zasebnost pri pošiljanju sporočil drugim uporabnikom TextSecure. Prosim preverite svojo telefonsko številko.</string>
<string name="registration_activity__your_country">VAŠA DRŽAVA</string>
<string name="registration_activity__your_country_code_and_phone_number">KODA DRŽAVE IN VAŠA
TELEFONSKA ŠTEVILKA</string>
<string name="registration_activity__phone_number">TELEFONSKA ŠTEVILKA</string>
<string name="registration_activity__register">Registriraj</string>
<string name="registration_activity__registration_will_transmit_some_contact_information_to_the_server_temporariliy">Pri registraciji se nekateri podatki uporabnika začasno posredujejo na strežnik.</string>
<string name="registration_activity__skip">Preskoči</string>
<!--registration_problems-->
<string name="registration_problems__some_possible_problems_include">Nekatere možni razlogi
@@ -505,9 +515,10 @@ bila uspešna.</string>
<string name="AndroidManifest__manage_identity_keys">Upravljanje identifikacijskih ključev</string>
<string name="AndroidManifest__complete_key_exchange">Dokončaj izmenjavo ključev</string>
<string name="AndroidManifest__log_submit">Oddaj sistemsko zabeležbo</string>
<string name="AndroidManifest__media_preview">Ogled medija</string>
<!--arrays.xml-->
<string name="arrays__import_export">Uvoz / izvoz</string>
<string name="arrays__my_identity_key">Moj identifikacijski ključ</string>
<string name="arrays__import_export">Uvoz/izvoz</string>
<string name="arrays__my_identity_key">Moja identifikacija</string>
<!--preferences.xml-->
<string name="preferences__general">Splošno</string>
<string name="preferences__push_sms_category">Pošiljanje in prejemanje</string>
@@ -680,7 +691,10 @@ bila uspešna.</string>
<string name="reminder_header_push_title">Vklopim sporočila TextSecure?</string>
<string name="reminder_header_push_text">Takojšnja dostava, večja zasebnost, brez stroškov SMS.</string>
<!--MediaPreviewActivity-->
<string name="MediaPreviewActivity_you">Vi</string>
<!--media_preview-->
<string name="media_preview__save_title">Shrani</string>
<!--media_preview_activity-->
<string name="media_preview_activity__image_content_description">Ogled slike</string>
<!--EOF-->
</resources>

View File

@@ -149,6 +149,10 @@
settings, and messages...
</string>
<!-- GcmRefreshJob -->
<string name="GcmRefreshJob_Permanent_TextSecure_communication_failure">Permanent TextSecure communication failure!</string>
<string name="GcmRefreshJob_TextSecure_was_unable_to_register_with_Google_Play_Services">TextSecure was unable to register with Google Play Services. Communication over the data channel has been disabled, please try re-registering from the TextSecure settings menu.</string>
<!-- GroupCreateActivity -->
<string name="GroupCreateActivity_actionbar_title">New group</string>
<string name="GroupCreateActivity_actionbar_update_title">Update group</string>

View File

@@ -16,16 +16,26 @@
<!-- ActionBar styles -->
<style name="TextSecure.DarkActionBar"
parent="@style/Widget.AppCompat.ActionBar">
<item name="android:icon">@drawable/actionbar_icon_holo_dark</item>
<item name="icon">@drawable/actionbar_icon_holo_dark</item>
<item name="background">@color/gray95</item>
<item name="elevation">2dp</item>
<item name="android:background">@color/gray95</item>
<item name="android:logo">@drawable/actionbar_icon_holo_dark</item>
<item name="logo">@drawable/actionbar_icon_holo_dark</item>
</style>
<style name="TextSecure.LightActionBar"
parent="@style/Widget.AppCompat.ActionBar">
<item name="android:icon">@drawable/actionbar_icon_holo_light</item>
<item name="icon">@drawable/actionbar_icon_holo_light</item>
<item name="android:background">@color/gray5</item>
<item name="background">@color/gray5</item>
<item name="elevation">2dp</item>
<item name="android:logo">@drawable/actionbar_icon_holo_light</item>
<item name="logo">@drawable/actionbar_icon_holo_light</item>
<item name="android:titleTextStyle">@style/TextSecure.TitleTextStyle</item>
<item name="titleTextStyle">@style/TextSecure.TitleTextStyle</item>
<item name="android:subtitleTextStyle">@style/TextSecure.SubtitleTextStyle</item>
<item name="subtitleTextStyle">@style/TextSecure.SubtitleTextStyle</item>
</style>
<style name="TextSecure.ClearTitleTextStyle" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
@@ -43,7 +53,8 @@
<style name="TextSecure.IntroActionBar" parent="Widget.AppCompat.Light.ActionBar.Solid">
<item name="background">@drawable/background_pattern_repeat</item>
<item name="elevation">0dp</item>
<item name="titleTextStyle">@style/TextSecure.ClearTitleTextStyle</item>
<item name="icon">@android:color/transparent</item>
</style>
<style name="transparent_progress">

View File

@@ -1,17 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="TextSecure.IntroTheme" parent="@style/Theme.AppCompat.Light">
<item name="colorPrimary">@android:color/transparent</item>
<!--<item name="colorPrimary">@android:color/transparent</item>-->
<item name="actionBarStyle">@style/TextSecure.IntroActionBar</item>
<item name="android:windowContentOverlay">@null</item>
</style>
<style name="TextSecure.LightTheme" parent="@style/Theme.AppCompat.Light">
<item name="logo">@drawable/actionbar_icon_holo_light</item>
<item name="android:logo">@drawable/actionbar_icon_holo_light</item>
<item name="android:actionBarStyle">@style/TextSecure.LightActionBar</item>
<item name="actionBarStyle">@style/TextSecure.LightActionBar</item>
<item name="colorPrimary">@color/gray5</item>
<item name="colorPrimaryDark">@color/gray95</item>
<item name="colorAccent">#ff259b24</item>
<item name="android:windowContentOverlay">@drawable/compat_actionbar_shadow_background</item>
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_background_read_light</item>
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_background_unread_light</item>
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_light</item>
@@ -84,10 +83,11 @@
</style>
<style name="TextSecure.DarkTheme" parent="@style/Theme.AppCompat">
<item name="logo">@drawable/actionbar_icon_holo_dark</item>
<item name="android:logo">@drawable/actionbar_icon_holo_dark</item>
<item name="android:actionBarStyle">@style/TextSecure.DarkActionBar</item>
<item name="actionBarStyle">@style/TextSecure.DarkActionBar</item>
<item name="colorPrimary">@color/gray95</item>
<item name="colorPrimaryDark">@color/gray95</item>
<item name="colorAccent">#ff259b24</item>
<item name="conversation_list_item_background_read">@drawable/conversation_list_item_background_read_dark</item>
<item name="conversation_list_item_background_unread">@drawable/conversation_list_item_background_unread_dark</item>
<item name="conversation_list_item_background_selected">@drawable/list_selected_holo_dark</item>
@@ -160,7 +160,7 @@
</style>
<style name="TextSecure.Light.Dialog"
parent="Theme.AppCompat.Light.Dialog"
parent="Theme.AppCompat.Light.DialogWhenLarge"
tools:ignore="NewApi">
<item name="android:windowFrame">@null</item>
<item name="android:windowTitleStyle">@style/TextSecureDialogWindowTitle</item>

View File

@@ -118,6 +118,14 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
dynamicLanguage.onResume(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content);
fragment.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onDestroy() {
MemoryCleaner.clean((MasterSecret) getIntent().getParcelableExtra("master_secret"));

View File

@@ -1037,6 +1037,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
ConversationFragment fragment = (ConversationFragment) getSupportFragmentManager()
.findFragmentById(R.id.fragment_content);
if (fragment == null) {
return;
}
if (refreshFragment) {
fragment.reload(recipients, threadId);

View File

@@ -69,10 +69,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
setContentView(R.layout.conversation_list_activity);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayUseLogoEnabled(true);
getSupportActionBar().setTitle(R.string.app_name);
initializeResources();

View File

@@ -23,13 +23,13 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import org.thoughtcrime.securesms.util.Base64;
import org.whispersystems.libaxolotl.IdentityKey;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.whispersystems.textsecure.zxing.integration.IntentIntegrator;
import org.whispersystems.textsecure.zxing.integration.IntentResult;
import org.whispersystems.libaxolotl.IdentityKey;
/**
* Activity for initiating/receiving key QR code scans.
@@ -99,11 +99,13 @@ public abstract class KeyScanningActivity extends PassphraseRequiredActionBarAct
}
protected void initiateScan() {
IntentIntegrator.initiateScan(this);
IntentIntegrator intentIntegrator = new IntentIntegrator(this);
intentIntegrator.initiateScan();
}
protected void initiateDisplay() {
IntentIntegrator.shareText(this, Base64.encodeBytes(getIdentityKeyToDisplay().serialize()));
IntentIntegrator intentIntegrator = new IntentIntegrator(this);
intentIntegrator.shareText(Base64.encodeBytes(getIdentityKeyToDisplay().serialize()));
}
protected abstract String getScanString();

View File

@@ -70,14 +70,17 @@ public class MediaPreviewActivity extends PassphraseRequiredActionBarActivity {
@Override
protected void onCreate(Bundle bundle) {
this.setTheme(R.style.TextSecure_DarkTheme);
dynamicLanguage.onCreate(this);
super.onCreate(bundle);
setFullscreenIfPossible();
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
dynamicLanguage.onCreate(this);
this.setTheme(R.style.TextSecure_DarkTheme);
super.onCreate(bundle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.media_preview_activity);
initializeResources();
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class PlayServicesProblemActivity extends FragmentActivity {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
PlayServicesProblemFragment fragment = new PlayServicesProblemFragment();
fragment.show(getSupportFragmentManager(), "dialog");
}
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms;
import android.app.Dialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import com.google.android.gms.common.GooglePlayServicesUtil;
public class PlayServicesProblemFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(@NonNull Bundle bundle) {
int code = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity());
return GooglePlayServicesUtil.getErrorDialog(code, getActivity(), 9111);
}
}

View File

@@ -29,6 +29,7 @@ import android.util.Pair;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
@@ -36,6 +37,7 @@ import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
@@ -52,6 +54,7 @@ import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Trimmer;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobManager;
import org.whispersystems.libaxolotl.InvalidMessageException;
import org.whispersystems.libaxolotl.util.guava.Optional;
import org.whispersystems.textsecure.api.util.InvalidNumberException;
@@ -154,8 +157,11 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
private static final Map<Long, SoftReference<SlideDeck>> slideCache =
Collections.synchronizedMap(new LRUCache<Long, SoftReference<SlideDeck>>(20));
private final JobManager jobManager;
public MmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
super(context, databaseHelper);
this.jobManager = ApplicationContext.getInstance(context).getJobManager();
}
public int getMessageCountForThread(long threadId) {
@@ -566,9 +572,9 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
DatabaseFactory.getThreadDatabase(context).update(threadId);
notifyConversationListeners(threadId);
Trimmer.trimThread(context, threadId);
jobManager.add(new TrimThreadJob(context, threadId));
return new Pair<Long, Long>(messageId, threadId);
return new Pair<>(messageId, threadId);
}
public Pair<Long, Long> insertMessageInbox(MasterSecret masterSecret,
@@ -644,7 +650,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
DatabaseFactory.getThreadDatabase(context).setUnread(threadId);
}
Trimmer.trimThread(context, threadId);
jobManager.add(new TrimThreadJob(context, threadId));
}
public long insertMessageOutbox(MasterSecret masterSecret, OutgoingMediaMessage message,
@@ -690,7 +696,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
long messageId = insertMediaMessage(masterSecret, sendRequest.getPduHeaders(),
sendRequest.getBody(), contentValues);
Trimmer.trimThread(context, threadId);
jobManager.add(new TrimThreadJob(context, threadId));
return messageId;
}

View File

@@ -27,8 +27,10 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.jobs.TrimThreadJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
@@ -37,7 +39,7 @@ import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
import org.thoughtcrime.securesms.sms.IncomingKeyExchangeMessage;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.Trimmer;
import org.whispersystems.jobqueue.JobManager;
import org.whispersystems.textsecure.api.util.InvalidNumberException;
import java.util.Set;
@@ -86,8 +88,11 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, RECEIPT_COUNT
};
private final JobManager jobManager;
public SmsDatabase(Context context, SQLiteOpenHelper databaseHelper) {
super(context, databaseHelper);
this.jobManager = ApplicationContext.getInstance(context).getJobManager();
}
private void updateTypeBitmask(long id, long maskOff, long maskOn) {
@@ -329,7 +334,8 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
DatabaseFactory.getThreadDatabase(context).update(record.getThreadId());
notifyConversationListeners(record.getThreadId());
Trimmer.trimThread(context, record.getThreadId());
jobManager.add(new TrimThreadJob(context, record.getThreadId()));
reader.close();
return new Pair<>(newMessageId, record.getThreadId());
@@ -417,9 +423,9 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
DatabaseFactory.getThreadDatabase(context).update(threadId);
notifyConversationListeners(threadId);
Trimmer.trimThread(context, threadId);
jobManager.add(new TrimThreadJob(context, threadId));
return new Pair<Long, Long>(messageId, threadId);
return new Pair<>(messageId, threadId);
}
public Pair<Long, Long> insertMessageInbox(IncomingTextMessage message) {
@@ -450,7 +456,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
DatabaseFactory.getThreadDatabase(context).update(threadId);
notifyConversationListeners(threadId);
Trimmer.trimThread(context, threadId);
jobManager.add(new TrimThreadJob(context, threadId));
return messageId;
}

View File

@@ -1,13 +1,35 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.jobs;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import org.thoughtcrime.securesms.PlayServicesProblemActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.push.TextSecureCommunicationFactory;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobParameters;
@@ -31,22 +53,20 @@ public class GcmRefreshJob extends ContextJob {
@Override
public void onRun() throws Exception {
String registrationId = TextSecurePreferences.getGcmRegistrationId(context);
TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context);
String registrationId = TextSecurePreferences.getGcmRegistrationId(context);
if (registrationId == null) {
Log.w(TAG, "GCM registrationId expired, reregistering...");
int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (result != ConnectionResult.SUCCESS) {
Toast.makeText(context, "Unable to register with GCM!", Toast.LENGTH_LONG).show();
notifyGcmFailure();
} else {
String gcmId = GoogleCloudMessaging.getInstance(context).register(REGISTRATION_ID);
accountManager.setGcmId(Optional.of(gcmId));
TextSecurePreferences.setGcmRegistrationId(context, gcmId);
}
String gcmId = GoogleCloudMessaging.getInstance(context).register(REGISTRATION_ID);
TextSecureAccountManager accountManager = TextSecureCommunicationFactory.createManager(context);
accountManager.setGcmId(Optional.of(gcmId));
TextSecurePreferences.setGcmRegistrationId(context, gcmId);
}
}
@@ -61,4 +81,22 @@ public class GcmRefreshJob extends ContextJob {
return true;
}
private void notifyGcmFailure() {
Intent intent = new Intent(context, PlayServicesProblemActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1122, intent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setSmallIcon(R.drawable.icon_notification);
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_action_warning_red));
builder.setContentTitle(context.getString(R.string.GcmRefreshJob_Permanent_TextSecure_communication_failure));
builder.setContentText(context.getString(R.string.GcmRefreshJob_TextSecure_was_unable_to_register_with_Google_Play_Services));
builder.setTicker(context.getString(R.string.GcmRefreshJob_Permanent_TextSecure_communication_failure));
builder.setVibrate(new long[] {0, 1000});
builder.setContentIntent(pendingIntent);
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE))
.notify(12, builder.build());
}
}

View File

@@ -0,0 +1,65 @@
/**
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.util.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.Job;
import org.whispersystems.jobqueue.JobParameters;
public class TrimThreadJob extends Job {
private static final String TAG = TrimThreadJob.class.getSimpleName();
private final Context context;
private final long threadId;
public TrimThreadJob(Context context, long threadId) {
super(JobParameters.newBuilder().withGroupId(TrimThreadJob.class.getSimpleName()).create());
this.context = context;
this.threadId = threadId;
}
@Override
public void onAdded() {
}
@Override
public void onRun() {
boolean trimmingEnabled = TextSecurePreferences.isThreadLengthTrimmingEnabled(context);
int threadLengthLimit = TextSecurePreferences.getThreadTrimLength(context);
if (!trimmingEnabled)
return;
DatabaseFactory.getThreadDatabase(context).trimThread(threadId, threadLengthLimit);
}
@Override
public boolean onShouldRetry(Exception exception) {
return false;
}
@Override
public void onCanceled() {
Log.w(TAG, "Canceling trim attempt: " + threadId);
}
}

View File

@@ -14,22 +14,6 @@ public class Trimmer {
new TrimmingProgressTask(context).execute(threadLengthLimit);
}
public static void trimThread(final Context context, final long threadId) {
boolean trimmingEnabled = TextSecurePreferences.isThreadLengthTrimmingEnabled(context);
final int threadLengthLimit = TextSecurePreferences.getThreadTrimLength(context);
if (!trimmingEnabled)
return;
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
DatabaseFactory.getThreadDatabase(context).trimThread(threadId, threadLengthLimit);
return null;
}
}.execute();
}
private static class TrimmingProgressTask extends AsyncTask<Integer, Integer, Void> implements ThreadDatabase.ProgressListener {
private ProgressDialog progressDialog;
private Context context;