Compare commits
75 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1e6c14443 | |||
| 58ada319bb | |||
| 45bfab9fbd | |||
| e5d8a2bc28 | |||
| 99b1e2ba43 | |||
| 27d632f17c | |||
| fbd53b3767 | |||
| 8f56d5872a | |||
| 0e75880c24 | |||
| 0e55a4ad5e | |||
| 6eed72a4d2 | |||
| 63f49efee1 | |||
| 7d52e125a3 | |||
| b4c1f214a0 | |||
| 02ea677a3c | |||
| 62e03e7ce4 | |||
| eaabc75501 | |||
| 749ccb1228 | |||
| 5f2f24116d | |||
| beb01e885c | |||
| 86a54970f4 | |||
| 179e8173c9 | |||
| 0a119d9d8e | |||
| ac6b82cc70 | |||
| 8d82552aaa | |||
| 247fb1a357 | |||
| 91c3d8e847 | |||
| 93f30ae34f | |||
| 8df4b6be39 | |||
| 4a9627118a | |||
| 52c495b307 | |||
| c037020918 | |||
| 7a2597186b | |||
| e41279f080 | |||
| 93f781b8dc | |||
| cbf40049a1 | |||
| 11eed61019 | |||
| 28763e686d | |||
| 6edca0eeb6 | |||
| f9c5f133d5 | |||
| c3cd3ceffb | |||
| 4482db9195 | |||
| 6f8db1352a | |||
| 5011f44ddf | |||
| fc6dded69a | |||
| 29731c02f4 | |||
| 728142d08d | |||
| 5c693c14b6 | |||
| a31307171e | |||
| 1a510d8787 | |||
| 7109c6c806 | |||
| 7d85e2c3e8 | |||
| 138144b938 | |||
| 0ed4c5a305 | |||
| 46832b2290 | |||
| 7aad748915 | |||
| 2887d1b807 | |||
| fca9076059 | |||
| 931283f98a | |||
| 2e7de766dd | |||
| 31de65880e | |||
| 7530bcd592 | |||
| 7deab10a9f | |||
| 5c1ff3c110 | |||
| b9d3740f58 | |||
| 87b5d2d246 | |||
| a41e0f7ca0 | |||
| 79b98a48c2 | |||
| e16df36e81 | |||
| 89a9d1b147 | |||
| 1f0f729871 | |||
| 683336d620 | |||
| 5515a665c3 | |||
| 8b5276c9fc | |||
| 5fc731b7e9 |
@@ -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>
|
||||
|
||||
@@ -255,8 +255,8 @@ android {
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
versionCode 392
|
||||
versionName "4.24.7"
|
||||
versionCode 393
|
||||
versionName "0.0.2"
|
||||
applicationId "chat.delta.androidii"
|
||||
|
||||
minSdkVersion 14
|
||||
|
||||
@@ -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 := \
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -5,4 +5,8 @@
|
||||
-keepclassmembers class ** {
|
||||
public void onEvent*(**);
|
||||
}
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 493 B |
|
After Width: | Height: | Size: 412 B |
|
Before Width: | Height: | Size: 478 B After Width: | Height: | Size: 330 B |
|
Before Width: | Height: | Size: 415 B After Width: | Height: | Size: 257 B |
|
Before Width: | Height: | Size: 321 B |
|
After Width: | Height: | Size: 302 B |
|
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 276 B |
|
Before Width: | Height: | Size: 261 B After Width: | Height: | Size: 228 B |
|
Before Width: | Height: | Size: 663 B |
|
After Width: | Height: | Size: 544 B |
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 278 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 752 B |
|
Before Width: | Height: | Size: 1023 B After Width: | Height: | Size: 473 B |
|
Before Width: | Height: | Size: 863 B After Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 998 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 590 B |
|
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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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">
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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" />
|
||||
|
||||
|
||||
@@ -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 -->
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||