From a79931be82d86f18367603d7edaa2306e240719c Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 8 Mar 2023 21:05:56 +0100 Subject: [PATCH 01/69] add DcBackupProvider add receiveBackup() wrappers --- jni/dc_wrapper.c | 64 ++++++++++++++++++++ src/com/b44t/messenger/DcBackupProvider.java | 28 +++++++++ src/com/b44t/messenger/DcContext.java | 4 ++ 3 files changed, 96 insertions(+) create mode 100644 src/com/b44t/messenger/DcBackupProvider.java diff --git a/jni/dc_wrapper.c b/jni/dc_wrapper.c index cef28d0d1b..5299992326 100644 --- a/jni/dc_wrapper.c +++ b/jni/dc_wrapper.c @@ -958,6 +958,21 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcContext_imexHasBackup(JNIEnv *env, j } +JNIEXPORT jlong Java_com_b44t_messenger_DcContext_newBackupProviderCPtr(JNIEnv *env, jobject obj) +{ + return (jlong)dc_backup_provider_new(get_dc_context(env, obj)); +} + + +JNIEXPORT jboolean Java_com_b44t_messenger_DcContext_receiveBackup(JNIEnv *env, jobject obj, jstring qr) +{ + CHAR_REF(qr); + jboolean ret = dc_receive_backup(get_dc_context(env, obj), qrPtr); + CHAR_UNREF(qr); + return ret; +} + + JNIEXPORT jint Java_com_b44t_messenger_DcContext_addAddressBook(JNIEnv *env, jobject obj, jstring adrbook) { CHAR_REF(adrbook); @@ -1956,6 +1971,55 @@ JNIEXPORT void Java_com_b44t_messenger_DcLot_unrefLotCPtr(JNIEnv *env, jobject o } +/******************************************************************************* + * DcBackupProvider + ******************************************************************************/ + + +static dc_backup_provider_t* get_dc_backup_provider(JNIEnv *env, jobject obj) +{ + static jfieldID fid = 0; + if (fid==0) { + jclass cls = (*env)->GetObjectClass(env, obj); + fid = (*env)->GetFieldID(env, cls, "backupProviderCPtr", "J" /*Signature, J=long*/); + } + if (fid) { + return (dc_backup_provider_t*)(*env)->GetLongField(env, obj, fid); + } + return NULL; +} + + +JNIEXPORT void Java_com_b44t_messenger_DcBackupProvider_unrefBackupProviderCPtr(JNIEnv *env, jobject obj) +{ + dc_backup_provider_unref(get_dc_backup_provider(env, obj)); +} + + +JNIEXPORT jstring Java_com_b44t_messenger_DcBackupProvider_getQr(JNIEnv *env, jobject obj) +{ + char* temp = dc_backup_provider_get_qr(get_dc_backup_provider(env, obj)); + jstring ret = JSTRING_NEW(temp); + dc_str_unref(temp); + return ret; +} + + +JNIEXPORT jstring Java_com_b44t_messenger_DcBackupProvider_getQrSvg(JNIEnv *env, jobject obj) +{ + char* temp = dc_backup_provider_get_qr_svg(get_dc_backup_provider(env, obj)); + jstring ret = JSTRING_NEW(temp); + dc_str_unref(temp); + return ret; +} + + +JNIEXPORT void Java_com_b44t_messenger_DcBackupProvider_waitForReceiver(JNIEnv *env, jobject obj) +{ + dc_backup_provider_wait(get_dc_backup_provider(env, obj)); +} + + /******************************************************************************* * DcProvider ******************************************************************************/ diff --git a/src/com/b44t/messenger/DcBackupProvider.java b/src/com/b44t/messenger/DcBackupProvider.java new file mode 100644 index 0000000000..fa65738738 --- /dev/null +++ b/src/com/b44t/messenger/DcBackupProvider.java @@ -0,0 +1,28 @@ +package com.b44t.messenger; + +public class DcBackupProvider { + + public DcBackupProvider(long backupProviderCPtr) { + this.backupProviderCPtr = backupProviderCPtr; + } + + @Override protected void finalize() throws Throwable { + super.finalize(); + unref(); + } + + public void unref() { + if (backupProviderCPtr == 0) { + unrefBackupProviderCPtr(); + backupProviderCPtr = 0; + } + } + + public native String getQr (); + public native String getQrSvg (); + public native void waitForReceiver (); + + // working with raw c-data + private long backupProviderCPtr; // CAVE: the name is referenced in the JNI + private native void unrefBackupProviderCPtr(); +} diff --git a/src/com/b44t/messenger/DcContext.java b/src/com/b44t/messenger/DcContext.java index aaa0c13228..caa7ca647b 100644 --- a/src/com/b44t/messenger/DcContext.java +++ b/src/com/b44t/messenger/DcContext.java @@ -49,6 +49,7 @@ public class DcContext { public final static int DC_QR_FPR_MISMATCH = 220; public final static int DC_QR_FPR_WITHOUT_ADDR = 230; public final static int DC_QR_ACCOUNT = 250; + public final static int DC_QR_BACKUP = 251; public final static int DC_QR_WEBRTC = 260; public final static int DC_QR_ADDR = 320; public final static int DC_QR_TEXT = 330; @@ -148,6 +149,8 @@ public void unref() { public native boolean continueKeyTransfer (int msg_id, String setup_code); public native void imex (int what, String dir); public native String imexHasBackup (String dir); + public DcBackupProvider newBackupProvider () { return new DcBackupProvider(newBackupProviderCPtr()); } + public native boolean receiveBackup (String qr); public native boolean mayBeValidAddr (String addr); public native int lookupContactIdByAddr(String addr); public native int[] getContacts (int flags, String query); @@ -251,4 +254,5 @@ public String getNameNAddr() { private native long getLocationsCPtr (int chat_id, int contact_id, long timestamp_start, long timestamp_end); private native long checkQrCPtr (String qr); private native long getProviderFromEmailWithDnsCPtr (String addr); + private native long newBackupProviderCPtr(); } From b32d853835f2f67e66ebd7b63325e25734a12bb3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 9 Mar 2023 14:22:26 +0100 Subject: [PATCH 02/69] add 'Add Another Device' item to settings --- res/drawable/ic_baseline_devices_24.xml | 5 +++++ res/values/strings.xml | 4 ++++ res/xml/preferences.xml | 5 +++++ .../securesms/ApplicationPreferencesActivity.java | 6 ++++++ 4 files changed, 20 insertions(+) create mode 100644 res/drawable/ic_baseline_devices_24.xml diff --git a/res/drawable/ic_baseline_devices_24.xml b/res/drawable/ic_baseline_devices_24.xml new file mode 100644 index 0000000000..28a7185062 --- /dev/null +++ b/res/drawable/ic_baseline_devices_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 432a3dd3c7..a40d90cded 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -465,6 +465,10 @@ You changed your email address from %1$s to %2$s.\n\nIf you now send a message to a verified group, contacts there will automatically replace the old with your new address.\n\nIt\'s highly advised to set up your old email provider to forward all emails to your new email address. Otherwise you might miss messages of contacts who did not get your new address yet. + + + Add Another Device + Incoming Messages diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index dc788390a7..e9a99dde3a 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -20,6 +20,11 @@ android:icon="@drawable/ic_brightness_6_24dp" android:layout="@layout/preference_item" /> + + Date: Thu, 9 Mar 2023 22:29:57 +0100 Subject: [PATCH 03/69] add android-ifaddrs core-rust uses getifaddrs() which is not available on android ndk. pull in the code from https://github.com/morristech/android-ifaddrs that provides an implementation. --- jni/Android.mk | 1 + jni/utils/android-ifaddrs/README.md | 8 + jni/utils/android-ifaddrs/ifaddrs.c | 600 ++++++++++++++++++++++++++++ jni/utils/android-ifaddrs/ifaddrs.h | 54 +++ 4 files changed, 663 insertions(+) create mode 100644 jni/utils/android-ifaddrs/README.md create mode 100644 jni/utils/android-ifaddrs/ifaddrs.c create mode 100644 jni/utils/android-ifaddrs/ifaddrs.h diff --git a/jni/Android.mk b/jni/Android.mk index 7b7a8ec04a..dec5cd8cf6 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -29,6 +29,7 @@ LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -DAVOID_T LOCAL_SRC_FILES := \ utils/org_thoughtcrime_securesms_util_FileUtils.cpp \ +utils/android-ifaddrs/ifaddrs.c \ dc_wrapper.c include $(BUILD_SHARED_LIBRARY) diff --git a/jni/utils/android-ifaddrs/README.md b/jni/utils/android-ifaddrs/README.md new file mode 100644 index 0000000000..58ce52f15b --- /dev/null +++ b/jni/utils/android-ifaddrs/README.md @@ -0,0 +1,8 @@ +android-ifaddrs +=============== + +An implementation of getifaddrs() for Android, since the NDK does not natively support it. + +Works just like you would expect on regular Linux. License information is present in each file (BSD license). + +[from ] diff --git a/jni/utils/android-ifaddrs/ifaddrs.c b/jni/utils/android-ifaddrs/ifaddrs.c new file mode 100644 index 0000000000..338fff887f --- /dev/null +++ b/jni/utils/android-ifaddrs/ifaddrs.c @@ -0,0 +1,600 @@ +/* +Copyright (c) 2013, Kenneth MacKay +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ifaddrs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct NetlinkList +{ + struct NetlinkList *m_next; + struct nlmsghdr *m_data; + unsigned int m_size; +} NetlinkList; + +static int netlink_socket(void) +{ + int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if(l_socket < 0) + { + return -1; + } + + struct sockaddr_nl l_addr; + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) + { + close(l_socket); + return -1; + } + + return l_socket; +} + +static int netlink_send(int p_socket, int p_request) +{ + char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; + memset(l_buffer, 0, sizeof(l_buffer)); + struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer; + struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); + + l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); + l_hdr->nlmsg_type = p_request; + l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; + l_hdr->nlmsg_pid = 0; + l_hdr->nlmsg_seq = p_socket; + l_msg->rtgen_family = AF_UNSPEC; + + struct sockaddr_nl l_addr; + memset(&l_addr, 0, sizeof(l_addr)); + l_addr.nl_family = AF_NETLINK; + return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); +} + +static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) +{ + struct msghdr l_msg; + struct iovec l_iov = { p_buffer, p_len }; + struct sockaddr_nl l_addr; + int l_result; + + for(;;) + { + l_msg.msg_name = (void *)&l_addr; + l_msg.msg_namelen = sizeof(l_addr); + l_msg.msg_iov = &l_iov; + l_msg.msg_iovlen = 1; + l_msg.msg_control = NULL; + l_msg.msg_controllen = 0; + l_msg.msg_flags = 0; + int l_result = recvmsg(p_socket, &l_msg, 0); + + if(l_result < 0) + { + if(errno == EINTR) + { + continue; + } + return -2; + } + + if(l_msg.msg_flags & MSG_TRUNC) + { // buffer was too small + return -1; + } + return l_result; + } +} + +static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) +{ + size_t l_size = 4096; + void *l_buffer = NULL; + + for(;;) + { + free(l_buffer); + l_buffer = malloc(l_size); + + int l_read = netlink_recv(p_socket, l_buffer, l_size); + *p_size = l_read; + if(l_read == -2) + { + free(l_buffer); + return NULL; + } + if(l_read >= 0) + { + pid_t l_pid = getpid(); + struct nlmsghdr *l_hdr; + for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + *p_done = 1; + break; + } + + if(l_hdr->nlmsg_type == NLMSG_ERROR) + { + free(l_buffer); + return NULL; + } + } + return l_buffer; + } + + l_size *= 2; + } +} + +static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) +{ + NetlinkList *l_item = malloc(sizeof(NetlinkList)); + l_item->m_next = NULL; + l_item->m_data = p_data; + l_item->m_size = p_size; + return l_item; +} + +static void freeResultList(NetlinkList *p_list) +{ + NetlinkList *l_cur; + while(p_list) + { + l_cur = p_list; + p_list = p_list->m_next; + free(l_cur->m_data); + free(l_cur); + } +} + +static NetlinkList *getResultList(int p_socket, int p_request) +{ + if(netlink_send(p_socket, p_request) < 0) + { + return NULL; + } + + NetlinkList *l_list = NULL; + NetlinkList *l_end = NULL; + int l_size; + int l_done = 0; + while(!l_done) + { + struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); + if(!l_hdr) + { // error + freeResultList(l_list); + return NULL; + } + + NetlinkList *l_item = newListItem(l_hdr, l_size); + if(!l_list) + { + l_list = l_item; + } + else + { + l_end->m_next = l_item; + } + l_end = l_item; + } + return l_list; +} + +static size_t maxSize(size_t a, size_t b) +{ + return (a > b ? a : b); +} + +static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) +{ + switch(p_family) + { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + case AF_PACKET: + return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); + default: + return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); + } +} + +static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) +{ + switch(p_family) + { + case AF_INET: + memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); + break; + case AF_INET6: + memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); + break; + case AF_PACKET: + memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); + ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; + break; + default: + memcpy(p_dest->sa_data, p_data, p_size); + break; + } + p_dest->sa_family = p_family; +} + +static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) +{ + if(!*p_resultList) + { + *p_resultList = p_entry; + } + else + { + struct ifaddrs *l_cur = *p_resultList; + while(l_cur->ifa_next) + { + l_cur = l_cur->ifa_next; + } + l_cur->ifa_next = p_entry; + } +} + +static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + size_t l_dataSize = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + struct rtattr *l_rta; + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); + break; + case IFLA_IFNAME: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + case IFLA_STATS: + l_dataSize += NLMSG_ALIGN(l_rtaSize); + break; + default: + break; + } + } + + struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize); + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = ""; + + char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + char *l_addr = l_name + l_nameSize; + char *l_data = l_addr + l_addrSize; + + l_entry->ifa_flags = l_info->ifi_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFLA_ADDRESS: + case IFLA_BROADCAST: + { + size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); + makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; + ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; + if(l_rta->rta_type == IFLA_ADDRESS) + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFLA_IFNAME: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + case IFLA_STATS: + memcpy(l_data, l_rtaData, l_rtaDataSize); + l_entry->ifa_data = l_data; + break; + default: + break; + } + } + + addToEnd(p_resultList, l_entry); + p_links[l_info->ifi_index - 1] = l_entry; +} + +static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); + + size_t l_nameSize = 0; + size_t l_addrSize = 0; + + int l_addedNetmask = 0; + + size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + struct rtattr *l_rta; + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + if(l_info->ifa_family == AF_PACKET) + { + continue; + } + + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_LOCAL: + if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) + { // make room for netmask + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + l_addedNetmask = 1; + } + case IFA_BROADCAST: + l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); + break; + case IFA_LABEL: + l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); + break; + default: + break; + } + } + + struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); + memset(l_entry, 0, sizeof(struct ifaddrs)); + l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name; + + char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); + char *l_addr = l_name + l_nameSize; + + l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags; + + l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); + for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) + { + void *l_rtaData = RTA_DATA(l_rta); + size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); + switch(l_rta->rta_type) + { + case IFA_ADDRESS: + case IFA_BROADCAST: + case IFA_LOCAL: + { + size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); + makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); + if(l_info->ifa_family == AF_INET6) + { + if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) + { + ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; + } + } + + if(l_rta->rta_type == IFA_ADDRESS) + { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + } + else if(l_rta->rta_type == IFA_LOCAL) + { + if(l_entry->ifa_addr) + { + l_entry->ifa_dstaddr = l_entry->ifa_addr; + } + l_entry->ifa_addr = (struct sockaddr *)l_addr; + } + else + { + l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; + } + l_addr += NLMSG_ALIGN(l_addrLen); + break; + } + case IFA_LABEL: + strncpy(l_name, l_rtaData, l_rtaDataSize); + l_name[l_rtaDataSize] = '\0'; + l_entry->ifa_name = l_name; + break; + default: + break; + } + } + + if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) + { + unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); + unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); + char l_mask[16] = {0}; + unsigned i; + for(i=0; i<(l_prefix/8); ++i) + { + l_mask[i] = 0xff; + } + l_mask[i] = 0xff << (8 - (l_prefix % 8)); + + makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); + l_entry->ifa_netmask = (struct sockaddr *)l_addr; + } + + addToEnd(p_resultList, l_entry); +} + +static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList) +{ + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + interpretLink(l_hdr, p_links, p_resultList); + } + else if(l_hdr->nlmsg_type == RTM_NEWADDR) + { + interpretAddr(l_hdr, p_links, p_resultList); + } + } + } +} + +static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList) +{ + unsigned l_links = 0; + pid_t l_pid = getpid(); + for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) + { + unsigned int l_nlsize = p_netlinkList->m_size; + struct nlmsghdr *l_hdr; + for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) + { + if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) + { + continue; + } + + if(l_hdr->nlmsg_type == NLMSG_DONE) + { + break; + } + + if(l_hdr->nlmsg_type == RTM_NEWLINK) + { + ++l_links; + } + } + } + + return l_links; +} + +int getifaddrs(struct ifaddrs **ifap) +{ + if(!ifap) + { + return -1; + } + *ifap = NULL; + + int l_socket = netlink_socket(); + if(l_socket < 0) + { + return -1; + } + + NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK); + if(!l_linkResults) + { + close(l_socket); + return -1; + } + + NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR); + if(!l_addrResults) + { + close(l_socket); + freeResultList(l_linkResults); + return -1; + } + + unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults); + struct ifaddrs *l_links[l_numLinks]; + memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *)); + + interpret(l_socket, l_linkResults, l_links, ifap); + interpret(l_socket, l_addrResults, l_links, ifap); + + freeResultList(l_linkResults); + freeResultList(l_addrResults); + close(l_socket); + return 0; +} + +void freeifaddrs(struct ifaddrs *ifa) +{ + struct ifaddrs *l_cur; + while(ifa) + { + l_cur = ifa; + ifa = ifa->ifa_next; + free(l_cur); + } +} diff --git a/jni/utils/android-ifaddrs/ifaddrs.h b/jni/utils/android-ifaddrs/ifaddrs.h new file mode 100644 index 0000000000..9cd19fec12 --- /dev/null +++ b/jni/utils/android-ifaddrs/ifaddrs.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp + */ + +#ifndef _IFADDRS_H_ +#define _IFADDRS_H_ + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +/* + * This may have been defined in . Note that if is + * to be included it must be included before this header file. + */ +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +#include + +__BEGIN_DECLS +extern int getifaddrs(struct ifaddrs **ifap); +extern void freeifaddrs(struct ifaddrs *ifa); +__END_DECLS + +#endif From c47a55b652595a6077473ef07f8a3d4048abcb40 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 9 Mar 2023 23:25:52 +0100 Subject: [PATCH 04/69] add BackupProviderActivity --- AndroidManifest.xml | 4 ++ res/layout/backup_provider_activity.xml | 9 ++++ .../ApplicationPreferencesActivity.java | 3 +- .../securesms/qr/BackupProviderActivity.java | 53 +++++++++++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 res/layout/backup_provider_activity.xml create mode 100644 src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 2c0e15a637..f557f88194 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -294,6 +294,10 @@ android:theme="@style/TextSecure.LightTheme" android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> + + diff --git a/res/layout/backup_provider_activity.xml b/res/layout/backup_provider_activity.xml new file mode 100644 index 0000000000..1ce304054e --- /dev/null +++ b/res/layout/backup_provider_activity.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 565ce3e371..71184ff9f3 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -51,6 +51,7 @@ import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.Prefs; +import org.thoughtcrime.securesms.qr.BackupProviderActivity; /** * The Activity for application preference display and management. @@ -261,7 +262,7 @@ public boolean onPreferenceClick(Preference preference) { fragment = new ChatsPreferenceFragment(); break; case PREFERENCE_CATEGORY_ADD_ANOTHER_DEVICE: - // TODO + startActivity(new Intent(getActivity(), BackupProviderActivity.class)); break; case PREFERENCE_CATEGORY_ADVANCED: fragment = new AdvancedPreferenceFragment(); diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java new file mode 100644 index 0000000000..7909c9405b --- /dev/null +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java @@ -0,0 +1,53 @@ +package org.thoughtcrime.securesms.qr; + +import android.os.Bundle; +import android.view.MenuItem; + +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.util.DynamicLanguage; +import org.thoughtcrime.securesms.util.DynamicTheme; + +public class BackupProviderActivity extends AppCompatActivity { + + private final DynamicTheme dynamicTheme = new DynamicTheme(); + private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); + + QrShowFragment fragment; // TODO: create BackupProviderFragment + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + dynamicTheme.onCreate(this); + dynamicLanguage.onCreate(this); + + setContentView(R.layout.backup_provider_activity); + fragment = (QrShowFragment)getSupportFragmentManager().findFragmentById(R.id.qrScannerFragment); + + ActionBar supportActionBar = getSupportActionBar(); + supportActionBar.setDisplayHomeAsUpEnabled(true); + supportActionBar.setTitle(R.string.add_another_device); + } + + @Override + protected void onResume() { + super.onResume(); + dynamicTheme.onResume(this); + dynamicLanguage.onResume(this); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + super.onOptionsItemSelected(item); + + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + } + + return false; + } +} From c6cfd5461d6894f53120a28fb5b721420c7daa01 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 10 Mar 2023 21:17:52 +0100 Subject: [PATCH 05/69] make SVG-hack reusable --- .../securesms/qr/QrShowFragment.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/QrShowFragment.java b/src/org/thoughtcrime/securesms/qr/QrShowFragment.java index a09bf89668..803ce90980 100644 --- a/src/org/thoughtcrime/securesms/qr/QrShowFragment.java +++ b/src/org/thoughtcrime/securesms/qr/QrShowFragment.java @@ -86,14 +86,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, SVGImageView imageView = view.findViewById(R.id.qrImage); try { - String svg_txt = dcContext.getSecurejoinQrSvg(chatId); - - // HACK: move avatar-letter down, baseline alignment not working, - // see https://github.com/deltachat/deltachat-core-rust/pull/2815#issuecomment-978067378 , - // suggestions welcome :) - svg_txt = svg_txt.replace("y=\"281.136\"", "y=\"290\""); - - SVG svg = SVG.getFromString(svg_txt); + SVG svg = SVG.getFromString(fixSVG(dcContext.getSecurejoinQrSvg(chatId))); imageView.setSVG(svg); } catch (SVGParseException e) { e.printStackTrace(); @@ -102,6 +95,13 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, return view; } + public static String fixSVG(String svg) { + // HACK: move avatar-letter down, baseline alignment not working, + // see https://github.com/deltachat/deltachat-core-rust/pull/2815#issuecomment-978067378 , + // suggestions welcome :) + return svg.replace("y=\"281.136\"", "y=\"296\""); + } + public void shareQr() { try { File file = new File(getActivity().getExternalCacheDir(), "share-qr.png"); From 412d383f88188149f207d9d17ad406873e0d08e1 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 10 Mar 2023 22:24:34 +0100 Subject: [PATCH 06/69] add BackupProviderFragment --- res/layout/backup_provider_activity.xml | 4 +- res/layout/backup_provider_fragment.xml | 26 ++++++ .../securesms/qr/BackupProviderActivity.java | 4 +- .../securesms/qr/BackupProviderFragment.java | 90 +++++++++++++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 res/layout/backup_provider_fragment.xml create mode 100644 src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java diff --git a/res/layout/backup_provider_activity.xml b/res/layout/backup_provider_activity.xml index 1ce304054e..87e0d3a19c 100644 --- a/res/layout/backup_provider_activity.xml +++ b/res/layout/backup_provider_activity.xml @@ -1,9 +1,9 @@ + android:id="@+id/backup_provider_fragment"> diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml new file mode 100644 index 0000000000..22ea7608fe --- /dev/null +++ b/res/layout/backup_provider_fragment.xml @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java index 7909c9405b..14cc7f5b82 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java @@ -15,7 +15,7 @@ public class BackupProviderActivity extends AppCompatActivity { private final DynamicTheme dynamicTheme = new DynamicTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); - QrShowFragment fragment; // TODO: create BackupProviderFragment + BackupProviderFragment fragment; @Override protected void onCreate(Bundle savedInstanceState) { @@ -24,7 +24,7 @@ protected void onCreate(Bundle savedInstanceState) { dynamicLanguage.onCreate(this); setContentView(R.layout.backup_provider_activity); - fragment = (QrShowFragment)getSupportFragmentManager().findFragmentById(R.id.qrScannerFragment); + fragment = (BackupProviderFragment)getSupportFragmentManager().findFragmentById(R.id.backup_provider_fragment); ActionBar supportActionBar = getSupportActionBar(); supportActionBar.setDisplayHomeAsUpEnabled(true); diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java new file mode 100644 index 0000000000..59ab15e14f --- /dev/null +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -0,0 +1,90 @@ +package org.thoughtcrime.securesms.qr; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; + +import com.b44t.messenger.DcBackupProvider; +import com.b44t.messenger.DcContext; +import com.b44t.messenger.DcEvent; + +import com.caverock.androidsvg.SVGImageView; +import com.caverock.androidsvg.SVG; +import com.caverock.androidsvg.SVGParseException; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.connect.DcEventCenter; +import org.thoughtcrime.securesms.connect.DcHelper; +import org.thoughtcrime.securesms.util.Util; + +public class BackupProviderFragment extends Fragment implements DcEventCenter.DcEventDelegate { + + private final static String TAG = BackupProviderFragment.class.getSimpleName(); + + private DcContext dcContext; + private DcBackupProvider dcBackupProvider; + + private TextView statusLine; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // keeping the screen on also avoids falling back from IDLE to POLL + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); + statusLine = view.findViewById(R.id.status_line); + statusLine.setText(R.string.one_moment); + + dcContext = DcHelper.getContext(getActivity()); + dcContext.stopIo(); + DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_IMEX_PROGRESS, this); + + new Thread(() -> { + dcBackupProvider = dcContext.newBackupProvider(); + if (dcBackupProvider != null) { + Util.runOnMain(() -> { + statusLine.setVisibility(View.GONE); + SVGImageView imageView = view.findViewById(R.id.qrImage); + try { + SVG svg = SVG.getFromString(QrShowFragment.fixSVG(dcBackupProvider.getQrSvg())); + imageView.setSVG(svg); + } catch (SVGParseException e) { + e.printStackTrace(); + } + new Thread(() -> { + dcBackupProvider.waitForReceiver(); + }).start(); + }); + } + }).start(); + + return view; + } + + @Override + public void onDestroyView() { + dcContext.stopOngoingProcess(); + dcContext.startIo(); + dcBackupProvider.unref(); + super.onDestroyView(); + DcHelper.getEventCenter(getActivity()).removeObservers(this); + } + + @Override + public void handleEvent(@NonNull DcEvent event) { + if (event.getId() == DcContext.DC_EVENT_IMEX_PROGRESS) { + Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + event.getData1Int()); + // TODO: update status line once core sends events during prepare and wait + } + } +} From 61d38c40c8052cfeda6973b764f6950d93d5f028 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 11 Mar 2023 21:01:54 +0100 Subject: [PATCH 07/69] prepare scanning backup codes --- res/layout/welcome_activity.xml | 2 +- res/values/strings.xml | 4 ++- res/xml/preferences.xml | 4 +-- .../ApplicationPreferencesActivity.java | 8 +++--- .../securesms/WelcomeActivity.java | 27 +++++++++++++------ .../securesms/qr/BackupProviderActivity.java | 2 +- .../securesms/qr/QrCodeHandler.java | 10 +++++++ 7 files changed, 40 insertions(+), 17 deletions(-) diff --git a/res/layout/welcome_activity.xml b/res/layout/welcome_activity.xml index 109a50727c..e4bfe53e86 100644 --- a/res/layout/welcome_activity.xml +++ b/res/layout/welcome_activity.xml @@ -68,7 +68,7 @@ android:layout_height="wrap_content" android:paddingLeft="24dp" android:paddingRight="24dp" - android:text="@string/scan_invitation_code"/> + android:text="@string/qrscan_title"/> diff --git a/res/values/strings.xml b/res/values/strings.xml index a40d90cded..89711c46c0 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -467,7 +467,9 @@ - Add Another Device + Add Another Device + Copy the account from the other device to this device? Both devices will work independently afterwards. + During copying, both devices must be on the same wifi or network. diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index e9a99dde3a..fa1624b8ce 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -20,8 +20,8 @@ android:icon="@drawable/ic_brightness_6_24dp" android:layout="@layout/preference_item" /> - diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 71184ff9f3..c4e5f37723 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -70,7 +70,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA private static final String PREFERENCE_CATEGORY_NOTIFICATIONS = "preference_category_notifications"; private static final String PREFERENCE_CATEGORY_APPEARANCE = "preference_category_appearance"; private static final String PREFERENCE_CATEGORY_CHATS = "preference_category_chats"; - private static final String PREFERENCE_CATEGORY_ADD_ANOTHER_DEVICE = "preference_category_add_another_device"; + private static final String PREFERENCE_CATEGORY_MULTIDEVICE = "preference_category_multidevice"; private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced"; private static final String PREFERENCE_CATEGORY_CONNECTIVITY = "preference_category_connectivity"; private static final String PREFERENCE_CATEGORY_HELP = "preference_category_help"; @@ -151,8 +151,8 @@ public void onCreate(Bundle icicle) { .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_APPEARANCE)); this.findPreference(PREFERENCE_CATEGORY_CHATS) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_CHATS)); - this.findPreference(PREFERENCE_CATEGORY_ADD_ANOTHER_DEVICE) - .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADD_ANOTHER_DEVICE)); + this.findPreference(PREFERENCE_CATEGORY_MULTIDEVICE) + .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_MULTIDEVICE)); this.findPreference(PREFERENCE_CATEGORY_ADVANCED) .setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_ADVANCED)); @@ -261,7 +261,7 @@ public boolean onPreferenceClick(Preference preference) { case PREFERENCE_CATEGORY_CHATS: fragment = new ChatsPreferenceFragment(); break; - case PREFERENCE_CATEGORY_ADD_ANOTHER_DEVICE: + case PREFERENCE_CATEGORY_MULTIDEVICE: startActivity(new Intent(getActivity(), BackupProviderActivity.class)); break; case PREFERENCE_CATEGORY_ADVANCED: diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java index f5f5fecb98..ca481222fb 100644 --- a/src/org/thoughtcrime/securesms/WelcomeActivity.java +++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java @@ -298,15 +298,16 @@ private void startQrAccountCreation(String qrCode) DcHelper.getEventCenter(this).captureNextError(); - if (!dcContext.setConfigFromQr(qrCode)) { - progressError(dcContext.getLastError()); - return; + if (dcContext.checkQr(qrCode).getState() == DcContext.DC_QR_BACKUP) { + progressError("TODO!!"); + } else { + if (!dcContext.setConfigFromQr(qrCode)) { + progressError(dcContext.getLastError()); + return; + } + DcHelper.getAccounts(this).stopIo(); + dcContext.configure(); } - - // calling configure() results in - // receiving multiple DC_EVENT_CONFIGURE_PROGRESS events - DcHelper.getAccounts(this).stopIo(); - dcContext.configure(); } private void progressError(String data2) { @@ -426,6 +427,16 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { .show(); break; + case DcContext.DC_QR_BACKUP: + new AlertDialog.Builder(this) + .setTitle(R.string.multidevice_title) + .setMessage(getString(R.string.multidevice_receiver_scanning_ask) + "\n\n" + getString(R.string.multidevice_same_network_hint)) + .setPositiveButton(R.string.perm_continue, (dialog, which) -> startQrAccountCreation(qrRaw)) + .setNegativeButton(R.string.cancel, null) + .setCancelable(false) + .show(); + break; + default: new AlertDialog.Builder(this) .setMessage(R.string.qraccount_qr_code_cannot_be_used) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java index 14cc7f5b82..035fc966e8 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java @@ -28,7 +28,7 @@ protected void onCreate(Bundle savedInstanceState) { ActionBar supportActionBar = getSupportActionBar(); supportActionBar.setDisplayHomeAsUpEnabled(true); - supportActionBar.setTitle(R.string.add_another_device); + supportActionBar.setTitle(R.string.multidevice_title); } @Override diff --git a/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java b/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java index fc06b3f139..ca3a5fa8fb 100644 --- a/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java +++ b/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java @@ -76,6 +76,16 @@ public void handleQrData(String rawString) { builder.setCancelable(false); break; + case DcContext.DC_QR_BACKUP: + builder.setTitle(R.string.multidevice_title); + builder.setMessage(activity.getString(R.string.multidevice_receiver_scanning_ask) + "\n\n" + activity.getString(R.string.multidevice_same_network_hint)); + builder.setPositiveButton(R.string.perm_continue, (dialog, which) -> { + AccountManager.getInstance().addAccountFromQr(activity, rawString); + }); + builder.setNegativeButton(R.string.cancel, null); + builder.setCancelable(false); + break; + case DcContext.DC_QR_LOGIN: String email = qrParsed.getText1(); builder.setMessage(activity.getString(R.string.qrlogin_ask_login_another, email)); From 3ec395ebb283831a406d2e833498a07f1e9a232e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 13 Mar 2023 13:52:27 +0100 Subject: [PATCH 08/69] Revert "add android-ifaddrs" This reverts commit 33b1424427620396f282805d37f8e05c67758546. --- jni/Android.mk | 1 - jni/utils/android-ifaddrs/README.md | 8 - jni/utils/android-ifaddrs/ifaddrs.c | 600 ---------------------------- jni/utils/android-ifaddrs/ifaddrs.h | 54 --- 4 files changed, 663 deletions(-) delete mode 100644 jni/utils/android-ifaddrs/README.md delete mode 100644 jni/utils/android-ifaddrs/ifaddrs.c delete mode 100644 jni/utils/android-ifaddrs/ifaddrs.h diff --git a/jni/Android.mk b/jni/Android.mk index dec5cd8cf6..7b7a8ec04a 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -29,7 +29,6 @@ LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -DAVOID_T LOCAL_SRC_FILES := \ utils/org_thoughtcrime_securesms_util_FileUtils.cpp \ -utils/android-ifaddrs/ifaddrs.c \ dc_wrapper.c include $(BUILD_SHARED_LIBRARY) diff --git a/jni/utils/android-ifaddrs/README.md b/jni/utils/android-ifaddrs/README.md deleted file mode 100644 index 58ce52f15b..0000000000 --- a/jni/utils/android-ifaddrs/README.md +++ /dev/null @@ -1,8 +0,0 @@ -android-ifaddrs -=============== - -An implementation of getifaddrs() for Android, since the NDK does not natively support it. - -Works just like you would expect on regular Linux. License information is present in each file (BSD license). - -[from ] diff --git a/jni/utils/android-ifaddrs/ifaddrs.c b/jni/utils/android-ifaddrs/ifaddrs.c deleted file mode 100644 index 338fff887f..0000000000 --- a/jni/utils/android-ifaddrs/ifaddrs.c +++ /dev/null @@ -1,600 +0,0 @@ -/* -Copyright (c) 2013, Kenneth MacKay -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "ifaddrs.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct NetlinkList -{ - struct NetlinkList *m_next; - struct nlmsghdr *m_data; - unsigned int m_size; -} NetlinkList; - -static int netlink_socket(void) -{ - int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if(l_socket < 0) - { - return -1; - } - - struct sockaddr_nl l_addr; - memset(&l_addr, 0, sizeof(l_addr)); - l_addr.nl_family = AF_NETLINK; - if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) - { - close(l_socket); - return -1; - } - - return l_socket; -} - -static int netlink_send(int p_socket, int p_request) -{ - char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; - memset(l_buffer, 0, sizeof(l_buffer)); - struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer; - struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); - - l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); - l_hdr->nlmsg_type = p_request; - l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; - l_hdr->nlmsg_pid = 0; - l_hdr->nlmsg_seq = p_socket; - l_msg->rtgen_family = AF_UNSPEC; - - struct sockaddr_nl l_addr; - memset(&l_addr, 0, sizeof(l_addr)); - l_addr.nl_family = AF_NETLINK; - return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); -} - -static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) -{ - struct msghdr l_msg; - struct iovec l_iov = { p_buffer, p_len }; - struct sockaddr_nl l_addr; - int l_result; - - for(;;) - { - l_msg.msg_name = (void *)&l_addr; - l_msg.msg_namelen = sizeof(l_addr); - l_msg.msg_iov = &l_iov; - l_msg.msg_iovlen = 1; - l_msg.msg_control = NULL; - l_msg.msg_controllen = 0; - l_msg.msg_flags = 0; - int l_result = recvmsg(p_socket, &l_msg, 0); - - if(l_result < 0) - { - if(errno == EINTR) - { - continue; - } - return -2; - } - - if(l_msg.msg_flags & MSG_TRUNC) - { // buffer was too small - return -1; - } - return l_result; - } -} - -static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) -{ - size_t l_size = 4096; - void *l_buffer = NULL; - - for(;;) - { - free(l_buffer); - l_buffer = malloc(l_size); - - int l_read = netlink_recv(p_socket, l_buffer, l_size); - *p_size = l_read; - if(l_read == -2) - { - free(l_buffer); - return NULL; - } - if(l_read >= 0) - { - pid_t l_pid = getpid(); - struct nlmsghdr *l_hdr; - for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) - { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) - { - continue; - } - - if(l_hdr->nlmsg_type == NLMSG_DONE) - { - *p_done = 1; - break; - } - - if(l_hdr->nlmsg_type == NLMSG_ERROR) - { - free(l_buffer); - return NULL; - } - } - return l_buffer; - } - - l_size *= 2; - } -} - -static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) -{ - NetlinkList *l_item = malloc(sizeof(NetlinkList)); - l_item->m_next = NULL; - l_item->m_data = p_data; - l_item->m_size = p_size; - return l_item; -} - -static void freeResultList(NetlinkList *p_list) -{ - NetlinkList *l_cur; - while(p_list) - { - l_cur = p_list; - p_list = p_list->m_next; - free(l_cur->m_data); - free(l_cur); - } -} - -static NetlinkList *getResultList(int p_socket, int p_request) -{ - if(netlink_send(p_socket, p_request) < 0) - { - return NULL; - } - - NetlinkList *l_list = NULL; - NetlinkList *l_end = NULL; - int l_size; - int l_done = 0; - while(!l_done) - { - struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); - if(!l_hdr) - { // error - freeResultList(l_list); - return NULL; - } - - NetlinkList *l_item = newListItem(l_hdr, l_size); - if(!l_list) - { - l_list = l_item; - } - else - { - l_end->m_next = l_item; - } - l_end = l_item; - } - return l_list; -} - -static size_t maxSize(size_t a, size_t b) -{ - return (a > b ? a : b); -} - -static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) -{ - switch(p_family) - { - case AF_INET: - return sizeof(struct sockaddr_in); - case AF_INET6: - return sizeof(struct sockaddr_in6); - case AF_PACKET: - return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); - default: - return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); - } -} - -static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) -{ - switch(p_family) - { - case AF_INET: - memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); - break; - case AF_INET6: - memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); - break; - case AF_PACKET: - memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); - ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; - break; - default: - memcpy(p_dest->sa_data, p_data, p_size); - break; - } - p_dest->sa_family = p_family; -} - -static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) -{ - if(!*p_resultList) - { - *p_resultList = p_entry; - } - else - { - struct ifaddrs *l_cur = *p_resultList; - while(l_cur->ifa_next) - { - l_cur = l_cur->ifa_next; - } - l_cur->ifa_next = p_entry; - } -} - -static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) -{ - struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); - - size_t l_nameSize = 0; - size_t l_addrSize = 0; - size_t l_dataSize = 0; - - size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); - struct rtattr *l_rta; - for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - void *l_rtaData = RTA_DATA(l_rta); - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - switch(l_rta->rta_type) - { - case IFLA_ADDRESS: - case IFLA_BROADCAST: - l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); - break; - case IFLA_IFNAME: - l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); - break; - case IFLA_STATS: - l_dataSize += NLMSG_ALIGN(l_rtaSize); - break; - default: - break; - } - } - - struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize); - memset(l_entry, 0, sizeof(struct ifaddrs)); - l_entry->ifa_name = ""; - - char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); - char *l_addr = l_name + l_nameSize; - char *l_data = l_addr + l_addrSize; - - l_entry->ifa_flags = l_info->ifi_flags; - - l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); - for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - void *l_rtaData = RTA_DATA(l_rta); - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - switch(l_rta->rta_type) - { - case IFLA_ADDRESS: - case IFLA_BROADCAST: - { - size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); - makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); - ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; - ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; - if(l_rta->rta_type == IFLA_ADDRESS) - { - l_entry->ifa_addr = (struct sockaddr *)l_addr; - } - else - { - l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; - } - l_addr += NLMSG_ALIGN(l_addrLen); - break; - } - case IFLA_IFNAME: - strncpy(l_name, l_rtaData, l_rtaDataSize); - l_name[l_rtaDataSize] = '\0'; - l_entry->ifa_name = l_name; - break; - case IFLA_STATS: - memcpy(l_data, l_rtaData, l_rtaDataSize); - l_entry->ifa_data = l_data; - break; - default: - break; - } - } - - addToEnd(p_resultList, l_entry); - p_links[l_info->ifi_index - 1] = l_entry; -} - -static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) -{ - struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); - - size_t l_nameSize = 0; - size_t l_addrSize = 0; - - int l_addedNetmask = 0; - - size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); - struct rtattr *l_rta; - for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - void *l_rtaData = RTA_DATA(l_rta); - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - if(l_info->ifa_family == AF_PACKET) - { - continue; - } - - switch(l_rta->rta_type) - { - case IFA_ADDRESS: - case IFA_LOCAL: - if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) - { // make room for netmask - l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); - l_addedNetmask = 1; - } - case IFA_BROADCAST: - l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); - break; - case IFA_LABEL: - l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); - break; - default: - break; - } - } - - struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); - memset(l_entry, 0, sizeof(struct ifaddrs)); - l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name; - - char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); - char *l_addr = l_name + l_nameSize; - - l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags; - - l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); - for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) - { - void *l_rtaData = RTA_DATA(l_rta); - size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); - switch(l_rta->rta_type) - { - case IFA_ADDRESS: - case IFA_BROADCAST: - case IFA_LOCAL: - { - size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); - makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); - if(l_info->ifa_family == AF_INET6) - { - if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) - { - ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; - } - } - - if(l_rta->rta_type == IFA_ADDRESS) - { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address - if(l_entry->ifa_addr) - { - l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; - } - else - { - l_entry->ifa_addr = (struct sockaddr *)l_addr; - } - } - else if(l_rta->rta_type == IFA_LOCAL) - { - if(l_entry->ifa_addr) - { - l_entry->ifa_dstaddr = l_entry->ifa_addr; - } - l_entry->ifa_addr = (struct sockaddr *)l_addr; - } - else - { - l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; - } - l_addr += NLMSG_ALIGN(l_addrLen); - break; - } - case IFA_LABEL: - strncpy(l_name, l_rtaData, l_rtaDataSize); - l_name[l_rtaDataSize] = '\0'; - l_entry->ifa_name = l_name; - break; - default: - break; - } - } - - if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) - { - unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); - unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); - char l_mask[16] = {0}; - unsigned i; - for(i=0; i<(l_prefix/8); ++i) - { - l_mask[i] = 0xff; - } - l_mask[i] = 0xff << (8 - (l_prefix % 8)); - - makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); - l_entry->ifa_netmask = (struct sockaddr *)l_addr; - } - - addToEnd(p_resultList, l_entry); -} - -static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList) -{ - pid_t l_pid = getpid(); - for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) - { - unsigned int l_nlsize = p_netlinkList->m_size; - struct nlmsghdr *l_hdr; - for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) - { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) - { - continue; - } - - if(l_hdr->nlmsg_type == NLMSG_DONE) - { - break; - } - - if(l_hdr->nlmsg_type == RTM_NEWLINK) - { - interpretLink(l_hdr, p_links, p_resultList); - } - else if(l_hdr->nlmsg_type == RTM_NEWADDR) - { - interpretAddr(l_hdr, p_links, p_resultList); - } - } - } -} - -static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList) -{ - unsigned l_links = 0; - pid_t l_pid = getpid(); - for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) - { - unsigned int l_nlsize = p_netlinkList->m_size; - struct nlmsghdr *l_hdr; - for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) - { - if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) - { - continue; - } - - if(l_hdr->nlmsg_type == NLMSG_DONE) - { - break; - } - - if(l_hdr->nlmsg_type == RTM_NEWLINK) - { - ++l_links; - } - } - } - - return l_links; -} - -int getifaddrs(struct ifaddrs **ifap) -{ - if(!ifap) - { - return -1; - } - *ifap = NULL; - - int l_socket = netlink_socket(); - if(l_socket < 0) - { - return -1; - } - - NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK); - if(!l_linkResults) - { - close(l_socket); - return -1; - } - - NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR); - if(!l_addrResults) - { - close(l_socket); - freeResultList(l_linkResults); - return -1; - } - - unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults); - struct ifaddrs *l_links[l_numLinks]; - memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *)); - - interpret(l_socket, l_linkResults, l_links, ifap); - interpret(l_socket, l_addrResults, l_links, ifap); - - freeResultList(l_linkResults); - freeResultList(l_addrResults); - close(l_socket); - return 0; -} - -void freeifaddrs(struct ifaddrs *ifa) -{ - struct ifaddrs *l_cur; - while(ifa) - { - l_cur = ifa; - ifa = ifa->ifa_next; - free(l_cur); - } -} diff --git a/jni/utils/android-ifaddrs/ifaddrs.h b/jni/utils/android-ifaddrs/ifaddrs.h deleted file mode 100644 index 9cd19fec12..0000000000 --- a/jni/utils/android-ifaddrs/ifaddrs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 1995, 1999 - * Berkeley Software Design, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp - */ - -#ifndef _IFADDRS_H_ -#define _IFADDRS_H_ - -struct ifaddrs { - struct ifaddrs *ifa_next; - char *ifa_name; - unsigned int ifa_flags; - struct sockaddr *ifa_addr; - struct sockaddr *ifa_netmask; - struct sockaddr *ifa_dstaddr; - void *ifa_data; -}; - -/* - * This may have been defined in . Note that if is - * to be included it must be included before this header file. - */ -#ifndef ifa_broadaddr -#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ -#endif - -#include - -__BEGIN_DECLS -extern int getifaddrs(struct ifaddrs **ifap); -extern void freeifaddrs(struct ifaddrs *ifa); -__END_DECLS - -#endif From 4ad021df77979a9830c533cde2c0678e2592d866 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 13 Mar 2023 16:53:14 +0100 Subject: [PATCH 09/69] more logging --- src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 59ab15e14f..737451d065 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -50,7 +50,9 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_IMEX_PROGRESS, this); new Thread(() -> { + Log.i(TAG, "##### newBackupProvider()"); dcBackupProvider = dcContext.newBackupProvider(); + Log.i(TAG, "##### newBackupProvider() returned"); if (dcBackupProvider != null) { Util.runOnMain(() -> { statusLine.setVisibility(View.GONE); @@ -62,7 +64,9 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, e.printStackTrace(); } new Thread(() -> { + Log.i(TAG, "##### waitForReceiver() with qr: "+dcBackupProvider.getQr()); dcBackupProvider.waitForReceiver(); + Log.i(TAG, "##### done waiting"); }).start(); }); } From c10c9814bb6cf9b3b340adfb7d30a09225e1ea36 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 14 Mar 2023 16:53:26 +0100 Subject: [PATCH 10/69] call receiveBackup() on scanning DC_QR_BACKUP --- src/org/thoughtcrime/securesms/WelcomeActivity.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java index ca481222fb..f69eeb8d43 100644 --- a/src/org/thoughtcrime/securesms/WelcomeActivity.java +++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java @@ -299,11 +299,16 @@ private void startQrAccountCreation(String qrCode) DcHelper.getEventCenter(this).captureNextError(); if (dcContext.checkQr(qrCode).getState() == DcContext.DC_QR_BACKUP) { - progressError("TODO!!"); + DcHelper.getAccounts(this).stopIo(); + new Thread(() -> { + Log.i(TAG, "##### receiveBackup() with qr: "+qrCode); + boolean res = dcContext.receiveBackup(qrCode); + Log.i(TAG, "##### receiveBackup() done with result: "+res); + }).start(); } else { if (!dcContext.setConfigFromQr(qrCode)) { - progressError(dcContext.getLastError()); - return; + progressError(dcContext.getLastError()); + return; } DcHelper.getAccounts(this).stopIo(); dcContext.configure(); From cf571e1964c618dc5905f08234c3f853cce414f2 Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 14 Mar 2023 18:38:50 +0000 Subject: [PATCH 11/69] Fixup for recvmmsg fallback --- jni/dc_wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jni/dc_wrapper.c b/jni/dc_wrapper.c index 5299992326..b08a5f2677 100644 --- a/jni/dc_wrapper.c +++ b/jni/dc_wrapper.c @@ -39,7 +39,7 @@ int sendmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int recvmmsg(int sockfd, struct mmsghdr *msgvec, unsigned int vlen, int flags, struct timespec *timeout) { - if (flags != -1) { + if (flags != 0) { // Not supported by the fallback. return -1; } From c8a889f51f5f527152a5a851f3520d0f8ee8cfe4 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 16 Mar 2023 22:41:11 +0100 Subject: [PATCH 12/69] protect BackupProviderActivity by system secret --- .../securesms/ApplicationPreferencesActivity.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index c4e5f37723..7fe83e16a8 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -46,12 +46,14 @@ import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment; import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment; import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment; +import org.thoughtcrime.securesms.preferences.ListSummaryPreferenceFragment; import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment; import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.Prefs; import org.thoughtcrime.securesms.qr.BackupProviderActivity; +import org.thoughtcrime.securesms.util.ScreenLockUtil; /** * The Activity for application preference display and management. @@ -107,6 +109,10 @@ public void onResume() { protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK && requestCode == ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS) { + startActivity(new Intent(this, BackupProviderActivity.class)); + return; + } Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content); fragment.onActivityResult(requestCode, resultCode, data); } @@ -262,7 +268,9 @@ public boolean onPreferenceClick(Preference preference) { fragment = new ChatsPreferenceFragment(); break; case PREFERENCE_CATEGORY_MULTIDEVICE: - startActivity(new Intent(getActivity(), BackupProviderActivity.class)); + if (!ScreenLockUtil.applyScreenLock(getActivity(), getString(R.string.multidevice_title), ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS)) { + startActivity(new Intent(getActivity(), BackupProviderActivity.class)); + } break; case PREFERENCE_CATEGORY_ADVANCED: fragment = new AdvancedPreferenceFragment(); From eb2a9f4675d7619533a208fae78ec5d3fc9d765e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 16 Mar 2023 23:48:56 +0100 Subject: [PATCH 13/69] show transfer progress as provided form the core; hide qr-code once scanned --- .../securesms/qr/BackupProviderFragment.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 737451d065..4827cac9cc 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -9,6 +9,7 @@ import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.b44t.messenger.DcBackupProvider; @@ -24,6 +25,8 @@ import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.util.Util; +import java.util.Locale; + public class BackupProviderFragment extends Fragment implements DcEventCenter.DcEventDelegate { private final static String TAG = BackupProviderFragment.class.getSimpleName(); @@ -32,6 +35,8 @@ public class BackupProviderFragment extends Fragment implements DcEventCenter.Dc private DcBackupProvider dcBackupProvider; private TextView statusLine; + private boolean transferStarted; + private SVGImageView qrImageView; @Override public void onCreate(Bundle bundle) { @@ -43,6 +48,8 @@ public void onCreate(Bundle bundle) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); statusLine = view.findViewById(R.id.status_line); + qrImageView = view.findViewById(R.id.qrImage); + statusLine.setText(R.string.one_moment); dcContext = DcHelper.getContext(getActivity()); @@ -56,10 +63,9 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, if (dcBackupProvider != null) { Util.runOnMain(() -> { statusLine.setVisibility(View.GONE); - SVGImageView imageView = view.findViewById(R.id.qrImage); try { SVG svg = SVG.getFromString(QrShowFragment.fixSVG(dcBackupProvider.getQrSvg())); - imageView.setSVG(svg); + qrImageView.setSVG(svg); } catch (SVGParseException e) { e.printStackTrace(); } @@ -87,8 +93,26 @@ public void onDestroyView() { @Override public void handleEvent(@NonNull DcEvent event) { if (event.getId() == DcContext.DC_EVENT_IMEX_PROGRESS) { - Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + event.getData1Int()); - // TODO: update status line once core sends events during prepare and wait + int permille = event.getData1Int(); + Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); + if (permille == 0) { + new AlertDialog.Builder(getActivity()) + .setMessage(dcContext.getLastError()) + .setPositiveButton(android.R.string.ok, null) + .setCancelable(false) + .show(); + } else if(permille <= 500) { + statusLine.setText(String.format(Locale.getDefault(), "Prepare... %d%%", permille/5)); + } else if (permille < 1000) { + statusLine.setText(String.format(Locale.getDefault(), "Transfer... %d%%", (permille-500)/5)); + if (!transferStarted) { + qrImageView.setVisibility(View.GONE); + statusLine.setVisibility(View.VISIBLE); + transferStarted = true; + } + } else if (permille == 1000) { + statusLine.setText("Done."); + } } } } From 1f40fec360aea50390c50f80a9622b029b4324f5 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 12:37:57 +0100 Subject: [PATCH 14/69] add a permanent notification for the provider --- .../securesms/qr/BackupProviderActivity.java | 14 +++++++-- .../securesms/qr/BackupProviderFragment.java | 31 +++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java index 035fc966e8..03abee73fc 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java @@ -7,6 +7,8 @@ import androidx.appcompat.app.AppCompatActivity; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.service.GenericForegroundService; +import org.thoughtcrime.securesms.service.NotificationController; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; @@ -15,22 +17,30 @@ public class BackupProviderActivity extends AppCompatActivity { private final DynamicTheme dynamicTheme = new DynamicTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); - BackupProviderFragment fragment; + NotificationController notificationController; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); dynamicTheme.onCreate(this); dynamicLanguage.onCreate(this); + notificationController = GenericForegroundService.startForegroundTask(this, getString(R.string.multidevice_title)); setContentView(R.layout.backup_provider_activity); - fragment = (BackupProviderFragment)getSupportFragmentManager().findFragmentById(R.id.backup_provider_fragment); ActionBar supportActionBar = getSupportActionBar(); supportActionBar.setDisplayHomeAsUpEnabled(true); supportActionBar.setTitle(R.string.multidevice_title); } + @Override + protected void onPause() { + super.onPause(); + if (isFinishing()) { + notificationController.close(); + } + } + @Override protected void onResume() { super.onResume(); diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 4827cac9cc..e834c85ed3 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -94,25 +94,38 @@ public void onDestroyView() { public void handleEvent(@NonNull DcEvent event) { if (event.getId() == DcContext.DC_EVENT_IMEX_PROGRESS) { int permille = event.getData1Int(); + int percent = 0; + int percentMax = 0; + String statusLineText = ""; + Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { - new AlertDialog.Builder(getActivity()) - .setMessage(dcContext.getLastError()) - .setPositiveButton(android.R.string.ok, null) - .setCancelable(false) - .show(); - } else if(permille <= 500) { - statusLine.setText(String.format(Locale.getDefault(), "Prepare... %d%%", permille/5)); + new AlertDialog.Builder(getActivity()) + .setMessage(dcContext.getLastError()) + .setPositiveButton(android.R.string.ok, null) + .setCancelable(false) + .show(); + } else if(permille < 500) { + percent = permille/5; + percentMax = 100; + statusLineText = String.format(Locale.getDefault(), "Prepare... %d%%", percent); + } else if(permille == 500) { + statusLineText = String.format(Locale.getDefault(), "Waiting for connection..."); } else if (permille < 1000) { - statusLine.setText(String.format(Locale.getDefault(), "Transfer... %d%%", (permille-500)/5)); + percent = (permille-500)/5; + percentMax = 100; + statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); if (!transferStarted) { qrImageView.setVisibility(View.GONE); statusLine.setVisibility(View.VISIBLE); transferStarted = true; } } else if (permille == 1000) { - statusLine.setText("Done."); + statusLineText = "Done."; } + + statusLine.setText(statusLineText); + ((BackupProviderActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); } } } From cb164b7a009bc0c849ec45e98bca3a7de0ff12b9 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 12:39:51 +0100 Subject: [PATCH 15/69] clarify what we are waiting for --- src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index e834c85ed3..6b28f33ca4 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -110,7 +110,7 @@ public void handleEvent(@NonNull DcEvent event) { percentMax = 100; statusLineText = String.format(Locale.getDefault(), "Prepare... %d%%", percent); } else if(permille == 500) { - statusLineText = String.format(Locale.getDefault(), "Waiting for connection..."); + statusLineText = String.format(Locale.getDefault(), "Waiting for receiver..."); } else if (permille < 1000) { percent = (permille-500)/5; percentMax = 100; From af5e4abbe17ff25a1acfaf879f9b322c9b7b535e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 16:31:26 +0100 Subject: [PATCH 16/69] add a permanent notification for the receiver --- src/org/thoughtcrime/securesms/WelcomeActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java index f69eeb8d43..402f6dce3a 100644 --- a/src/org/thoughtcrime/securesms/WelcomeActivity.java +++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java @@ -299,6 +299,7 @@ private void startQrAccountCreation(String qrCode) DcHelper.getEventCenter(this).captureNextError(); if (dcContext.checkQr(qrCode).getState() == DcContext.DC_QR_BACKUP) { + notificationController = GenericForegroundService.startForegroundTask(this, getString(R.string.multidevice_title)); DcHelper.getAccounts(this).stopIo(); new Thread(() -> { Log.i(TAG, "##### receiveBackup() with qr: "+qrCode); From f80e7424256f14cf2623a0895d1fec5177f69b59 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 17:42:55 +0100 Subject: [PATCH 17/69] ask before finishing BackupProviderActivity --- .../securesms/qr/BackupProviderActivity.java | 36 ++++++++++++++++++- .../securesms/qr/BackupProviderFragment.java | 6 ++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java index 03abee73fc..fc2a31c07e 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java @@ -4,6 +4,7 @@ import android.view.MenuItem; import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import org.thoughtcrime.securesms.R; @@ -14,6 +15,12 @@ public class BackupProviderActivity extends AppCompatActivity { + public enum TransferState { + TRANSFER_UNKNOWN, TRANSFER_ERROR, TRANSFER_SUCCESS; + }; + + private TransferState transferState = TransferState.TRANSFER_UNKNOWN; + private final DynamicTheme dynamicTheme = new DynamicTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @@ -48,16 +55,43 @@ protected void onResume() { dynamicLanguage.onResume(this); } + @Override + public void onBackPressed() { + finishOrAskToFinish(); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { case android.R.id.home: - finish(); + finishOrAskToFinish(); return true; } return false; } + + public void setTransferState(TransferState transferState) { + this.transferState = transferState; + } + + private void finishOrAskToFinish() { + switch (transferState) { + case TRANSFER_ERROR: + case TRANSFER_SUCCESS: + finish(); + break; + + default: + new AlertDialog.Builder(this) + .setMessage("Abort transfer?") + .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish()) + .setNegativeButton(R.string.cancel, null) + .setCancelable(false) + .show(); + break; + } + } } diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 6b28f33ca4..994d15f73f 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -35,7 +35,6 @@ public class BackupProviderFragment extends Fragment implements DcEventCenter.Dc private DcBackupProvider dcBackupProvider; private TextView statusLine; - private boolean transferStarted; private SVGImageView qrImageView; @Override @@ -100,6 +99,7 @@ public void handleEvent(@NonNull DcEvent event) { Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { + ((BackupProviderActivity)getActivity()).setTransferState(BackupProviderActivity.TransferState.TRANSFER_ERROR); new AlertDialog.Builder(getActivity()) .setMessage(dcContext.getLastError()) .setPositiveButton(android.R.string.ok, null) @@ -115,13 +115,13 @@ public void handleEvent(@NonNull DcEvent event) { percent = (permille-500)/5; percentMax = 100; statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); - if (!transferStarted) { + if (qrImageView.getVisibility() != View.GONE) { qrImageView.setVisibility(View.GONE); statusLine.setVisibility(View.VISIBLE); - transferStarted = true; } } else if (permille == 1000) { statusLineText = "Done."; + ((BackupProviderActivity)getActivity()).setTransferState(BackupProviderActivity.TransferState.TRANSFER_SUCCESS); } statusLine.setText(statusLineText); From e98d9ee49d6489967cc62ab0160729e8feb127ec Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 17:46:25 +0100 Subject: [PATCH 18/69] it is fine to cancel the abort question by tapping outside the alert --- src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java index fc2a31c07e..73d4f80679 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java @@ -89,7 +89,6 @@ private void finishOrAskToFinish() { .setMessage("Abort transfer?") .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish()) .setNegativeButton(R.string.cancel, null) - .setCancelable(false) .show(); break; } From 3e0b61640f5ace72d3a180c2001f48b058fd1684 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 19:02:06 +0100 Subject: [PATCH 19/69] remove outdated comment from 'keep screen on' --- src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 994d15f73f..4ab4c84464 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -40,7 +40,7 @@ public class BackupProviderFragment extends Fragment implements DcEventCenter.Dc @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); - getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // keeping the screen on also avoids falling back from IDLE to POLL + getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @Override From 1b9571a10b3ed3de8bdfe1720c61ae2c40ceb65e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 20:39:50 +0100 Subject: [PATCH 20/69] add and check TRANSFER_MODE --- .../ApplicationPreferencesActivity.java | 11 ++++++--- .../securesms/qr/BackupProviderActivity.java | 23 ++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index 7fe83e16a8..cd0cf6d905 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -46,7 +46,6 @@ import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment; import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment; import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment; -import org.thoughtcrime.securesms.preferences.ListSummaryPreferenceFragment; import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment; import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -110,7 +109,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK && requestCode == ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS) { - startActivity(new Intent(this, BackupProviderActivity.class)); + showBackupProvider(); return; } Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content); @@ -141,6 +140,12 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } } + public void showBackupProvider() { + Intent intent = new Intent(this, BackupProviderActivity.class); + intent.putExtra(BackupProviderActivity.TRANSFER_MODE, BackupProviderActivity.TransferMode.SENDER_SHOW_QR.getInt()); + startActivity(intent); + } + public static class ApplicationPreferenceFragment extends CorrectedPreferenceFragment implements DcEventCenter.DcEventDelegate { @Override @@ -269,7 +274,7 @@ public boolean onPreferenceClick(Preference preference) { break; case PREFERENCE_CATEGORY_MULTIDEVICE: if (!ScreenLockUtil.applyScreenLock(getActivity(), getString(R.string.multidevice_title), ScreenLockUtil.REQUEST_CODE_CONFIRM_CREDENTIALS)) { - startActivity(new Intent(getActivity(), BackupProviderActivity.class)); + ((ApplicationPreferencesActivity)getActivity()).showBackupProvider(); } break; case PREFERENCE_CATEGORY_ADVANCED: diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java index 73d4f80679..32478702e5 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java @@ -15,10 +15,25 @@ public class BackupProviderActivity extends AppCompatActivity { + public enum TransferMode { + INVALID(0), + SENDER_SHOW_QR(1), + RECEIVER_SCAN_QR(2); + private final int i; + TransferMode(int i) { this.i = i; } + public int getInt() { return i; } + public static TransferMode fromInt(int i) { return values()[i]; } + }; + public enum TransferState { - TRANSFER_UNKNOWN, TRANSFER_ERROR, TRANSFER_SUCCESS; + TRANSFER_UNKNOWN, + TRANSFER_ERROR, + TRANSFER_SUCCESS; }; + public static final String TRANSFER_MODE = "transfer_mode"; + + private TransferMode transferMode = TransferMode.RECEIVER_SCAN_QR; private TransferState transferState = TransferState.TRANSFER_UNKNOWN; private final DynamicTheme dynamicTheme = new DynamicTheme(); @@ -31,6 +46,12 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); dynamicTheme.onCreate(this); dynamicLanguage.onCreate(this); + + transferMode = TransferMode.fromInt(getIntent().getIntExtra(TRANSFER_MODE, TransferMode.INVALID.getInt())); + if (transferMode == TransferMode.INVALID) { + throw new RuntimeException("invalid transfer mode"); + } + notificationController = GenericForegroundService.startForegroundTask(this, getString(R.string.multidevice_title)); setContentView(R.layout.backup_provider_activity); From 61596b9ab653a220c41bbee78f947e044596592c Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 20:42:39 +0100 Subject: [PATCH 21/69] rename BackupProviderActivity to BackupTransferActivity --- AndroidManifest.xml | 2 +- .../securesms/ApplicationPreferencesActivity.java | 6 +++--- .../thoughtcrime/securesms/qr/BackupProviderFragment.java | 6 +++--- ...kupProviderActivity.java => BackupTransferActivity.java} | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename src/org/thoughtcrime/securesms/qr/{BackupProviderActivity.java => BackupTransferActivity.java} (98%) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index f557f88194..85622bda43 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -294,7 +294,7 @@ android:theme="@style/TextSecure.LightTheme" android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> - diff --git a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java index cd0cf6d905..8ee8c274fa 100644 --- a/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java +++ b/src/org/thoughtcrime/securesms/ApplicationPreferencesActivity.java @@ -51,7 +51,7 @@ import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.Prefs; -import org.thoughtcrime.securesms.qr.BackupProviderActivity; +import org.thoughtcrime.securesms.qr.BackupTransferActivity; import org.thoughtcrime.securesms.util.ScreenLockUtil; /** @@ -141,8 +141,8 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } public void showBackupProvider() { - Intent intent = new Intent(this, BackupProviderActivity.class); - intent.putExtra(BackupProviderActivity.TRANSFER_MODE, BackupProviderActivity.TransferMode.SENDER_SHOW_QR.getInt()); + Intent intent = new Intent(this, BackupTransferActivity.class); + intent.putExtra(BackupTransferActivity.TRANSFER_MODE, BackupTransferActivity.TransferMode.SENDER_SHOW_QR.getInt()); startActivity(intent); } diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 4ab4c84464..ec111cd07a 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -99,7 +99,7 @@ public void handleEvent(@NonNull DcEvent event) { Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { - ((BackupProviderActivity)getActivity()).setTransferState(BackupProviderActivity.TransferState.TRANSFER_ERROR); + ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); new AlertDialog.Builder(getActivity()) .setMessage(dcContext.getLastError()) .setPositiveButton(android.R.string.ok, null) @@ -121,11 +121,11 @@ public void handleEvent(@NonNull DcEvent event) { } } else if (permille == 1000) { statusLineText = "Done."; - ((BackupProviderActivity)getActivity()).setTransferState(BackupProviderActivity.TransferState.TRANSFER_SUCCESS); + ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); } statusLine.setText(statusLineText); - ((BackupProviderActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); + ((BackupTransferActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); } } } diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java similarity index 98% rename from src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java rename to src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 32478702e5..c91609826f 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -13,7 +13,7 @@ import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; -public class BackupProviderActivity extends AppCompatActivity { +public class BackupTransferActivity extends AppCompatActivity { public enum TransferMode { INVALID(0), From 1b991bee2ec82ab01430f3f7b71fb5d43f3e12dd Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 21:05:47 +0100 Subject: [PATCH 22/69] use our base activity --- res/layout/backup_provider_activity.xml | 8 ++----- .../securesms/qr/BackupTransferActivity.java | 24 ++++++++++++++----- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/res/layout/backup_provider_activity.xml b/res/layout/backup_provider_activity.xml index 87e0d3a19c..f1d2ec44ca 100644 --- a/res/layout/backup_provider_activity.xml +++ b/res/layout/backup_provider_activity.xml @@ -1,9 +1,5 @@ - - - - + android:id="@+id/backup_provider_fragment" /> diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index c91609826f..15683b5574 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -2,18 +2,19 @@ import android.os.Bundle; import android.view.MenuItem; +import android.widget.Toast; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; +import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.service.GenericForegroundService; import org.thoughtcrime.securesms.service.NotificationController; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; -public class BackupTransferActivity extends AppCompatActivity { +public class BackupTransferActivity extends PassphraseRequiredActionBarActivity { public enum TransferMode { INVALID(0), @@ -42,20 +43,31 @@ public enum TransferState { NotificationController notificationController; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + protected void onPreCreate() { dynamicTheme.onCreate(this); dynamicLanguage.onCreate(this); + } + + @Override + protected void onCreate(Bundle icicle, boolean ready) { + super.onCreate(icicle, ready); transferMode = TransferMode.fromInt(getIntent().getIntExtra(TRANSFER_MODE, TransferMode.INVALID.getInt())); - if (transferMode == TransferMode.INVALID) { - throw new RuntimeException("invalid transfer mode"); + if (transferMode != TransferMode.INVALID) { + Toast.makeText(this, "bad transfer mode", Toast.LENGTH_LONG).show(); + finish(); } notificationController = GenericForegroundService.startForegroundTask(this, getString(R.string.multidevice_title)); setContentView(R.layout.backup_provider_activity); + switch(transferMode) { + case SENDER_SHOW_QR: + initFragment(android.R.id.content, new BackupProviderFragment(), dynamicLanguage.getCurrentLocale(), icicle); + break; + } + ActionBar supportActionBar = getSupportActionBar(); supportActionBar.setDisplayHomeAsUpEnabled(true); supportActionBar.setTitle(R.string.multidevice_title); From f5192c6623513d6130388baa960919a49e5013c7 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 21:20:39 +0100 Subject: [PATCH 23/69] start/stop IO in base activity --- src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java | 2 -- src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index ec111cd07a..1bb3ed045b 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -52,7 +52,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, statusLine.setText(R.string.one_moment); dcContext = DcHelper.getContext(getActivity()); - dcContext.stopIo(); DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_IMEX_PROGRESS, this); new Thread(() -> { @@ -83,7 +82,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, @Override public void onDestroyView() { dcContext.stopOngoingProcess(); - dcContext.startIo(); dcBackupProvider.unref(); super.onDestroyView(); DcHelper.getEventCenter(getActivity()).removeObservers(this); diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 15683b5574..9607a7d11d 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.service.GenericForegroundService; import org.thoughtcrime.securesms.service.NotificationController; import org.thoughtcrime.securesms.util.DynamicLanguage; @@ -58,6 +59,8 @@ protected void onCreate(Bundle icicle, boolean ready) { finish(); } + DcHelper.getAccounts(this).stopIo(); + notificationController = GenericForegroundService.startForegroundTask(this, getString(R.string.multidevice_title)); setContentView(R.layout.backup_provider_activity); @@ -78,6 +81,7 @@ protected void onPause() { super.onPause(); if (isFinishing()) { notificationController.close(); + DcHelper.getAccounts(this).startIo(); } } From 21122b95cbbf3ecbbe751ce9c38c6b9a6af130c2 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 22:09:34 +0100 Subject: [PATCH 24/69] use BackupTransferActivity also for scanning --- .../securesms/WelcomeActivity.java | 29 +++++++------- .../securesms/qr/BackupTransferActivity.java | 40 ++++++++++++++----- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java index 402f6dce3a..4b2dcf22f0 100644 --- a/src/org/thoughtcrime/securesms/WelcomeActivity.java +++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java @@ -32,6 +32,7 @@ import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.mms.AttachmentManager; import org.thoughtcrime.securesms.permissions.Permissions; +import org.thoughtcrime.securesms.qr.BackupTransferActivity; import org.thoughtcrime.securesms.qr.QrCodeHandler; import org.thoughtcrime.securesms.qr.RegistrationQrActivity; import org.thoughtcrime.securesms.service.GenericForegroundService; @@ -125,6 +126,7 @@ public void onStart() { super.onStart(); String qrAccount = getIntent().getStringExtra(QR_ACCOUNT_EXTRA); if (qrAccount!=null) { + getIntent().removeExtra(QR_ACCOUNT_EXTRA); manualConfigure = false; startQrAccountCreation(qrAccount); } @@ -287,6 +289,13 @@ private void startQrAccountCreation(String qrCode) progressDialog = null; } + if (dcContext.checkQr(qrCode).getState() == DcContext.DC_QR_BACKUP) { + Intent intent = new Intent(this, BackupTransferActivity.class); + intent.putExtra(BackupTransferActivity.TRANSFER_MODE, BackupTransferActivity.TransferMode.RECEIVER_SCAN_QR.getInt()); + startActivity(intent); + return; + } + progressDialog = new ProgressDialog(this); progressDialog.setMessage(getResources().getString(R.string.one_moment)); progressDialog.setCanceledOnTouchOutside(false); @@ -298,22 +307,12 @@ private void startQrAccountCreation(String qrCode) DcHelper.getEventCenter(this).captureNextError(); - if (dcContext.checkQr(qrCode).getState() == DcContext.DC_QR_BACKUP) { - notificationController = GenericForegroundService.startForegroundTask(this, getString(R.string.multidevice_title)); - DcHelper.getAccounts(this).stopIo(); - new Thread(() -> { - Log.i(TAG, "##### receiveBackup() with qr: "+qrCode); - boolean res = dcContext.receiveBackup(qrCode); - Log.i(TAG, "##### receiveBackup() done with result: "+res); - }).start(); - } else { - if (!dcContext.setConfigFromQr(qrCode)) { - progressError(dcContext.getLastError()); - return; - } - DcHelper.getAccounts(this).stopIo(); - dcContext.configure(); + if (!dcContext.setConfigFromQr(qrCode)) { + progressError(dcContext.getLastError()); + return; } + DcHelper.getAccounts(this).stopIo(); + dcContext.configure(); } private void progressError(String data2) { diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 9607a7d11d..ae6a1fe65f 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -1,13 +1,19 @@ package org.thoughtcrime.securesms.qr; +import static org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity.LOCALE_EXTRA; + import android.os.Bundle; import android.view.MenuItem; import android.widget.Toast; +import androidx.annotation.IdRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; -import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity; +import org.thoughtcrime.securesms.BaseActionBarActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.service.GenericForegroundService; @@ -15,7 +21,9 @@ import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; -public class BackupTransferActivity extends PassphraseRequiredActionBarActivity { +import java.util.Locale; + +public class BackupTransferActivity extends BaseActionBarActivity { public enum TransferMode { INVALID(0), @@ -44,19 +52,14 @@ public enum TransferState { NotificationController notificationController; @Override - protected void onPreCreate() { + protected void onCreate(Bundle icicle) { + super.onCreate(icicle); dynamicTheme.onCreate(this); dynamicLanguage.onCreate(this); - } - - @Override - protected void onCreate(Bundle icicle, boolean ready) { - super.onCreate(icicle, ready); transferMode = TransferMode.fromInt(getIntent().getIntExtra(TRANSFER_MODE, TransferMode.INVALID.getInt())); - if (transferMode != TransferMode.INVALID) { - Toast.makeText(this, "bad transfer mode", Toast.LENGTH_LONG).show(); - finish(); + if (transferMode == TransferMode.INVALID) { + throw new RuntimeException("bad transfer mode"); } DcHelper.getAccounts(this).stopIo(); @@ -130,4 +133,19 @@ private void finishOrAskToFinish() { break; } } + + protected T initFragment(@IdRes int target, + @NonNull T fragment, + @Nullable Locale locale, + @Nullable Bundle extras) + { + Bundle args = new Bundle(); + args.putSerializable(LOCALE_EXTRA, locale); + if (extras != null) { + args.putAll(extras); + } + fragment.setArguments(args); + getSupportFragmentManager().beginTransaction().replace(target, fragment).commitAllowingStateLoss(); + return fragment; + } } From 487a1861b89a89df1c798e708a48f81cde22b362 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 17 Mar 2023 22:28:14 +0100 Subject: [PATCH 25/69] add BackupReceiverFragment --- .../securesms/WelcomeActivity.java | 1 + .../securesms/qr/BackupReceiverFragment.java | 100 ++++++++++++++++++ .../securesms/qr/BackupTransferActivity.java | 43 +++++--- 3 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java index 4b2dcf22f0..6ee13dfb49 100644 --- a/src/org/thoughtcrime/securesms/WelcomeActivity.java +++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java @@ -292,6 +292,7 @@ private void startQrAccountCreation(String qrCode) if (dcContext.checkQr(qrCode).getState() == DcContext.DC_QR_BACKUP) { Intent intent = new Intent(this, BackupTransferActivity.class); intent.putExtra(BackupTransferActivity.TRANSFER_MODE, BackupTransferActivity.TransferMode.RECEIVER_SCAN_QR.getInt()); + intent.putExtra(BackupTransferActivity.QR_CODE, qrCode); startActivity(intent); return; } diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java new file mode 100644 index 0000000000..be6c465aa1 --- /dev/null +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -0,0 +1,100 @@ +package org.thoughtcrime.securesms.qr; + +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; + +import com.b44t.messenger.DcBackupProvider; +import com.b44t.messenger.DcContext; +import com.b44t.messenger.DcEvent; + +import com.caverock.androidsvg.SVGImageView; +import com.caverock.androidsvg.SVG; +import com.caverock.androidsvg.SVGParseException; + +import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.connect.DcEventCenter; +import org.thoughtcrime.securesms.connect.DcHelper; +import org.thoughtcrime.securesms.util.Util; + +import java.util.Locale; + +public class BackupReceiverFragment extends Fragment implements DcEventCenter.DcEventDelegate { + + private final static String TAG = BackupProviderFragment.class.getSimpleName(); + + private DcContext dcContext; + private TextView statusLine; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); + statusLine = view.findViewById(R.id.status_line); + + statusLine.setText(R.string.one_moment); + + dcContext = DcHelper.getContext(getActivity()); + DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_IMEX_PROGRESS, this); + + String qrCode = getActivity().getIntent().getStringExtra(BackupTransferActivity.QR_CODE); + + new Thread(() -> { + Log.i(TAG, "##### receiveBackup() with qr: "+qrCode); + boolean res = dcContext.receiveBackup(qrCode); + Log.i(TAG, "##### receiveBackup() done with result: "+res); + }).start(); + + return view; + } + + @Override + public void onDestroyView() { + dcContext.stopOngoingProcess(); + super.onDestroyView(); + DcHelper.getEventCenter(getActivity()).removeObservers(this); + } + + @Override + public void handleEvent(@NonNull DcEvent event) { + if (event.getId() == DcContext.DC_EVENT_IMEX_PROGRESS) { + int permille = event.getData1Int(); + int percent = 0; + int percentMax = 0; + String statusLineText = ""; + + Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); + if (permille == 0) { + ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); + new AlertDialog.Builder(getActivity()) + .setMessage(dcContext.getLastError()) + .setPositiveButton(android.R.string.ok, null) + .setCancelable(false) + .show(); + } else if (permille < 1000) { + percent = permille/10; + percentMax = 100; + statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); + } else if (permille == 1000) { + statusLineText = "Done."; + ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); + } + + statusLine.setText(statusLineText); + ((BackupTransferActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); + } + } +} diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index ae6a1fe65f..6916adde0b 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -4,7 +4,6 @@ import android.os.Bundle; import android.view.MenuItem; -import android.widget.Toast; import androidx.annotation.IdRes; import androidx.annotation.NonNull; @@ -42,6 +41,7 @@ public enum TransferState { }; public static final String TRANSFER_MODE = "transfer_mode"; + public static final String QR_CODE = "qr_code"; private TransferMode transferMode = TransferMode.RECEIVER_SCAN_QR; private TransferState transferState = TransferState.TRANSFER_UNKNOWN; @@ -72,6 +72,10 @@ protected void onCreate(Bundle icicle) { case SENDER_SHOW_QR: initFragment(android.R.id.content, new BackupProviderFragment(), dynamicLanguage.getCurrentLocale(), icicle); break; + + case RECEIVER_SCAN_QR: + initFragment(android.R.id.content, new BackupReceiverFragment(), dynamicLanguage.getCurrentLocale(), icicle); + break; } ActionBar supportActionBar = getSupportActionBar(); @@ -121,31 +125,36 @@ private void finishOrAskToFinish() { switch (transferState) { case TRANSFER_ERROR: case TRANSFER_SUCCESS: - finish(); + doFinish(); break; default: new AlertDialog.Builder(this) .setMessage("Abort transfer?") - .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> finish()) + .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> doFinish()) .setNegativeButton(R.string.cancel, null) .show(); break; } } - protected T initFragment(@IdRes int target, - @NonNull T fragment, - @Nullable Locale locale, - @Nullable Bundle extras) - { - Bundle args = new Bundle(); - args.putSerializable(LOCALE_EXTRA, locale); - if (extras != null) { - args.putAll(extras); - } - fragment.setArguments(args); - getSupportFragmentManager().beginTransaction().replace(target, fragment).commitAllowingStateLoss(); - return fragment; - } + private void doFinish() { + // TODO: for receiver, launch chatlist and remove welcome + finish(); + } + + protected T initFragment(@IdRes int target, + @NonNull T fragment, + @Nullable Locale locale, + @Nullable Bundle extras) + { + Bundle args = new Bundle(); + args.putSerializable(LOCALE_EXTRA, locale); + if (extras != null) { + args.putAll(extras); + } + fragment.setArguments(args); + getSupportFragmentManager().beginTransaction().replace(target, fragment).commitAllowingStateLoss(); + return fragment; + } } From 731c6619674cf56da2d0932e45452584638049a2 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 18 Mar 2023 00:22:08 +0100 Subject: [PATCH 26/69] show detailed transfer progress --- .../securesms/qr/BackupProviderFragment.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 1bb3ed045b..2664496d71 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -103,14 +103,16 @@ public void handleEvent(@NonNull DcEvent event) { .setPositiveButton(android.R.string.ok, null) .setCancelable(false) .show(); - } else if(permille < 500) { - percent = permille/5; + } else if(permille < 400) { + percent = permille * 100 / 400; percentMax = 100; statusLineText = String.format(Locale.getDefault(), "Prepare... %d%%", percent); - } else if(permille == 500) { + } else if(permille == 400) { statusLineText = String.format(Locale.getDefault(), "Waiting for receiver..."); + } else if(permille <= 450) { + statusLineText = String.format(Locale.getDefault(), "Receiver connected..."); } else if (permille < 1000) { - percent = (permille-500)/5; + percent = (permille-450)/5; percentMax = 100; statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); if (qrImageView.getVisibility() != View.GONE) { From 934ed18bdb8632d68f49143569665e76d2562606 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 18 Mar 2023 00:34:11 +0100 Subject: [PATCH 27/69] show details instead of percent during preparation, for now --- .../securesms/qr/BackupProviderFragment.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 2664496d71..1ef59badac 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -97,17 +97,19 @@ public void handleEvent(@NonNull DcEvent event) { Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { - ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); + ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); new AlertDialog.Builder(getActivity()) .setMessage(dcContext.getLastError()) .setPositiveButton(android.R.string.ok, null) .setCancelable(false) .show(); - } else if(permille < 400) { - percent = permille * 100 / 400; - percentMax = 100; - statusLineText = String.format(Locale.getDefault(), "Prepare... %d%%", percent); - } else if(permille == 400) { + } else if(permille <= 100) { + statusLineText = String.format(Locale.getDefault(), "Exporting database..."); + } else if(permille <= 300) { + statusLineText = String.format(Locale.getDefault(), "Creating collection..."); + } else if(permille <= 350) { + statusLineText = String.format(Locale.getDefault(), "Collection created."); + } else if(permille <= 400) { statusLineText = String.format(Locale.getDefault(), "Waiting for receiver..."); } else if(permille <= 450) { statusLineText = String.format(Locale.getDefault(), "Receiver connected..."); From f64c812da468a04e245af745939d7950c6031039 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 18 Mar 2023 00:52:33 +0100 Subject: [PATCH 28/69] launch chatlist and remove welcome when transfer is done --- src/org/thoughtcrime/securesms/WelcomeActivity.java | 7 +++++++ .../thoughtcrime/securesms/qr/BackupTransferActivity.java | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java index 6ee13dfb49..80aa73d59c 100644 --- a/src/org/thoughtcrime/securesms/WelcomeActivity.java +++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java @@ -362,6 +362,13 @@ public void handleEvent(@NonNull DcEvent event) { if (eventId== DcContext.DC_EVENT_IMEX_PROGRESS ) { long progress = event.getData1Int(); + if (progressDialog == null || notificationController == null) { + // IMEX runs in BackupTransferActivity + if (progress == 1000) { + finish(); // transfer done - remove ourself from the activity stack (finishAffinity is available in API 16, we're targeting API 14) + } + return; + } if (progress==0/*error/aborted*/) { if (!imexUserAborted) { progressError(dcContext.getLastError()); diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 6916adde0b..694e91b38c 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -2,6 +2,7 @@ import static org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity.LOCALE_EXTRA; +import android.content.Intent; import android.os.Bundle; import android.view.MenuItem; @@ -13,6 +14,7 @@ import androidx.fragment.app.Fragment; import org.thoughtcrime.securesms.BaseActionBarActivity; +import org.thoughtcrime.securesms.ConversationListActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.service.GenericForegroundService; @@ -139,7 +141,9 @@ private void finishOrAskToFinish() { } private void doFinish() { - // TODO: for receiver, launch chatlist and remove welcome + if (transferMode == TransferMode.RECEIVER_SCAN_QR && transferState == TransferState.TRANSFER_SUCCESS) { + startActivity(new Intent(getApplicationContext(), ConversationListActivity.class)); + } finish(); } From d4446b3e21b8c5c06cfe4b5e3fbebc070d10ada9 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 18 Mar 2023 00:58:39 +0100 Subject: [PATCH 29/69] redirect to chatlist automatically after transfer succeeded --- src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java | 3 ++- src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index be6c465aa1..68aca564d6 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -89,8 +89,9 @@ public void handleEvent(@NonNull DcEvent event) { percentMax = 100; statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); } else if (permille == 1000) { - statusLineText = "Done."; ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); + ((BackupTransferActivity)getActivity()).doFinish(); + return; } statusLine.setText(statusLineText); diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 694e91b38c..a36c2e3a19 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -140,7 +140,7 @@ private void finishOrAskToFinish() { } } - private void doFinish() { + public void doFinish() { if (transferMode == TransferMode.RECEIVER_SCAN_QR && transferState == TransferState.TRANSFER_SUCCESS) { startActivity(new Intent(getApplicationContext(), ConversationListActivity.class)); } From da269dc574ce3f04cded7cfab0f8647fb4fab5ea Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 18 Mar 2023 01:05:16 +0100 Subject: [PATCH 30/69] reword --- src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 68aca564d6..53c5863ced 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -45,7 +45,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); statusLine = view.findViewById(R.id.status_line); - statusLine.setText(R.string.one_moment); + statusLine.setText("Connecting..."); dcContext = DcHelper.getContext(getActivity()); DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_IMEX_PROGRESS, this); From b982bdbb5bef2260b105af19a983eb6c64b6e7f6 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 18 Mar 2023 01:13:16 +0100 Subject: [PATCH 31/69] make log accessible from send and receive activities --- res/menu/backup_transfer_menu.xml | 9 +++++++++ .../securesms/qr/BackupTransferActivity.java | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 res/menu/backup_transfer_menu.xml diff --git a/res/menu/backup_transfer_menu.xml b/res/menu/backup_transfer_menu.xml new file mode 100644 index 0000000000..a0399b9614 --- /dev/null +++ b/res/menu/backup_transfer_menu.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index a36c2e3a19..66d03b347f 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -4,6 +4,7 @@ import android.content.Intent; import android.os.Bundle; +import android.view.Menu; import android.view.MenuItem; import androidx.annotation.IdRes; @@ -15,6 +16,7 @@ import org.thoughtcrime.securesms.BaseActionBarActivity; import org.thoughtcrime.securesms.ConversationListActivity; +import org.thoughtcrime.securesms.LogViewActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.service.GenericForegroundService; @@ -101,6 +103,12 @@ protected void onResume() { dynamicLanguage.onResume(this); } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.backup_transfer_menu, menu); + return super.onCreateOptionsMenu(menu); + } + @Override public void onBackPressed() { finishOrAskToFinish(); @@ -114,6 +122,9 @@ public boolean onOptionsItemSelected(MenuItem item) { case android.R.id.home: finishOrAskToFinish(); return true; + case R.id.view_log_button: + startActivity(new Intent(this, LogViewActivity.class)); + return true; } return false; From 6a1d430b2cb2abe4c9dae494ea035f7209fc6ee5 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 18 Mar 2023 01:14:06 +0100 Subject: [PATCH 32/69] bump version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d71013968e..fd46802a9f 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ android { defaultConfig { versionCode 649 - versionName "1.35.1" + versionName "1.35.2" applicationId "com.b44t.messenger" multiDexEnabled true From e9f2413d70b4a815d37e126a697bb27415a3e728 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Mar 2023 13:25:41 +0100 Subject: [PATCH 33/69] show error if backup provider creation fails --- src/com/b44t/messenger/DcBackupProvider.java | 4 ++ .../securesms/qr/BackupProviderFragment.java | 41 +++++++++---------- .../securesms/qr/BackupTransferActivity.java | 19 +++++++++ 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/src/com/b44t/messenger/DcBackupProvider.java b/src/com/b44t/messenger/DcBackupProvider.java index fa65738738..0a0b4c3426 100644 --- a/src/com/b44t/messenger/DcBackupProvider.java +++ b/src/com/b44t/messenger/DcBackupProvider.java @@ -6,6 +6,10 @@ public DcBackupProvider(long backupProviderCPtr) { this.backupProviderCPtr = backupProviderCPtr; } + public boolean isOk() { + return backupProviderCPtr != 0; + } + @Override protected void finalize() throws Throwable { super.finalize(); unref(); diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 1ef59badac..2b03db4b48 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -58,22 +58,25 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Log.i(TAG, "##### newBackupProvider()"); dcBackupProvider = dcContext.newBackupProvider(); Log.i(TAG, "##### newBackupProvider() returned"); - if (dcBackupProvider != null) { - Util.runOnMain(() -> { - statusLine.setVisibility(View.GONE); - try { - SVG svg = SVG.getFromString(QrShowFragment.fixSVG(dcBackupProvider.getQrSvg())); - qrImageView.setSVG(svg); - } catch (SVGParseException e) { - e.printStackTrace(); - } - new Thread(() -> { - Log.i(TAG, "##### waitForReceiver() with qr: "+dcBackupProvider.getQr()); - dcBackupProvider.waitForReceiver(); - Log.i(TAG, "##### done waiting"); - }).start(); - }); - } + Util.runOnMain(() -> { + statusLine.setVisibility(View.GONE); + if (!dcBackupProvider.isOk()) { + ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); + ((BackupTransferActivity)getActivity()).showLastErrorAlert("Cannot create backup provider; try over in a minute"); + return; + } + try { + SVG svg = SVG.getFromString(QrShowFragment.fixSVG(dcBackupProvider.getQrSvg())); + qrImageView.setSVG(svg); + } catch (SVGParseException e) { + e.printStackTrace(); + } + new Thread(() -> { + Log.i(TAG, "##### waitForReceiver() with qr: "+dcBackupProvider.getQr()); + dcBackupProvider.waitForReceiver(); + Log.i(TAG, "##### done waiting"); + }).start(); + }); }).start(); return view; @@ -98,11 +101,7 @@ public void handleEvent(@NonNull DcEvent event) { Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); - new AlertDialog.Builder(getActivity()) - .setMessage(dcContext.getLastError()) - .setPositiveButton(android.R.string.ok, null) - .setCancelable(false) - .show(); + ((BackupTransferActivity)getActivity()).showLastErrorAlert("Error"); } else if(permille <= 100) { statusLineText = String.format(Locale.getDefault(), "Exporting database..."); } else if(permille <= 300) { diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 66d03b347f..14416f5b53 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -158,6 +158,25 @@ public void doFinish() { finish(); } + public void showLastErrorAlert(@NonNull String errorContext) { + String lastError = DcHelper.getContext(this).getLastError(); + if (lastError.isEmpty()) { + lastError = ""; + } + + String error = errorContext; + if (!error.isEmpty()) { + error += ": "; + } + error += lastError; + + new AlertDialog.Builder(this) + .setMessage(error) + .setPositiveButton(android.R.string.ok, null) + .setCancelable(false) + .show(); + } + protected T initFragment(@IdRes int target, @NonNull T fragment, @Nullable Locale locale, From 2a2d4d543d77b211bf36523fc88a941484a85afc Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Mar 2023 14:15:31 +0100 Subject: [PATCH 34/69] remove unneeded format() --- .../securesms/qr/BackupProviderFragment.java | 11 +++++------ .../securesms/qr/BackupReceiverFragment.java | 6 ------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 2b03db4b48..32f4923186 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -9,7 +9,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.b44t.messenger.DcBackupProvider; @@ -103,15 +102,15 @@ public void handleEvent(@NonNull DcEvent event) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); ((BackupTransferActivity)getActivity()).showLastErrorAlert("Error"); } else if(permille <= 100) { - statusLineText = String.format(Locale.getDefault(), "Exporting database..."); + statusLineText = "Exporting database..."; } else if(permille <= 300) { - statusLineText = String.format(Locale.getDefault(), "Creating collection..."); + statusLineText = "Creating collection..."; } else if(permille <= 350) { - statusLineText = String.format(Locale.getDefault(), "Collection created."); + statusLineText = "Collection created."; } else if(permille <= 400) { - statusLineText = String.format(Locale.getDefault(), "Waiting for receiver..."); + statusLineText = "Waiting for receiver..."; } else if(permille <= 450) { - statusLineText = String.format(Locale.getDefault(), "Receiver connected..."); + statusLineText = "Receiver connected..."; } else if (permille < 1000) { percent = (permille-450)/5; percentMax = 100; diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 53c5863ced..42ed84cd05 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -12,18 +12,12 @@ import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; -import com.b44t.messenger.DcBackupProvider; import com.b44t.messenger.DcContext; import com.b44t.messenger.DcEvent; -import com.caverock.androidsvg.SVGImageView; -import com.caverock.androidsvg.SVG; -import com.caverock.androidsvg.SVGParseException; - import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.DcEventCenter; import org.thoughtcrime.securesms.connect.DcHelper; -import org.thoughtcrime.securesms.util.Util; import java.util.Locale; From 56afe08f4925d24b1c6f61fa7ecdd732e56e878e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Mar 2023 16:43:33 +0100 Subject: [PATCH 35/69] show some context in the errors alerts, hide QR code sooner --- .../securesms/qr/BackupProviderFragment.java | 15 ++++++++++----- .../securesms/qr/BackupReceiverFragment.java | 6 +----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 32f4923186..9a31fa1121 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -95,12 +95,14 @@ public void handleEvent(@NonNull DcEvent event) { int permille = event.getData1Int(); int percent = 0; int percentMax = 0; + boolean hideQrCode = false; String statusLineText = ""; Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); - ((BackupTransferActivity)getActivity()).showLastErrorAlert("Error"); + ((BackupTransferActivity)getActivity()).showLastErrorAlert("Sending Error"); + hideQrCode = true; } else if(permille <= 100) { statusLineText = "Exporting database..."; } else if(permille <= 300) { @@ -111,21 +113,24 @@ public void handleEvent(@NonNull DcEvent event) { statusLineText = "Waiting for receiver..."; } else if(permille <= 450) { statusLineText = "Receiver connected..."; + hideQrCode = true; } else if (permille < 1000) { percent = (permille-450)/5; percentMax = 100; statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); - if (qrImageView.getVisibility() != View.GONE) { - qrImageView.setVisibility(View.GONE); - statusLine.setVisibility(View.VISIBLE); - } + hideQrCode = true; } else if (permille == 1000) { statusLineText = "Done."; ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); + hideQrCode = true; } statusLine.setText(statusLineText); ((BackupTransferActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); + if (hideQrCode && qrImageView.getVisibility() != View.GONE) { + qrImageView.setVisibility(View.GONE); + statusLine.setVisibility(View.VISIBLE); + } } } } diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 42ed84cd05..af3c38bfc0 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -73,11 +73,7 @@ public void handleEvent(@NonNull DcEvent event) { Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); - new AlertDialog.Builder(getActivity()) - .setMessage(dcContext.getLastError()) - .setPositiveButton(android.R.string.ok, null) - .setCancelable(false) - .show(); + ((BackupTransferActivity)getActivity()).showLastErrorAlert("Receiving Error"); } else if (permille < 1000) { percent = permille/10; percentMax = 100; From 9bd3be8c5e941d895729b986c18999ad7242e7a7 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Mar 2023 17:02:07 +0100 Subject: [PATCH 36/69] calculate transfer percentage as specified --- .../securesms/qr/BackupReceiverFragment.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index af3c38bfc0..4f1e9c9157 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -74,10 +74,16 @@ public void handleEvent(@NonNull DcEvent event) { if (permille == 0) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); ((BackupTransferActivity)getActivity()).showLastErrorAlert("Receiving Error"); - } else if (permille < 1000) { - percent = permille/10; + } else if (permille <= 50) { + statusLineText = "Receiving collection..."; // "Connected" + } else if (permille <= 100) { + statusLineText = "Collection received."; + } else if (permille <= 950 ) { + percent = ((permille-100)*100)/850; percentMax = 100; statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); + } else if (permille < 1000) { + statusLineText = "Finishing..."; // range not used, should not happen } else if (permille == 1000) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); ((BackupTransferActivity)getActivity()).doFinish(); From 317c2f19d032e8db649f534b56ce2928e1de833e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 20 Mar 2023 22:44:55 +0100 Subject: [PATCH 37/69] show a 'close' instead of a 'back' button to make visually clear, things are aborted (there is a quesion anyway) --- src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 14416f5b53..e12d582e71 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -84,6 +84,7 @@ protected void onCreate(Bundle icicle) { ActionBar supportActionBar = getSupportActionBar(); supportActionBar.setDisplayHomeAsUpEnabled(true); + supportActionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp); supportActionBar.setTitle(R.string.multidevice_title); } From 05300a9877bf9a6947e712a4972ef65b20ef0953 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 21 Mar 2023 12:04:23 +0100 Subject: [PATCH 38/69] add option to copy backup-qr-code to clipboard --- res/menu/backup_transfer_menu.xml | 5 ++++ .../securesms/qr/BackupProviderFragment.java | 26 +++++++++++++++++++ .../securesms/qr/BackupTransferActivity.java | 5 ++-- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/res/menu/backup_transfer_menu.xml b/res/menu/backup_transfer_menu.xml index a0399b9614..a86bfc8186 100644 --- a/res/menu/backup_transfer_menu.xml +++ b/res/menu/backup_transfer_menu.xml @@ -2,6 +2,11 @@ + + diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 9a31fa1121..eb66365165 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -3,10 +3,13 @@ import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; @@ -47,6 +50,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); statusLine = view.findViewById(R.id.status_line); qrImageView = view.findViewById(R.id.qrImage); + setHasOptionsMenu(true); statusLine.setText(R.string.one_moment); @@ -89,6 +93,28 @@ public void onDestroyView() { DcHelper.getEventCenter(getActivity()).removeObservers(this); } + @Override + public void onPrepareOptionsMenu(Menu menu) { + menu.findItem(R.id.copy).setVisible(qrImageView.getVisibility() == View.VISIBLE); + super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + super.onOptionsItemSelected(item); + + switch (item.getItemId()) { + case R.id.copy: + if (dcBackupProvider != null) { + Util.writeTextToClipboard(getActivity(), dcBackupProvider.getQr()); + Toast.makeText(getActivity(), getString(R.string.done), Toast.LENGTH_SHORT).show(); + } + return true; + } + + return false; + } + @Override public void handleEvent(@NonNull DcEvent event) { if (event.getId() == DcContext.DC_EVENT_IMEX_PROGRESS) { diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index e12d582e71..9fb33139c8 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -105,9 +105,10 @@ protected void onResume() { } @Override - public boolean onCreateOptionsMenu(Menu menu) { + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); getMenuInflater().inflate(R.menu.backup_transfer_menu, menu); - return super.onCreateOptionsMenu(menu); + return super.onPrepareOptionsMenu(menu); } @Override From 89d26ad37b97a40c3de59be5a1c69787bea803ac Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 21 Mar 2023 13:08:40 +0100 Subject: [PATCH 39/69] remove vague retry statement, core will show a detailed error soon --- src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index eb66365165..248d8b7c1d 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -65,7 +65,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, statusLine.setVisibility(View.GONE); if (!dcBackupProvider.isOk()) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); - ((BackupTransferActivity)getActivity()).showLastErrorAlert("Cannot create backup provider; try over in a minute"); + ((BackupTransferActivity)getActivity()).showLastErrorAlert("Cannot create backup provider"); return; } try { From f1f49d4501286003187b09a444b68731a1960dea Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 21 Mar 2023 14:46:14 +0100 Subject: [PATCH 40/69] warn about QR codes on clipboard getting invalidated --- .../securesms/qr/BackupProviderFragment.java | 1 + .../securesms/qr/BackupTransferActivity.java | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 248d8b7c1d..f1ac02f100 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -108,6 +108,7 @@ public boolean onOptionsItemSelected(MenuItem item) { if (dcBackupProvider != null) { Util.writeTextToClipboard(getActivity(), dcBackupProvider.getQr()); Toast.makeText(getActivity(), getString(R.string.done), Toast.LENGTH_SHORT).show(); + ((BackupTransferActivity)getActivity()).warnAboutCopiedQrCodeOnAbort = true; } return true; } diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 9fb33139c8..6d0053a0ec 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -54,6 +54,7 @@ public enum TransferState { private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); NotificationController notificationController; + public boolean warnAboutCopiedQrCodeOnAbort = false; @Override protected void onCreate(Bundle icicle) { @@ -144,12 +145,16 @@ private void finishOrAskToFinish() { break; default: + String msg = "Abort transfer?"; + if (warnAboutCopiedQrCodeOnAbort) { + msg += "\n\n" + "This will invalidate the QR code copied to clipboard."; + } new AlertDialog.Builder(this) - .setMessage("Abort transfer?") + .setMessage(msg) .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> doFinish()) .setNegativeButton(R.string.cancel, null) .show(); - break; + break; } } From bdcfe0db881a73705c59e6d97270da3d590ff812 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 21 Mar 2023 17:21:23 +0100 Subject: [PATCH 41/69] make basic strings translatable --- res/values/strings.xml | 16 +++++++++++++++- .../securesms/qr/BackupProviderFragment.java | 14 +++++++------- .../securesms/qr/BackupReceiverFragment.java | 8 ++++---- .../securesms/qr/BackupTransferActivity.java | 4 ++-- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 89711c46c0..643be90047 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -468,8 +468,22 @@ Add Another Device + Make sure both devices are on the same Wi-Fi or network + Install and start Delta Chat 1.36 or newer on your other device (https://get.delta.chat) + During setup, tap “Scan QR Code” and scan the code shown here Copy the account from the other device to this device? Both devices will work independently afterwards. - During copying, both devices must be on the same wifi or network. + Exporting database… + Creating collection… + Collection created. + Waiting for receiver… + Connecting… + Receiving collection… + Collection received. + Receiver connected… + Transferring… + Abort transfer? + This will invalidate the QR code copied to clipboard. + Troubleshooting diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index f1ac02f100..eb6173b6a0 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -131,23 +131,23 @@ public void handleEvent(@NonNull DcEvent event) { ((BackupTransferActivity)getActivity()).showLastErrorAlert("Sending Error"); hideQrCode = true; } else if(permille <= 100) { - statusLineText = "Exporting database..."; + statusLineText = getString(R.string.multidevice_exporting_database); } else if(permille <= 300) { - statusLineText = "Creating collection..."; + statusLineText = getString(R.string.multidevice_creating_collection); } else if(permille <= 350) { - statusLineText = "Collection created."; + statusLineText = getString(R.string.multidevice_collection_created); } else if(permille <= 400) { - statusLineText = "Waiting for receiver..."; + statusLineText = getString(R.string.multidevice_waiting_for_receiver); } else if(permille <= 450) { - statusLineText = "Receiver connected..."; + statusLineText = getString(R.string.multidevice_receiver_connected); hideQrCode = true; } else if (permille < 1000) { percent = (permille-450)/5; percentMax = 100; - statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); + statusLineText = getString(R.string.multidevice_transferring) + String.format(Locale.getDefault(), " %d%%", percent); hideQrCode = true; } else if (permille == 1000) { - statusLineText = "Done."; + statusLineText = getString(R.string.done); ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); hideQrCode = true; } diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 4f1e9c9157..9df844bbe9 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -39,7 +39,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); statusLine = view.findViewById(R.id.status_line); - statusLine.setText("Connecting..."); + statusLine.setText(R.string.multidevice_connecting); dcContext = DcHelper.getContext(getActivity()); DcHelper.getEventCenter(getActivity()).addObserver(DcContext.DC_EVENT_IMEX_PROGRESS, this); @@ -75,13 +75,13 @@ public void handleEvent(@NonNull DcEvent event) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); ((BackupTransferActivity)getActivity()).showLastErrorAlert("Receiving Error"); } else if (permille <= 50) { - statusLineText = "Receiving collection..."; // "Connected" + statusLineText = getString(R.string.multidevice_receiving_collection); // "Connected" } else if (permille <= 100) { - statusLineText = "Collection received."; + statusLineText = getString(R.string.multidevice_collection_received); } else if (permille <= 950 ) { percent = ((permille-100)*100)/850; percentMax = 100; - statusLineText = String.format(Locale.getDefault(), "Transfer... %d%%", percent); + statusLineText = getString(R.string.multidevice_transferring) + String.format(Locale.getDefault(), " %d%%", percent); } else if (permille < 1000) { statusLineText = "Finishing..."; // range not used, should not happen } else if (permille == 1000) { diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 6d0053a0ec..cc5e427c0e 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -145,9 +145,9 @@ private void finishOrAskToFinish() { break; default: - String msg = "Abort transfer?"; + String msg = getString(R.string.multidevice_abort); if (warnAboutCopiedQrCodeOnAbort) { - msg += "\n\n" + "This will invalidate the QR code copied to clipboard."; + msg += "\n\n" + getString(R.string.multidevice_abort_will_invalidate_copied_qr); } new AlertDialog.Builder(this) .setMessage(msg) From 81cb8c0ebb73707f39084f8acab234c5eb5280c0 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 21 Mar 2023 20:50:13 +0100 Subject: [PATCH 42/69] add troubleshooting menu item (once help is evolved, it may be a more visible button, may be localized, may be offline) --- res/menu/backup_transfer_menu.xml | 4 ++++ .../thoughtcrime/securesms/qr/BackupTransferActivity.java | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/res/menu/backup_transfer_menu.xml b/res/menu/backup_transfer_menu.xml index a86bfc8186..e0485a7a97 100644 --- a/res/menu/backup_transfer_menu.xml +++ b/res/menu/backup_transfer_menu.xml @@ -2,6 +2,10 @@ + + Date: Tue, 21 Mar 2023 23:34:44 +0100 Subject: [PATCH 43/69] rename to backup_transfer_fragment.xml --- ...ackup_provider_fragment.xml => backup_transfer_fragment.xml} | 0 src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java | 2 +- src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename res/layout/{backup_provider_fragment.xml => backup_transfer_fragment.xml} (100%) diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_transfer_fragment.xml similarity index 100% rename from res/layout/backup_provider_fragment.xml rename to res/layout/backup_transfer_fragment.xml diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index eb6173b6a0..7bd592cd18 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -47,7 +47,7 @@ public void onCreate(Bundle bundle) { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); + View view = inflater.inflate(R.layout.backup_transfer_fragment, container, false); statusLine = view.findViewById(R.id.status_line); qrImageView = view.findViewById(R.id.qrImage); setHasOptionsMenu(true); diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 9df844bbe9..f2ce7b215c 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -36,7 +36,7 @@ public void onCreate(Bundle bundle) { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); + View view = inflater.inflate(R.layout.backup_transfer_fragment, container, false); statusLine = view.findViewById(R.id.status_line); statusLine.setText(R.string.multidevice_connecting); From 00f7c1672749f0c9d6b6400b0c108cb019536cba Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 00:36:27 +0100 Subject: [PATCH 44/69] add detailed instructions --- res/layout/backup_transfer_fragment.xml | 26 +++++++++++++++++++ .../securesms/qr/BackupProviderFragment.java | 13 +++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/res/layout/backup_transfer_fragment.xml b/res/layout/backup_transfer_fragment.xml index 22ea7608fe..e847ab5d43 100644 --- a/res/layout/backup_transfer_fragment.xml +++ b/res/layout/backup_transfer_fragment.xml @@ -16,6 +16,19 @@ android:textSize="22sp" tools:text="One moment..."/> + + + + diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 7bd592cd18..70cbfdebe8 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -37,6 +37,8 @@ public class BackupProviderFragment extends Fragment implements DcEventCenter.Dc private DcBackupProvider dcBackupProvider; private TextView statusLine; + private TextView topText; + private TextView bottomText; private SVGImageView qrImageView; @Override @@ -49,6 +51,8 @@ public void onCreate(Bundle bundle) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.backup_transfer_fragment, container, false); statusLine = view.findViewById(R.id.status_line); + topText = view.findViewById(R.id.top_text); + bottomText = view.findViewById(R.id.bottom_text); qrImageView = view.findViewById(R.id.qrImage); setHasOptionsMenu(true); @@ -62,12 +66,17 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, dcBackupProvider = dcContext.newBackupProvider(); Log.i(TAG, "##### newBackupProvider() returned"); Util.runOnMain(() -> { - statusLine.setVisibility(View.GONE); if (!dcBackupProvider.isOk()) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); ((BackupTransferActivity)getActivity()).showLastErrorAlert("Cannot create backup provider"); return; } + statusLine.setVisibility(View.GONE); + topText.setText("➊ " + getString(R.string.multidevice_same_network_hint) + "\n\n" + + "➋ " + getString(R.string.multidevice_install_dc_on_other_device)); + bottomText.setText("➌ " + getString(R.string.multidevice_tap_scan_on_other_device)); + topText.setVisibility(View.VISIBLE); + bottomText.setVisibility(View.VISIBLE); try { SVG svg = SVG.getFromString(QrShowFragment.fixSVG(dcBackupProvider.getQrSvg())); qrImageView.setSVG(svg); @@ -156,6 +165,8 @@ public void handleEvent(@NonNull DcEvent event) { ((BackupTransferActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); if (hideQrCode && qrImageView.getVisibility() != View.GONE) { qrImageView.setVisibility(View.GONE); + topText.setVisibility(View.GONE); + bottomText.setVisibility(View.GONE); statusLine.setVisibility(View.VISIBLE); } } From 476ff022bba41d431c28bf6193784bd19e2f7518 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 11:56:08 +0100 Subject: [PATCH 45/69] move 1,2,3 layout to the .xml --- res/layout/backup_provider_fragment.xml | 100 ++++++++++++++++++ res/layout/backup_receiver_fragment.xml | 18 ++++ res/layout/backup_transfer_fragment.xml | 52 --------- .../securesms/qr/BackupProviderFragment.java | 11 +- .../securesms/qr/BackupReceiverFragment.java | 2 +- 5 files changed, 121 insertions(+), 62 deletions(-) create mode 100644 res/layout/backup_provider_fragment.xml create mode 100644 res/layout/backup_receiver_fragment.xml delete mode 100644 res/layout/backup_transfer_fragment.xml diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml new file mode 100644 index 0000000000..f876304e61 --- /dev/null +++ b/res/layout/backup_provider_fragment.xml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/backup_receiver_fragment.xml b/res/layout/backup_receiver_fragment.xml new file mode 100644 index 0000000000..57013ecbd1 --- /dev/null +++ b/res/layout/backup_receiver_fragment.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/res/layout/backup_transfer_fragment.xml b/res/layout/backup_transfer_fragment.xml deleted file mode 100644 index e847ab5d43..0000000000 --- a/res/layout/backup_transfer_fragment.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 70cbfdebe8..4e0d0e5886 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -37,8 +37,7 @@ public class BackupProviderFragment extends Fragment implements DcEventCenter.Dc private DcBackupProvider dcBackupProvider; private TextView statusLine; - private TextView topText; - private TextView bottomText; + private View topText; private SVGImageView qrImageView; @Override @@ -49,10 +48,9 @@ public void onCreate(Bundle bundle) { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.backup_transfer_fragment, container, false); + View view = inflater.inflate(R.layout.backup_provider_fragment, container, false); statusLine = view.findViewById(R.id.status_line); topText = view.findViewById(R.id.top_text); - bottomText = view.findViewById(R.id.bottom_text); qrImageView = view.findViewById(R.id.qrImage); setHasOptionsMenu(true); @@ -72,11 +70,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, return; } statusLine.setVisibility(View.GONE); - topText.setText("➊ " + getString(R.string.multidevice_same_network_hint) + "\n\n" - + "➋ " + getString(R.string.multidevice_install_dc_on_other_device)); - bottomText.setText("➌ " + getString(R.string.multidevice_tap_scan_on_other_device)); topText.setVisibility(View.VISIBLE); - bottomText.setVisibility(View.VISIBLE); try { SVG svg = SVG.getFromString(QrShowFragment.fixSVG(dcBackupProvider.getQrSvg())); qrImageView.setSVG(svg); @@ -166,7 +160,6 @@ public void handleEvent(@NonNull DcEvent event) { if (hideQrCode && qrImageView.getVisibility() != View.GONE) { qrImageView.setVisibility(View.GONE); topText.setVisibility(View.GONE); - bottomText.setVisibility(View.GONE); statusLine.setVisibility(View.VISIBLE); } } diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index f2ce7b215c..55da702cec 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -36,7 +36,7 @@ public void onCreate(Bundle bundle) { @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.backup_transfer_fragment, container, false); + View view = inflater.inflate(R.layout.backup_receiver_fragment, container, false); statusLine = view.findViewById(R.id.status_line); statusLine.setText(R.string.multidevice_connecting); From d39b3733573c4a05c649e07c31413109d0fc6b43 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 12:35:34 +0100 Subject: [PATCH 46/69] fix layout --- res/layout/backup_provider_fragment.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml index f876304e61..2762ac77cc 100644 --- a/res/layout/backup_provider_fragment.xml +++ b/res/layout/backup_provider_fragment.xml @@ -21,7 +21,7 @@ android:layout_height="wrap_content" android:layout_margin="16dp" android:orientation="vertical" - android:visibility="visible"> + android:visibility="gone"> From 0cbf08110f258d12cb0da18ddf1e12375377d93c Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 12:47:44 +0100 Subject: [PATCH 47/69] use text size used elsewhere --- res/layout/backup_provider_fragment.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml index 2762ac77cc..899d45532c 100644 --- a/res/layout/backup_provider_fragment.xml +++ b/res/layout/backup_provider_fragment.xml @@ -36,14 +36,14 @@ android:gravity="center_vertical" android:text="➊" android:textColor="?attr/emoji_text_color" - android:textSize="17sp"/> + android:textSize="16sp"/> + android:textSize="16sp"/> + android:textSize="16sp"/> + android:textSize="16sp"/> + android:textSize="16sp"/> + android:textSize="16sp"/> From 3dafc9d77781bfa4297cfa6f69761fe1d04fcdcb Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 13:26:05 +0100 Subject: [PATCH 48/69] do best effort to show SSID on sending device --- res/layout/backup_provider_fragment.xml | 2 +- .../securesms/qr/BackupProviderFragment.java | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml index 899d45532c..cb371619c0 100644 --- a/res/layout/backup_provider_fragment.xml +++ b/res/layout/backup_provider_fragment.xml @@ -26,7 +26,6 @@ = android.os.Build.VERSION_CODES.M) { + new Thread(() -> { + try { + // depending on the android version, getting the SSID requires none, all or one of + // ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE and maybe even more. + final WifiManager wifiManager = (WifiManager)getActivity().getApplicationContext().getSystemService(Context.WIFI_SERVICE); + if (wifiManager.isWifiEnabled()) { + final WifiInfo info = wifiManager.getConnectionInfo(); + final String ssid = info.getSSID(); + Log.i(TAG, "wifi ssid: "+ssid); + if (!ssid.equals("")) { // "" is returned on insufficient rights + Util.runOnMain(() -> { + String txt = getString(R.string.multidevice_same_network_hint) + " (" + ssid + ")"; + ((TextView) getView().findViewById(R.id.same_network_hint)).setText(txt); + }); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + return view; } From 2e2ac6fe881e040ea6c1b48427f3666758d37fb3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 13:49:03 +0100 Subject: [PATCH 49/69] make SSID code reusable for receiver --- .../securesms/qr/BackupProviderFragment.java | 26 +-------------- .../securesms/qr/BackupTransferActivity.java | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 5bed839496..2c8826d989 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -1,8 +1,5 @@ package org.thoughtcrime.securesms.qr; -import android.content.Context; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -88,28 +85,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, }); }).start(); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { - new Thread(() -> { - try { - // depending on the android version, getting the SSID requires none, all or one of - // ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE and maybe even more. - final WifiManager wifiManager = (WifiManager)getActivity().getApplicationContext().getSystemService(Context.WIFI_SERVICE); - if (wifiManager.isWifiEnabled()) { - final WifiInfo info = wifiManager.getConnectionInfo(); - final String ssid = info.getSSID(); - Log.i(TAG, "wifi ssid: "+ssid); - if (!ssid.equals("")) { // "" is returned on insufficient rights - Util.runOnMain(() -> { - String txt = getString(R.string.multidevice_same_network_hint) + " (" + ssid + ")"; - ((TextView) getView().findViewById(R.id.same_network_hint)).setText(txt); - }); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - }).start(); - } + ((BackupTransferActivity)getActivity()).amendSSID(view.findViewById(R.id.same_network_hint)); return view; } diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index db7b8d5329..d6774df27a 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -2,10 +2,15 @@ import static org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity.LOCALE_EXTRA; +import android.content.Context; import android.content.Intent; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; import android.os.Bundle; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; +import android.widget.TextView; import androidx.annotation.IdRes; import androidx.annotation.NonNull; @@ -24,11 +29,14 @@ import org.thoughtcrime.securesms.service.NotificationController; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; +import org.thoughtcrime.securesms.util.Util; import java.util.Locale; public class BackupTransferActivity extends BaseActionBarActivity { + private final static String TAG = BackupTransferActivity.class.getSimpleName(); + public enum TransferMode { INVALID(0), SENDER_SHOW_QR(1), @@ -189,6 +197,30 @@ public void showLastErrorAlert(@NonNull String errorContext) { .show(); } + public void amendSSID(final TextView textView) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + new Thread(() -> { + try { + // depending on the android version, getting the SSID requires none, all or one of + // ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, ACCESS_NETWORK_STATE and maybe even more. + final WifiManager wifiManager = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE); + if (wifiManager.isWifiEnabled()) { + final WifiInfo info = wifiManager.getConnectionInfo(); + final String ssid = info.getSSID(); + Log.i(TAG, "wifi ssid: "+ssid); + if (!ssid.equals("")) { // "" may be returned on insufficient rights + Util.runOnMain(() -> { + textView.setText(textView.getText() + " (" + ssid + ")"); + }); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + } + protected T initFragment(@IdRes int target, @NonNull T fragment, @Nullable Locale locale, From 765cbeb302fc1c17e16083f0af476e911706ce91 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 14:39:11 +0100 Subject: [PATCH 50/69] adapt to otherwise used font style --- res/layout/backup_provider_fragment.xml | 3 ++- res/layout/backup_receiver_fragment.xml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml index cb371619c0..67f6a83df0 100644 --- a/res/layout/backup_provider_fragment.xml +++ b/res/layout/backup_provider_fragment.xml @@ -12,7 +12,8 @@ android:layout_marginTop="40sp" android:gravity="center_horizontal" android:textAlignment="center" - android:textSize="22sp" + android:textColor="?attr/emoji_text_color" + android:textSize="20sp" tools:text="One moment..."/> From b8a618b2b4a0b0126e00f8b1c7bcd926f3541743 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 14:52:56 +0100 Subject: [PATCH 51/69] show ssid also for receiver --- res/layout/backup_receiver_fragment.xml | 11 +++++++++++ .../securesms/qr/BackupReceiverFragment.java | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/res/layout/backup_receiver_fragment.xml b/res/layout/backup_receiver_fragment.xml index 54648af90a..01f413e735 100644 --- a/res/layout/backup_receiver_fragment.xml +++ b/res/layout/backup_receiver_fragment.xml @@ -16,4 +16,15 @@ android:textSize="20sp" tools:text="One moment..."/> + + diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 55da702cec..a58b8820a0 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -27,6 +27,7 @@ public class BackupReceiverFragment extends Fragment implements DcEventCenter.Dc private DcContext dcContext; private TextView statusLine; + private TextView sameNetworkHint; @Override public void onCreate(Bundle bundle) { @@ -38,6 +39,7 @@ public void onCreate(Bundle bundle) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.backup_receiver_fragment, container, false); statusLine = view.findViewById(R.id.status_line); + sameNetworkHint = view.findViewById(R.id.same_network_hint); statusLine.setText(R.string.multidevice_connecting); @@ -52,6 +54,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Log.i(TAG, "##### receiveBackup() done with result: "+res); }).start(); + ((BackupTransferActivity)getActivity()).amendSSID(sameNetworkHint); + return view; } @@ -68,6 +72,7 @@ public void handleEvent(@NonNull DcEvent event) { int permille = event.getData1Int(); int percent = 0; int percentMax = 0; + boolean hideSameNetworkHint = false; String statusLineText = ""; Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); @@ -75,13 +80,16 @@ public void handleEvent(@NonNull DcEvent event) { ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); ((BackupTransferActivity)getActivity()).showLastErrorAlert("Receiving Error"); } else if (permille <= 50) { - statusLineText = getString(R.string.multidevice_receiving_collection); // "Connected" + statusLineText = getString(R.string.multidevice_receiving_collection); // "Connected" + hideSameNetworkHint = true; } else if (permille <= 100) { - statusLineText = getString(R.string.multidevice_collection_received); + statusLineText = getString(R.string.multidevice_collection_received); + hideSameNetworkHint = true; } else if (permille <= 950 ) { percent = ((permille-100)*100)/850; percentMax = 100; statusLineText = getString(R.string.multidevice_transferring) + String.format(Locale.getDefault(), " %d%%", percent); + hideSameNetworkHint = true; } else if (permille < 1000) { statusLineText = "Finishing..."; // range not used, should not happen } else if (permille == 1000) { @@ -92,6 +100,9 @@ public void handleEvent(@NonNull DcEvent event) { statusLine.setText(statusLineText); ((BackupTransferActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); + if (hideSameNetworkHint && sameNetworkHint.getVisibility() != View.GONE) { + sameNetworkHint.setVisibility(View.GONE); + } } } } From 4933a4595e5371fc2881bc26951a61e8ac0c57f8 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 15:12:48 +0100 Subject: [PATCH 52/69] minor refactorings --- .../securesms/qr/BackupProviderFragment.java | 20 +++++++++++-------- .../securesms/qr/BackupReceiverFragment.java | 16 +++++++++------ .../securesms/qr/BackupTransferActivity.java | 2 +- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 2c8826d989..708cf66768 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -65,8 +65,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Log.i(TAG, "##### newBackupProvider() returned"); Util.runOnMain(() -> { if (!dcBackupProvider.isOk()) { - ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); - ((BackupTransferActivity)getActivity()).showLastErrorAlert("Cannot create backup provider"); + getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); + getTransferActivity().showLastErrorAlert("Cannot create backup provider"); return; } statusLine.setVisibility(View.GONE); @@ -85,7 +85,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, }); }).start(); - ((BackupTransferActivity)getActivity()).amendSSID(view.findViewById(R.id.same_network_hint)); + getTransferActivity().appendSSID(view.findViewById(R.id.same_network_hint)); return view; } @@ -113,7 +113,7 @@ public boolean onOptionsItemSelected(MenuItem item) { if (dcBackupProvider != null) { Util.writeTextToClipboard(getActivity(), dcBackupProvider.getQr()); Toast.makeText(getActivity(), getString(R.string.done), Toast.LENGTH_SHORT).show(); - ((BackupTransferActivity)getActivity()).warnAboutCopiedQrCodeOnAbort = true; + getTransferActivity().warnAboutCopiedQrCodeOnAbort = true; } return true; } @@ -132,8 +132,8 @@ public void handleEvent(@NonNull DcEvent event) { Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { - ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); - ((BackupTransferActivity)getActivity()).showLastErrorAlert("Sending Error"); + getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); + getTransferActivity().showLastErrorAlert("Sending Error"); hideQrCode = true; } else if(permille <= 100) { statusLineText = getString(R.string.multidevice_exporting_database); @@ -153,12 +153,12 @@ public void handleEvent(@NonNull DcEvent event) { hideQrCode = true; } else if (permille == 1000) { statusLineText = getString(R.string.done); - ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); + getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); hideQrCode = true; } statusLine.setText(statusLineText); - ((BackupTransferActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); + getTransferActivity().notificationController.setProgress(percentMax, percent, statusLineText); if (hideQrCode && qrImageView.getVisibility() != View.GONE) { qrImageView.setVisibility(View.GONE); topText.setVisibility(View.GONE); @@ -166,4 +166,8 @@ public void handleEvent(@NonNull DcEvent event) { } } } + + private BackupTransferActivity getTransferActivity() { + return (BackupTransferActivity) getActivity(); + } } diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index a58b8820a0..b413f17a3e 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -54,7 +54,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Log.i(TAG, "##### receiveBackup() done with result: "+res); }).start(); - ((BackupTransferActivity)getActivity()).amendSSID(sameNetworkHint); + getTransferActivity().appendSSID(sameNetworkHint); return view; } @@ -77,8 +77,8 @@ public void handleEvent(@NonNull DcEvent event) { Log.i(TAG,"DC_EVENT_IMEX_PROGRESS, " + permille); if (permille == 0) { - ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); - ((BackupTransferActivity)getActivity()).showLastErrorAlert("Receiving Error"); + getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); + getTransferActivity().showLastErrorAlert("Receiving Error"); } else if (permille <= 50) { statusLineText = getString(R.string.multidevice_receiving_collection); // "Connected" hideSameNetworkHint = true; @@ -93,16 +93,20 @@ public void handleEvent(@NonNull DcEvent event) { } else if (permille < 1000) { statusLineText = "Finishing..."; // range not used, should not happen } else if (permille == 1000) { - ((BackupTransferActivity)getActivity()).setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); - ((BackupTransferActivity)getActivity()).doFinish(); + getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); + getTransferActivity().doFinish(); return; } statusLine.setText(statusLineText); - ((BackupTransferActivity)getActivity()).notificationController.setProgress(percentMax, percent, statusLineText); + getTransferActivity().notificationController.setProgress(percentMax, percent, statusLineText); if (hideSameNetworkHint && sameNetworkHint.getVisibility() != View.GONE) { sameNetworkHint.setVisibility(View.GONE); } } } + + private BackupTransferActivity getTransferActivity() { + return (BackupTransferActivity) getActivity(); + } } diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index d6774df27a..cdd32c94f8 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -197,7 +197,7 @@ public void showLastErrorAlert(@NonNull String errorContext) { .show(); } - public void amendSSID(final TextView textView) { + public void appendSSID(final TextView textView) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { new Thread(() -> { try { From 9a36de9358da716796c181ee391d0bcbccb3a1f6 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 16:13:11 +0100 Subject: [PATCH 53/69] make qr code subtitle translatable --- res/values/strings.xml | 2 ++ src/org/thoughtcrime/securesms/connect/DcHelper.java | 1 + 2 files changed, 3 insertions(+) diff --git a/res/values/strings.xml b/res/values/strings.xml index 643be90047..c0dc01828f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -471,6 +471,8 @@ Make sure both devices are on the same Wi-Fi or network Install and start Delta Chat 1.36 or newer on your other device (https://get.delta.chat) During setup, tap “Scan QR Code” and scan the code shown here + + Scan to set up another device for %1$s Copy the account from the other device to this device? Both devices will work independently afterwards. Exporting database… Creating collection… diff --git a/src/org/thoughtcrime/securesms/connect/DcHelper.java b/src/org/thoughtcrime/securesms/connect/DcHelper.java index cc6c78e030..a4160bad81 100644 --- a/src/org/thoughtcrime/securesms/connect/DcHelper.java +++ b/src/org/thoughtcrime/securesms/connect/DcHelper.java @@ -238,6 +238,7 @@ public static void setStockTranslations(Context context) { dcContext.setStockTranslation(121, context.getString(R.string.connectivity_not_connected)); dcContext.setStockTranslation(122, context.getString(R.string.aeap_addr_changed)); dcContext.setStockTranslation(123, context.getString(R.string.aeap_explanation)); + dcContext.setStockTranslation(162, context.getString(R.string.multidevice_qr_subtitle)); } public static File getImexDir() { From 8d676a816da5d5e20510ab4aa89b814119523d6b Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 16:41:31 +0100 Subject: [PATCH 54/69] tune down 'same network hint' on scanning device --- res/layout/backup_receiver_fragment.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/layout/backup_receiver_fragment.xml b/res/layout/backup_receiver_fragment.xml index 01f413e735..e5921a4f24 100644 --- a/res/layout/backup_receiver_fragment.xml +++ b/res/layout/backup_receiver_fragment.xml @@ -24,7 +24,7 @@ android:layout_weight="1" android:gravity="bottom" android:text="@string/multidevice_same_network_hint" - android:textColor="?attr/emoji_text_color" + android:textColor="@color/gray50" android:textSize="16sp"/> From 3aa376d05847b26c410f3abc1b318ca45a62ef62 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 17:26:27 +0100 Subject: [PATCH 55/69] add progress bar to provider --- res/layout/backup_provider_fragment.xml | 10 +++++++++- .../securesms/qr/BackupProviderFragment.java | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml index 67f6a83df0..7c3799316c 100644 --- a/res/layout/backup_provider_fragment.xml +++ b/res/layout/backup_provider_fragment.xml @@ -5,7 +5,7 @@ xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical"> - + + { + progressBar.setVisibility(View.GONE); if (!dcBackupProvider.isOk()) { getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); getTransferActivity().showLastErrorAlert("Cannot create backup provider"); @@ -152,17 +157,27 @@ public void handleEvent(@NonNull DcEvent event) { statusLineText = getString(R.string.multidevice_transferring) + String.format(Locale.getDefault(), " %d%%", percent); hideQrCode = true; } else if (permille == 1000) { - statusLineText = getString(R.string.done); + statusLineText = getString(R.string.done) + " \uD83D\uDE00"; getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); + progressBar.setVisibility(View.GONE); hideQrCode = true; } statusLine.setText(statusLineText); getTransferActivity().notificationController.setProgress(percentMax, percent, statusLineText); + if (percentMax == 0) { + progressBar.setIndeterminate(true); + } else { + progressBar.setIndeterminate(false); + progressBar.setMax(percentMax); + progressBar.setProgress(percent); + } + if (hideQrCode && qrImageView.getVisibility() != View.GONE) { qrImageView.setVisibility(View.GONE); topText.setVisibility(View.GONE); statusLine.setVisibility(View.VISIBLE); + progressBar.setVisibility(permille == 1000 ? View.GONE : View.VISIBLE); } } } From 87f45dd81ecba708a8d006859202cc9b1d80d0c0 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 22 Mar 2023 17:35:26 +0100 Subject: [PATCH 56/69] add progress bar to receiver --- res/layout/backup_receiver_fragment.xml | 8 ++++++++ .../securesms/qr/BackupReceiverFragment.java | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/res/layout/backup_receiver_fragment.xml b/res/layout/backup_receiver_fragment.xml index e5921a4f24..afe0db1289 100644 --- a/res/layout/backup_receiver_fragment.xml +++ b/res/layout/backup_receiver_fragment.xml @@ -16,6 +16,14 @@ android:textSize="20sp" tools:text="One moment..."/> + + Date: Thu, 23 Mar 2023 19:08:54 +0100 Subject: [PATCH 57/69] bump version --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fd46802a9f..2e4e3dc304 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ android { defaultConfig { versionCode 649 - versionName "1.35.2" + versionName "1.35.3" applicationId "com.b44t.messenger" multiDexEnabled true From 5f271d8d036361f2593952e91944ba404385bd6c Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 23 Mar 2023 19:11:37 +0100 Subject: [PATCH 58/69] use 'Add Second Device' wording MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this seems slightly catchier as "Add Another Device" and has less "A" esp. in "Add as Another Device" :) also at least translation to german seems nicer ("Zweitgerät"), most ppl will use max. two devices, but even if more, that should still be fine. this was also the first intuition also by other devs in their mockups, so we'll give it a try. --- res/values/strings.xml | 8 +++++--- src/org/thoughtcrime/securesms/WelcomeActivity.java | 2 +- .../thoughtcrime/securesms/qr/BackupTransferActivity.java | 5 +++-- src/org/thoughtcrime/securesms/qr/QrCodeHandler.java | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index c0dc01828f..d35fba92c6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -467,12 +467,14 @@ - Add Another Device + + Add Second Device Make sure both devices are on the same Wi-Fi or network Install and start Delta Chat 1.36 or newer on your other device (https://get.delta.chat) During setup, tap “Scan QR Code” and scan the code shown here - - Scan to set up another device for %1$s + + Scan to set up second device for %1$s + Add as Second Device Copy the account from the other device to this device? Both devices will work independently afterwards. Exporting database… Creating collection… diff --git a/src/org/thoughtcrime/securesms/WelcomeActivity.java b/src/org/thoughtcrime/securesms/WelcomeActivity.java index 80aa73d59c..47990cca60 100644 --- a/src/org/thoughtcrime/securesms/WelcomeActivity.java +++ b/src/org/thoughtcrime/securesms/WelcomeActivity.java @@ -442,7 +442,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { case DcContext.DC_QR_BACKUP: new AlertDialog.Builder(this) - .setTitle(R.string.multidevice_title) + .setTitle(R.string.multidevice_reveiver_title) .setMessage(getString(R.string.multidevice_receiver_scanning_ask) + "\n\n" + getString(R.string.multidevice_same_network_hint)) .setPositiveButton(R.string.perm_continue, (dialog, which) -> startQrAccountCreation(qrRaw)) .setNegativeButton(R.string.cancel, null) diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index cdd32c94f8..6f78be2bfd 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -78,7 +78,8 @@ protected void onCreate(Bundle icicle) { DcHelper.getAccounts(this).stopIo(); - notificationController = GenericForegroundService.startForegroundTask(this, getString(R.string.multidevice_title)); + String title = getString(transferMode == TransferMode.RECEIVER_SCAN_QR ? R.string.multidevice_reveiver_title : R.string.multidevice_title); + notificationController = GenericForegroundService.startForegroundTask(this, title); setContentView(R.layout.backup_provider_activity); @@ -95,7 +96,7 @@ protected void onCreate(Bundle icicle) { ActionBar supportActionBar = getSupportActionBar(); supportActionBar.setDisplayHomeAsUpEnabled(true); supportActionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp); - supportActionBar.setTitle(R.string.multidevice_title); + supportActionBar.setTitle(title); } @Override diff --git a/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java b/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java index ca3a5fa8fb..f672ca82e6 100644 --- a/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java +++ b/src/org/thoughtcrime/securesms/qr/QrCodeHandler.java @@ -77,7 +77,7 @@ public void handleQrData(String rawString) { break; case DcContext.DC_QR_BACKUP: - builder.setTitle(R.string.multidevice_title); + builder.setTitle(R.string.multidevice_reveiver_title); builder.setMessage(activity.getString(R.string.multidevice_receiver_scanning_ask) + "\n\n" + activity.getString(R.string.multidevice_same_network_hint)); builder.setPositiveButton(R.string.perm_continue, (dialog, which) -> { AccountManager.getInstance().addAccountFromQr(activity, rawString); From 46871bcbc1365b83d683ddd5b823ddcc1ecd5130 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 23 Mar 2023 19:16:21 +0100 Subject: [PATCH 59/69] use "Exporting/Preparing/Prepared Account" wording let's give that a try - "Account" is also widely used, so that seems to make some sense. even if not 100% fitting, it seems better than introducing the new term "Collection". --- res/values/strings.xml | 15 ++++++++++----- .../securesms/qr/BackupProviderFragment.java | 6 +++--- .../securesms/qr/BackupReceiverFragment.java | 4 ++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index d35fba92c6..e5f106fa18 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -476,14 +476,19 @@ Scan to set up second device for %1$s Add as Second Device Copy the account from the other device to this device? Both devices will work independently afterwards. - Exporting database… - Creating collection… - Collection created. + + Exporting account… + + Preparing account… + + Account prepared. + Waiting for receiver… + Connecting… - Receiving collection… - Collection received. + Receiver connected… + Transferring… Abort transfer? This will invalidate the QR code copied to clipboard. diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index ab299dded9..30b1fea84d 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -141,11 +141,11 @@ public void handleEvent(@NonNull DcEvent event) { getTransferActivity().showLastErrorAlert("Sending Error"); hideQrCode = true; } else if(permille <= 100) { - statusLineText = getString(R.string.multidevice_exporting_database); + statusLineText = getString(R.string.multidevice_exporting_account); } else if(permille <= 300) { - statusLineText = getString(R.string.multidevice_creating_collection); + statusLineText = getString(R.string.multidevice_preparing_account); } else if(permille <= 350) { - statusLineText = getString(R.string.multidevice_collection_created); + statusLineText = getString(R.string.multidevice_account_prepared); } else if(permille <= 400) { statusLineText = getString(R.string.multidevice_waiting_for_receiver); } else if(permille <= 450) { diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 2340abdad0..5002537409 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -84,10 +84,10 @@ public void handleEvent(@NonNull DcEvent event) { getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); getTransferActivity().showLastErrorAlert("Receiving Error"); } else if (permille <= 50) { - statusLineText = getString(R.string.multidevice_receiving_collection); // "Connected" + statusLineText = getString(R.string.multidevice_preparing_account); // "Connected" hideSameNetworkHint = true; } else if (permille <= 100) { - statusLineText = getString(R.string.multidevice_collection_received); + statusLineText = getString(R.string.multidevice_account_prepared); hideSameNetworkHint = true; } else if (permille <= 950 ) { percent = ((permille-100)*100)/850; From 37b49bc182623e90e1ee09f917bf523ea3db0fa4 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Thu, 23 Mar 2023 19:41:51 +0100 Subject: [PATCH 60/69] refine abort question --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index e5f106fa18..b7ccabcf06 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -490,7 +490,7 @@ Receiver connected… Transferring… - Abort transfer? + Abort setting up second device? This will invalidate the QR code copied to clipboard. Troubleshooting From dcea54ef7fc399aeb1395ccdfc439cd1008be568 Mon Sep 17 00:00:00 2001 From: bjoern Date: Fri, 24 Mar 2023 10:17:49 +0100 Subject: [PATCH 61/69] Update res/layout/backup_provider_fragment.xml Co-authored-by: Hocuri --- res/layout/backup_provider_fragment.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/layout/backup_provider_fragment.xml b/res/layout/backup_provider_fragment.xml index 7c3799316c..2cc5b24fed 100644 --- a/res/layout/backup_provider_fragment.xml +++ b/res/layout/backup_provider_fragment.xml @@ -30,7 +30,8 @@ android:layout_height="wrap_content" android:layout_margin="16dp" android:orientation="vertical" - android:visibility="gone"> + android:visibility="gone" + tools:visibility="visible"> Date: Fri, 24 Mar 2023 10:19:17 +0100 Subject: [PATCH 62/69] Update src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java Co-authored-by: Hocuri --- src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 30b1fea84d..532055d541 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -110,7 +110,7 @@ public void onPrepareOptionsMenu(Menu menu) { } @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(@NonNull MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { From 007dd6d35cc14d8efe9370606119f25e27f14e12 Mon Sep 17 00:00:00 2001 From: bjoern Date: Fri, 24 Mar 2023 10:19:53 +0100 Subject: [PATCH 63/69] Update src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java Co-authored-by: Hocuri --- src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 5002537409..947c991db4 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -10,7 +10,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.b44t.messenger.DcContext; From 2f9f6ddc5c88acf7ed9dbb18659fa1f86492e971 Mon Sep 17 00:00:00 2001 From: bjoern Date: Fri, 24 Mar 2023 10:20:04 +0100 Subject: [PATCH 64/69] Update src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java Co-authored-by: Hocuri --- src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java index 6f78be2bfd..1f41b90d2e 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java +++ b/src/org/thoughtcrime/securesms/qr/BackupTransferActivity.java @@ -128,7 +128,7 @@ public void onBackPressed() { } @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(@NonNull MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { From 80f2036709a8e6dadcd5021ccd5ff7984a1152c8 Mon Sep 17 00:00:00 2001 From: bjoern Date: Fri, 24 Mar 2023 10:20:37 +0100 Subject: [PATCH 65/69] Update src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java Co-authored-by: Hocuri --- src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 947c991db4..db04327393 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -94,7 +94,7 @@ public void handleEvent(@NonNull DcEvent event) { statusLineText = getString(R.string.multidevice_transferring) + String.format(Locale.getDefault(), " %d%%", percent); hideSameNetworkHint = true; } else if (permille < 1000) { - statusLineText = "Finishing..."; // range not used, should not happen + statusLineText = "Finishing..."; // range not used, should not happen } else if (permille == 1000) { getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_SUCCESS); getTransferActivity().doFinish(); From df71751ddeda3ea6184fd74288bd34c8e0731d83 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 24 Mar 2023 10:23:17 +0100 Subject: [PATCH 66/69] remove string duplicate --- res/values/strings.xml | 2 -- src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index b7ccabcf06..f73c6068db 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -485,8 +485,6 @@ Waiting for receiver… - Connecting… - Receiver connected… Transferring… diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index db04327393..77861d518a 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -43,7 +43,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, progressBar = view.findViewById(R.id.progress_bar); sameNetworkHint = view.findViewById(R.id.same_network_hint); - statusLine.setText(R.string.multidevice_connecting); + statusLine.setText(R.string.connectivity_connecting); progressBar.setIndeterminate(true); dcContext = DcHelper.getContext(getActivity()); From fe0522564c97f5251ce1c207666bac63d778b6c6 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 24 Mar 2023 11:11:55 +0100 Subject: [PATCH 67/69] refine 1,2,3 --- res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index f73c6068db..e715c4f754 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -470,8 +470,8 @@ Add Second Device Make sure both devices are on the same Wi-Fi or network - Install and start Delta Chat 1.36 or newer on your other device (https://get.delta.chat) - During setup, tap “Scan QR Code” and scan the code shown here + Install Delta Chat 1.36 or newer on your other device (https://get.delta.chat) + Start Delta Chat, tap “Scan QR Code” and scan the code shown here Scan to set up second device for %1$s Add as Second Device From 279580e20b757cf2b4a67dfac038de050a038a79 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 24 Mar 2023 14:24:41 +0100 Subject: [PATCH 68/69] simplify string ids --- res/values/strings.xml | 16 ++++++++-------- .../securesms/qr/BackupProviderFragment.java | 12 ++++++------ .../securesms/qr/BackupReceiverFragment.java | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index e715c4f754..021f9cb95f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -476,20 +476,20 @@ Scan to set up second device for %1$s Add as Second Device Copy the account from the other device to this device? Both devices will work independently afterwards. + Abort setting up second device? + This will invalidate the QR code copied to clipboard. - Exporting account… + Exporting account… - Preparing account… + Preparing account… - Account prepared. + Account prepared. - Waiting for receiver… + Waiting for receiver… - Receiver connected… + Receiver connected… - Transferring… - Abort setting up second device? - This will invalidate the QR code copied to clipboard. + Transferring… Troubleshooting diff --git a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java index 532055d541..c190c00360 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupProviderFragment.java @@ -141,20 +141,20 @@ public void handleEvent(@NonNull DcEvent event) { getTransferActivity().showLastErrorAlert("Sending Error"); hideQrCode = true; } else if(permille <= 100) { - statusLineText = getString(R.string.multidevice_exporting_account); + statusLineText = getString(R.string.exporting_account); } else if(permille <= 300) { - statusLineText = getString(R.string.multidevice_preparing_account); + statusLineText = getString(R.string.preparing_account); } else if(permille <= 350) { - statusLineText = getString(R.string.multidevice_account_prepared); + statusLineText = getString(R.string.account_prepared); } else if(permille <= 400) { - statusLineText = getString(R.string.multidevice_waiting_for_receiver); + statusLineText = getString(R.string.waiting_for_receiver); } else if(permille <= 450) { - statusLineText = getString(R.string.multidevice_receiver_connected); + statusLineText = getString(R.string.receiver_connected); hideQrCode = true; } else if (permille < 1000) { percent = (permille-450)/5; percentMax = 100; - statusLineText = getString(R.string.multidevice_transferring) + String.format(Locale.getDefault(), " %d%%", percent); + statusLineText = getString(R.string.transferring) + String.format(Locale.getDefault(), " %d%%", percent); hideQrCode = true; } else if (permille == 1000) { statusLineText = getString(R.string.done) + " \uD83D\uDE00"; diff --git a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java index 77861d518a..b3b38fb3ea 100644 --- a/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java +++ b/src/org/thoughtcrime/securesms/qr/BackupReceiverFragment.java @@ -83,15 +83,15 @@ public void handleEvent(@NonNull DcEvent event) { getTransferActivity().setTransferState(BackupTransferActivity.TransferState.TRANSFER_ERROR); getTransferActivity().showLastErrorAlert("Receiving Error"); } else if (permille <= 50) { - statusLineText = getString(R.string.multidevice_preparing_account); // "Connected" + statusLineText = getString(R.string.preparing_account); // "Connected" hideSameNetworkHint = true; } else if (permille <= 100) { - statusLineText = getString(R.string.multidevice_account_prepared); + statusLineText = getString(R.string.account_prepared); hideSameNetworkHint = true; } else if (permille <= 950 ) { percent = ((permille-100)*100)/850; percentMax = 100; - statusLineText = getString(R.string.multidevice_transferring) + String.format(Locale.getDefault(), " %d%%", percent); + statusLineText = getString(R.string.transferring) + String.format(Locale.getDefault(), " %d%%", percent); hideSameNetworkHint = true; } else if (permille < 1000) { statusLineText = "Finishing..."; // range not used, should not happen From 12f94be6f8a14f333d68e14ba7727050205d7405 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 24 Mar 2023 14:50:12 +0100 Subject: [PATCH 69/69] focus on what matters --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 021f9cb95f..0987c51cc6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -475,7 +475,7 @@ Scan to set up second device for %1$s Add as Second Device - Copy the account from the other device to this device? Both devices will work independently afterwards. + Copy the account from the other device to this device? Abort setting up second device? This will invalidate the QR code copied to clipboard.