Compare commits

...

75 Commits

Author SHA1 Message Date
B. Petersen a1e6c14443 use different app name for X-Mailer header 2018-10-15 15:31:39 +02:00
Florian Haar 58ada319bb Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-15 11:38:05 +02:00
Florian Haar 45bfab9fbd Adjust the CreateProfileActivity UI #87 2018-10-15 11:36:09 +02:00
B. Petersen e5d8a2bc28 update error indicator 2018-10-14 23:25:32 +02:00
B. Petersen 99b1e2ba43 harden getConfigInt() 2018-10-14 12:11:07 +02:00
B. Petersen 27d632f17c show sender names in groups, closes #85 2018-10-13 22:34:24 +02:00
B. Petersen fbd53b3767 make opened chat as being noticed, closes #66 2018-10-13 16:56:29 +02:00
B. Petersen 8f56d5872a adding SELF to the list of contacts so that one can easily create a self-chat 2018-10-13 15:33:34 +02:00
daniel.boehrs 0e75880c24 show "verified" icon in contact list and in chat title #80 2018-10-12 15:54:58 +02:00
B. Petersen 0e55a4ad5e Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-12 13:56:11 +02:00
B. Petersen 6eed72a4d2 bump version 2018-10-12 13:56:08 +02:00
Florian Haar 63f49efee1 Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-12 11:10:10 +02:00
Florian Haar 7d52e125a3 Allow for customized Background image #50 2018-10-12 11:03:29 +02:00
B. Petersen b4c1f214a0 show compound messages 2018-10-11 18:38:55 +02:00
B. Petersen 02ea677a3c speed up encryption by disable debug, tackles https://github.com/deltachat/deltachat-core/issues/376 2018-10-10 23:13:02 +02:00
B. Petersen 62e03e7ce4 tweak contact deletion, closes #83 2018-10-10 15:53:02 +02:00
B. Petersen eaabc75501 Update messenger-backend submodule. 2018-10-10 15:23:45 +02:00
B. Petersen 749ccb1228 adapt to new api 2018-10-10 15:23:27 +02:00
daniel.boehrs 5f2f24116d ask before deleting contacts #82 2018-10-10 14:40:44 +02:00
B. Petersen beb01e885c remove dead backup functionality 2018-10-09 17:45:15 +02:00
B. Petersen 86a54970f4 correct logical contact-delete-failed check introduced by me with the last commit 2018-10-09 17:33:52 +02:00
B. Petersen 179e8173c9 delete contacts in thread 2018-10-09 17:16:56 +02:00
daniel.boehrs 0a119d9d8e Fixed highlighting issue in #37 2018-10-09 16:38:11 +02:00
B. Petersen ac6b82cc70 Merge branch 'master' of https://github.com/deltachat/deltachat-android-ii 2018-10-09 15:48:27 +02:00
B. Petersen 8d82552aaa remove unused classes 2018-10-09 15:48:14 +02:00
daniel.boehrs 247fb1a357 Delete all selected contacts not always working #81 2018-10-09 15:47:38 +02:00
daniel.boehrs 91c3d8e847 Optimize loading for adress book sync #46 2018-10-09 15:38:49 +02:00
B. Petersen 93f30ae34f Update messenger-backend submodule. 2018-10-09 10:56:35 +02:00
B. Petersen 8df4b6be39 wording of login button: no need to register to delta chat, only log-in required 2018-10-08 17:41:31 +02:00
daniel.boehrs 4a9627118a remove unused permissions, delay requests #68 2018-10-08 12:56:54 +02:00
daniel.boehrs 52c495b307 add contacts from system address book to contact database #46 2018-10-08 10:46:59 +02:00
daniel.boehrs c037020918 Adjust UI for disabled contact list entries #37 2018-10-08 09:23:58 +02:00
B. Petersen 7a2597186b remove unused country selection code 2018-10-08 00:56:59 +02:00
B. Petersen e41279f080 remove more unsued sms code 2018-10-08 00:42:00 +02:00
B. Petersen 93f781b8dc remove some unsued sms code 2018-10-08 00:13:12 +02:00
B. Petersen cbf40049a1 Update messenger-backend submodule. 2018-10-07 18:28:11 +02:00
B. Petersen 11eed61019 adapt to new API 2018-10-07 18:27:59 +02:00
daniel.boehrs 28763e686d backup, manage keys does not work when system secret is disabled #77 2018-10-05 14:37:14 +02:00
daniel.boehrs 6edca0eeb6 add status/footer to "your profile" settings #76 2018-10-05 14:25:48 +02:00
daniel.boehrs f9c5f133d5 add option to delete a single contact #37 2018-10-05 13:27:31 +02:00
B. Petersen c3cd3ceffb Update messenger-backend submodule. 2018-10-04 21:39:22 +02:00
B. Petersen 4482db9195 adapt to new core-api 2018-10-04 21:38:29 +02:00
B. Petersen 6f8db1352a show image-messages 2018-10-03 22:09:40 +02:00
B. Petersen 5011f44ddf open attachments 2018-10-03 18:28:34 +02:00
B. Petersen fc6dded69a remove unused downloadClickListeners 2018-10-03 17:09:06 +02:00
B. Petersen 29731c02f4 remove unused spinners from attachment views 2018-10-03 15:19:50 +02:00
B. Petersen 728142d08d so not show setup message as file 2018-10-03 15:14:51 +02:00
B. Petersen 5c693c14b6 prepare showing documents/images/audio 2018-10-02 23:22:47 +02:00
B. Petersen a31307171e typo 2018-10-02 22:19:10 +02:00
B. Petersen 1a510d8787 pass default status text to the core 2018-10-02 22:08:56 +02:00
B. Petersen 7109c6c806 use fallback text in settings screen if display-name is not yet set 2018-10-02 21:53:00 +02:00
B. Petersen 7d85e2c3e8 use dynamic applicationId for the providers, not more conflicts with signal, closes #75 2018-10-02 20:51:29 +02:00
B. Petersen 138144b938 suggest bubbles 2018-10-02 19:37:07 +02:00
B. Petersen 0ed4c5a305 remove unused clustering code 2018-10-02 19:26:57 +02:00
B. Petersen 46832b2290 remove contact-joined-event-option, closes #67 2018-10-02 18:12:55 +02:00
B. Petersen 7aad748915 tweak checkmarks and message-item-footer, closes #52 2018-10-02 17:42:35 +02:00
B. Petersen 2887d1b807 prefere preference setting from core, closes #64 2018-10-02 17:41:36 +02:00
daniel.boehrs fca9076059 Remove Settings / Notifications / Calls category #14 2018-10-02 15:06:34 +02:00
daniel.boehrs 931283f98a Add security check to backup and key export #14 2018-10-02 14:40:28 +02:00
daniel.boehrs 2e7de766dd Adjust version and versionName #65 2018-10-02 14:21:57 +02:00
daniel.boehrs 31de65880e Fix unwanted screen lock after initial activation 2018-10-02 13:13:41 +02:00
daniel.boehrs 7530bcd592 Adjust screen lock 2018-10-02 09:26:27 +02:00
B. Petersen 7deab10a9f cleanup chat preferences 2018-10-01 23:24:07 +02:00
B. Petersen 5c1ff3c110 handle MDNs options, closes #63 2018-10-01 20:57:38 +02:00
B. Petersen b9d3740f58 hide the pending-spinning-wheel from the chat list if there are no messages, closes #60 2018-10-01 17:30:44 +02:00
daniel.boehrs 87b5d2d246 Added prefill for RegistrationAcivity 2018-10-01 16:30:11 +02:00
daniel.boehrs a41e0f7ca0 Added strings and fixed dismissable lock dialog 2018-10-01 16:07:17 +02:00
daniel.boehrs 79b98a48c2 App screen lock #42 2018-10-01 15:15:48 +02:00
B. Petersen e16df36e81 center emoji as well as send/attach buttons vertically, closes #61 2018-10-01 14:46:38 +02:00
B. Petersen 89a9d1b147 draw a line atop of the expanded attachment drawer, closes #59 2018-10-01 14:35:23 +02:00
B. Petersen 1f0f729871 remove 'mark all read' for now, closes #53 2018-10-01 11:52:21 +02:00
B. Petersen 683336d620 handle incoming autocrypt setup messages, closes #43 2018-09-30 19:44:21 +02:00
B. Petersen 5515a665c3 sending autocrypt setup messages, setting prefer_encrypt 2018-09-30 16:14:41 +02:00
björn petersen 8b5276c9fc Merge pull request #58 from deltachat/work-on-asm
add asm controls
2018-09-29 14:00:53 +02:00
B. Petersen 5fc731b7e9 add asm controls
add explaining autocrypt text
2018-09-29 13:59:47 +02:00
194 changed files with 2220 additions and 15075 deletions
+11 -80
View File
@@ -5,10 +5,6 @@
<uses-sdk tools:overrideLibrary="com.amulyakhare.textdrawable,com.astuetz.pagerslidingtabstrip,pl.tajchert.waitingdots,com.h6ah4i.android.multiselectlistpreferencecompat,android.support.v13,com.davemorrissey.labs.subscaleview,com.tomergoldst.tooltips,com.klinker.android.send_message,com.takisoft.colorpicker,android.support.v14.preference"/>
<permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"
android:label="Access to TextSecure Secrets"
android:protectionLevel="signature" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.location" android:required="false"/>
@@ -28,13 +24,6 @@
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
@@ -88,10 +77,6 @@
<uses-permission android:name="android.permission.RAISED_THREAD_PRIORITY" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<permission android:name="org.thoughtcrime.securesms.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="org.thoughtcrime.securesms.permission.C2D_MESSAGE" />
<application android:name=".ApplicationContext"
android:icon="@mipmap/ic_launcher_dev"
android:label="@string/app_name"
@@ -117,9 +102,6 @@
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|fontScale"
android:launchMode="singleTask"/>
<activity android:name=".CountrySelectionActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".InviteActivity"
android:theme="@style/TextSecure.HighlightTheme"
android:windowSoftInputMode="stateHidden"
@@ -213,11 +195,6 @@
android:windowSoftInputMode="stateVisible"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DatabaseMigrationActivity"
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".DatabaseUpgradeActivity"
android:theme="@style/NoAnimation.Theme.AppCompat.Light.DarkActionBar"
android:launchMode="singleTask"
@@ -348,23 +325,9 @@
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<service android:enabled="true" android:name="org.thoughtcrime.securesms.service.WebRtcCallService"/>
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
<service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/>
<service android:enabled="true" android:name=".service.MessageRetrievalService"/>
<service android:name=".service.QuickResponseService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</service>
<service android:name=".service.AccountAuthenticatorService" android:exported="true">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
@@ -396,39 +359,6 @@
</intent-filter>
</receiver>
<receiver android:name=".service.SmsListener"
android:permission="android.permission.BROADCAST_SMS"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="1001">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
<intent-filter>
<action android:name="android.provider.Telephony.SMS_DELIVER"/>
</intent-filter>
</receiver>
<receiver android:name=".service.SmsDeliveryListener"
android:exported="true">
<intent-filter>
<action android:name="org.thoughtcrime.securesms.services.MESSAGE_SENT"/>
</intent-filter>
</receiver>
<receiver android:name=".service.MmsListener"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_WAP_PUSH">
<intent-filter android:priority="1001">
<action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED"/>
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER"/>
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
<receiver android:name=".notifications.MarkReadReceiver"
android:enabled="true"
android:exported="false">
@@ -466,15 +396,15 @@
<provider android:name=".providers.PartProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="org.thoughtcrime.provider.securesms" />
android:authorities="${applicationId}.provider.securesms" />
<provider android:name=".providers.MmsBodyProvider"
android:grantUriPermissions="true"
android:exported="false"
android:authorities="org.thoughtcrime.provider.securesms.mms" />
android:authorities="${applicationId}.provider.securesms.mms" />
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="org.thoughtcrime.securesms.fileprovider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
@@ -482,6 +412,13 @@
</provider>
<provider
android:name=".connect.AttachmentsContentProvider"
android:authorities="${applicationId}.attachments"
android:grantUriPermissions="true"
android:exported="false">
</provider>
<receiver android:name=".service.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
@@ -501,13 +438,7 @@
</intent-filter>
</receiver>
<receiver android:name=".service.LocalBackupListener">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".service.PersistentConnectionBootListener">
<receiver android:name=".service.PersistentConnectionBootListener">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
+2 -2
View File
@@ -255,8 +255,8 @@ android {
}
defaultConfig {
versionCode 392
versionName "4.24.7"
versionCode 393
versionName "0.0.2"
applicationId "chat.delta.androidii"
minSdkVersion 14
+1 -1
View File
@@ -871,7 +871,7 @@ LOCAL_STATIC_LIBRARIES := etpan sasl2 sqlite crypto libiconv
# "breakpad" was placed after "crypto", NativeLoader.cpp after dc_wrapper.c
LOCAL_CFLAGS := -w -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno -std=c99
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS
LOCAL_SRC_FILES := \
+4 -4
View File
@@ -1,5 +1,5 @@
APP_PLATFORM := android-14
APP_ABI := armeabi armeabi-v7a x86
APP_PLATFORM := android-9
APP_STL := stlport_static
APP_CPPFLAGS += -fexceptions
APP_OPTIM := debug
NDK_TOOLCHAIN_VERSION := 4.9
APP_STL := gnustl_static
+6 -31
View File
@@ -345,9 +345,9 @@ JNIEXPORT void Java_com_b44t_messenger_DcContext_blockContact(JNIEnv *env, jobje
}
JNIEXPORT jint Java_com_b44t_messenger_DcContext_deleteContact(JNIEnv *env, jobject obj, jint contact_id)
JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_deleteContact(JNIEnv *env, jobject obj, jint contact_id)
{
return (jint)dc_delete_contact(get_dc_context(env, obj), contact_id);
return (jboolean)dc_delete_contact(get_dc_context(env, obj), contact_id);
}
@@ -499,9 +499,9 @@ JNIEXPORT jlong Java_com_b44t_messenger_DcContext_getMsgCPtr(JNIEnv *env, jobjec
}
JNIEXPORT jlong Java_com_b44t_messenger_DcContext_createMsgCPtr(JNIEnv *env, jobject obj)
JNIEXPORT jlong Java_com_b44t_messenger_DcContext_createMsgCPtr(JNIEnv *env, jobject obj, jint viewtype)
{
return (jlong)dc_msg_new(get_dc_context(env, obj));
return (jlong)dc_msg_new(get_dc_context(env, obj), viewtype);
}
@@ -587,39 +587,20 @@ JNIEXPORT void Java_com_b44t_messenger_DcContext_setConfig(JNIEnv *env, jobject
}
JNIEXPORT void Java_com_b44t_messenger_DcContext_setConfigInt(JNIEnv *env, jobject obj, jstring key, jint value)
{
CHAR_REF(key);
dc_set_config_int(get_dc_context(env, obj), keyPtr, value);
CHAR_UNREF(key);
}
JNIEXPORT jstring Java_com_b44t_messenger_DcContext_getConfig(JNIEnv *env, jobject obj, jstring key, jstring def/*may be NULL*/)
{
CHAR_REF(key);
CHAR_REF(def);
char* temp = dc_get_config(get_dc_context(env, obj), keyPtr, defPtr /*is NULL if value is NULL, CHAR_REF() handles this*/);
char* temp = dc_get_config(get_dc_context(env, obj), keyPtr);
jstring ret = NULL;
if (temp) {
ret = JSTRING_NEW(temp);
}
free(temp);
CHAR_UNREF(key);
CHAR_UNREF(def);
return ret; /* returns NULL only if key is unset and "def" is NULL */
}
JNIEXPORT jint Java_com_b44t_messenger_DcContext_getConfigInt(JNIEnv *env, jobject obj, jstring key, jint def)
{
CHAR_REF(key);
jint ret = dc_get_config_int(get_dc_context(env, obj), keyPtr, def);
CHAR_UNREF(key);
return ret;
}
/* DcContext - out-of-band verification */
JNIEXPORT jlong Java_com_b44t_messenger_DcContext_checkQrCPtr(JNIEnv *env, jobject obj, jstring qr)
@@ -981,7 +962,7 @@ JNIEXPORT jlong Java_com_b44t_messenger_DcMsg_getTimestamp(JNIEnv *env, jobject
JNIEXPORT jint Java_com_b44t_messenger_DcMsg_getType(JNIEnv *env, jobject obj)
{
return dc_msg_get_type(get_dc_msg(env, obj));
return dc_msg_get_viewtype(get_dc_msg(env, obj));
}
@@ -1122,12 +1103,6 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcMsg_getSetupCodeBegin(JNIEnv *env, j
}
JNIEXPORT void Java_com_b44t_messenger_DcMsg_setType(JNIEnv *env, jobject obj, int type)
{
dc_msg_set_type(get_dc_msg(env, obj), type);
}
JNIEXPORT void Java_com_b44t_messenger_DcMsg_setText(JNIEnv *env, jobject obj, jstring text)
{
CHAR_REF(text);
+4
View File
@@ -5,4 +5,8 @@
-keepclassmembers class ** {
public void onEvent*(**);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

After

Width:  |  Height:  |  Size: 330 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 B

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1023 B

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 863 B

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 413 B

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="@color/transparent_black_30"
android:endColor="@color/transparent_black"
android:angle="90"/>
</shape>
@@ -6,7 +6,11 @@
android:bottom="2px">
<shape android:shape="rectangle">
<corners android:radius="@dimen/message_corner_radius"/>
<corners
android:topLeftRadius="@dimen/message_corner_radius"
android:topRightRadius="@dimen/message_corner_radius"
android:bottomRightRadius="@dimen/message_corner_radius"
android:bottomLeftRadius="@dimen/message_corner_collapse_radius" />
<solid android:color="@color/white" />
</shape>
</item>
@@ -6,7 +6,11 @@
android:bottom="2px">
<shape android:shape="rectangle">
<corners android:radius="@dimen/message_corner_radius"/>
<corners
android:topLeftRadius="@dimen/message_corner_radius"
android:topRightRadius="@dimen/message_corner_radius"
android:bottomRightRadius="@dimen/message_corner_collapse_radius"
android:bottomLeftRadius="@dimen/message_corner_radius" />
<solid android:color="@color/white" />
</shape>
</item>
-26
View File
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="@+id/sms_failed_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_error"
android:visibility="gone"
android:tint="@color/core_red"
tools:visibility="visible"
android:contentDescription="@string/conversation_item_sent__send_failed_indicator_description" />
<ImageView
android:id="@+id/pending_approval_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_error"
android:tint="@color/core_light_60"
android:visibility="gone"
tools:visibility="visible"
android:layout_gravity="center_vertical"
android:contentDescription="@string/conversation_item_sent__pending_approval_description" />
</merge>
+208 -197
View File
@@ -1,224 +1,235 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attachment_type_selector_background">
android:layout_height="wrap_content">
<org.thoughtcrime.securesms.components.RecentPhotoViewRail
android:id="@+id/recent_photos"
android:layout_width="match_parent"
android:layout_height="90dp"
android:padding="4dp"/>
<View android:layout_width="match_parent"
android:layout_height="4dp"
android:background="@drawable/attachment_selector_shadow"/>
<LinearLayout android:orientation="horizontal"
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:weightSum="4">
android:background="?attachment_type_selector_background">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.RecentPhotoViewRail
android:id="@+id/recent_photos"
android:layout_width="match_parent"
android:layout_height="90dp"
android:padding="4dp"/>
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/gallery_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_image_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__gallery_description"
app:circleColor="@color/purple_400"/>
<TextView android:layout_marginTop="10dp"
style="@style/AttachmentTypeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/attachment_type_selector__gallery"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/audio_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_headset_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__audio_description"
app:circleColor="@color/orange_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__audio"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/document_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_insert_drive_file_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__file_description"
app:circleColor="@color/red_400"/>
<TextView android:layout_marginTop="10dp"
style="@style/AttachmentTypeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/attachment_type_selector__file"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:layout_weight="1">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/contact_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_person_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__contact_description"
app:circleColor="@color/blue_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__contact"/>
</LinearLayout>
</LinearLayout>
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:weightSum="4">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/camera_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_camera_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__camera_description"
app:circleColor="@color/green_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__camera"/>
</LinearLayout>
<LinearLayout android:id="@+id/location_linear_layout"
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:weightSum="4">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/location_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_location_on_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__location_description"
app:circleColor="@color/blue_grey_400"/>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__location"/>
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/gallery_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_image_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__gallery_description"
app:circleColor="@color/purple_400"/>
<TextView android:layout_marginTop="10dp"
style="@style/AttachmentTypeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/attachment_type_selector__gallery"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/audio_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_headset_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__audio_description"
app:circleColor="@color/orange_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__audio"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_weight="1"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/document_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_insert_drive_file_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__file_description"
app:circleColor="@color/red_400"/>
<TextView android:layout_marginTop="10dp"
style="@style/AttachmentTypeLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/attachment_type_selector__file"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:layout_weight="1">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/contact_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_person_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__contact_description"
app:circleColor="@color/blue_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__contact"/>
</LinearLayout>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
<LinearLayout android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
android:layout_marginTop="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:weightSum="4">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/giphy_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_gif_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__gif_description"
app:circleColor="@color/cyan_400"/>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/camera_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_camera_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__camera_description"
app:circleColor="@color/green_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__camera"/>
</LinearLayout>
<LinearLayout android:id="@+id/location_linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/location_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_location_on_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__location_description"
app:circleColor="@color/blue_grey_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__location"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/giphy_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_gif_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__gif_description"
app:circleColor="@color/cyan_400"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__gif"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/close_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_keyboard_arrow_down_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__drawer_description"
app:circleColor="@color/gray50"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text=" "/>
</LinearLayout>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text="@string/attachment_type_selector__gif"/>
</LinearLayout>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.CircleColorImageView
android:id="@+id/close_button"
android:layout_width="53dp"
android:layout_height="53dp"
android:src="@drawable/ic_keyboard_arrow_down_white_24dp"
android:scaleType="center"
android:contentDescription="@string/attachment_type_selector__drawer_description"
app:circleColor="@color/gray50"/>
<TextView android:layout_marginTop="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/AttachmentTypeLabel"
android:text=" "/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
-11
View File
@@ -20,17 +20,6 @@
android:layout_gravity="center"
android:gravity="center">
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/download_progress"
android:layout_width="48dp"
android:layout_height="48dp"
android:visibility="gone"
android:layout_gravity="center"
app:matProg_barColor="@color/white"
app:matProg_linearProgress="true"
app:matProg_spinSpeed="0.333"
tools:visibility="gone"/>
<ImageView android:id="@+id/play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -34,59 +34,4 @@
android:visibility="gone"
android:layout_gravity="end"/>
<LinearLayout android:id="@+id/show_contacts_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
android:visibility="gone"
tools:visibility="visible">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"
app:matProg_circleRadius="145dp"
app:matProg_barWidth="6dp"
app:matProg_rimColor="@color/signal_primary"
app:matProg_barColor="@color/signal_primary_dark"
app:matProg_progressIndeterminate="true"
tools:visibility="visible"
/>
<ImageView android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/no_contacts"/>
</FrameLayout>
<TextView android:id="@+id/show_contacts_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:textSize="15sp"
android:lineSpacingMultiplier="1.3"
android:gravity="center"
android:text="@string/contact_selection_list_fragment__signal_needs_access_to_your_contacts_in_order_to_display_them"/>
<Button android:id="@+id/show_contacts_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_gravity="center_horizontal"
android:background="@color/signal_primary"
android:textColor="@color/white"
android:padding="10dp"
android:text="@string/contact_selection_list_fragment__show_contacts"/>
</LinearLayout>
</FrameLayout>
+11 -11
View File
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.contacts.ContactSelectionListItem
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
@@ -8,7 +7,7 @@
android:orientation="horizontal"
android:gravity="center_vertical"
android:focusable="true"
android:background="@drawable/conversation_item_background"
android:background="?attr/conversation_list_item_background"
android:paddingLeft="48dp"
android:paddingStart="48dp"
android:paddingRight="24dp"
@@ -33,15 +32,16 @@
android:orientation="vertical">
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp"
tools:text="Frieeeeeeedrich Nieeeeeeeeeetzsche" />
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
android:drawablePadding="5dp"
android:ellipsize="marquee"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp"
tools:text="Frieeeeeeedrich Nieeeeeeeeeetzsche" />
<LinearLayout android:id="@+id/number_container"
android:orientation="horizontal"
+1
View File
@@ -2,6 +2,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/conversation_container"
android:layout_width="fill_parent"
android:layout_height="match_parent">
+1 -1
View File
@@ -203,7 +203,7 @@
android:layout_marginLeft="12dp"
android:layout_marginStart="12dp"
android:background="@drawable/circle_tintable"
android:layout_gravity="bottom">
android:layout_gravity="center_vertical">
<ImageButton
android:id="@+id/attach_button"
+12 -51
View File
@@ -8,54 +8,6 @@
android:orientation="horizontal"
tools:parentTag="org.thoughtcrime.securesms.components.ConversationItemFooter">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginRight="6dp"
android:layout_marginEnd="6dp"
android:orientation="horizontal"
android:gravity="left|start|center_vertical">
<TextView
android:id="@+id/footer_date"
android:autoLink="none"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:linksClickable="false"
style="@style/Signal.Text.Caption.MessageSent"
android:textColor="?conversation_item_sent_text_secondary_color"
android:textAllCaps="true"
tools:text="30 mins"/>
<org.thoughtcrime.securesms.components.ExpirationTimerView
android:id="@+id/footer_expiration_timer"
android:layout_gravity="center_vertical|end"
android:layout_marginLeft="6dp"
android:layout_marginStart="6dp"
android:layout_width="12dp"
android:layout_height="12dp"
android:visibility="gone"
tools:visibility="visible"/>
</LinearLayout>
<TextView
android:id="@+id/footer_sim_info"
android:autoLink="none"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="15sp"
android:linksClickable="false"
style="@style/Signal.Text.Caption.MessageSent"
android:layout_gravity="right|end|bottom"
android:fontFamily="sans-serif-light"
android:paddingLeft="4dp"
android:paddingStart="4dp"
android:visibility="gone"
tools:visibility="visible"
tools:text="to SIM1" />
<ImageView
android:id="@+id/footer_secure_indicator"
android:layout_width="12dp"
@@ -66,12 +18,21 @@
android:contentDescription="@string/conversation_item__secure_message_description"
tools:visibility="visible"/>
<TextView
android:id="@+id/footer_date"
android:autoLink="none"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:linksClickable="false"
style="@style/Signal.Text.Caption.MessageSent"
android:textColor="?conversation_item_sent_text_secondary_color"
android:textAllCaps="true"
tools:text="30 mins"/>
<org.thoughtcrime.securesms.components.DeliveryStatusView
android:id="@+id/footer_delivery_status"
android:layout_width="20dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="3dp"
android:layout_marginStart="3dp"/>
android:layout_gravity="center_vertical"/>
</merge>
+1 -22
View File
@@ -86,20 +86,6 @@
tools:visibility="visible"
tools:text="+14152222222"/>
<TextView
android:id="@+id/group_message_sender_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="4sp"
android:paddingLeft="4sp"
style="@style/Signal.Text.Preview"
android:fontFamily="sans-serif-regular"
android:textColor="?conversation_item_received_text_primary_color"
android:textStyle="italic"
android:maxLines="1"
android:ellipsize="end"
tools:text="~Clement Duval"/>
</LinearLayout>
<org.thoughtcrime.securesms.components.QuoteView
@@ -171,6 +157,7 @@
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_bottom_padding"
android:gravity="end"
android:clipChildren="false"
android:clipToPadding="false"
android:alpha="0.7"
@@ -179,13 +166,5 @@
</LinearLayout>
<org.thoughtcrime.securesms.components.AlertView
android:id="@+id/indicators_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:orientation="vertical"
android:gravity="center_vertical"/>
</RelativeLayout>
</org.thoughtcrime.securesms.ConversationItem>
+5 -1
View File
@@ -125,6 +125,7 @@
android:layout_marginLeft="@dimen/message_bubble_horizontal_padding"
android:layout_marginRight="@dimen/message_bubble_horizontal_padding"
android:layout_marginBottom="@dimen/message_bubble_bottom_padding"
android:gravity="end"
android:clipChildren="false"
android:clipToPadding="false"
app:footer_text_color="?attr/conversation_item_sent_text_secondary_color"
@@ -132,7 +133,10 @@
</LinearLayout>
<org.thoughtcrime.securesms.components.AlertView
<!-- the following view is only left because it is used as a reference for positioning above.
removing would require some re-layouting, it's just not done yet.-->
<View
android:visibility="gone"
android:id="@+id/indicators_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+34 -32
View File
@@ -36,45 +36,47 @@
android:weightSum="1"
android:orientation="horizontal">
<org.thoughtcrime.securesms.components.FromTextView
android:id="@+id/from"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/thumbnail"
android:layout_toStartOf="@+id/thumbnail"
style="@style/Signal.Text.Body"
android:fontFamily="sans-serif-medium"
android:textColor="?attr/conversation_list_item_contact_color"
android:maxLines="1"
tools:text="Jules Bonnot"
android:ellipsize="end"
android:layout_marginBottom="2dp"
android:drawablePadding="5dp"/>
<LinearLayout
android:id="@+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/thumbnail"
android:layout_toStartOf="@+id/thumbnail">
<org.thoughtcrime.securesms.components.AlertView
android:id="@+id/indicators_parent"
android:layout_width="18dp"
android:layout_height="18dp"
android:paddingTop="2dp"
android:layout_marginRight="2dp"
android:layout_marginEnd="2dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/from"
app:useSmallIcon="true"
android:visibility="gone"
tools:visibility="visible"/>
<org.thoughtcrime.securesms.components.FromTextView
android:id="@+id/from_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Signal.Text.Body"
android:fontFamily="sans-serif-medium"
android:textColor="?attr/conversation_list_item_contact_color"
android:maxLines="1"
tools:text="Jules Bonnot"
android:ellipsize="end"
android:layout_marginBottom="2dp"
android:drawablePadding="5dp"/>
<ImageView
android:src="@drawable/ic_verified"
android:id="@+id/verified_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="5dp"
android:paddingStart="5dp"
android:visibility="gone"/>
</LinearLayout>
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/subject"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/from"
android:layout_toRightOf="@id/indicators_parent"
android:layout_toEndOf="@id/indicators_parent"
android:layout_toLeftOf="@+id/status"
android:layout_toStartOf="@+id/status"
android:paddingRight="1dp"
+38 -48
View File
@@ -39,59 +39,49 @@
tools:src="@drawable/ic_contact_picture"
android:contentDescription="@string/conversation_list_item_view__contact_photo_image"/>
<RelativeLayout android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/contact_photo_image"
android:layout_toEndOf="@id/contact_photo_image"
android:layout_centerVertical="true">
<android.support.constraint.ConstraintLayout
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/contact_photo_image"
android:layout_toRightOf="@id/contact_photo_image">
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="18dp"
android:transitionName="recipient_name"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
style="@style/TextSecure.TitleTextStyle"
tools:ignore="UnusedAttribute"/>
android:id="@+id/title"
style="@style/TextSecure.TitleTextStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:drawablePadding="5dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="18dp"
android:transitionName="recipient_name" />
<ImageView android:id="@+id/verified_indicator"
android:src="@drawable/ic_check_circle_white_18dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp"
android:layout_marginEnd="3dp"
android:layout_gravity="bottom"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/title"
android:alpha="0.7"
android:visibility="gone"/>
<ImageView
android:id="@+id/verified_indicator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:src="@drawable/ic_verified"
android:visibility="visible"
android:layout_marginLeft="5dp"
app:layout_constraintBottom_toBottomOf="@id/title"
app:layout_constraintStart_toEndOf="@id/title"
app:layout_constraintTop_toTopOf="@id/title"
android:layout_marginStart="5dp" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:layout_gravity="center_vertical|start"
android:gravity="center_vertical"
android:layout_toRightOf="@id/verified_indicator"
android:layout_toEndOf="@id/verified_indicator"
android:layout_below="@id/title"
android:textDirection="ltr"
android:textSize="13dp"
tools:text="(123) 123-1234"
style="@style/TextSecure.SubtitleTextStyle"/>
android:id="@+id/subtitle"
style="@style/TextSecure.SubtitleTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textDirection="ltr"
android:textSize="13dp"
app:layout_constraintTop_toBottomOf="@id/title"
tools:text="(123) 123-1234" />
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
</org.thoughtcrime.securesms.ConversationTitleView>
-28
View File
@@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dip"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:id="@+id/country_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:textSize="18sp"
android:textStyle="bold" />
<TextView android:id="@+id/country_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18.0sp"
android:textStyle="bold"
android:textColor="#7b7b7b"
android:gravity="right|center"
android:layout_marginLeft="4dip"
android:layout_marginRight="5dip"
android:layout_gravity="right|center"/>
</LinearLayout>
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<fragment android:id="@+id/fragment_content"
android:name="org.thoughtcrime.securesms.CountrySelectionFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
-27
View File
@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#ffffff">
<EditText android:id="@+id/country_search"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawableLeft="@drawable/ic_menu_search_holo_light"
android:hint="@string/country_selection_fragment__search" />
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#ffdddddd"
android:dividerHeight="1.0px"
android:choiceMode="singleChoice" />
<TextView android:id="@android:id/empty"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/country_selection_fragment__loading_countries" />
</LinearLayout>
+11 -10
View File
@@ -20,16 +20,6 @@
android:visibility="gone"
android:contentDescription="@string/conversation_item_sent__delivered_description" />
<ImageView android:id="@+id/delivered_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:src="@drawable/ic_delivery_status_delivered"
android:paddingLeft="2dp"
android:visibility="gone"
android:contentDescription="@string/conversation_item_sent__delivered_description"
tools:visibility="gone"/>
<ImageView android:id="@+id/read_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -41,4 +31,15 @@
android:tint="@color/core_blue"
tools:visibility="visible"/>
<ImageView android:id="@+id/failed_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:src="@drawable/ic_delivery_status_failed"
android:paddingLeft="2dp"
android:visibility="gone"
android:contentDescription="@string/conversation_item_sent__send_failed_indicator_description"
android:tint="@color/core_blue"
tools:visibility="visible"/>
</merge>
-12
View File
@@ -21,18 +21,6 @@
android:focusable="false"
android:gravity="center">
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/download_progress"
android:layout_width="48dp"
android:layout_height="48dp"
android:visibility="gone"
android:clickable="false"
android:layout_gravity="center"
app:matProg_barColor="@color/white"
app:matProg_linearProgress="true"
app:matProg_spinSpeed="0.333"
tools:visibility="gone"/>
<FrameLayout
android:id="@+id/icon_container"
android:layout_width="wrap_content"
@@ -0,0 +1,19 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="0dp"
android:background="@color/amber_50"
android:padding="0dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/preferences_autocrypt__explain"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:background="?pref_divider"/>
</LinearLayout>
+19 -17
View File
@@ -43,6 +43,25 @@
</LinearLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/status"
android:layout_marginTop="4dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.TextInputEditText
android:id="@+id/status_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/default_status_hint"
android:gravity="top|left"
android:maxLines="3"
android:inputType="textMultiLine" />
</android.support.design.widget.TextInputLayout>
<LinearLayout android:id="@+id/information_link_container"
android:clickable="true"
android:orientation="horizontal"
@@ -81,23 +100,6 @@
android:clipChildren="false"
android:clipToPadding="false">
<com.dd.CircularProgressButton
android:id="@+id/finish_button"
app:cpb_textIdle="@string/profile_create_activity__finish"
app:cpb_selectorIdle="@drawable/progress_button_state"
app:cpb_colorIndicator="@color/white"
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="50dp"
android:textAllCaps="true"
android:background="@color/signal_primary"
android:textColor="@color/white"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="20dp"
android:layout_gravity="center_horizontal"/>
<TextView android:id="@+id/password_account_settings_button"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
+1 -1
View File
@@ -341,7 +341,7 @@
app:cpb_colorProgress="@color/textsecure_primary"
app:cpb_cornerRadius="50dp"
app:cpb_selectorIdle="@drawable/progress_button_state"
app:cpb_textIdle="@string/registration_activity__register"
app:cpb_textIdle="@string/registration_activity__login"
app:layout_constraintEnd_toEndOf="@id/guideline_root_end"
app:layout_constraintStart_toStartOf="@id/guideline_root_start"
app:layout_constraintTop_toBottomOf="@id/register_button_spacer_top" />
+144
View File
@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- the FrameLayout is needed as View.inflate() without a root discards all layout_-attributes -->
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:layout_marginLeft="24dp"
android:layout_marginStart="24dp"
android:layout_marginRight="24dp"
android:layout_marginEnd="24dp"
android:columnCount="6"
android:rowCount="1">
<!-- 1st row -->
<EditText
android:id="@+id/setupCode0"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:layout_marginBottom="8dp"
android:text=" - "
android:textAppearance="@style/TextAppearance.AppCompat"/>
<EditText
android:id="@+id/setupCode1"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:text=" - "
android:textAppearance="@style/TextAppearance.AppCompat"/>
<EditText
android:id="@+id/setupCode2"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:layout_marginBottom="8dp"
android:text=" - "
android:textAppearance="@style/TextAppearance.AppCompat"/>
<!-- 2nd row -->
<EditText
android:id="@+id/setupCode3"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:layout_marginBottom="8dp"
android:text=" - "
android:textAppearance="@style/TextAppearance.AppCompat"/>
<EditText
android:id="@+id/setupCode4"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:layout_marginBottom="8dp"
android:text=" - "
android:textAppearance="@style/TextAppearance.AppCompat"/>
<EditText
android:id="@+id/setupCode5"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:text=" - "
android:textAppearance="@style/TextAppearance.AppCompat"/>
<!-- 3rd row -->
<EditText
android:id="@+id/setupCode6"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:text=" - "
android:layout_marginBottom="8dp"
android:textAppearance="@style/TextAppearance.AppCompat"/>
<EditText
android:id="@+id/setupCode7"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:text=" - "
android:layout_marginBottom="8dp"
android:textAppearance="@style/TextAppearance.AppCompat"/>
<EditText
android:id="@+id/setupCode8"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:inputType="numberDecimal"
android:maxLength="4"
android:minEms="3"/>
<TextView
android:text=" "
android:layout_marginBottom="8dp"
android:textAppearance="@style/TextAppearance.AppCompat"/>
</GridLayout>
</FrameLayout>
-26
View File
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.pnikosis.materialishprogress.ProgressWheel
android:id="@+id/progress_wheel"
android:layout_width="@dimen/transfer_controls_contracted_width"
android:layout_height="@dimen/transfer_controls_contracted_width"
android:visibility="gone"
android:layout_gravity="center"
app:matProg_barColor="@color/white"
app:matProg_linearProgress="true"
app:matProg_spinSpeed="0.333" />
<TextView android:id="@+id/download_details"
android:layout_width="@dimen/transfer_controls_expanded_width"
android:layout_height="@dimen/transfer_controls_contracted_width"
android:padding="15dp"
android:gravity="center"
android:longClickable="false"
android:textColor="?conversation_item_received_text_primary_color"
android:drawableLeft="@drawable/ic_file_download_white_36dp"
android:textSize="16dp"
android:visibility="gone"
android:textStyle="bold" />
</merge>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_create_profile"
android:title="@string/profile_create_activity__finish"
app:showAsAction="always"
android:icon="@drawable/check"/>
</menu>
-3
View File
@@ -7,9 +7,6 @@
<item android:title="@string/text_secure_normal__menu_clear_passphrase"
android:id="@+id/menu_clear_passphrase" />
<item android:title="@string/text_secure_normal__mark_all_as_read"
android:id="@+id/menu_mark_all_read" />
<item android:title="@string/text_secure_normal__invite_friends"
android:id="@+id/menu_invite" />
-26
View File
@@ -213,33 +213,7 @@
</string-array>
<!-- discrete MIME type (the part before the "/") -->
<string-array name="pref_media_download_entries">
<item>image</item>
<item>audio</item>
<item>video</item>
<item>documents</item>
</string-array>
<string-array name="pref_media_download_values">
<item>@string/arrays__images</item>
<item>@string/arrays__audio</item>
<item>@string/arrays__video</item>
<item>@string/arrays__documents</item>
</string-array>
<string-array name="pref_media_download_mobile_data_default">
<item>image</item>
<item>audio</item>
</string-array>
<string-array name="pref_media_download_wifi_default">
<item>image</item>
<item>audio</item>
<item>video</item>
<item>documents</item>
</string-array>
<string-array name="pref_media_download_roaming_default" />
<!-- RedPhone -->
-4
View File
@@ -177,10 +177,6 @@
<attr name="iconColor" format="color" />
</declare-styleable>
<declare-styleable name="AlertView">
<attr name="useSmallIcon" format="boolean" />
</declare-styleable>
<declare-styleable name="AudioView">
<attr name="widgetBackground" format="color"/>
<attr name="foregroundTintColor" format="color" />
+1
View File
@@ -59,6 +59,7 @@
<color name="sticker_selected_color">#99ffffff</color>
<color name="transparent">#00FFFFFF</color>
<color name="transparent_black">#00000000</color>
<color name="MediaOverview_Media_selected_overlay">#88000000</color>
+1 -3
View File
@@ -18,7 +18,7 @@
<!-- TODO: Consolidate these two message corner things -->
<dimen name="message_corner_radius">16dp</dimen>
<dimen name="message_corner_collapse_radius">4dp</dimen>
<dimen name="message_corner_collapse_radius">1dp</dimen>
<dimen name="message_bubble_corner_radius">2dp</dimen>
<dimen name="message_bubble_shadow_distance">1.5dp</dimen>
<dimen name="message_bubble_horizontal_padding">12dp</dimen>
@@ -72,6 +72,4 @@
<dimen name="floating_action_button_margin">16dp</dimen>
<dimen name="alertview_small_icon_size">14dp</dimen>
</resources>
+36 -5
View File
@@ -39,8 +39,10 @@
<string name="ApplicationPreferencesActivity_off">off</string>
<string name="ApplicationPreferencesActivity_Off">Off</string>
<string name="ApplicationPreferencesActivity_sms_mms_summary">SMS %1$s, MMS %2$s</string>
<string name="ApplicationPreferencesActivity_privacy_summary">Screen lock %1$s, Registration lock %2$s</string>
<string name="ApplicationPreferencesActivity_privacy_summary">Screen lock %1$s, Read receipts %2$s</string>
<string name="ApplicationPreferencesActivity_appearance_summary">Theme %1$s, Language %2$s</string>
<!-- AppearancePreferenceFragment -->
<string name="AppearancePreferencesFragment_background_save_error">Background image could not be saved</string>
<!-- AppProtectionPreferenceFragment -->
<plurals name="AppProtectionPreferenceFragment_minutes">
@@ -117,7 +119,6 @@
<string name="ConversationItem_click_to_approve_unencrypted_sms_dialog_title">Fallback to unencrypted SMS?</string>
<string name="ConversationItem_click_to_approve_unencrypted_mms_dialog_title">Fallback to unencrypted MMS?</string>
<string name="ConversationItem_click_to_approve_unencrypted_dialog_message">This message will <b>not</b> be encrypted because the recipient is no longer a Delta Chat user.\n\nSend unsecured message?</string>
<string name="ConversationItem_unable_to_open_media">Can\'t find an app able to open this media.</string>
<string name="ConversationItem_copied_text">Copied %s</string>
<string name="ConversationItem_from_s">from %s</string>
<string name="ConversationItem_to_s">to %s</string>
@@ -293,6 +294,8 @@
<!-- ShareActivity -->
<string name="ShareActivity_share_with">Share with</string>
<string name="ShareActivity_unable_to_open_media">Can\'t find an app able to open this media.</string>
<string name="ShareActivity_file_not_found">Could not find %1$s.</string>
<!-- ExperienceUpgradeActivity -->
<string name="ExperienceUpgradeActivity_welcome_to_signal_dgaf">Welcome to Delta Chat.</string>
@@ -748,6 +751,9 @@
<!-- ContactSelectionListFragment-->
<string name="ContactSelectionListFragment_signal_requires_the_contacts_permission_in_order_to_display_your_contacts">Delta Chat requires the Contacts permission in order to display your contacts, but it has been permanently denied. Please continue to the app settings menu, select \"Permissions\", and enable \"Contacts\".</string>
<string name="ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection">Error retrieving contacts, check your network connection</string>
<string name="ContactSelectionListFragment_error_deleting_contacts_check_existing_conversations">Error deleting contacts, some contacts couldn\'t get deleted. Please delete existing conversations before.</string>
<string name="ContactSelectionListFragment_contact_delete_confirmation_title">Delete contacts?</string>
<string name="ContactSelectionListFragment_contact_delete_confirmation_message">This will permanently delete the selected contacts.\n\nContacts with ongoing chats and contacts from the system\'s address book cannot be deleted permanently.</string>
<!-- blocked_contacts_fragment -->
<string name="blocked_contacts_fragment__no_blocked_contacts">No blocked contacts</string>
@@ -1063,15 +1069,15 @@
<string name="preferences__pressing_the_enter_key_will_send_text_messages">Pressing the Enter key will send text messages</string>
<string name="preferences__choose_identity">Choose identity</string>
<string name="preferences__choose_your_contact_entry_from_the_contacts_list">Choose your contact entry from the contacts list.</string>
<string name="preferences__change_passphrase">Change passphrase</string>
<string name="preferences__change_your_passphrase">Change your passphrase</string>
<string name="preferences__change_passphrase">Change secret</string>
<string name="preferences__change_your_passphrase">Change your pin / pattern / fingerprint via system settings</string>
<string name="preferences__enable_passphrase">Enable passphrase screen lock</string>
<string name="preferences__lock_signal_and_message_notifications_with_a_passphrase">Lock screen and notifications with a passphrase</string>
<string name="preferences__screen_security">Screen security</string>
<string name="preferences__screen_security_restart_warning">To apply the screen security setting please restart the app</string>
<string name="preferences__disable_screen_security_to_allow_screen_shots">Block screenshots in the recents list and inside the app</string>
<string name="preferences__auto_lock_signal_after_a_specified_time_interval_of_inactivity">Auto-lock Delta Chat after a specified time interval of inactivity</string>
<string name="preferences__inactivity_timeout_passphrase">Inactivity timeout passphrase</string>
<string name="preferences__inactivity_timeout_passphrase">Inactivity timeout lock</string>
<string name="preferences__inactivity_timeout_interval">Inactivity timeout interval</string>
<string name="preferences__notifications">Notifications</string>
<string name="preferences__led_color">LED color</string>
@@ -1157,6 +1163,7 @@
<string name="preferences_chats__message_text_size">Message font size</string>
<string name="preferences_events__contact_joined_signal">Contact joined Delta Chat</string>
<string name="preferences_notifications__priority">Priority</string>
<string name="preferences_other">Other</string>
<string name="preferences_backup__export_explain">A backup helps you to set up a new installation on this or on another device.\n\nThe backup will contain all messages, contacts and chats and your end-to-end Autocrypt setup. Keep the backup file in a safe place or delete it as soon as possible.</string>
<string name="preferences_backup__export_start_button">Start backup</string>
<string name="preferences_backup__backup_written_to_x">Backup written successfully to %1$s</string>
@@ -1169,6 +1176,10 @@
<string name="preferences_managekeys__import_explain">Import secret keys from \"%1$s\"?\n\n• Existing secret keys will not be deleted\n\n• The last imported key will be used as the new default key unless it has the word \"legacy\" in its filename</string>
<string name="preferences_managekeys__secret_keys_exported_to_x">Secret keys written successfully to \"%1$s\".</string>
<string name="preferences_managekeys__secret_keys_imported_from_x">Secret keys imported from \"%1$s\".</string>
<string name="preferences_autocrypt">Autocrypt</string>
<string name="preferences_autocrypt__send_asm">Send Autocrypt Setup Message</string>
<string name="preferences_autocrypt__prefer_e2ee">Prefer end-to-end encryption</string>
<string name="preferences_autocrypt__explain">Autocrypt is a new and open specification for automatic end-to-end email encryption.\n\nYour end-to-end setup is created automatically as needed and you can transfer it between devices with Autocrypt Setup Messages.</string>
<!-- **************************************** -->
@@ -1441,6 +1452,18 @@
<string name="import_backup_ask">Backup found at \"%1$s\".\n\nDo you want to import and use all data and settings from it?</string>
<string name="import_backup_no_backup_found">No backups found.\n\nCopy the backup to \"%1$s\" and try again. Alternatively, press \"Start messaging\" to go with the normal setup process.</string>
<string name="autocrypt__button_send_asm">Send Autocrypt Setup Message</string>
<string name="autocrypt__msg_before_sending_asm">An \"Autocrypt Setup Message\" securely shares your end-to-end setup with other Autocrypt-compliant apps.\n\nThe setup will be encrypted by a setup code which is displayed here and must be typed on the other device.</string>
<string name="autocrypt__msg_after_sending_asm">Your setup has been sent to yourself. Switch to the other device and open the setup message. You should be prompted for a setup code. Type the following digits into the prompt:\n\n%1$s\n\nOnce you\'re done, your other device will be ready to use Autocrypt.</string>
<string name="autocrypt__asm_subject">Autocrypt Setup Message</string>
<string name="autocrypt__asm_general_body">This is the Autocrypt Setup Message used to transfer your end-to-end setup between clients.\n\nTo decrypt and use your setup, open the message in an Autocrypt-compliant client and enter the setup code presented on the generating device.</string>
<string name="autocrypt__asm_tap_body">This is the Autocrypt Setup Message used to transfer your end-to-end setup between clients.\n\nTo decrypt and use your setup, tap on this message.</string>
<string name="autocrypt__continue_transfer_title">Autocrypt Setup Message</string>
<string name="autocrypt__continue_transfer_please_enter_code">Please enter the setup code that is displayed on the other device.</string>
<string name="autocrypt__continue_transfer_bad_code">Bad setup code. Please try again.\n\nIf you do not remember the setup code, just send another Autocrypt Setup Message from the other device.</string>
<string name="autocrypt__continue_transfer_succeeded">End-to-end setup transferred. This device is now ready to use Autocrypt with the same setup as the other device.</string>
<string name="autocrypt__continue_button_retry">Retry</string>
<!-- Generic and reusable strings -->
<string name="email_address">Email address</string>
<string name="bad_email_address">Bad email address.</string>
@@ -1456,5 +1479,13 @@
<string name="contact_selection_list__type_email_above">Type email address above</string>
<string name="text_secure_normal__menu_new_chat">New chat</string>
<string name="help_url">https://delta.chat/en/help</string>
<string name="security_authentication_failed">Authentication failed.</string>
<string name="security_authentication_unlock_title">Unlock Delta Chat</string>
<string name="security_authentication_unlock_description">Please enter your system defined secret to unlock Delta Chat.</string>
<!-- Translators: The URL should not be localized, it is not clear which languuage the receiver prefers and the language will be detected on the server -->
<string name="default_status_text">Sent with my Delta Chat Messenger: https://delta.chat</string>
<string name="default_status_hint">Status text</string>
<string name="registration_activity__login">Login</string>
<string name="preferences__chat_background">Chat-Background</string>
</resources>
+20 -6
View File
@@ -1,12 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference android:key="pref_backup"
android:title="@string/preferences__backup"/>
<PreferenceCategory android:key="media_download" android:title="@string/preferences_autocrypt">
<Preference android:key="pref_send_autocrypt_setup_message"
android:title="@string/preferences_autocrypt__send_asm"/>
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="true"
android:key="pref_prefer_e2ee"
android:title="@string/preferences_autocrypt__prefer_e2ee"/>
</PreferenceCategory>
<Preference android:key="pref_manage_keys"
android:title="@string/preferences__manage_keys"/>
<PreferenceCategory android:layout="@layout/preference_divider_explain_autocrypt"/>
<Preference android:key="pref_submit_debug_logs"
android:title="@string/preferences__submit_debug_log"/>
<PreferenceCategory android:key="media_download" android:title="@string/preferences_other">
<Preference android:key="pref_backup"
android:title="@string/preferences__backup"
android:summary="@string/preferences_chats__backup_chats_to_external_storage"/>
<Preference android:key="pref_manage_keys"
android:title="@string/preferences__manage_keys"/>
<Preference android:key="pref_submit_debug_logs"
android:title="@string/preferences__submit_debug_log"/>
</PreferenceCategory>
</PreferenceScreen>
+44 -45
View File
@@ -1,65 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/preferences_app_protection__screen_lock">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_android_screen_lock"
android:summary="@string/preferences_app_protection__lock_signal_access_with_android_screen_lock_or_fingerprint"
android:title="@string/preferences_app_protection__screen_lock" />
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_timeout_passphrase"
android:summary="@string/preferences__auto_lock_signal_after_a_specified_time_interval_of_inactivity"
android:title="@string/preferences__inactivity_timeout_passphrase" />
<Preference
android:dependency="pref_timeout_passphrase"
android:key="pref_timeout_interval"
android:title="@string/preferences__inactivity_timeout_interval" />
<Preference
android:key="pref_change_passphrase"
android:summary="@string/preferences__change_your_passphrase"
android:title="@string/preferences__change_passphrase" />
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider" />
<PreferenceCategory android:title="@string/preferences_app_protection__app_access">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="pref_android_screen_lock"
android:defaultValue="false"
android:title="@string/preferences_app_protection__screen_lock"
android:summary="@string/preferences_app_protection__lock_signal_access_with_android_screen_lock_or_fingerprint"/>
<Preference android:title="@string/preferences_app_protection__screen_lock_inactivity_timeout"
android:key="pref_android_screen_lock_timeout"
android:dependency="pref_android_screen_lock"/>
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="pref_enable_passphrase_temporary"
android:defaultValue="true"
android:title="@string/preferences__enable_passphrase"
android:summary="@string/preferences__lock_signal_and_message_notifications_with_a_passphrase"/>
<Preference android:key="pref_change_passphrase"
android:title="@string/preferences__change_passphrase"
android:summary="@string/preferences__change_your_passphrase"
android:dependency="pref_enable_passphrase_temporary"/>
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_timeout_passphrase"
android:title="@string/preferences__inactivity_timeout_passphrase"
android:summary="@string/preferences__auto_lock_signal_after_a_specified_time_interval_of_inactivity"
android:dependency="pref_enable_passphrase_temporary"/>
<Preference android:title="@string/preferences__inactivity_timeout_interval"
android:key="pref_timeout_interval"
android:dependency="pref_timeout_passphrase"/>
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_screen_security"
android:title="@string/preferences__screen_security"
android:summary="@string/preferences__disable_screen_security_to_allow_screen_shots" />
android:defaultValue="false"
android:key="pref_screen_security"
android:summary="@string/preferences__disable_screen_security_to_allow_screen_shots"
android:title="@string/preferences__screen_security" />
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_incognito_keyboard"
android:title="@string/preferences__incognito_keyboard"
android:summary="@string/preferences__request_keyboard_to_disable_personalized_learning"/>
android:summary="@string/preferences__request_keyboard_to_disable_personalized_learning"
android:title="@string/preferences__incognito_keyboard" />
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider"/>
<PreferenceCategory android:layout="@layout/preference_divider" />
<PreferenceCategory android:title="@string/preferences_app_protection__communication">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_read_receipts"
android:title="@string/preferences__read_receipts"
android:summary="@string/preferences__if_read_receipts_are_disabled_you_wont_be_able_to_see_read_receipts"/>
android:defaultValue="false"
android:key="pref_read_receipts"
android:summary="@string/preferences__if_read_receipts_are_disabled_you_wont_be_able_to_see_read_receipts"
android:title="@string/preferences__read_receipts" />
<Preference
android:key="preference_category_blocked"
android:title="@string/preferences_app_protection__blocked_contacts" />
<Preference android:key="preference_category_blocked"
android:title="@string/preferences_app_protection__blocked_contacts" />
</PreferenceCategory>
</PreferenceScreen>
+5
View File
@@ -15,4 +15,9 @@
android:entries="@array/language_entries"
android:entryValues="@array/language_values"
android:defaultValue="zz"/>
<Preference
android:key="pref_chat_background"
android:title="@string/preferences__chat_background"
/>
</PreferenceScreen>
-52
View File
@@ -2,34 +2,6 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<PreferenceCategory android:key="media_download" android:title="@string/preferences_chats__media_auto_download">
<MultiSelectListPreference
android:title="@string/preferences_chats__when_using_mobile_data"
android:key="pref_media_download_mobile"
android:defaultValue="@array/pref_media_download_mobile_data_default"
android:persistent="true"
android:entries="@array/pref_media_download_values"
android:entryValues="@array/pref_media_download_entries" />
<MultiSelectListPreference
android:title="@string/preferences_chats__when_using_wifi"
android:key="pref_media_download_wifi"
android:defaultValue="@array/pref_media_download_wifi_default"
android:persistent="true"
android:entries="@array/pref_media_download_values"
android:entryValues="@array/pref_media_download_entries" />
<MultiSelectListPreference
android:title="@string/preferences_chats__when_roaming"
android:key="pref_media_download_roaming"
android:defaultValue="@array/pref_media_download_roaming_default"
android:persistent="true"
android:entries="@array/pref_media_download_values"
android:entryValues="@array/pref_media_download_entries" />
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider"/>
<PreferenceCategory android:title="@string/preferences_chats__chats">
<org.thoughtcrime.securesms.preferences.widgets.SignalListPreference
android:key="pref_message_body_text_size"
@@ -39,12 +11,6 @@
android:defaultValue="16">
</org.thoughtcrime.securesms.preferences.widgets.SignalListPreference>
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="true"
android:key="pref_show_invite_reminder"
android:title="@string/preferences_chats__show_invitation_prompts"
android:summary="@string/preferences_chats__display_invitation_prompts_for_contacts_without_signal" />
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_system_emoji"
@@ -79,22 +45,4 @@
android:dependency="pref_trim_threads" />
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider"/>
<PreferenceCategory android:key="backup_category" android:title="@string/preferences_chats__backups">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_backup_enabled"
android:title="@string/preferences_chats__chat_backups"
android:summary="@string/preferences_chats__backup_chats_to_external_storage" />
<org.thoughtcrime.securesms.preferences.widgets.ProgressPreference
android:key="pref_backup_create"
android:title="@string/preferences_chats__create_backup"
android:persistent="false"
android:dependency="pref_backup_enabled"
tools:summary="Last backup: 3 days ago"/>
</PreferenceCategory>
</PreferenceScreen>
-33
View File
@@ -69,37 +69,4 @@
android:entryValues="@array/pref_notification_priority_values"/>
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider"/>
<PreferenceCategory android:title="@string/preferences_notifications__calls">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="pref_call_notifications"
android:title="@string/preferences__notifications"
android:defaultValue="true" />
<org.thoughtcrime.securesms.preferences.widgets.SignalPreference
android:dependency="pref_call_notifications"
android:key="pref_call_ringtone"
android:title="@string/preferences_notifications__ringtone"
android:persistent="false"
android:defaultValue="content://settings/system/ringtone" />
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:dependency="pref_call_notifications"
android:key="pref_call_vibrate"
android:defaultValue="true"
android:title="@string/preferences__vibrate"/>
</PreferenceCategory>
<PreferenceCategory android:layout="@layout/preference_divider"/>
<PreferenceCategory android:title="@string/preferences_notifications__events">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="pref_enable_new_contacts_notifications"
android:title="@string/preferences_events__contact_joined_signal"
android:defaultValue="true" />
</PreferenceCategory>
</PreferenceScreen>
+10 -5
View File
@@ -27,6 +27,11 @@ import android.support.annotation.NonNull;
public class DcContext {
public final static int DC_PREF_DEFAULT_E2EE_ENABLED = 1;
public final static int DC_PREF_DEFAULT_MDNS_ENABLED = 1;
public final static int DC_PREF_DEFAULT_TRIM_ENABLED = 0;
public final static int DC_PREF_DEFAULT_TRIM_LENGTH = 500;
public final static int DC_EVENT_INFO = 100;
public final static int DC_EVENT_WARNING = 300;
public final static int DC_EVENT_ERROR = 400;
@@ -89,9 +94,9 @@ public class DcContext {
public native void performSmtpIdle ();
public native void interruptSmtpIdle ();
public native void setConfig (String key, String value);
public native void setConfigInt (String key, int value);
public void setConfigInt (String key, int value) { setConfig(key, Integer.toString(value)); }
public native String getConfig (String key, String def);
public native int getConfigInt (String key, int def);
public int getConfigInt (String key, int def) { try{return Integer.parseInt(getConfig(key, Integer.toString(def)));} catch(Exception e) {} return 0; }
public native String getInfo ();
public native String initiateKeyTransfer ();
public native boolean continueKeyTransfer (int msg_id, String setup_code);
@@ -107,7 +112,7 @@ public class DcContext {
public native int createContact (String name, String addr);
public native void blockContact (int id, int block);
public native String getContactEncrInfo (int contact_id);
public native int deleteContact (int id);
public native boolean deleteContact (int id);
public native int addAddressBook (String adrbook);
public @NonNull DcChatlist getChatlist (int listflags, String query, int queryId) { return new DcChatlist(getChatlistCPtr(listflags, query, queryId)); }
public @NonNull DcChat getChat (int chat_id) { return new DcChat(getChatCPtr(chat_id)); }
@@ -137,7 +142,7 @@ public class DcContext {
public native String getMsgInfo (int id);
public native int getFreshMsgCount (int chat_id);
public native void deleteMsgs (int msg_ids[]);
public native void forwardMsgs (int msg_ids[], int chat_ids);
public native void forwardMsgs (int msg_ids[], int chat_id);
public native int sendMsg (int chat_id, DcMsg msg);
public native int sendTextMsg (int chat_id, String text);
public native int sendVcardMsg (int chat_id, int contact_id);
@@ -161,7 +166,7 @@ public class DcContext {
// working with raw c-data
private long contextCPtr; // CAVE: the name is referenced in the JNI
private native long createContextCPtr(String osName);
public native long createMsgCPtr ();
public native long createMsgCPtr (int viewtype);
private native long getChatlistCPtr (int listflags, String query, int queryId);
private native long getChatCPtr (int chat_id);
private native long getMsgCPtr (int id);
+2 -3
View File
@@ -57,8 +57,8 @@ public class DcMsg {
public final static int DC_MSG_ID_MARKER1 = 1;
public final static int DC_MSG_ID_DAYMARKER = 9;
public DcMsg(DcContext context) {
msgCPtr = context.createMsgCPtr();
public DcMsg(DcContext context, int viewtype) {
msgCPtr = context.createMsgCPtr(viewtype);
}
public DcMsg(long msgCPtr) {
@@ -107,7 +107,6 @@ public class DcMsg {
public native boolean isSetupMessage ();
public native String getSetupCodeBegin ();
public native boolean isIncreation ();
public native void setType (int type);
public native void setText (String text);
public native void setFile (String file, String filemime);
public native void setDimension (int width, int height);
@@ -16,19 +16,15 @@
*/
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.arch.lifecycle.DefaultLifecycleObserver;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.ProcessLifecycleOwner;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.multidex.MultiDexApplication;
import android.util.Log;
import com.google.android.gms.security.ProviderInstaller;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.crypto.PRNGFixes;
import org.thoughtcrime.securesms.dependencies.AxolotlStorageModule;
@@ -41,10 +37,10 @@ import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirementProv
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.ServiceRequirementProvider;
import org.thoughtcrime.securesms.jobs.requirements.SqlCipherMigrationRequirementProvider;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.PeerConnectionFactory.InitializationOptions;
@@ -55,7 +51,6 @@ import org.whispersystems.libsignal.util.AndroidSignalProtocolLogger;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import dagger.ObjectGraph;
@@ -105,7 +100,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
public void onStart(@NonNull LifecycleOwner owner) {
isAppVisible = true;
Log.i(TAG, "App is now visible.");
executePendingContactSync();
}
@@ -113,6 +107,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
public void onStop(@NonNull LifecycleOwner owner) {
isAppVisible = false;
Log.i(TAG, "App is no longer visible.");
ScreenLockUtil.shouldLockApp = true;
}
@Override
@@ -148,7 +143,6 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
.withDependencyInjector(this)
.withJobSerializer(new JavaJobSerializer())
.withRequirementProviders(new MasterSecretRequirementProvider(this),
new ServiceRequirementProvider(this),
new NetworkRequirementProvider(this),
new SqlCipherMigrationRequirementProvider())
.withConsumerThreads(5)
@@ -66,6 +66,8 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats";
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
public static final int REQUEST_CODE_SET_BACKGROUND = 11;
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms;
import android.annotation.TargetApi;
import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Build;
import android.os.Build.VERSION_CODES;
@@ -15,16 +14,23 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.widget.Toast;
import org.thoughtcrime.securesms.util.ScreenLockUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.lang.reflect.Field;
import java.util.Timer;
import static org.thoughtcrime.securesms.util.ScreenLockUtil.shouldLockApp;
public abstract class BaseActionBarActivity extends AppCompatActivity {
private static final String TAG = BaseActionBarActivity.class.getSimpleName();
private Timer timer;
@Override
protected void onCreate(Bundle savedInstanceState) {
if (BaseActivity.isMenuWorkaroundRequired()) {
@@ -33,10 +39,52 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
}
@Override
protected void onStart() {
super.onStart();
if (ScreenLockUtil.isScreenLockEnabled(this) && shouldLockApp) {
ScreenLockUtil.applyScreenLock(this);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS) {
if (resultCode == RESULT_OK) {
shouldLockApp = false;
} else {
Toast.makeText(this, R.string.security_authentication_failed, Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onResume() {
super.onResume();
initializeScreenshotSecurity();
initializeScreenLockTimeout();
}
private void initializeScreenLockTimeout() {
if (ScreenLockUtil.isScreenLockTimeoutEnabled(this)) {
timer = ScreenLockUtil.scheduleScreenLockTimer(timer, this);
}
}
@Override
protected void onPause() {
super.onPause();
tearDownScreenLockTimeout();
}
private void tearDownScreenLockTimeout() {
ScreenLockUtil.cancelScreenLockTimer(timer);
}
@Override
public void onUserInteraction() {
super.onUserInteraction();
initializeScreenLockTimeout();
}
@Override
@@ -20,8 +20,6 @@ import java.util.Set;
public interface BindableConversationItem extends Unbindable {
void bind(@NonNull DcMsg messageRecord,
@NonNull Optional<DcMsg> previousMessageRecord,
@NonNull Optional<DcMsg> nextMessageRecord,
@NonNull DcChat dcChat,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale,
@@ -19,6 +19,8 @@ package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -27,38 +29,41 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.support.v7.view.ActionMode;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import com.pnikosis.materialishprogress.ProgressWheel;
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcContactsLoader;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.DirectoryHelper;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
@@ -86,13 +91,11 @@ public class ContactSelectionListFragment extends Fragment
private Set<String> selectedContacts;
private OnContactSelectedListener onContactSelectedListener;
private SwipeRefreshLayout swipeRefresh;
private View showContactsLayout;
private Button showContactsButton;
private TextView showContactsDescription;
private ProgressWheel showContactsProgress;
private String cursorFilter;
private RecyclerView recyclerView;
private RecyclerViewFastScroller fastScroller;
private ActionMode actionMode;
private ActionMode.Callback actionModeCallback;
@Override
public void onActivityCreated(Bundle icicle) {
@@ -112,26 +115,11 @@ public class ContactSelectionListFragment extends Fragment
@Override
public void onStart() {
super.onStart();
this.getLoaderManager().initLoader(0, null, this);
Permissions.with(this)
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS)
.ifNecessary()
.onAllGranted(() -> {
if (!TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
handleContactPermissionGranted();
} else {
this.getLoaderManager().initLoader(0, null, this);
}
})
.onAnyDenied(() -> {
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
if (getActivity().getIntent().getBooleanExtra(RECENTS, false)) {
getLoaderManager().initLoader(0, null, ContactSelectionListFragment.this);
} else {
initializeNoContactsPermission();
}
})
.onAllGranted(this::handleContactPermissionGranted)
.execute();
}
@@ -143,18 +131,86 @@ public class ContactSelectionListFragment extends Fragment
recyclerView = ViewUtil.findById(view, R.id.recycler_view);
swipeRefresh = ViewUtil.findById(view, R.id.swipe_refresh);
fastScroller = ViewUtil.findById(view, R.id.fast_scroller);
showContactsLayout = view.findViewById(R.id.show_contacts_container);
showContactsButton = view.findViewById(R.id.show_contacts_button);
showContactsDescription = view.findViewById(R.id.show_contacts_description);
showContactsProgress = view.findViewById(R.id.progress);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
actionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = getActivity().getMenuInflater();
inflater.inflate(R.menu.action_mode_delete, menu);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.action_mode_status_bar));
}
return true;
}
swipeRefresh.setEnabled(getActivity().getIntent().getBooleanExtra(REFRESHABLE, true) &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN);
@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.menu_select_all:
handleSelectAll();
return true;
case R.id.menu_delete_selected:
handleDeleteSelected();
return true;
}
return false;
}
@Override
public void onDestroyActionMode(ActionMode actionMode) {
ContactSelectionListFragment.this.actionMode = null;
getContactSelectionListAdapter().resetActionModeSelection();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedArray color = getActivity().getTheme().obtainStyledAttributes(new int[] {android.R.attr.statusBarColor});
getActivity().getWindow().setStatusBarColor(color.getColor(0, Color.BLACK));
color.recycle();
}
}
};
// There shouldn't be the need to pull to refresh the contacts
// swipeRefresh.setEnabled(getActivity().getIntent().getBooleanExtra(REFRESHABLE, true) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN);
swipeRefresh.setEnabled(false);
return view;
}
private void handleSelectAll() {
getContactSelectionListAdapter().selectAll();
}
private void handleDeleteSelected() {
Dialogs.showResponseDialog(getActivity(), getString(R.string.ContactSelectionListFragment_contact_delete_confirmation_title), getString(R.string.ContactSelectionListFragment_contact_delete_confirmation_message), (dialogInterface, i) -> {
ContactSelectionListAdapter adapter = getContactSelectionListAdapter();
final SparseIntArray actionModeSelection = adapter.getActionModeSelection().clone();
new Thread(() -> {
boolean failed = false;
for (int index = 0; index < actionModeSelection.size(); index++) {
int contactId = actionModeSelection.valueAt(index);
boolean currentFailed = !dcContext.deleteContact(contactId);
failed = currentFailed || failed;
}
if (failed) {
Util.runOnMain(()-> {
Toast.makeText(getActivity(), R.string.ContactSelectionListFragment_error_deleting_contacts_check_existing_conversations, Toast.LENGTH_LONG).show();
});
}
}).start();
adapter.resetActionModeSelection();
actionMode.finish();
});
}
private ContactSelectionListAdapter getContactSelectionListAdapter() {
return (ContactSelectionListAdapter) recyclerView.getAdapter();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
@@ -187,28 +243,6 @@ public class ContactSelectionListFragment extends Fragment
recyclerView.addItemDecoration(new StickyHeaderDecoration(adapter, true, true));
}
private void initializeNoContactsPermission() {
swipeRefresh.setVisibility(View.GONE);
showContactsLayout.setVisibility(View.VISIBLE);
showContactsProgress.setVisibility(View.INVISIBLE);
showContactsDescription.setText(R.string.contact_selection_list_fragment__signal_needs_access_to_your_contacts_in_order_to_display_them);
showContactsButton.setVisibility(View.VISIBLE);
showContactsButton.setOnClickListener(v -> {
Permissions.with(this)
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS)
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.ContactSelectionListFragment_signal_requires_the_contacts_permission_in_order_to_display_your_contacts))
.onSomeGranted(permissions -> {
if (permissions.contains(Manifest.permission.WRITE_CONTACTS)) {
handleContactPermissionGranted();
}
})
.execute();
});
}
public void setQueryFilter(String filter) {
this.cursorFilter = filter;
this.getLoaderManager().restartLoader(0, null, this);
@@ -234,7 +268,7 @@ public class ContactSelectionListFragment extends Fragment
@Override
public Loader<DcContactsLoader.Ret> onCreateLoader(int id, Bundle args) {
boolean addCreateGroupLinks = !isMulti();
int listflags = 0;
int listflags = DcContext.DC_GCL_ADD_SELF;
if(isSelectVerfied()) {
listflags = DcContext.DC_GCL_VERIFIED_ONLY;
}
@@ -243,9 +277,6 @@ public class ContactSelectionListFragment extends Fragment
@Override
public void onLoadFinished(Loader<DcContactsLoader.Ret> loader, DcContactsLoader.Ret data) {
swipeRefresh.setVisibility(View.VISIBLE);
showContactsLayout.setVisibility(View.GONE);
((ContactSelectionListAdapter) recyclerView.getAdapter()).changeData(data);
emptyText.setText(R.string.contact_selection_group_activity__no_contacts);
boolean useFastScroller = (recyclerView.getAdapter().getItemCount() > 20);
@@ -264,46 +295,41 @@ public class ContactSelectionListFragment extends Fragment
@SuppressLint("StaticFieldLeak")
private void handleContactPermissionGranted() {
new AsyncTask<Void, Void, Boolean>() {
@Override
protected void onPreExecute() {
swipeRefresh.setVisibility(View.GONE);
showContactsLayout.setVisibility(View.VISIBLE);
showContactsButton.setVisibility(View.INVISIBLE);
showContactsDescription.setText(R.string.ConversationListFragment_loading);
showContactsProgress.setVisibility(View.VISIBLE);
showContactsProgress.spin();
}
new AsyncTask<Void, Void, Void>() {
@Override
protected Boolean doInBackground(Void... voids) {
try {
DirectoryHelper.refreshDirectory(getContext(), false);
return true;
} catch (IOException e) {
Log.w(TAG, e);
}
return false;
protected Void doInBackground(Void... voids) {
loadSystemContacts();
return null;
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
showContactsLayout.setVisibility(View.GONE);
swipeRefresh.setVisibility(View.VISIBLE);
reset();
} else {
Toast.makeText(getContext(), R.string.ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection, Toast.LENGTH_LONG).show();
initializeNoContactsPermission();
}
}
}.execute();
}
private void loadSystemContacts() {
Thread thread = new Thread() {
@Override
public void run() {
ContactAccessor contactAccessor = ContactAccessor.getInstance();
String allSystemContacts = contactAccessor.getAllSystemContactsAsString(getContext());
if (!allSystemContacts.isEmpty()) {
dcContext.addAddressBook(allSystemContacts);
}
}
};
thread.start();
}
private class ListClickListener implements ContactSelectionListAdapter.ItemClickListener {
@Override
public void onItemClick(ContactSelectionListItem contact)
public void onItemClick(ContactSelectionListItem contact, boolean handleActionMode)
{
if (handleActionMode) {
if (actionMode != null) {
finishActionModeIfSelectionIsEmpty();
}
return;
}
int specialId = contact.getSpecialId();
String addr = contact.getNumber();
if (!isMulti() || !selectedContacts.contains(addr))
@@ -337,9 +363,24 @@ public class ContactSelectionListFragment extends Fragment
}
}
}
@Override
public void onItemLongClick(ContactSelectionListItem view) {
if (actionMode == null) {
actionMode = ((AppCompatActivity)getActivity()).startSupportActionMode(actionModeCallback);
} else {
finishActionModeIfSelectionIsEmpty();
}
}
}
public void setOnContactSelectedListener(OnContactSelectedListener onContactSelectedListener) {
private void finishActionModeIfSelectionIsEmpty() {
if (getContactSelectionListAdapter().getActionModeSelection().size() == 0) {
actionMode.finish();
}
}
public void setOnContactSelectedListener(OnContactSelectedListener onContactSelectedListener) {
this.onContactSelectedListener = onContactSelectedListener;
}
@@ -27,7 +27,6 @@ import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -136,12 +135,9 @@ import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.scribbles.ScribbleActivity;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.CharacterCalculator.CharacterState;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ExpirationUtil;
@@ -166,7 +162,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static org.thoughtcrime.securesms.TransportOption.Type;
import static org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
/**
@@ -297,6 +292,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
});
dcContext.marknoticedChat((int)threadId);
dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_CHAT_MODIFIED);
dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_CONTACTS_CHANGED);
}
@@ -1428,35 +1425,27 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
outgoingMessage = outgoingMessageCandidate;
}
Permissions.with(this)
.request(Manifest.permission.SEND_SMS, Manifest.permission.READ_SMS)
.ifNecessary(!isSecureText || forceSms)
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_sms_permission_in_order_to_send_an_sms))
.onAllGranted(() -> {
inputPanel.clearQuote();
attachmentManager.clear(glideRequests, false);
composeText.setText("");
final long id = fragment.stageOutgoingMessage(outgoingMessage);
inputPanel.clearQuote();
attachmentManager.clear(glideRequests, false);
composeText.setText("");
final long id = fragment.stageOutgoingMessage(outgoingMessage);
new AsyncTask<Void, Void, Long>() {
@Override
protected Long doInBackground(Void... param) {
if (initiating) {
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
}
new AsyncTask<Void, Void, Long>() {
@Override
protected Long doInBackground(Void... param) {
if (initiating) {
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(recipient, true);
}
return MessageSender.send(context, outgoingMessage, threadId, forceSms, () -> fragment.releaseOutgoingMessage(id));
}
return MessageSender.send(context, outgoingMessage, threadId, false, () -> fragment.releaseOutgoingMessage(id));
}
@Override
protected void onPostExecute(Long result) {
sendComplete(result);
future.set(null);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
})
.onAnyDenied(() -> future.set(null))
.execute();
@Override
protected void onPostExecute(Long result) {
sendComplete(result);
future.set(null);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
return future;
}
@@ -191,11 +191,9 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
ConversationAdapter.ViewHolder holder = (ConversationAdapter.ViewHolder)viewHolder;
//Optional<DcMsg> previous = position >= dcMsgList.length-1? Optional.absent() : Optional.of(getMsg(position+1));
//Optional<DcMsg> next = position <= 0? Optional.absent() : Optional.of(getMsg(position-1));
boolean pulseHighlight = position == positionToPulseHighlight;
holder.getItem().bind(getMsg(position), null, null, dcChat, glideRequests, locale, batchSelected, recipient, pulseHighlight);
holder.getItem().bind(getMsg(position), dcChat, glideRequests, locale, batchSelected, recipient, pulseHighlight);
if (pulseHighlight) {
positionToPulseHighlight = -1;
@@ -245,7 +243,7 @@ public class ConversationAdapter <V extends View & BindableConversationItem>
else if (type==DcMsg.DC_MSG_AUDIO || type==DcMsg.DC_MSG_VOICE) {
return dcMsg.isOutgoing()? MESSAGE_TYPE_AUDIO_OUTGOING : MESSAGE_TYPE_AUDIO_INCOMING;
}
else if (type==DcMsg.DC_MSG_FILE) {
else if (type==DcMsg.DC_MSG_FILE && !dcMsg.isSetupMessage()) {
return dcMsg.isOutgoing()? MESSAGE_TYPE_DOCUMENT_OUTGOING : MESSAGE_TYPE_DOCUMENT_INCOMING;
}
else if (type==DcMsg.DC_MSG_IMAGE || type==DcMsg.DC_MSG_GIF || type==DcMsg.DC_MSG_VIDEO) {
@@ -21,10 +21,13 @@ import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.app.Fragment;
@@ -37,8 +40,11 @@ import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.text.ClipboardManager;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -48,6 +54,8 @@ import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewSwitcher;
@@ -56,6 +64,7 @@ import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEventCenter;
import com.b44t.messenger.DcMsg;
import com.bumptech.glide.request.RequestOptions;
import org.thoughtcrime.securesms.ConversationAdapter.HeaderViewHolder;
import org.thoughtcrime.securesms.ConversationAdapter.ItemClickListener;
@@ -73,9 +82,12 @@ import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
@@ -112,6 +124,7 @@ public class ConversationFragment extends Fragment
private RecyclerView.ItemDecoration lastSeenDecoration;
private View scrollToBottomButton;
private TextView scrollDateHeader;
private FrameLayout frameLayout;
private ApplicationDcContext dcContext;
@@ -128,12 +141,14 @@ public class ConversationFragment extends Fragment
dcContext.eventCenter.addObserver(this, DcContext.DC_EVENT_MSG_READ);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle bundle) {
final View view = inflater.inflate(R.layout.conversation_fragment, container, false);
list = ViewUtil.findById(view, android.R.id.list);
scrollToBottomButton = ViewUtil.findById(view, R.id.scroll_to_bottom_button);
scrollDateHeader = ViewUtil.findById(view, R.id.scroll_date_header);
frameLayout = ViewUtil.findById(view, R.id.conversation_container);
scrollToBottomButton.setOnClickListener(v -> scrollToBottom());
@@ -142,6 +157,9 @@ public class ConversationFragment extends Fragment
list.setLayoutManager(layoutManager);
list.setItemAnimator(null);
String backgroundImagePath = TextSecurePreferences.getBackgroundImagePath(getContext());
Drawable image = Drawable.createFromPath(backgroundImagePath);
frameLayout.setBackground(image);
return view;
}
@@ -342,7 +360,7 @@ public class ConversationFragment extends Fragment
StringBuilder result = new StringBuilder();
DcMsg prevMsg = new DcMsg(dcContext);
DcMsg prevMsg = new DcMsg(dcContext, DcMsg.DC_MSG_TEXT);
for (DcMsg msg : dcMsgsList) {
if (result.length()>0) {
result.append("\n\n");
@@ -651,6 +669,80 @@ public class ConversationFragment extends Fragment
}
}
void querySetupCode(final DcMsg dcMsg, String[] preload)
{
if( !dcMsg.isSetupMessage()) {
return;
}
View gl = View.inflate(getActivity(), R.layout.setup_code_grid, null);
final EditText[] editTexts = {
(EditText) gl.findViewById(R.id.setupCode0), (EditText) gl.findViewById(R.id.setupCode1), (EditText) gl.findViewById(R.id.setupCode2),
(EditText) gl.findViewById(R.id.setupCode3), (EditText) gl.findViewById(R.id.setupCode4), (EditText) gl.findViewById(R.id.setupCode5),
(EditText) gl.findViewById(R.id.setupCode6), (EditText) gl.findViewById(R.id.setupCode7), (EditText) gl.findViewById(R.id.setupCode8)
};
android.app.AlertDialog.Builder builder1 = new android.app.AlertDialog.Builder(getActivity());
builder1.setView(gl);
editTexts[0].setText(dcMsg.getSetupCodeBegin());
editTexts[0].setSelection(editTexts[0].getText().length());
for( int i = 0; i < 9; i++ ) {
if( preload != null && i < preload.length ) {
editTexts[i].setText(preload[i]);
editTexts[i].setSelection(editTexts[i].getText().length());
}
editTexts[i].addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if( s.length()==4 ) {
for ( int i = 0; i < 8; i++ ) {
if( editTexts[i].hasFocus() && editTexts[i+1].getText().length()<4 ) {
editTexts[i+1].requestFocus();
break;
}
}
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
builder1.setTitle(getActivity().getString(R.string.autocrypt__continue_transfer_title));
builder1.setMessage(getActivity().getString(R.string.autocrypt__continue_transfer_please_enter_code));
builder1.setNegativeButton(android.R.string.cancel, null);
builder1.setCancelable(false); // prevent the dialog from being dismissed accidentally (when the dialog is closed, the setup code is gone forever and the user has to create a new setup message)
builder1.setPositiveButton(android.R.string.ok, (dialog, which) -> {
String setup_code = "";
final String[] preload1 = new String[9];
for ( int i = 0; i < 9; i++ ) {
preload1[i] = editTexts[i].getText().toString();
setup_code += preload1[i];
}
boolean success = dcContext.continueKeyTransfer(dcMsg.getId(), setup_code);
android.app.AlertDialog.Builder builder2 = new android.app.AlertDialog.Builder(getActivity());
builder2.setTitle(getActivity().getString(R.string.autocrypt__continue_transfer_title));
builder2.setMessage(getActivity().getString(success? R.string.autocrypt__continue_transfer_succeeded : R.string.autocrypt__continue_transfer_bad_code));
if( success ) {
builder2.setPositiveButton(android.R.string.ok, null);
}
else {
builder2.setNegativeButton(android.R.string.cancel, null);
builder2.setPositiveButton(R.string.autocrypt__continue_button_retry, (dialog1, which1) -> querySetupCode(dcMsg, preload1));
}
builder2.show();
});
builder1.show();
}
private class ConversationFragmentItemClickListener implements ItemClickListener {
@Override
@@ -666,6 +758,9 @@ public class ConversationFragment extends Fragment
actionMode.setTitle(String.valueOf(getListAdapter().getSelectedItems().size()));
}
}
else if(messageRecord.isSetupMessage()) {
querySetupCode(messageRecord,null);
}
}
@Override
@@ -16,14 +16,11 @@
*/
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.support.annotation.DimenRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -39,13 +36,11 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.b44t.messenger.DcChat;
import com.b44t.messenger.DcContact;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.AlertView;
import org.thoughtcrime.securesms.components.AudioView;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.ConversationItemFooter;
@@ -56,16 +51,12 @@ import org.thoughtcrime.securesms.components.SharedContactView;
import org.thoughtcrime.securesms.connect.ApplicationDcContext;
import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob;
import org.thoughtcrime.securesms.mms.AudioSlide;
import org.thoughtcrime.securesms.mms.DocumentSlide;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.LongClickCopySpan;
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
@@ -73,7 +64,6 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.views.Stub;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.HashSet;
import java.util.List;
@@ -89,16 +79,17 @@ import java.util.Set;
*/
public class ConversationItem extends LinearLayout
implements RecipientModifiedListener, BindableConversationItem
implements BindableConversationItem
{
private static final String TAG = ConversationItem.class.getSimpleName();
private static final int MAX_MEASURE_CALLS = 3;
private DcMsg messageRecord;
private DcChat dcChat;
private DcContact dcContact;
private Locale locale;
private boolean groupThread;
private Recipient recipient;
private GlideRequests glideRequests;
protected ViewGroup bodyBubble;
@@ -106,11 +97,9 @@ public class ConversationItem extends LinearLayout
private TextView bodyText;
private ConversationItemFooter footer;
private TextView groupSender;
private TextView groupSenderProfileName;
private View groupSenderHolder;
private AvatarImageView contactPhoto;
private ViewGroup contactPhotoHolder;
private AlertView alertView;
private ViewGroup container;
private @NonNull Set<DcMsg> batchSelected = new HashSet<>();
@@ -125,7 +114,6 @@ public class ConversationItem extends LinearLayout
private int measureCalls;
private final PassthroughClickListener passthroughClickListener = new PassthroughClickListener();
private final AttachmentDownloadClickListener downloadClickListener = new AttachmentDownloadClickListener();
private final SharedContactEventListener sharedContactEventListener = new SharedContactEventListener();
private final SharedContactClickListener sharedContactClickListener = new SharedContactClickListener();
@@ -156,8 +144,6 @@ public class ConversationItem extends LinearLayout
this.bodyText = findViewById(R.id.conversation_item_body);
this.footer = findViewById(R.id.conversation_item_footer);
this.groupSender = findViewById(R.id.group_message_sender);
this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile);
this.alertView = findViewById(R.id.indicators_parent);
this.contactPhoto = findViewById(R.id.contact_photo);
this.contactPhotoHolder = findViewById(R.id.contact_photo_container);
this.bodyBubble = findViewById(R.id.body_bubble);
@@ -179,8 +165,6 @@ public class ConversationItem extends LinearLayout
@Override
public void bind(@NonNull DcMsg messageRecord,
@NonNull Optional<DcMsg> previousDcMsg,
@NonNull Optional<DcMsg> nextDcMsg,
@NonNull DcChat dcChat,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale,
@@ -189,29 +173,29 @@ public class ConversationItem extends LinearLayout
boolean pulseHighlight)
{
this.messageRecord = messageRecord;
this.dcChat = dcChat;
this.locale = locale;
this.glideRequests = glideRequests;
this.batchSelected = batchSelected;
this.conversationRecipient = recipients;
this.groupThread = dcChat.isGroup();
this.recipient = dcContext.getRecipient(dcContext.getChat(messageRecord.getChatId()));
this.recipient.addListener(this);
this.conversationRecipient.addListener(this);
if (groupThread && !messageRecord.isOutgoing()) {
this.dcContact = dcContext.getContact(messageRecord.getFromId());
}
setGutterSizes(messageRecord, groupThread);
setMessageShape(messageRecord, previousDcMsg, nextDcMsg, groupThread);
setMediaAttributes(messageRecord, previousDcMsg, nextDcMsg, conversationRecipient, groupThread);
setMessageShape(messageRecord, groupThread);
setMediaAttributes(messageRecord, conversationRecipient, groupThread);
setInteractionState(messageRecord, pulseHighlight);
setBodyText(messageRecord);
setBubbleState(messageRecord);
setStatusIcons(messageRecord);
setContactPhoto(recipient);
setGroupMessageStatus(messageRecord, recipient);
setAuthor(messageRecord, previousDcMsg, nextDcMsg, groupThread);
setQuote(messageRecord, previousDcMsg, nextDcMsg, groupThread);
setMessageSpacing(context, messageRecord, previousDcMsg, nextDcMsg, groupThread);
setFooter(messageRecord, nextDcMsg, locale, groupThread);
setContactPhoto();
setGroupMessageStatus();
setAuthor(messageRecord, groupThread);
setQuote(messageRecord, groupThread);
setMessageSpacing(context, messageRecord, groupThread);
setFooter(messageRecord, locale, groupThread);
}
@Override
@@ -284,9 +268,6 @@ public class ConversationItem extends LinearLayout
@Override
public void unbind() {
if (recipient != null) {
recipient.removeListener(this);
}
}
public DcMsg getMessageRecord() {
@@ -300,7 +281,11 @@ public class ConversationItem extends LinearLayout
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
} else {
bodyBubble.getBackground().setColorFilter(defaultBubbleColor, PorterDuff.Mode.MULTIPLY);
bodyBubble.getBackground().setColorFilter(dcContext.getRecipient(messageRecord.getChatId()).getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
if(groupThread && dcContact!=null) {
bodyBubble.getBackground().setColorFilter(dcContext.getRecipient(dcContact).getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
} else {
bodyBubble.getBackground().setColorFilter(dcContext.getRecipient(dcChat).getColor().toConversationColor(context), PorterDuff.Mode.MULTIPLY);
}
}
if (audioViewStub.resolved()) {
@@ -350,38 +335,26 @@ public class ConversationItem extends LinearLayout
}
}
private boolean isCaptionlessMms(DcMsg messageRecord) {
return false;
// return TextUtils.isEmpty(messageRecord.getText()) && messageRecord.isMms();
}
private boolean hasAudio(DcMsg messageRecord) {
return false;
// return messageRecord.isMms() && ((MmsDcMsg)messageRecord).getSlideDeck().getAudioSlide() != null;
int type = messageRecord.getType();
return type==DcMsg.DC_MSG_AUDIO || type==DcMsg.DC_MSG_VOICE;
}
private boolean hasThumbnail(DcMsg messageRecord) {
return false;
// return messageRecord.isMms() && ((MmsDcMsg)messageRecord).getSlideDeck().getThumbnailSlide() != null;
int type = messageRecord.getType();
return type==DcMsg.DC_MSG_GIF || type==DcMsg.DC_MSG_IMAGE || type==DcMsg.DC_MSG_VIDEO;
}
private boolean hasOnlyThumbnail(DcMsg messageRecord) {
return hasThumbnail(messageRecord) && !hasAudio(messageRecord) && !hasDocument(messageRecord) && !hasSharedContact(messageRecord);
return hasThumbnail(messageRecord) && !hasAudio(messageRecord) && !hasDocument(messageRecord);
}
private boolean hasDocument(DcMsg messageRecord) {
return false;
// return messageRecord.isMms() && ((MmsDcMsg)messageRecord).getSlideDeck().getDocumentSlide() != null;
private boolean hasDocument(DcMsg dcMsg) {
return dcMsg.getType()==DcMsg.DC_MSG_FILE && !dcMsg.isSetupMessage();
}
private boolean hasQuote(DcMsg messageRecord) {
return false;
// return messageRecord.isMms() && ((MmsDcMsg)messageRecord).getQuote() != null;
}
private boolean hasSharedContact(DcMsg messageRecord) {
return false;
// return messageRecord.isMms() && !((MmsDcMsg)messageRecord).getSharedContacts().isEmpty();
}
private void setBodyText(DcMsg messageRecord) {
@@ -389,94 +362,82 @@ public class ConversationItem extends LinearLayout
bodyText.setFocusable(false);
bodyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, TextSecurePreferences.getMessageBodyTextSize(context));
if (isCaptionlessMms(messageRecord)) {
bodyText.setVisibility(View.GONE);
} else {
bodyText.setText(linkifyMessageBody(new SpannableString(messageRecord.getText()), batchSelected.isEmpty()));
String text = messageRecord.getText();
if (messageRecord.isSetupMessage()) {
bodyText.setText(context.getString(R.string.autocrypt__asm_tap_body));
bodyText.setVisibility(View.VISIBLE);
}
else if (text.isEmpty()) {
bodyText.setVisibility(View.GONE);
}
else {
bodyText.setText(linkifyMessageBody(new SpannableString(text), batchSelected.isEmpty()));
bodyText.setVisibility(View.VISIBLE);
}
}
private void setMediaAttributes(@NonNull DcMsg messageRecord,
@NonNull Optional<DcMsg> previousRecord,
@NonNull Optional<DcMsg> nextRecord,
@NonNull Recipient conversationRecipient,
boolean isGroupThread)
@NonNull Recipient conversationRecipient,
boolean isGroupThread)
{
boolean showControls = !messageRecord.isFailed() && !Util.isOwnNumber(context, conversationRecipient.getAddress());
// if (hasSharedContact(messageRecord)) {
// sharedContactStub.get().setVisibility(VISIBLE);
// if (audioViewStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
// if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
// if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
//
// sharedContactStub.get().setContact(((MediaMmsDcMsg) messageRecord).getSharedContacts().get(0), glideRequests, locale);
// sharedContactStub.get().setEventListener(sharedContactEventListener);
// sharedContactStub.get().setOnClickListener(sharedContactClickListener);
// sharedContactStub.get().setOnLongClickListener(passthroughClickListener);
//
// setSharedContactCorners(messageRecord, previousRecord, nextRecord, isGroupThread);
//
// ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// footer.setVisibility(GONE);
// } else if (hasAudio(messageRecord)) {
// audioViewStub.get().setVisibility(View.VISIBLE);
// if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
// if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
// if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
//
// //noinspection ConstantConditions
// audioViewStub.get().setAudio(((MediaMmsDcMsg) messageRecord).getSlideDeck().getAudioSlide(), showControls);
// audioViewStub.get().setDownloadClickListener(downloadClickListener);
// audioViewStub.get().setOnLongClickListener(passthroughClickListener);
//
// ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// footer.setVisibility(VISIBLE);
// } else if (hasDocument(messageRecord)) {
// documentViewStub.get().setVisibility(View.VISIBLE);
// if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
// if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
// if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
//
// //noinspection ConstantConditions
// documentViewStub.get().setDocument(((MediaMmsDcMsg)messageRecord).getSlideDeck().getDocumentSlide(), showControls);
// documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
// documentViewStub.get().setDownloadClickListener(downloadClickListener);
// documentViewStub.get().setOnLongClickListener(passthroughClickListener);
//
// ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// footer.setVisibility(VISIBLE);
// } else if (hasThumbnail(messageRecord)) {
// mediaThumbnailStub.get().setVisibility(View.VISIBLE);
// if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
// if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
// if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
//
// //noinspection ConstantConditions
// Slide thumbnailSlide = ((MmsDcMsg) messageRecord).getSlideDeck().getThumbnailSlide();
// Attachment attachment = thumbnailSlide.asAttachment();
// mediaThumbnailStub.get().setImageResource(glideRequests,
// thumbnailSlide,
// showControls,
// false,
// attachment.getWidth(),
// attachment.getHeight());
// mediaThumbnailStub.get().setThumbnailClickListener(new ThumbnailClickListener());
// mediaThumbnailStub.get().setDownloadClickListener(downloadClickListener);
// mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
// mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
// mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
//
// setThumbnailOutlineCorners(messageRecord, previousRecord, nextRecord, isGroupThread);
//
// ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// footer.setVisibility(VISIBLE);
// } else {
if (hasAudio(messageRecord)) {
audioViewStub.get().setVisibility(View.VISIBLE);
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
//noinspection ConstantConditions
audioViewStub.get().setAudio(new AudioSlide(context, messageRecord), showControls);
audioViewStub.get().setOnLongClickListener(passthroughClickListener);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
footer.setVisibility(VISIBLE);
}
else if (hasDocument(messageRecord)) {
documentViewStub.get().setVisibility(View.VISIBLE);
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
//noinspection ConstantConditions
documentViewStub.get().setDocument(new DocumentSlide(context, messageRecord), showControls);
documentViewStub.get().setDocumentClickListener(new ThumbnailClickListener());
documentViewStub.get().setOnLongClickListener(passthroughClickListener);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
footer.setVisibility(VISIBLE);
}
else if (hasThumbnail(messageRecord)) {
mediaThumbnailStub.get().setVisibility(View.VISIBLE);
if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
//noinspection ConstantConditions
mediaThumbnailStub.get().setImageResource(glideRequests,
new DocumentSlide(context, messageRecord),
showControls,
false,
messageRecord.getWidth(100),
messageRecord.getHeight(100));
mediaThumbnailStub.get().setThumbnailClickListener(new ThumbnailClickListener());
mediaThumbnailStub.get().setOnLongClickListener(passthroughClickListener);
mediaThumbnailStub.get().setOnClickListener(passthroughClickListener);
mediaThumbnailStub.get().showShade(TextUtils.isEmpty(messageRecord.getText()));
setThumbnailOutlineCorners(messageRecord, isGroupThread);
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
footer.setVisibility(VISIBLE);
}
else {
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().setVisibility(View.GONE);
if (audioViewStub.resolved()) audioViewStub.get().setVisibility(View.GONE);
if (documentViewStub.resolved()) documentViewStub.get().setVisibility(View.GONE);
@@ -485,13 +446,11 @@ public class ConversationItem extends LinearLayout
ViewUtil.updateLayoutParams(bodyText, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ViewUtil.updateLayoutParams(groupSenderHolder, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
footer.setVisibility(VISIBLE);
// }
}
}
private void setThumbnailOutlineCorners(@NonNull DcMsg current,
@NonNull Optional<DcMsg> previous,
@NonNull Optional<DcMsg> next,
boolean isGroupThread)
boolean isGroupThread)
{
int defaultRadius = readDimen(R.dimen.message_corner_radius);
int collapseRadius = readDimen(R.dimen.message_corner_collapse_radius);
@@ -501,39 +460,17 @@ public class ConversationItem extends LinearLayout
int bottomLeft = defaultRadius;
int bottomRight = defaultRadius;
if (isSingularMessage(current, previous, next, isGroupThread)) {
topLeft = defaultRadius;
topRight = defaultRadius;
bottomLeft = defaultRadius;
bottomRight = defaultRadius;
} else if (isStartOfMessageCluster(current, previous, isGroupThread)) {
if (current.isOutgoing()) {
bottomRight = collapseRadius;
} else {
bottomLeft = collapseRadius;
}
} else if (isEndOfMessageCluster(current, next, isGroupThread)) {
if (current.isOutgoing()) {
topRight = collapseRadius;
} else {
topLeft = collapseRadius;
}
} else {
if (current.isOutgoing()) {
topRight = collapseRadius;
bottomRight = collapseRadius;
} else {
topLeft = collapseRadius;
bottomLeft = collapseRadius;
}
}
topLeft = defaultRadius;
topRight = defaultRadius;
bottomLeft = defaultRadius;
bottomRight = defaultRadius;
if (!TextUtils.isEmpty(current.getText())) {
bottomLeft = 0;
bottomRight = 0;
}
if (isStartOfMessageCluster(current, previous, isGroupThread) && !current.isOutgoing() && isGroupThread) {
if (!current.isOutgoing() && isGroupThread) {
topLeft = 0;
topRight = 0;
}
@@ -546,25 +483,17 @@ public class ConversationItem extends LinearLayout
mediaThumbnailStub.get().setOutlineCorners(topLeft, topRight, bottomRight, bottomLeft);
}
private void setSharedContactCorners(@NonNull DcMsg current, @NonNull Optional<DcMsg> previous, @NonNull Optional<DcMsg> next, boolean isGroupThread) {
if (isSingularMessage(current, previous, next, isGroupThread) || isEndOfMessageCluster(current, next, isGroupThread)) {
sharedContactStub.get().setSingularStyle();
} else {
if (current.isOutgoing()) {
sharedContactStub.get().setClusteredOutgoingStyle();
} else {
sharedContactStub.get().setClusteredIncomingStyle();
}
}
private void setSharedContactCorners(@NonNull DcMsg current, boolean isGroupThread) {
sharedContactStub.get().setSingularStyle();
}
private void setContactPhoto(@NonNull Recipient recipient) {
private void setContactPhoto() {
if (contactPhoto == null) return;
if (messageRecord.isOutgoing() || !groupThread) {
if (messageRecord.isOutgoing() || !groupThread || dcContact ==null) {
contactPhoto.setVisibility(View.GONE);
} else {
contactPhoto.setAvatar(glideRequests, recipient, true);
contactPhoto.setAvatar(glideRequests, dcContext.getRecipient(dcContact), true);
contactPhoto.setVisibility(View.VISIBLE);
}
}
@@ -583,17 +512,7 @@ public class ConversationItem extends LinearLayout
return messageBody;
}
private void setStatusIcons(DcMsg messageRecord) {
bodyText.setCompoundDrawablesWithIntrinsicBounds(0, 0, messageRecord.isSetupMessage() ? R.drawable.ic_menu_login : 0, 0);
if (messageRecord.isFailed()) {
alertView.setFailed();
} else {
alertView.setNone();
}
}
private void setQuote(@NonNull DcMsg current, @NonNull Optional<DcMsg> previous, @NonNull Optional<DcMsg> next, boolean isGroupThread) {
private void setQuote(@NonNull DcMsg current, boolean isGroupThread) {
// if (current.isMms() && !current.isMmsNotification() && ((MediaMmsDcMsg)current).getQuote() != null) {
// Quote quote = ((MediaMmsDcMsg)current).getQuote();
// assert quote != null;
@@ -647,28 +566,20 @@ public class ConversationItem extends LinearLayout
}
}
private void setFooter(@NonNull DcMsg current, @NonNull Optional<DcMsg> next, @NonNull Locale locale, boolean isGroupThread) {
private void setFooter(@NonNull DcMsg current, @NonNull Locale locale, boolean isGroupThread) {
ViewUtil.updateLayoutParams(footer, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
footer.setVisibility(GONE);
if (sharedContactStub.resolved()) sharedContactStub.get().getFooter().setVisibility(GONE);
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.get().getFooter().setVisibility(GONE);
/*boolean differentMinutes = next.isPresent() && !DateUtils.isSameBriefRelativeTimestamp(context, locale, next.get().getTimestamp(), current.getTimestamp());
if (current.getExpiresIn() > 0 || !current.isSecure() || current.isPending() ||
current.isFailed() || differentMinutes || isEndOfMessageCluster(current, next, isGroupThread))
{*/
ConversationItemFooter activeFooter = getActiveFooter(current);
activeFooter.setVisibility(VISIBLE);
activeFooter.setMessageRecord(current, locale);
//}
ConversationItemFooter activeFooter = getActiveFooter(current);
activeFooter.setVisibility(VISIBLE);
activeFooter.setMessageRecord(current, locale);
}
private ConversationItemFooter getActiveFooter(@NonNull DcMsg messageRecord) {
if (hasSharedContact(messageRecord)) {
return sharedContactStub.get().getFooter();
} else if (hasOnlyThumbnail(messageRecord) && TextUtils.isEmpty(messageRecord.getText())) {
if (hasOnlyThumbnail(messageRecord) && TextUtils.isEmpty(messageRecord.getText())) {
return mediaThumbnailStub.get().getFooter();
} else {
return footer;
@@ -680,111 +591,41 @@ public class ConversationItem extends LinearLayout
}
private boolean shouldInterceptClicks(DcMsg messageRecord) {
return batchSelected.isEmpty() && (messageRecord.isFailed() ||
messageRecord.isSetupMessage());
return batchSelected.isEmpty() && (messageRecord.isFailed());
}
@SuppressLint("SetTextI18n")
private void setGroupMessageStatus(DcMsg messageRecord, Recipient recipient) {
if (groupThread && !messageRecord.isOutgoing()) {
this.groupSender.setText(recipient.toShortString());
if (recipient.getName() == null && !TextUtils.isEmpty(recipient.getProfileName())) {
this.groupSenderProfileName.setText("~" + recipient.getProfileName());
this.groupSenderProfileName.setVisibility(View.VISIBLE);
} else {
this.groupSenderProfileName.setText(null);
this.groupSenderProfileName.setVisibility(View.GONE);
}
private void setGroupMessageStatus() {
if (groupThread && !messageRecord.isOutgoing() && dcContact !=null) {
this.groupSender.setText(dcContact.getDisplayName());
}
}
private void setAuthor(@NonNull DcMsg current, @NonNull Optional<DcMsg> previous, @NonNull Optional<DcMsg> next, boolean isGroupThread) {
private void setAuthor(@NonNull DcMsg current, boolean isGroupThread) {
if (isGroupThread && !current.isOutgoing()) {
if (contactPhotoHolder != null) {
contactPhotoHolder.setVisibility(VISIBLE);
}
/*if (!previous.isPresent() || previous.get().isInfo() || current.getFromId() != previous.get().getFromId() ||
!DateUtils.isSameDay(previous.get().getTimestamp(), current.getTimestamp()))
{*/
groupSenderHolder.setVisibility(VISIBLE);
/*} else {
groupSenderHolder.setVisibility(GONE);
}*/
//if (!next.isPresent() || next.get().isInfo() || current.getFromId() != previous.get().getFromId()) {
contactPhoto.setVisibility(VISIBLE);
//} else {
// contactPhoto.setVisibility(GONE);
//}
groupSenderHolder.setVisibility(VISIBLE);
contactPhoto.setVisibility(VISIBLE);
} else {
groupSenderHolder.setVisibility(GONE);
if (contactPhotoHolder != null) {
contactPhotoHolder.setVisibility(GONE);
}
}
}
private void setMessageShape(@NonNull DcMsg current, @NonNull Optional<DcMsg> previous, @NonNull Optional<DcMsg> next, boolean isGroupThread) {
private void setMessageShape(@NonNull DcMsg current, boolean isGroupThread) {
int background;
if (isSingularMessage(current, previous, next, isGroupThread)) {
background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_alone
: R.drawable.message_bubble_background_received_alone;
} else if (isStartOfMessageCluster(current, previous, isGroupThread)) {
background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_start
: R.drawable.message_bubble_background_received_start;
} else if (isEndOfMessageCluster(current, next, isGroupThread)) {
background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_end
: R.drawable.message_bubble_background_received_end;
} else {
background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_middle
: R.drawable.message_bubble_background_received_middle;
}
background = current.isOutgoing() ? R.drawable.message_bubble_background_sent_alone
: R.drawable.message_bubble_background_received_alone;
bodyBubble.setBackgroundResource(background);
}
private boolean isStartOfMessageCluster(@NonNull DcMsg current, @NonNull Optional<DcMsg> previous, boolean isGroupThread) {
return true;
/*if (isGroupThread) {
return !previous.isPresent() || previous.get().isInfo() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) ||
current.getFromId() != previous.get().getFromId();
} else {
return !previous.isPresent() || previous.get().isInfo() || !DateUtils.isSameDay(current.getTimestamp(), previous.get().getTimestamp()) ||
current.isOutgoing() != previous.get().isOutgoing();
}*/
}
private boolean isEndOfMessageCluster(@NonNull DcMsg current, @NonNull Optional<DcMsg> next, boolean isGroupThread) {
return true;
/*if (isGroupThread) {
return !next.isPresent() || next.get().isInfo() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) ||
current.getFromId() != next.get().getFromId();
} else {
return !next.isPresent() || next.get().isInfo() || !DateUtils.isSameDay(current.getTimestamp(), next.get().getTimestamp()) ||
current.isOutgoing() != next.get().isOutgoing();
}*/
}
private boolean isSingularMessage(@NonNull DcMsg current, @NonNull Optional<DcMsg> previous, @NonNull Optional<DcMsg> next, boolean isGroupThread) {
return true;
//return isStartOfMessageCluster(current, previous, isGroupThread) && isEndOfMessageCluster(current, next, isGroupThread);
}
private void setMessageSpacing(@NonNull Context context, @NonNull DcMsg current, @NonNull Optional<DcMsg> previous, @NonNull Optional<DcMsg> next, boolean isGroupThread) {
private void setMessageSpacing(@NonNull Context context, @NonNull DcMsg current, boolean isGroupThread) {
int spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_collapse);
int spacingBottom = spacingTop;
/*if (isStartOfMessageCluster(current, previous, isGroupThread)) {
spacingTop = readDimen(context, R.dimen.conversation_vertical_message_spacing_default);
}
if (isEndOfMessageCluster(current, next, isGroupThread)) {
spacingBottom = readDimen(context, R.dimen.conversation_vertical_message_spacing_default);
}*/
ViewUtil.setPaddingTop(this, spacingTop);
ViewUtil.setPaddingBottom(this, spacingBottom);
}
@@ -795,16 +636,6 @@ public class ConversationItem extends LinearLayout
/// Event handlers
@Override
public void onModified(final Recipient modified) {
Util.runOnMain(() -> {
setBubbleState(messageRecord);
setContactPhoto(recipient);
setGroupMessageStatus(messageRecord, recipient);
setAudioViewTint(messageRecord, conversationRecipient);
});
}
private class SharedContactEventListener implements SharedContactView.EventListener {
@Override
public void onAddToContactsClicked(@NonNull Contact contact) {
@@ -845,27 +676,6 @@ public class ConversationItem extends LinearLayout
}
}
private class AttachmentDownloadClickListener implements SlideClickListener {
@Override
public void onClick(View v, final Slide slide) {
// if (messageRecord.isMmsNotification()) {
// ApplicationContext.getInstance(context)
// .getJobManager()
// .add(new MmsDownloadJob(context, messageRecord.getId(),
// messageRecord.getThreadId(), false));
// } else {
DatabaseFactory.getAttachmentDatabase(context).setTransferState(messageRecord.getId(),
slide.asAttachment(),
AttachmentDatabase.TRANSFER_PROGRESS_STARTED);
ApplicationContext.getInstance(context)
.getJobManager()
.add(new AttachmentDownloadJob(context, messageRecord.getId(),
((DatabaseAttachment)slide.asAttachment()).getAttachmentId(), true));
// }
}
}
private class ThumbnailClickListener implements SlideClickListener {
public void onClick(final View v, final Slide slide) {
if (shouldInterceptClicks(messageRecord) || !batchSelected.isEmpty()) {
@@ -882,18 +692,7 @@ public class ConversationItem extends LinearLayout
context.startActivity(intent);
} else if (slide.getUri() != null) {
Log.w(TAG, "Clicked: " + slide.getUri() + " , " + slide.getContentType());
Uri publicUri = PartAuthority.getAttachmentPublicUri(slide.getUri());
Log.w(TAG, "Public URI: " + publicUri);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(PartAuthority.getAttachmentPublicUri(slide.getUri()), slide.getContentType());
try {
context.startActivity(intent);
} catch (ActivityNotFoundException anfe) {
Log.w(TAG, "No activity existed to view the media.");
Toast.makeText(context, R.string.ConversationItem_unable_to_open_media, Toast.LENGTH_LONG).show();
}
dcContext.openForViewOrShare(slide.getDcMsgId(), Intent.ACTION_VIEW);
}
}
}
@@ -161,7 +161,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
case R.id.menu_new_chat: createChat(); return true;
case R.id.menu_settings: handleDisplaySettings(); return true;
case R.id.menu_clear_passphrase: handleClearPassphrase(); return true;
case R.id.menu_mark_all_read: handleMarkAllRead(); return true;
case R.id.menu_invite: handleInvite(); return true;
case R.id.menu_help: handleHelp(); return true;
}
@@ -217,18 +216,6 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
startService(intent);
}
@SuppressLint("StaticFieldLeak")
private void handleMarkAllRead() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Context context = ConversationListActivity.this;
DcHelper.getContext(context).marknoticedAllChats();
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void handleInvite() {
startActivity(new Intent(this, InviteActivity.class));
}
@@ -410,7 +410,7 @@ public class ConversationListFragment extends Fragment
if (archive) inflater.inflate(R.menu.conversation_list_batch_unarchive, menu);
else inflater.inflate(R.menu.conversation_list_batch_archive, menu);
inflater.inflate(R.menu.conversation_list_batch, menu);
inflater.inflate(R.menu.action_mode_delete, menu);
mode.setTitle("1");
@@ -41,7 +41,6 @@ import com.annimon.stream.Stream;
import com.b44t.messenger.DcLot;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.components.AlertView;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.DeliveryStatusView;
import org.thoughtcrime.securesms.components.FromTextView;
@@ -81,8 +80,8 @@ public class ConversationListItem extends RelativeLayout
private TextView dateView;
private TextView archivedView;
private DeliveryStatusView deliveryStatusIndicator;
private AlertView alertView;
private ImageView unreadIndicator;
private ImageView verifiedIndicator;
private long lastSeen;
private int unreadCount;
@@ -103,14 +102,14 @@ public class ConversationListItem extends RelativeLayout
protected void onFinishInflate() {
super.onFinishInflate();
this.subjectView = findViewById(R.id.subject);
this.fromView = findViewById(R.id.from);
this.fromView = findViewById(R.id.from_text);
this.dateView = findViewById(R.id.date);
this.deliveryStatusIndicator = findViewById(R.id.delivery_status);
this.alertView = findViewById(R.id.indicators_parent);
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.thumbnailView = findViewById(R.id.thumbnail);
this.archivedView = findViewById(R.id.archived);
this.unreadIndicator = findViewById(R.id.unread_indicator);
this.verifiedIndicator = findViewById(R.id.verified_indicator);
thumbnailView.setClickable(false);
ViewUtil.setTextViewGravityStart(this.fromView, getContext());
@@ -177,6 +176,7 @@ public class ConversationListItem extends RelativeLayout
setRippleColor(recipient);
setUnreadIndicator(thread);
this.contactPhotoImage.setAvatar(glideRequests, recipient, true);
verifiedIndicator.setVisibility(thread.isVerified() ? VISIBLE : GONE);
}
public void bind(@NonNull Recipient contact,
@@ -196,7 +196,6 @@ public class ConversationListItem extends RelativeLayout
archivedView.setVisibility(GONE);
unreadIndicator.setVisibility(GONE);
deliveryStatusIndicator.setNone();
alertView.setNone();
thumbnailView.setVisibility(GONE);
setBatchState(false);
@@ -221,7 +220,6 @@ public class ConversationListItem extends RelativeLayout
archivedView.setVisibility(GONE);
unreadIndicator.setVisibility(GONE);
deliveryStatusIndicator.setNone();
alertView.setNone();
thumbnailView.setVisibility(GONE);
setBatchState(false);
@@ -287,20 +285,20 @@ public class ConversationListItem extends RelativeLayout
if (state==DcMsg.DC_STATE_IN_FRESH || state==DcMsg.DC_STATE_IN_NOTICED) {
deliveryStatusIndicator.setNone();
alertView.setNone();
} else if (state==DcMsg.DC_STATE_OUT_ERROR) {
deliveryStatusIndicator.setNone();
alertView.setFailed();
deliveryStatusIndicator.setFailed();
} else {
alertView.setNone();
if(state==DcMsg.DC_STATE_OUT_MDN_RCVD) {
deliveryStatusIndicator.setRead();
}
else if(state==DcMsg.DC_STATE_OUT_DELIVERED) {
deliveryStatusIndicator.setDelivered();
deliveryStatusIndicator.setSent();
}
else if (state==DcMsg.DC_STATE_OUT_PENDING){
deliveryStatusIndicator.setPending();
}
else {
deliveryStatusIndicator.setPending();
deliveryStatusIndicator.setNone();
}
}
}
@@ -73,8 +73,6 @@ public class ConversationUpdateItem extends LinearLayout
@Override
public void bind(@NonNull DcMsg messageRecord,
@NonNull Optional<DcMsg> previousMessageRecord,
@NonNull Optional<DcMsg> nextMessageRecord,
@NonNull DcChat dcChat,
@NonNull GlideRequests glideRequests,
@NonNull Locale locale,
@@ -1,28 +0,0 @@
package org.thoughtcrime.securesms;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class CountrySelectionActivity extends BaseActivity
implements CountrySelectionFragment.CountrySelectedListener
{
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
this.setContentView(R.layout.country_selection);
}
@Override
public void countrySelected(String countryName, int countryCode) {
Intent result = getIntent();
result.putExtra("country_name", countryName);
result.putExtra("country_code", countryCode);
this.setResult(RESULT_OK, result);
this.finish();
}
}
@@ -1,100 +0,0 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import org.thoughtcrime.securesms.database.loaders.CountryListLoader;
import java.util.ArrayList;
import java.util.Map;
public class CountrySelectionFragment extends ListFragment implements LoaderManager.LoaderCallbacks<ArrayList<Map<String, String>>> {
private EditText countryFilter;
private CountrySelectedListener listener;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
return inflater.inflate(R.layout.country_selection_fragment, container, false);
}
@Override
public void onActivityCreated(Bundle bundle) {
super.onActivityCreated(bundle);
this.countryFilter = (EditText)getView().findViewById(R.id.country_search);
this.countryFilter.addTextChangedListener(new FilterWatcher());
getLoaderManager().initLoader(0, null, this).forceLoad();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.listener = (CountrySelectedListener)activity;
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
Map<String, String> item = (Map<String, String>)this.getListAdapter().getItem(position);
if (this.listener != null) {
this.listener.countrySelected(item.get("country_name"),
Integer.parseInt(item.get("country_code").substring(1)));
}
}
@Override
public Loader<ArrayList<Map<String, String>>> onCreateLoader(int arg0, Bundle arg1) {
return new CountryListLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<ArrayList<Map<String, String>>> loader,
ArrayList<Map<String, String>> results)
{
String[] from = {"country_name", "country_code"};
int[] to = {R.id.country_name, R.id.country_code};
this.setListAdapter(new SimpleAdapter(getActivity(), results, R.layout.country_list_item, from, to));
if (this.countryFilter != null && this.countryFilter.getText().length() != 0) {
((SimpleAdapter)getListAdapter()).getFilter().filter(this.countryFilter.getText().toString());
}
}
@Override
public void onLoaderReset(Loader<ArrayList<Map<String, String>>> arg0) {
this.setListAdapter(null);
}
public interface CountrySelectedListener {
public void countrySelected(String countryName, int countryCode);
}
private class FilterWatcher implements TextWatcher {
@Override
public void afterTextChanged(Editable s) {
if (getListAdapter() != null) {
((SimpleAdapter)getListAdapter()).getFilter().filter(s.toString());
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
}
}
@@ -16,11 +16,14 @@ import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.design.widget.TextInputEditText;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewAnimationUtils;
@@ -31,7 +34,6 @@ import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.dd.CircularProgressButton;
import com.soundcloud.android.crop.Crop;
import org.thoughtcrime.securesms.components.InputAwareLayout;
@@ -91,16 +93,18 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
private InputAwareLayout container;
private ImageView avatar;
private CircularProgressButton finishButton;
private EditText name;
private EmojiToggle emojiToggle;
private EmojiDrawer emojiDrawer;
private TextInputEditText statusView;
private View reveal;
private MenuItem finishMenuItem;
private Intent nextIntent;
private byte[] avatarBytes;
private File captureFile;
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
@@ -113,15 +117,25 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
getSupportActionBar().setTitle(R.string.CreateProfileActivity_your_profile_info);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
initializeResources();
initializeEmojiInput();
initializeProfileName(getIntent().getBooleanExtra(EXCLUDE_SYSTEM, false));
initializeProfileAvatar(getIntent().getBooleanExtra(EXCLUDE_SYSTEM, false));
initializeStatusText();
ApplicationContext.getInstance(this).injectDependencies(this);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuInflater inflater = this.getMenuInflater();
inflater.inflate(R.menu.preferences_create_profile_menu, menu);
finishMenuItem = menu.findItem(R.id.menu_create_profile);
return true;
}
@Override
public void onResume() {
super.onResume();
@@ -136,6 +150,9 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
case android.R.id.home:
onBackPressed();
return true;
case R.id.menu_create_profile:
handleUpload();
break;
}
return false;
@@ -227,8 +244,8 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
this.emojiToggle = ViewUtil.findById(this, R.id.emoji_toggle);
this.emojiDrawer = ViewUtil.findById(this, R.id.emoji_drawer);
this.container = ViewUtil.findById(this, R.id.container);
this.finishButton = ViewUtil.findById(this, R.id.finish_button);
this.reveal = ViewUtil.findById(this, R.id.reveal);
this.statusView = ViewUtil.findById(this, R.id.status_text);
this.nextIntent = getIntent().getParcelableExtra(NEXT_INTENT);
this.avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(this, getResources().getColor(R.color.grey_400)));
@@ -246,20 +263,15 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
name.setError(getString(R.string.CreateProfileActivity_too_long));
finishButton.setEnabled(false);
} else if (name.getError() != null || !finishButton.isEnabled()) {
name.setError(null);
finishButton.setEnabled(true);
}
}
});
this.finishButton.setOnClickListener(view -> {
this.finishButton.setIndeterminateProgressMode(true);
this.finishButton.setProgress(50);
handleUpload();
if(finishMenuItem != null){
if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
name.setError(getString(R.string.CreateProfileActivity_too_long));
finishMenuItem.setEnabled(false);
} else if (name.getError() != null || !finishMenuItem.isEnabled()) {
name.setError(null);
finishMenuItem.setEnabled(true);
}
}}
});
passwordAccountSettings.setOnClickListener(view -> {
@@ -374,6 +386,14 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
this.name.setOnClickListener(v -> container.showSoftkey(name));
}
private void initializeStatusText() {
String status = DcHelper.get(this, DcHelper.CONFIG_SELF_STATUS);
if (status.isEmpty()) {
status = getString(R.string.default_status_text);
}
statusView.setText(status);
}
private Intent createAvatarSelectionIntent(@Nullable File captureFile, boolean includeClear, boolean includeCamera) {
List<Intent> extraIntents = new LinkedList<>();
Intent galleryIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
@@ -440,6 +460,7 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
Context context = CreateProfileActivity.this;
byte[] profileKey = ProfileKeyUtil.getProfileKey(CreateProfileActivity.this);
DcHelper.set(context, DcHelper.CONFIG_DISPLAY_NAME, name);
setStatusText();
TextSecurePreferences.setProfileName(context, name);
try {
@@ -470,27 +491,28 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void setStatusText() {
String newStatus = statusView.getText().toString().trim();
String defaultStatus = getString(R.string.default_status_text);
if (newStatus.equals(defaultStatus)) {
DcHelper.set(this, DcHelper.CONFIG_SELF_STATUS, null);
} else {
DcHelper.set(this, DcHelper.CONFIG_SELF_STATUS, newStatus);
}
}
private void handleFinishedLegacy() {
finishButton.setProgress(0);
if (nextIntent != null) startActivity(nextIntent);
finish();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void handleFinishedLollipop() {
int[] finishButtonLocation = new int[2];
int[] revealLocation = new int[2];
finishButton.getLocationInWindow(finishButtonLocation);
reveal.getLocationInWindow(revealLocation);
int finishX = finishButtonLocation[0] - revealLocation[0];
int finishY = finishButtonLocation[1] - revealLocation[1];
finishX += finishButton.getWidth() / 2;
finishY += finishButton.getHeight() / 2;
Animator animation = ViewAnimationUtils.createCircularReveal(reveal, finishX, finishY, 0f, (float) Math.max(reveal.getWidth(), reveal.getHeight()));
Animator animation = ViewAnimationUtils.createCircularReveal(reveal, reveal.getWidth(), 0, 0f, (float) Math.max(reveal.getWidth(), reveal.getHeight()));
animation.setDuration(500);
animation.addListener(new Animator.AnimatorListener() {
@Override
@@ -498,7 +520,6 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
@Override
public void onAnimationEnd(Animator animation) {
finishButton.setProgress(0);
if (nextIntent != null) startActivity(nextIntent);
finish();
}
@@ -1,194 +0,0 @@
package org.thoughtcrime.securesms;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcelable;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription;
import org.thoughtcrime.securesms.service.ApplicationMigrationService;
import org.thoughtcrime.securesms.service.ApplicationMigrationService.ImportState;
public class DatabaseMigrationActivity extends PassphraseRequiredActionBarActivity {
private final ImportServiceConnection serviceConnection = new ImportServiceConnection();
private final ImportStateHandler importStateHandler = new ImportStateHandler();
private final BroadcastReceiver completedReceiver = new NullReceiver();
private LinearLayout promptLayout;
private LinearLayout progressLayout;
private Button skipButton;
private Button importButton;
private ProgressBar progress;
private TextView progressLabel;
private ApplicationMigrationService importService;
private boolean isVisible = false;
@Override
protected void onCreate(Bundle bundle, boolean ready) {
setContentView(R.layout.database_migration_activity);
initializeResources();
initializeServiceBinding();
}
@Override
public void onResume() {
super.onResume();
isVisible = true;
registerForCompletedNotification();
}
@Override
public void onPause() {
super.onPause();
isVisible = false;
unregisterForCompletedNotification();
}
@Override
public void onDestroy() {
super.onDestroy();
shutdownServiceBinding();
}
@Override
public void onBackPressed() {
}
private void initializeServiceBinding() {
Intent intent = new Intent(this, ApplicationMigrationService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private void initializeResources() {
this.promptLayout = (LinearLayout)findViewById(R.id.prompt_layout);
this.progressLayout = (LinearLayout)findViewById(R.id.progress_layout);
this.skipButton = (Button) findViewById(R.id.skip_button);
this.importButton = (Button) findViewById(R.id.import_button);
this.progress = (ProgressBar) findViewById(R.id.import_progress);
this.progressLabel = (TextView) findViewById(R.id.import_status);
this.progressLayout.setVisibility(View.GONE);
this.promptLayout.setVisibility(View.GONE);
this.importButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(DatabaseMigrationActivity.this, ApplicationMigrationService.class);
intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE);
intent.putExtra("master_secret", (Parcelable)getIntent().getParcelableExtra("master_secret"));
startService(intent);
promptLayout.setVisibility(View.GONE);
progressLayout.setVisibility(View.VISIBLE);
}
});
this.skipButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ApplicationMigrationService.setDatabaseImported(DatabaseMigrationActivity.this);
handleImportComplete();
}
});
}
private void registerForCompletedNotification() {
IntentFilter filter = new IntentFilter();
filter.addAction(ApplicationMigrationService.COMPLETED_ACTION);
filter.setPriority(1000);
registerReceiver(completedReceiver, filter);
}
private void unregisterForCompletedNotification() {
unregisterReceiver(completedReceiver);
}
private void shutdownServiceBinding() {
unbindService(serviceConnection);
}
private void handleStateIdle() {
this.promptLayout.setVisibility(View.VISIBLE);
this.progressLayout.setVisibility(View.GONE);
}
private void handleStateProgress(ProgressDescription update) {
this.promptLayout.setVisibility(View.GONE);
this.progressLayout.setVisibility(View.VISIBLE);
this.progressLabel.setText(update.primaryComplete + "/" + update.primaryTotal);
double max = this.progress.getMax();
double primaryTotal = update.primaryTotal;
double primaryComplete = update.primaryComplete;
double secondaryTotal = update.secondaryTotal;
double secondaryComplete = update.secondaryComplete;
this.progress.setProgress((int)Math.round((primaryComplete / primaryTotal) * max));
this.progress.setSecondaryProgress((int)Math.round((secondaryComplete / secondaryTotal) * max));
}
private void handleImportComplete() {
if (isVisible) {
if (getIntent().hasExtra("next_intent")) {
startActivity((Intent)getIntent().getParcelableExtra("next_intent"));
} else {
startActivity(new Intent(this, ConversationListActivity.class));
}
}
finish();
}
private class ImportStateHandler extends Handler {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case ImportState.STATE_IDLE: handleStateIdle(); break;
case ImportState.STATE_MIGRATING_IN_PROGRESS: handleStateProgress((ProgressDescription)message.obj); break;
case ImportState.STATE_MIGRATING_COMPLETE: handleImportComplete(); break;
}
}
}
private class ImportServiceConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
importService = ((ApplicationMigrationService.ApplicationMigrationBinder)service).getService();
importService.setImportStateHandler(importStateHandler);
ImportState state = importService.getState();
importStateHandler.obtainMessage(state.state, state.progress).sendToTarget();
}
@Override
public void onServiceDisconnected(ComponentName name) {
importService.setImportStateHandler(null);
}
}
private static class NullReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
abortBroadcast();
}
}
}
@@ -68,7 +68,7 @@ public class PassphraseCreateActivity extends PassphraseActivity {
TextSecurePreferences.setLastExperienceVersionCode(PassphraseCreateActivity.this, Util.getCurrentApkReleaseVersion(PassphraseCreateActivity.this));
TextSecurePreferences.setPasswordDisabled(PassphraseCreateActivity.this, true);
TextSecurePreferences.setReadReceiptsEnabled(PassphraseCreateActivity.this, true);
// TextSecurePreferences.setReadReceiptsEnabled(PassphraseCreateActivity.this, true);
return null;
}
@@ -1,47 +0,0 @@
package org.thoughtcrime.securesms;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.SwitchCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.thoughtcrime.securesms.jobs.MultiDeviceReadReceiptUpdateJob;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
public class ReadReceiptsIntroFragment extends Fragment {
public static ReadReceiptsIntroFragment newInstance() {
ReadReceiptsIntroFragment fragment = new ReadReceiptsIntroFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
public ReadReceiptsIntroFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.experience_upgrade_preference_fragment, container, false);
SwitchCompat preference = ViewUtil.findById(v, R.id.preference);
preference.setChecked(TextSecurePreferences.isReadReceiptsEnabled(getContext()));
preference.setOnCheckedChangeListener((buttonView, isChecked) -> {
TextSecurePreferences.setReadReceiptsEnabled(getContext(), isChecked);
ApplicationContext.getInstance(getContext())
.getJobManager()
.add(new MultiDeviceReadReceiptUpdateJob(getContext(), isChecked));
});
return v;
}
}
@@ -59,7 +59,6 @@ import org.thoughtcrime.securesms.preferences.widgets.ColorPickerPreference;
import org.thoughtcrime.securesms.preferences.widgets.ContactPreference;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.Dialogs;
import org.thoughtcrime.securesms.util.DynamicLanguage;
@@ -438,10 +437,7 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
public boolean onPreferenceChange(Preference preference, Object newValue) {
Uri value = (Uri)newValue;
Uri defaultValue;
if (calls) defaultValue = TextSecurePreferences.getCallNotificationRingtone(getContext());
else defaultValue = TextSecurePreferences.getNotificationRingtone(getContext());
Uri defaultValue = TextSecurePreferences.getNotificationRingtone(getContext());
if (defaultValue.equals(value)) value = null;
else if (value == null) value = Uri.EMPTY;
@@ -469,16 +465,8 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
@Override
public boolean onPreferenceClick(Preference preference) {
Uri current;
Uri defaultUri;
if (calls) {
current = recipient.getCallRingtone();
defaultUri = TextSecurePreferences.getCallNotificationRingtone(getContext());
} else {
current = recipient.getMessageRingtone();
defaultUri = TextSecurePreferences.getNotificationRingtone(getContext());
}
Uri current = recipient.getMessageRingtone();
Uri defaultUri = TextSecurePreferences.getNotificationRingtone(getContext());
if (current == null) current = Settings.System.DEFAULT_NOTIFICATION_URI;
else if (current.toString().isEmpty()) current = null;
@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
@@ -12,7 +10,6 @@ import android.support.annotation.NonNull;
import android.support.constraint.Group;
import android.support.design.widget.TextInputEditText;
import android.text.TextUtils;
import android.util.Log;
import android.util.Patterns;
import android.view.View;
import android.widget.ImageView;
@@ -28,6 +25,16 @@ import org.thoughtcrime.securesms.connect.DcHelper;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.util.Dialogs;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_ADDRESS;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_PASSWORD;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_PORT;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_SERVER;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_MAIL_USER;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_PASSWORD;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_PORT;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_SERVER;
import static org.thoughtcrime.securesms.connect.DcHelper.CONFIG_SEND_USER;
/**
* The register account activity. Prompts ths user for their registration information
* and begins the account registration process.
@@ -63,7 +70,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
setContentView(R.layout.registration_activity);
initializeResources();
initializePermissions();
DcHelper.getContext(this).eventCenter.addObserver(this, DcContext.DC_EVENT_CONFIGURE_PROGRESS);
}
@@ -99,6 +105,21 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
advancedTextView.setOnClickListener(l -> onAdvancedSettings());
advancedIcon.setOnClickListener(l -> onAdvancedSettings());
advancedIcon.setRotation(45);
boolean isConfigured = DcHelper.isConfigured(getApplicationContext());
if (isConfigured) {
TextInputEditText imapLoginInput = findViewById(R.id.imap_login_text);
emailInput.setText(DcHelper.get(this, CONFIG_ADDRESS));
passwordInput.setText(DcHelper.get(this, CONFIG_MAIL_PASSWORD));
imapLoginInput.setText(DcHelper.get(this, CONFIG_MAIL_USER));
imapServerInput.setText(DcHelper.get(this, CONFIG_MAIL_SERVER));
imapPortInput.setText(DcHelper.get(this, CONFIG_MAIL_PORT));
TextInputEditText smtpLoginInput = findViewById(R.id.smtp_login_text);
TextInputEditText smtpPasswordInput = findViewById(R.id.smtp_port_text);
smtpLoginInput.setText(DcHelper.get(this, CONFIG_SEND_USER));
smtpPasswordInput.setText(DcHelper.get(this, CONFIG_SEND_PASSWORD));
smtpServerInput.setText(DcHelper.get(this, CONFIG_SEND_SERVER));
smtpPortInput.setText(DcHelper.get(this, CONFIG_SEND_PORT));
}
}
private void focusListener(View view, boolean focused, VerificationType type) {
@@ -174,17 +195,6 @@ public class RegistrationActivity extends BaseActionBarActivity implements DcEve
}
}
@SuppressLint("InlinedApi")
private void initializePermissions() {
Permissions.with(RegistrationActivity.this)
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
.ifNecessary()
.withRationaleDialog(getString(R.string.RegistrationActivity_dialog_permission_text),
R.drawable.ic_contacts_white_48dp, R.drawable.ic_folder_white_48dp)
.execute();
}
private void onLogin() {
if (!verifyRequiredFields()) {
Toast.makeText(this, R.string.RegistrationActivity_error_required_fields, Toast.LENGTH_LONG).show();
@@ -1,86 +0,0 @@
package org.thoughtcrime.securesms.backup;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.util.BackupUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
public class BackupDialog {
public static void showEnableBackupDialog(@NonNull Context context, @NonNull SwitchPreferenceCompat preference) {
String[] password = BackupUtil.generateBackupPassphrase();
AlertDialog dialog = new AlertDialog.Builder(context)
.setTitle(R.string.BackupDialog_enable_local_backups)
.setView(R.layout.backup_enable_dialog)
.setPositiveButton(R.string.BackupDialog_enable_backups, null)
.setNegativeButton(android.R.string.cancel, null)
.create();
dialog.setOnShowListener(created -> {
Button button = ((AlertDialog) created).getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener(v -> {
CheckBox confirmationCheckBox = dialog.findViewById(R.id.confirmation_check);
if (confirmationCheckBox.isChecked()) {
TextSecurePreferences.setBackupPassphrase(context, Util.join(password, " "));
TextSecurePreferences.setBackupEnabled(context, true);
LocalBackupListener.schedule(context);
preference.setChecked(true);
created.dismiss();
} else {
Toast.makeText(context, R.string.BackupDialog_please_acknowledge_your_understanding_by_marking_the_confirmation_check_box, Toast.LENGTH_LONG).show();
}
});
});
dialog.show();
CheckBox checkBox = dialog.findViewById(R.id.confirmation_check);
TextView textView = dialog.findViewById(R.id.confirmation_text);
((TextView)dialog.findViewById(R.id.code_first)).setText(password[0]);
((TextView)dialog.findViewById(R.id.code_second)).setText(password[1]);
((TextView)dialog.findViewById(R.id.code_third)).setText(password[2]);
((TextView)dialog.findViewById(R.id.code_fourth)).setText(password[3]);
((TextView)dialog.findViewById(R.id.code_fifth)).setText(password[4]);
((TextView)dialog.findViewById(R.id.code_sixth)).setText(password[5]);
textView.setOnClickListener(v -> checkBox.toggle());
dialog.findViewById(R.id.number_table).setOnClickListener(v -> {
((ClipboardManager)context.getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("text", Util.join(password, " ")));
Toast.makeText(context, R.string.BackupDialog_copied_to_clipboard, Toast.LENGTH_LONG).show();
});
}
public static void showDisableBackupDialog(@NonNull Context context, @NonNull SwitchPreferenceCompat preference) {
new AlertDialog.Builder(context)
.setTitle(R.string.BackupDialog_delete_backups)
.setMessage(R.string.BackupDialog_disable_and_delete_all_local_backups)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.BackupDialog_delete_backups_statement, (dialog, which) -> {
TextSecurePreferences.setBackupPassphrase(context, null);
TextSecurePreferences.setBackupEnabled(context, false);
BackupUtil.deleteAllBackups();
preference.setChecked(false);
})
.create()
.show();
}
}
File diff suppressed because it is too large Load Diff
@@ -1,65 +0,0 @@
package org.thoughtcrime.securesms.backup;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.greenrobot.eventbus.EventBus;
import org.whispersystems.libsignal.util.ByteUtil;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public abstract class FullBackupBase {
@SuppressWarnings("unused")
private static final String TAG = FullBackupBase.class.getSimpleName();
static class BackupStream {
static @NonNull byte[] getBackupKey(@NonNull String passphrase, @Nullable byte[] salt) {
try {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, 0));
MessageDigest digest = MessageDigest.getInstance("SHA-512");
byte[] input = passphrase.replace(" ", "").getBytes();
byte[] hash = input;
if (salt != null) digest.update(salt);
for (int i=0;i<250000;i++) {
if (i % 1000 == 0) EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, 0));
digest.update(hash);
hash = digest.digest(input);
}
return ByteUtil.trim(hash, 32);
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
}
}
public static class BackupEvent {
public enum Type {
PROGRESS,
FINISHED
}
private final Type type;
private final int count;
BackupEvent(Type type, int count) {
this.type = type;
this.count = count;
}
public Type getType() {
return type;
}
public int getCount() {
return count;
}
}
}
@@ -1,384 +0,0 @@
package org.thoughtcrime.securesms.backup;
import android.content.Context;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import com.annimon.stream.function.Consumer;
import com.annimon.stream.function.Predicate;
import com.google.protobuf.ByteString;
import net.sqlcipher.database.SQLiteDatabase;
import org.greenrobot.eventbus.EventBus;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.OneTimePreKeyDatabase;
import org.thoughtcrime.securesms.database.SearchDatabase;
import org.thoughtcrime.securesms.database.SessionDatabase;
import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.kdf.HKDFv3;
import org.whispersystems.libsignal.util.ByteUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.List;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class FullBackupExporter extends FullBackupBase {
@SuppressWarnings("unused")
private static final String TAG = FullBackupExporter.class.getSimpleName();
public static void export(@NonNull Context context,
@NonNull AttachmentSecret attachmentSecret,
@NonNull SQLiteDatabase input,
@NonNull File output,
@NonNull String passphrase)
throws IOException
{
BackupFrameOutputStream outputStream = new BackupFrameOutputStream(output, passphrase);
outputStream.writeDatabaseVersion(input.getVersion());
List<String> tables = exportSchema(input, outputStream);
int count = 0;
for (String table : tables) {
if (table.equals(SmsDatabase.TABLE_NAME) || table.equals(MmsDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, cursor -> cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0, null, count);
} else if (table.equals(GroupReceiptDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))), null, count);
} else if (table.equals(AttachmentDatabase.TABLE_NAME)) {
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))), cursor -> exportAttachment(attachmentSecret, cursor, outputStream), count);
} else if (!table.equals(SignedPreKeyDatabase.TABLE_NAME) &&
!table.equals(OneTimePreKeyDatabase.TABLE_NAME) &&
!table.equals(SessionDatabase.TABLE_NAME) &&
!table.startsWith(SearchDatabase.SMS_FTS_TABLE_NAME) &&
!table.startsWith(SearchDatabase.MMS_FTS_TABLE_NAME))
{
count = exportTable(table, input, outputStream, null, null, count);
}
}
for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(preference);
}
for (File avatar : AvatarHelper.getAvatarFiles(context)) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
outputStream.write(avatar.getName(), new FileInputStream(avatar), avatar.length());
}
outputStream.writeEnd();
outputStream.close();
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, ++count));
}
private static List<String> exportSchema(@NonNull SQLiteDatabase input, @NonNull BackupFrameOutputStream outputStream)
throws IOException
{
List<String> tables = new LinkedList<>();
try (Cursor cursor = input.rawQuery("SELECT sql, name, type FROM sqlite_master", null)) {
while (cursor != null && cursor.moveToNext()) {
String sql = cursor.getString(0);
String name = cursor.getString(1);
String type = cursor.getString(2);
if (sql != null) {
boolean isSmsFtsSecretTable = name != null && !name.equals(SearchDatabase.SMS_FTS_TABLE_NAME) && name.startsWith(SearchDatabase.SMS_FTS_TABLE_NAME);
boolean isMmsFtsSecretTable = name != null && !name.equals(SearchDatabase.MMS_FTS_TABLE_NAME) && name.startsWith(SearchDatabase.MMS_FTS_TABLE_NAME);
if (!isSmsFtsSecretTable && !isMmsFtsSecretTable) {
if ("table".equals(type)) {
tables.add(name);
}
outputStream.write(BackupProtos.SqlStatement.newBuilder().setStatement(cursor.getString(0)).build());
}
}
}
}
return tables;
}
private static int exportTable(@NonNull String table,
@NonNull SQLiteDatabase input,
@NonNull BackupFrameOutputStream outputStream,
@Nullable Predicate<Cursor> predicate,
@Nullable Consumer<Cursor> postProcess,
int count)
throws IOException
{
String template = "INSERT INTO " + table + " VALUES ";
try (Cursor cursor = input.rawQuery("SELECT * FROM " + table, null)) {
while (cursor != null && cursor.moveToNext()) {
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
if (predicate == null || predicate.test(cursor)) {
StringBuilder statement = new StringBuilder(template);
BackupProtos.SqlStatement.Builder statementBuilder = BackupProtos.SqlStatement.newBuilder();
statement.append('(');
for (int i=0;i<cursor.getColumnCount();i++) {
statement.append('?');
if (cursor.getType(i) == Cursor.FIELD_TYPE_STRING) {
statementBuilder.addParameters(BackupProtos.SqlStatement.SqlParameter.newBuilder().setStringParamter(cursor.getString(i)));
} else if (cursor.getType(i) == Cursor.FIELD_TYPE_FLOAT) {
statementBuilder.addParameters(BackupProtos.SqlStatement.SqlParameter.newBuilder().setDoubleParameter(cursor.getDouble(i)));
} else if (cursor.getType(i) == Cursor.FIELD_TYPE_INTEGER) {
statementBuilder.addParameters(BackupProtos.SqlStatement.SqlParameter.newBuilder().setIntegerParameter(cursor.getLong(i)));
} else if (cursor.getType(i) == Cursor.FIELD_TYPE_BLOB) {
statementBuilder.addParameters(BackupProtos.SqlStatement.SqlParameter.newBuilder().setBlobParameter(ByteString.copyFrom(cursor.getBlob(i))));
} else if (cursor.getType(i) == Cursor.FIELD_TYPE_NULL) {
statementBuilder.addParameters(BackupProtos.SqlStatement.SqlParameter.newBuilder().setNullparameter(true));
} else {
throw new AssertionError("unknown type?" + cursor.getType(i));
}
if (i < cursor.getColumnCount()-1) {
statement.append(',');
}
}
statement.append(')');
outputStream.write(statementBuilder.setStatement(statement.toString()).build());
if (postProcess != null) postProcess.accept(cursor);
}
}
}
return count;
}
private static void exportAttachment(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream) {
try {
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID));
long uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID));
long size = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.SIZE));
String data = cursor.getString(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA));
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(AttachmentDatabase.DATA_RANDOM));
if (!TextUtils.isEmpty(data) && size <= 0) {
size = calculateVeryOldStreamLength(attachmentSecret, random, data);
}
if (!TextUtils.isEmpty(data) && size > 0) {
InputStream inputStream;
if (random != null && random.length == 32) inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
else inputStream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, new File(data));
outputStream.write(new AttachmentId(rowId, uniqueId), inputStream, size);
}
} catch (IOException e) {
Log.w(TAG, e);
}
}
private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) throws IOException {
long result = 0;
InputStream inputStream;
if (random != null && random.length == 32) inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
else inputStream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, new File(data));
int read;
byte[] buffer = new byte[8192];
while ((read = inputStream.read(buffer, 0, buffer.length)) != -1) {
result += read;
}
return result;
}
private static boolean isForNonExpiringMessage(@NonNull SQLiteDatabase db, long mmsId) {
String[] columns = new String[] { MmsDatabase.EXPIRES_IN };
String where = MmsDatabase.ID + " = ?";
String[] args = new String[] { String.valueOf(mmsId) };
try (Cursor mmsCursor = db.query(MmsDatabase.TABLE_NAME, columns, where, args, null, null, null)) {
if (mmsCursor != null && mmsCursor.moveToFirst()) {
return mmsCursor.getLong(0) == 0;
}
}
return false;
}
private static class BackupFrameOutputStream extends BackupStream {
private final OutputStream outputStream;
private final Cipher cipher;
private final Mac mac;
private final byte[] cipherKey;
private final byte[] macKey;
private byte[] iv;
private int counter;
private BackupFrameOutputStream(@NonNull File output, @NonNull String passphrase) throws IOException {
try {
byte[] salt = Util.getSecretBytes(32);
byte[] key = getBackupKey(passphrase, salt);
byte[] derived = new HKDFv3().deriveSecrets(key, "Backup Export".getBytes(), 64);
byte[][] split = ByteUtil.split(derived, 32, 32);
this.cipherKey = split[0];
this.macKey = split[1];
this.cipher = Cipher.getInstance("AES/CTR/NoPadding");
this.mac = Mac.getInstance("HmacSHA256");
this.outputStream = new FileOutputStream(output);
this.iv = Util.getSecretBytes(16);
this.counter = Conversions.byteArrayToInt(iv);
mac.init(new SecretKeySpec(macKey, "HmacSHA256"));
byte[] header = BackupProtos.BackupFrame.newBuilder().setHeader(BackupProtos.Header.newBuilder()
.setIv(ByteString.copyFrom(iv))
.setSalt(ByteString.copyFrom(salt)))
.build().toByteArray();
outputStream.write(Conversions.intToByteArray(header.length));
outputStream.write(header);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
throw new AssertionError(e);
}
}
public void write(BackupProtos.SharedPreference preference) throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder().setPreference(preference).build());
}
public void write(BackupProtos.SqlStatement statement) throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder().setStatement(statement).build());
}
public void write(@NonNull String avatarName, @NonNull InputStream in, long size) throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder()
.setAvatar(BackupProtos.Avatar.newBuilder()
.setName(avatarName)
.setLength(Util.toIntExact(size))
.build())
.build());
writeStream(in);
}
public void write(@NonNull AttachmentId attachmentId, @NonNull InputStream in, long size) throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder()
.setAttachment(BackupProtos.Attachment.newBuilder()
.setRowId(attachmentId.getRowId())
.setAttachmentId(attachmentId.getUniqueId())
.setLength(Util.toIntExact(size))
.build())
.build());
writeStream(in);
}
void writeDatabaseVersion(int version) throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder()
.setVersion(BackupProtos.DatabaseVersion.newBuilder().setVersion(version))
.build());
}
void writeEnd() throws IOException {
write(outputStream, BackupProtos.BackupFrame.newBuilder().setEnd(true).build());
}
private void writeStream(@NonNull InputStream inputStream) throws IOException {
try {
Conversions.intToByteArray(iv, 0, counter++);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv));
mac.update(iv);
byte[] buffer = new byte[8192];
int read;
while ((read = inputStream.read(buffer)) != -1) {
byte[] ciphertext = cipher.update(buffer, 0, read);
if (ciphertext != null) {
outputStream.write(ciphertext);
mac.update(ciphertext);
}
}
byte[] remainder = cipher.doFinal();
outputStream.write(remainder);
mac.update(remainder);
byte[] attachmentDigest = mac.doFinal();
outputStream.write(attachmentDigest, 0, 10);
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e);
}
}
private void write(@NonNull OutputStream out, @NonNull BackupProtos.BackupFrame frame) throws IOException {
try {
Conversions.intToByteArray(iv, 0, counter++);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(cipherKey, "AES"), new IvParameterSpec(iv));
byte[] frameCiphertext = cipher.doFinal(frame.toByteArray());
byte[] frameMac = mac.doFinal(frameCiphertext);
byte[] length = Conversions.intToByteArray(frameCiphertext.length + 10);
out.write(length);
out.write(frameCiphertext);
out.write(frameMac, 0, 10);
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
throw new AssertionError(e);
}
}
public void close() throws IOException {
outputStream.close();
}
}
}
@@ -1,72 +0,0 @@
package org.thoughtcrime.securesms.components;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build.VERSION_CODES;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.thoughtcrime.securesms.R;
public class AlertView extends LinearLayout {
private static final String TAG = AlertView.class.getSimpleName();
private ImageView approvalIndicator;
private ImageView failedIndicator;
public AlertView(Context context) {
this(context, null);
}
public AlertView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(attrs);
}
@TargetApi(VERSION_CODES.HONEYCOMB)
public AlertView(final Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize(attrs);
}
private void initialize(AttributeSet attrs) {
inflate(getContext(), R.layout.alert_view, this);
approvalIndicator = findViewById(R.id.pending_approval_indicator);
failedIndicator = findViewById(R.id.sms_failed_indicator);
if (attrs != null) {
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.AlertView, 0, 0);
boolean useSmallIcon = typedArray.getBoolean(R.styleable.AlertView_useSmallIcon, false);
typedArray.recycle();
if (useSmallIcon) {
int size = getResources().getDimensionPixelOffset(R.dimen.alertview_small_icon_size);
failedIndicator.getLayoutParams().width = size;
failedIndicator.getLayoutParams().height = size;
requestLayout();
}
}
}
public void setNone() {
this.setVisibility(View.GONE);
}
public void setPendingApproval() {
this.setVisibility(View.VISIBLE);
approvalIndicator.setVisibility(View.VISIBLE);
failedIndicator.setVisibility(View.GONE);
}
public void setFailed() {
this.setVisibility(View.VISIBLE);
approvalIndicator.setVisibility(View.GONE);
failedIndicator.setVisibility(View.VISIBLE);
}
}
@@ -46,7 +46,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
private final @NonNull ImageView playButton;
private final @NonNull ImageView pauseButton;
private final @NonNull ImageView downloadButton;
private final @NonNull ProgressWheel downloadProgress;
private final @NonNull SeekBar seekBar;
private final @NonNull TextView timestamp;
@@ -71,7 +70,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
this.playButton = (ImageView) findViewById(R.id.play);
this.pauseButton = (ImageView) findViewById(R.id.pause);
this.downloadButton = (ImageView) findViewById(R.id.download);
this.downloadProgress = (ProgressWheel) findViewById(R.id.download_progress);
this.seekBar = (SeekBar) findViewById(R.id.seek);
this.timestamp = (TextView) findViewById(R.id.timestamp);
@@ -95,37 +93,12 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!EventBus.getDefault().isRegistered(this)) EventBus.getDefault().register(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
EventBus.getDefault().unregister(this);
}
public void setAudio(final @NonNull AudioSlide audio,
final boolean showControls)
{
if (showControls && audio.isPendingDownload()) {
controlToggle.displayQuick(downloadButton);
seekBar.setEnabled(false);
downloadButton.setOnClickListener(new DownloadClickedListener(audio));
if (downloadProgress.isSpinning()) downloadProgress.stopSpinning();
} else if (showControls && audio.getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_STARTED) {
controlToggle.displayQuick(downloadProgress);
seekBar.setEnabled(false);
downloadProgress.spin();
} else {
controlToggle.displayQuick(playButton);
seekBar.setEnabled(true);
if (downloadProgress.isSpinning()) downloadProgress.stopSpinning();
}
controlToggle.displayQuick(playButton);
seekBar.setEnabled(true);
this.audioSlidePlayer = AudioSlidePlayer.createFor(getContext(), audio, this);
}
@@ -135,10 +108,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
}
}
public void setDownloadClickListener(@Nullable SlideClickListener listener) {
this.downloadListener = listener;
}
@Override
public void onStart() {
if (this.pauseButton.getVisibility() != View.VISIBLE) {
@@ -214,7 +183,6 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
}
this.downloadButton.setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
this.downloadProgress.setBarColor(foregroundTint);
this.timestamp.setTextColor(foregroundTint);
this.seekBar.getProgressDrawable().setColorFilter(foregroundTint, PorterDuff.Mode.SRC_IN);
@@ -322,17 +290,4 @@ public class AudioView extends FrameLayout implements AudioSlidePlayer.Listener
return true;
}
}
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
public void onEventAsync(final PartProgressEvent event) {
if (audioSlidePlayer != null && event.attachment.equals(this.audioSlidePlayer.getAudioSlide().asAttachment())) {
Util.runOnMain(new Runnable() {
@Override
public void run() {
downloadProgress.setInstantProgress(((float) event.progress) / event.total);
}
});
}
}
}
@@ -1,10 +1,7 @@
package org.thoughtcrime.securesms.components;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
@@ -15,23 +12,14 @@ import android.widget.TextView;
import com.b44t.messenger.DcMsg;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.permissions.Permissions;
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.dualsim.SubscriptionInfoCompat;
import org.thoughtcrime.securesms.util.dualsim.SubscriptionManagerCompat;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.Locale;
public class ConversationItemFooter extends LinearLayout {
private TextView dateView;
private TextView simView;
private ExpirationTimerView timerView;
private ImageView secureIndicatorView;
private DeliveryStatusView deliveryStatusView;
@@ -54,8 +42,6 @@ public class ConversationItemFooter extends LinearLayout {
inflate(getContext(), R.layout.conversation_item_footer, this);
dateView = findViewById(R.id.footer_date);
simView = findViewById(R.id.footer_sim_info);
timerView = findViewById(R.id.footer_expiration_timer);
secureIndicatorView = findViewById(R.id.footer_secure_indicator);
deliveryStatusView = findViewById(R.id.footer_delivery_status);
@@ -70,91 +56,26 @@ public class ConversationItemFooter extends LinearLayout {
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
timerView.stopAnimation();
}
public void setMessageRecord(@NonNull DcMsg messageRecord, @NonNull Locale locale) {
presentDate(messageRecord, locale);
presentSimInfo(messageRecord);
presentTimer(messageRecord);
presentSecureIndicator(messageRecord);
presentDeliveryStatus(messageRecord);
}
public void setTextColor(int color) {
dateView.setTextColor(color);
simView.setTextColor(color);
}
public void setIconColor(int color) {
timerView.setColorFilter(color);
secureIndicatorView.setColorFilter(color);
deliveryStatusView.setTint(color);
}
private void presentDate(@NonNull DcMsg messageRecord, @NonNull Locale locale) {
dateView.forceLayout();
if (messageRecord.isFailed()) {
dateView.setText(R.string.ConversationItem_error_not_delivered);
} else {
dateView.setText(DateUtils.getTimeOfDayTimeSpanString(getContext(), locale, messageRecord.getTimestamp()));
}
}
private void presentSimInfo(@NonNull DcMsg messageRecord) {
SubscriptionManagerCompat subscriptionManager = new SubscriptionManagerCompat(getContext());
if (messageRecord.getSubscriptionId() == -1 || !Permissions.hasAll(getContext(), Manifest.permission.READ_PHONE_STATE) || subscriptionManager.getActiveSubscriptionInfoList().size() < 2) {
simView.setVisibility(View.GONE);
} else {
Optional<SubscriptionInfoCompat> subscriptionInfo = subscriptionManager.getActiveSubscriptionInfo(messageRecord.getSubscriptionId());
if (subscriptionInfo.isPresent() && messageRecord.isOutgoing()) {
simView.setText(getContext().getString(R.string.ConversationItem_from_s, subscriptionInfo.get().getDisplayName()));
simView.setVisibility(View.VISIBLE);
} else if (subscriptionInfo.isPresent()) {
simView.setText(getContext().getString(R.string.ConversationItem_to_s, subscriptionInfo.get().getDisplayName()));
simView.setVisibility(View.VISIBLE);
} else {
simView.setVisibility(View.GONE);
}
}
}
@SuppressLint("StaticFieldLeak")
private void presentTimer(@NonNull final DcMsg messageRecord) {
if (messageRecord.getExpiresIn() > 0 && !messageRecord.isPending()) {
this.timerView.setVisibility(View.VISIBLE);
this.timerView.setPercentComplete(0);
if (messageRecord.getExpireStarted() > 0) {
this.timerView.setExpirationTime(messageRecord.getExpireStarted(),
messageRecord.getExpiresIn());
this.timerView.startAnimation();
if (messageRecord.getExpireStarted() + messageRecord.getExpiresIn() <= System.currentTimeMillis()) {
ApplicationContext.getInstance(getContext()).getExpiringMessageManager().checkSchedule();
}
} else if (!messageRecord.isOutgoing() && !messageRecord.isMediaPending()) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
ExpiringMessageManager expirationManager = ApplicationContext.getInstance(getContext()).getExpiringMessageManager();
long id = messageRecord.getId();
boolean mms = messageRecord.isMms();
if (mms) DatabaseFactory.getMmsDatabase(getContext()).markExpireStarted(id);
else DatabaseFactory.getSmsDatabase(getContext()).markExpireStarted(id);
expirationManager.scheduleDeletion(id, mms, messageRecord.getExpiresIn());
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
} else {
this.timerView.setVisibility(View.GONE);
}
dateView.setText(DateUtils.getTimeOfDayTimeSpanString(getContext(), locale, messageRecord.getTimestamp()));
}
private void presentSecureIndicator(@NonNull DcMsg messageRecord) {
@@ -162,14 +83,10 @@ public class ConversationItemFooter extends LinearLayout {
}
private void presentDeliveryStatus(@NonNull DcMsg messageRecord) {
if (!messageRecord.isFailed()) {
if (!messageRecord.isOutgoing()) deliveryStatusView.setNone();
else if (messageRecord.isPending()) deliveryStatusView.setPending();
else if (messageRecord.isRemoteRead()) deliveryStatusView.setRead();
else if (messageRecord.isDelivered()) deliveryStatusView.setDelivered();
else deliveryStatusView.setSent();
} else {
deliveryStatusView.setNone();
}
if (!messageRecord.isOutgoing()) deliveryStatusView.setNone();
else if (messageRecord.isRemoteRead()) deliveryStatusView.setRead();
else if (messageRecord.isDelivered()) deliveryStatusView.setSent();
else if (messageRecord.isFailed()) deliveryStatusView.setFailed();
else deliveryStatusView.setPending();
}
}
@@ -168,15 +168,7 @@ public class ConversationItemThumbnail extends FrameLayout {
thumbnail.setThumbnailClickListener(listener);
}
public void setDownloadClickListener(SlideClickListener listener) {
thumbnail.setDownloadClickListener(listener);
}
public void clear(GlideRequests glideRequests) {
thumbnail.clear(glideRequests);
}
public void showProgressSpinner() {
thumbnail.showProgressSpinner();
}
}
@@ -33,8 +33,8 @@ public class DeliveryStatusView extends FrameLayout {
private final ImageView pendingIndicator;
private final ImageView sentIndicator;
private final ImageView deliveredIndicator;
private final ImageView readIndicator;
private final ImageView failedIndicator;
public DeliveryStatusView(Context context) {
this(context, null);
@@ -49,10 +49,10 @@ public class DeliveryStatusView extends FrameLayout {
inflate(context, R.layout.delivery_status_view, this);
this.deliveredIndicator = findViewById(R.id.delivered_indicator);
this.sentIndicator = findViewById(R.id.sent_indicator);
this.pendingIndicator = findViewById(R.id.pending_indicator);
this.readIndicator = findViewById(R.id.read_indicator);
this.failedIndicator = findViewById(R.id.failed_indicator);
if (attrs != null) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DeliveryStatusView, 0, 0);
@@ -70,8 +70,8 @@ public class DeliveryStatusView extends FrameLayout {
pendingIndicator.setVisibility(View.VISIBLE);
pendingIndicator.startAnimation(ROTATION_ANIMATION);
sentIndicator.setVisibility(View.GONE);
deliveredIndicator.setVisibility(View.GONE);
readIndicator.setVisibility(View.GONE);
failedIndicator.setVisibility(View.GONE);
}
public void setSent() {
@@ -79,17 +79,8 @@ public class DeliveryStatusView extends FrameLayout {
pendingIndicator.setVisibility(View.GONE);
pendingIndicator.clearAnimation();
sentIndicator.setVisibility(View.VISIBLE);
deliveredIndicator.setVisibility(View.GONE);
readIndicator.setVisibility(View.GONE);
}
public void setDelivered() {
this.setVisibility(View.VISIBLE);
pendingIndicator.setVisibility(View.GONE);
pendingIndicator.clearAnimation();
sentIndicator.setVisibility(View.GONE);
deliveredIndicator.setVisibility(View.VISIBLE);
readIndicator.setVisibility(View.GONE);
failedIndicator.setVisibility(View.GONE);
}
public void setRead() {
@@ -97,14 +88,23 @@ public class DeliveryStatusView extends FrameLayout {
pendingIndicator.setVisibility(View.GONE);
pendingIndicator.clearAnimation();
sentIndicator.setVisibility(View.GONE);
deliveredIndicator.setVisibility(View.GONE);
readIndicator.setVisibility(View.VISIBLE);
failedIndicator.setVisibility(View.GONE);
}
public void setFailed() {
this.setVisibility(View.VISIBLE);
pendingIndicator.setVisibility(View.GONE);
pendingIndicator.clearAnimation();
sentIndicator.setVisibility(View.GONE);
readIndicator.setVisibility(View.GONE);
failedIndicator.setVisibility(View.VISIBLE);
}
public void setTint(int color) {
pendingIndicator.setColorFilter(color);
deliveredIndicator.setColorFilter(color);
sentIndicator.setColorFilter(color);
readIndicator.setColorFilter(color);
failedIndicator.setColorFilter(color);
}
}
@@ -4,11 +4,9 @@ package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
@@ -16,13 +14,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.pnikosis.materialishprogress.ProgressWheel;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.mms.DocumentSlide;
import org.thoughtcrime.securesms.mms.SlideClickListener;
import org.thoughtcrime.securesms.util.Util;
@@ -34,7 +26,6 @@ public class DocumentView extends FrameLayout {
private final @NonNull AnimatingToggle controlToggle;
private final @NonNull ImageView downloadButton;
private final @NonNull ProgressWheel downloadProgress;
private final @NonNull View container;
private final @NonNull ViewGroup iconContainer;
private final @NonNull TextView fileName;
@@ -61,7 +52,6 @@ public class DocumentView extends FrameLayout {
this.iconContainer = findViewById(R.id.icon_container);
this.controlToggle = findViewById(R.id.control_toggle);
this.downloadButton = findViewById(R.id.download);
this.downloadProgress = findViewById(R.id.download_progress);
this.fileName = findViewById(R.id.file_name);
this.fileSize = findViewById(R.id.file_size);
this.document = findViewById(R.id.document);
@@ -77,10 +67,6 @@ public class DocumentView extends FrameLayout {
}
}
public void setDownloadClickListener(@Nullable SlideClickListener listener) {
this.downloadListener = listener;
}
public void setDocumentClickListener(@Nullable SlideClickListener listener) {
this.viewListener = listener;
}
@@ -88,17 +74,7 @@ public class DocumentView extends FrameLayout {
public void setDocument(final @NonNull DocumentSlide documentSlide,
final boolean showControls)
{
if (showControls && documentSlide.isPendingDownload()) {
controlToggle.displayQuick(downloadButton);
downloadButton.setOnClickListener(new DownloadClickedListener(documentSlide));
if (downloadProgress.isSpinning()) downloadProgress.stopSpinning();
} else if (showControls && documentSlide.getTransferState() == AttachmentDatabase.TRANSFER_PROGRESS_STARTED) {
controlToggle.displayQuick(downloadProgress);
downloadProgress.spin();
} else {
controlToggle.displayQuick(iconContainer);
if (downloadProgress.isSpinning()) downloadProgress.stopSpinning();
}
controlToggle.displayQuick(iconContainer);
this.documentSlide = documentSlide;
@@ -144,18 +120,6 @@ public class DocumentView extends FrameLayout {
return "";
}
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
public void onEventAsync(final PartProgressEvent event) {
if (documentSlide != null && event.attachment.equals(this.documentSlide.asAttachment())) {
Util.runOnMain(new Runnable() {
@Override
public void run() {
downloadProgress.setInstantProgress(((float) event.progress) / event.total);
}
});
}
}
private class DownloadClickedListener implements View.OnClickListener {
private final @NonNull DocumentSlide slide;
@@ -178,7 +142,7 @@ public class DocumentView extends FrameLayout {
@Override
public void onClick(View v) {
if (!slide.isPendingDownload() && !slide.isInProgress() && viewListener != null) {
if (viewListener != null) {
viewListener.onClick(v, slide);
}
}
@@ -1,122 +0,0 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.Util;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;
public class ExpirationTimerView extends android.support.v7.widget.AppCompatImageView {
private long startedAt;
private long expiresIn;
private boolean visible = false;
private boolean stopped = true;
private final int[] frames = new int[]{ R.drawable.timer00,
R.drawable.timer05,
R.drawable.timer10,
R.drawable.timer15,
R.drawable.timer20,
R.drawable.timer25,
R.drawable.timer30,
R.drawable.timer35,
R.drawable.timer40,
R.drawable.timer45,
R.drawable.timer50,
R.drawable.timer55,
R.drawable.timer60 };
public ExpirationTimerView(Context context) {
super(context);
}
public ExpirationTimerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ExpirationTimerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setExpirationTime(long startedAt, long expiresIn) {
this.startedAt = startedAt;
this.expiresIn = expiresIn;
setPercentComplete(calculateProgress(this.startedAt, this.expiresIn));
}
public void setPercentComplete(float percentage) {
float percentFull = 1 - percentage;
int frame = (int) Math.ceil(percentFull * (frames.length - 1));
frame = Math.max(0, Math.min(frame, frames.length - 1));
setImageResource(frames[frame]);
}
public void startAnimation() {
synchronized (this) {
visible = true;
if (!stopped) return;
else stopped = false;
}
Util.runOnMainDelayed(new AnimationUpdateRunnable(this), calculateAnimationDelay(this.startedAt, this.expiresIn));
}
public void stopAnimation() {
synchronized (this) {
visible = false;
}
}
private float calculateProgress(long startedAt, long expiresIn) {
long progressed = System.currentTimeMillis() - startedAt;
float percentComplete = (float)progressed / (float)expiresIn;
return Math.max(0, Math.min(percentComplete, 1));
}
private long calculateAnimationDelay(long startedAt, long expiresIn) {
long progressed = System.currentTimeMillis() - startedAt;
long remaining = expiresIn - progressed;
if (remaining < TimeUnit.SECONDS.toMillis(30)) {
return 50;
} else {
return 1000;
}
}
private static class AnimationUpdateRunnable implements Runnable {
private final WeakReference<ExpirationTimerView> expirationTimerViewReference;
private AnimationUpdateRunnable(@NonNull ExpirationTimerView expirationTimerView) {
this.expirationTimerViewReference = new WeakReference<>(expirationTimerView);
}
@Override
public void run() {
ExpirationTimerView timerView = expirationTimerViewReference.get();
if (timerView == null) return;
timerView.setExpirationTime(timerView.startedAt, timerView.expiresIn);
synchronized (timerView) {
if (!timerView.visible) {
timerView.stopped = true;
return;
}
}
Util.runOnMainDelayed(this, timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn));
}
}
}

Some files were not shown because too many files have changed in this diff Show More