From e18c08bc97fd6fa3c7f7e28eb1310cadf0b3ba23 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 30 Jul 2022 17:38:25 +0000 Subject: [PATCH 1/4] ndk-make.sh: error out if ANDROID_NDK_ROOT is not set --- ndk-make.sh | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/ndk-make.sh b/ndk-make.sh index 21de034ef..ae4225455 100755 --- a/ndk-make.sh +++ b/ndk-make.sh @@ -36,22 +36,25 @@ echo "starting time: `date`" : "${ANDROID_NDK_ROOT:=$ANDROID_NDK_HOME}" : "${ANDROID_NDK_ROOT:=$ANDROID_NDK}" -if test ! -z "$ANDROID_NDK_ROOT"; then - echo Setting CARGO_TARGET environment variables. - - if test -z "$NDK_HOST_TAG"; then - KERNEL="$(uname -s | tr '[:upper:]' '[:lower:]')" - ARCH="$(uname -m)" - NDK_HOST_TAG="$KERNEL-$ARCH" - fi - - TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$NDK_HOST_TAG" - export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang" - export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/aarch64-linux-android21-clang" - export CARGO_TARGET_I686_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/i686-linux-android16-clang" - export CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/x86_64-linux-android21-clang" +if test -z "$ANDROID_NDK_ROOT"; then + echo "ANDROID_NDK_ROOT is not set" + exit 1 fi +echo Setting CARGO_TARGET environment variables. + +if test -z "$NDK_HOST_TAG"; then + KERNEL="$(uname -s | tr '[:upper:]' '[:lower:]')" + ARCH="$(uname -m)" + NDK_HOST_TAG="$KERNEL-$ARCH" +fi + +TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$NDK_HOST_TAG" +export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang" +export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/aarch64-linux-android21-clang" +export CARGO_TARGET_I686_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/i686-linux-android16-clang" +export CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/x86_64-linux-android21-clang" + # Check if the argument is a correct architecture: if test $1 && echo "armeabi-v7a arm64-v8a x86 x86_64" | grep -vwq $1; then echo "Architecture '$1' not known, possible values are armeabi-v7a, arm64-v8a, x86 and x86_64." From 6ac1984f7c0b531f42cc6dc4164f4294c94438e4 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 30 Jul 2022 17:39:18 +0000 Subject: [PATCH 2/4] ndk-make.sh: use full path to ndk-build Remove the requirement to have ndk-build in the PATH. --- .github/workflows/preview-apk.yml | 2 +- Dockerfile | 2 +- ndk-make.sh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/preview-apk.yml b/.github/workflows/preview-apk.yml index a0cbfba48..dacee4c48 100644 --- a/.github/workflows/preview-apk.yml +++ b/.github/workflows/preview-apk.yml @@ -40,7 +40,7 @@ jobs: env: ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} run: | - export PATH="${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/:${ANDROID_NDK_ROOT}" + export PATH="${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/" ./scripts/install-toolchains.sh && ./ndk-make.sh - name: Validate Gradle Wrapper diff --git a/Dockerfile b/Dockerfile index 0de294634..8393ebc76 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,7 +37,7 @@ ENV PATH ${PATH}:${ANDROID_SDK_ROOT}/cmdline-tools/bin RUN sdkmanager --sdk_root=${ANDROID_SDK_ROOT} 'ndk;23.2.8568313' ENV ANDROID_NDK_ROOT ${ANDROID_SDK_ROOT}/ndk/23.2.8568313 -ENV PATH ${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/:${ANDROID_NDK_ROOT} +ENV PATH ${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none ENV PATH ${PATH}:/home/${USER}/.cargo/bin diff --git a/ndk-make.sh b/ndk-make.sh index ae4225455..5bf8a76f3 100755 --- a/ndk-make.sh +++ b/ndk-make.sh @@ -144,10 +144,10 @@ echo -- ndk-build -- cd ../.. if test $1; then - ndk-build APP_ABI="$1" + "$ANDROID_NDK_ROOT/ndk-build" APP_ABI="$1" else # We are compiling for all architectures defined in Application.mk - ndk-build + "$ANDROID_NDK_ROOT/ndk-build" fi if test $1; then From 2c49febc92d600d1cea3c100e69c474bd495fa5b Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 30 Jul 2022 17:39:58 +0000 Subject: [PATCH 3/4] Move ndk-make.sh to scripts/ Keep symlink for backwards compatibility. --- .github/workflows/preview-apk.yml | 2 +- README.md | 4 +- ndk-make.sh | 160 +----------------------------- scripts/ndk-make.sh | 159 +++++++++++++++++++++++++++++ 4 files changed, 163 insertions(+), 162 deletions(-) mode change 100755 => 120000 ndk-make.sh create mode 100755 scripts/ndk-make.sh diff --git a/.github/workflows/preview-apk.yml b/.github/workflows/preview-apk.yml index dacee4c48..e2a5c1eb1 100644 --- a/.github/workflows/preview-apk.yml +++ b/.github/workflows/preview-apk.yml @@ -41,7 +41,7 @@ jobs: ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} run: | export PATH="${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/" - ./scripts/install-toolchains.sh && ./ndk-make.sh + scripts/install-toolchains.sh && scripts/ndk-make.sh - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/README.md b/README.md index c8367e93e..b4d67cf42 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ You can leave the container with Ctrl+D or by typing `exit` and re-enter it with Within the container, install toolchains and build the native library: ``` deltachat@6012dcb974fe:/home/app$ scripts/install-toolchains.sh -deltachat@6012dcb974fe:/home/app$ ./ndk-make.sh +deltachat@6012dcb974fe:/home/app$ scripts/ndk-make.sh ``` Then, [build an APK](https://developer.android.com/studio/build/building-cmdline): @@ -118,7 +118,7 @@ done with care. Then, install Rust using [rustup](https://rustup.rs/). Install Rust toolchains for cross-compilation by executing `scripts/install-toolchains.sh`. -After that, call `./ndk-make.sh` in the root directory to build core-rust. +After that, call `scripts/ndk-make.sh` in the root directory to build core-rust. Afterwards run the project in Android Studio. The project requires API 25. With chance, that's it :) - if not, read on how to set up a proper development diff --git a/ndk-make.sh b/ndk-make.sh deleted file mode 100755 index 5bf8a76f3..000000000 --- a/ndk-make.sh +++ /dev/null @@ -1,159 +0,0 @@ -#!/bin/sh - -# If you want to speed up compilation, you can run this script with your -# architecture as an argument: -# -# ./ndk-make.sh arm64-v8a -# -# Possible values are armeabi-v7a, arm64-v8a, x86 and x86_64. -# You should be able to find out your architecture by running: -# -# adb shell uname -m -# -# Or you just guess your phone's architecture to be arm64-v8a and if you -# guessed wrongly, a warning message will pop up inside the app, telling -# you what the correct one is. -# -# The values in the following lines mean the same: -# -# armeabi-v7a, armv7 and arm -# arm64-v8a, aarch64 and arm64 -# x86 and i686 -# (there are no synonyms for x86_64) -# -# -# If you put this in your .bashrc, then you can directly build and -# deploy DeltaChat from the jni/deltachat-core-rust directory by -# typing `nmake`: -# -# nmake() {(cd ../..; ./ndk-make.sh arm64-v8a && ./gradlew installFatDebug; notify-send "install finished")} -# -# -# If anything doesn't work, please open an issue!! - -set -e -echo "starting time: `date`" - -: "${ANDROID_NDK_ROOT:=$ANDROID_NDK_HOME}" -: "${ANDROID_NDK_ROOT:=$ANDROID_NDK}" -if test -z "$ANDROID_NDK_ROOT"; then - echo "ANDROID_NDK_ROOT is not set" - exit 1 -fi - -echo Setting CARGO_TARGET environment variables. - -if test -z "$NDK_HOST_TAG"; then - KERNEL="$(uname -s | tr '[:upper:]' '[:lower:]')" - ARCH="$(uname -m)" - NDK_HOST_TAG="$KERNEL-$ARCH" -fi - -TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$NDK_HOST_TAG" -export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang" -export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/aarch64-linux-android21-clang" -export CARGO_TARGET_I686_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/i686-linux-android16-clang" -export CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/x86_64-linux-android21-clang" - -# Check if the argument is a correct architecture: -if test $1 && echo "armeabi-v7a arm64-v8a x86 x86_64" | grep -vwq $1; then - echo "Architecture '$1' not known, possible values are armeabi-v7a, arm64-v8a, x86 and x86_64." - exit -fi - -cd jni -jnidir=$PWD -rm -f armeabi-v7a/* -rm -f arm64-v8a/* -rm -f x86/* -rm -f x86_64/* -mkdir -p armeabi-v7a -mkdir -p arm64-v8a -mkdir -p x86 -mkdir -p x86_64 - -cd deltachat-core-rust - -# fix build on MacOS Catalina -unset CPATH - -if test -z $1; then - echo Full build - - # According to 1.45.0 changelog in https://github.com/rust-lang/rust/blob/master/RELEASES.md, - # "The recommended way to control LTO is with Cargo profiles, either in Cargo.toml or .cargo/config, or by setting CARGO_PROFILE__LTO in the environment." - export CARGO_PROFILE_RELEASE_LTO=on - RELEASE="release" - RELEASEFLAG="--release" -else - echo Fast, partial, slow debug build. DO NOT UPLOAD THE APK ANYWHERE. - - RELEASE="debug" - RELEASEFLAG= -fi - -# Work around the bug in the build of Rust standard library. -# It is built against r22b NDK toolchains and still requires -lgcc instead of -lunwind used in newer r23 NDK. -# See discussion at -TMPLIB="$(mktemp -d)" -if test -z "$(find "$ANDROID_NDK_ROOT" -name libgcc.a -print -quit)"; then - # NDK is does not contain libgcc.a, add a linker script to fake it. - echo 'INPUT(-lunwind)' >"$TMPLIB/libgcc.a" -fi - -if test -z $1 || test $1 = armeabi-v7a; then - echo "-- cross compiling to armv7-linux-androideabi (arm) --" - export CFLAGS=-D__ANDROID_API__=16 - TARGET_CC=armv7a-linux-androideabi16-clang \ - TARGET_AR=llvm-ar \ - cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi -- -L "$TMPLIB" - cp target/armv7-linux-androideabi/$RELEASE/libdeltachat.a $jnidir/armeabi-v7a -fi - -if test -z $1 || test $1 = arm64-v8a; then - echo "-- cross compiling to aarch64-linux-android (arm64) --" - export CFLAGS=-D__ANDROID_API__=21 - TARGET_CC=aarch64-linux-android21-clang \ - TARGET_AR=llvm-ar \ - cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi -- -L "$TMPLIB" - cp target/aarch64-linux-android/$RELEASE/libdeltachat.a $jnidir/arm64-v8a -fi - -if test -z $1 || test $1 = x86; then - echo "-- cross compiling to i686-linux-android (x86) --" - export CFLAGS=-D__ANDROID_API__=16 - TARGET_CC=i686-linux-android16-clang \ - TARGET_AR=llvm-ar \ - cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target i686-linux-android -p deltachat_ffi -- -L "$TMPLIB" - cp target/i686-linux-android/$RELEASE/libdeltachat.a $jnidir/x86 -fi - -if test -z $1 || test $1 = x86_64; then - echo "-- cross compiling to x86_64-linux-android (x86_64) --" - export CFLAGS=-D__ANDROID_API__=21 - TARGET_CC=x86_64-linux-android21-clang \ - TARGET_AR=llvm-ar \ - cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi -- -L "$TMPLIB" - cp target/x86_64-linux-android/$RELEASE/libdeltachat.a $jnidir/x86_64 -fi - -rm -fr "$TMPLIB" - -echo -- ndk-build -- - -cd ../.. - -if test $1; then - "$ANDROID_NDK_ROOT/ndk-build" APP_ABI="$1" -else - # We are compiling for all architectures defined in Application.mk - "$ANDROID_NDK_ROOT/ndk-build" -fi - -if test $1; then - echo "NDK_ARCH=$1" >ndkArch -else - rm -f ndkArch # Remove ndkArch, ignore if it doesn't exist -fi - -echo "ending time: `date`" diff --git a/ndk-make.sh b/ndk-make.sh new file mode 120000 index 000000000..b9fbea053 --- /dev/null +++ b/ndk-make.sh @@ -0,0 +1 @@ +scripts/ndk-make.sh \ No newline at end of file diff --git a/scripts/ndk-make.sh b/scripts/ndk-make.sh new file mode 100755 index 000000000..eb03de147 --- /dev/null +++ b/scripts/ndk-make.sh @@ -0,0 +1,159 @@ +#!/bin/sh + +# If you want to speed up compilation, you can run this script with your +# architecture as an argument: +# +# scripts/ndk-make.sh arm64-v8a +# +# Possible values are armeabi-v7a, arm64-v8a, x86 and x86_64. +# You should be able to find out your architecture by running: +# +# adb shell uname -m +# +# Or you just guess your phone's architecture to be arm64-v8a and if you +# guessed wrongly, a warning message will pop up inside the app, telling +# you what the correct one is. +# +# The values in the following lines mean the same: +# +# armeabi-v7a, armv7 and arm +# arm64-v8a, aarch64 and arm64 +# x86 and i686 +# (there are no synonyms for x86_64) +# +# +# If you put this in your .bashrc, then you can directly build and +# deploy DeltaChat from the jni/deltachat-core-rust directory by +# typing `nmake`: +# +# nmake() {(cd ../..; scripts/ndk-make.sh arm64-v8a && ./gradlew installFatDebug; notify-send "install finished")} +# +# +# If anything doesn't work, please open an issue!! + +set -e +echo "starting time: `date`" + +: "${ANDROID_NDK_ROOT:=$ANDROID_NDK_HOME}" +: "${ANDROID_NDK_ROOT:=$ANDROID_NDK}" +if test -z "$ANDROID_NDK_ROOT"; then + echo "ANDROID_NDK_ROOT is not set" + exit 1 +fi + +echo Setting CARGO_TARGET environment variables. + +if test -z "$NDK_HOST_TAG"; then + KERNEL="$(uname -s | tr '[:upper:]' '[:lower:]')" + ARCH="$(uname -m)" + NDK_HOST_TAG="$KERNEL-$ARCH" +fi + +TOOLCHAIN="$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/$NDK_HOST_TAG" +export CARGO_TARGET_ARMV7_LINUX_ANDROIDEABI_LINKER="$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang" +export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/aarch64-linux-android21-clang" +export CARGO_TARGET_I686_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/i686-linux-android16-clang" +export CARGO_TARGET_X86_64_LINUX_ANDROID_LINKER="$TOOLCHAIN/bin/x86_64-linux-android21-clang" + +# Check if the argument is a correct architecture: +if test $1 && echo "armeabi-v7a arm64-v8a x86 x86_64" | grep -vwq $1; then + echo "Architecture '$1' not known, possible values are armeabi-v7a, arm64-v8a, x86 and x86_64." + exit +fi + +cd jni +jnidir=$PWD +rm -f armeabi-v7a/* +rm -f arm64-v8a/* +rm -f x86/* +rm -f x86_64/* +mkdir -p armeabi-v7a +mkdir -p arm64-v8a +mkdir -p x86 +mkdir -p x86_64 + +cd deltachat-core-rust + +# fix build on MacOS Catalina +unset CPATH + +if test -z $1; then + echo Full build + + # According to 1.45.0 changelog in https://github.com/rust-lang/rust/blob/master/RELEASES.md, + # "The recommended way to control LTO is with Cargo profiles, either in Cargo.toml or .cargo/config, or by setting CARGO_PROFILE__LTO in the environment." + export CARGO_PROFILE_RELEASE_LTO=on + RELEASE="release" + RELEASEFLAG="--release" +else + echo Fast, partial, slow debug build. DO NOT UPLOAD THE APK ANYWHERE. + + RELEASE="debug" + RELEASEFLAG= +fi + +# Work around the bug in the build of Rust standard library. +# It is built against r22b NDK toolchains and still requires -lgcc instead of -lunwind used in newer r23 NDK. +# See discussion at +TMPLIB="$(mktemp -d)" +if test -z "$(find "$ANDROID_NDK_ROOT" -name libgcc.a -print -quit)"; then + # NDK is does not contain libgcc.a, add a linker script to fake it. + echo 'INPUT(-lunwind)' >"$TMPLIB/libgcc.a" +fi + +if test -z $1 || test $1 = armeabi-v7a; then + echo "-- cross compiling to armv7-linux-androideabi (arm) --" + export CFLAGS=-D__ANDROID_API__=16 + TARGET_CC=armv7a-linux-androideabi16-clang \ + TARGET_AR=llvm-ar \ + cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi -- -L "$TMPLIB" + cp target/armv7-linux-androideabi/$RELEASE/libdeltachat.a $jnidir/armeabi-v7a +fi + +if test -z $1 || test $1 = arm64-v8a; then + echo "-- cross compiling to aarch64-linux-android (arm64) --" + export CFLAGS=-D__ANDROID_API__=21 + TARGET_CC=aarch64-linux-android21-clang \ + TARGET_AR=llvm-ar \ + cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi -- -L "$TMPLIB" + cp target/aarch64-linux-android/$RELEASE/libdeltachat.a $jnidir/arm64-v8a +fi + +if test -z $1 || test $1 = x86; then + echo "-- cross compiling to i686-linux-android (x86) --" + export CFLAGS=-D__ANDROID_API__=16 + TARGET_CC=i686-linux-android16-clang \ + TARGET_AR=llvm-ar \ + cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target i686-linux-android -p deltachat_ffi -- -L "$TMPLIB" + cp target/i686-linux-android/$RELEASE/libdeltachat.a $jnidir/x86 +fi + +if test -z $1 || test $1 = x86_64; then + echo "-- cross compiling to x86_64-linux-android (x86_64) --" + export CFLAGS=-D__ANDROID_API__=21 + TARGET_CC=x86_64-linux-android21-clang \ + TARGET_AR=llvm-ar \ + cargo +`cat rust-toolchain` rustc $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi -- -L "$TMPLIB" + cp target/x86_64-linux-android/$RELEASE/libdeltachat.a $jnidir/x86_64 +fi + +rm -fr "$TMPLIB" + +echo -- ndk-build -- + +cd ../.. + +if test $1; then + "$ANDROID_NDK_ROOT/ndk-build" APP_ABI="$1" +else + # We are compiling for all architectures defined in Application.mk + "$ANDROID_NDK_ROOT/ndk-build" +fi + +if test $1; then + echo "NDK_ARCH=$1" >ndkArch +else + rm -f ndkArch # Remove ndkArch, ignore if it doesn't exist +fi + +echo "ending time: `date`" From 853000f8dc330864f33a8f0c54e0888e8dbba992 Mon Sep 17 00:00:00 2001 From: bjoern Date: Mon, 15 Aug 2022 11:30:14 +0200 Subject: [PATCH 4/4] option to add webxdc apps to home screen (#2353) * add 'Add to Home Screen' menus for webxdc apps * make adding shortcut basically work * avoid starting webxdc from foreign accounts * recreate back stack, if possible according to https://developer.android.com/training/notify-user/navigation : "When you start an activity from a notification, you must preserve the user's expected navigation experience. Tapping Back should take the user back through the app's normal work flow to the Home screen [...]" same seems to be true for shortcuts using the same class for constructing the back stack. the back stack is reconstructed for API 26 (Oreo, 2017) or newer, for oder API `requestPinShortcut()` only uses the top-level activity for the shortcut. working around that is probably possible, but would be quite some effort in an already complicated area and would result in bugs that are not so easy to see. also, on these old androids, users are probably used to the no-back-stack behaviour. * show a warning if app was deleted * add 'Add to Home Screen' also to gallery beside chat- and webxdc-activity, this is the third place where the webxdc is listed. as adding may result in dialogs from the launcher, we allow the option only for a single selected webxdc, as otherwise a series of dialogs would pop up. * show 'Done' toast short, this is what we are doing at all the other places when showing 'Done' --- AndroidManifest.xml | 4 +- res/menu/conversation_context.xml | 5 ++ res/menu/profile_context.xml | 5 ++ res/menu/webxdc.xml | 2 + res/values/strings.xml | 2 + src/com/b44t/messenger/DcMsg.java | 4 + .../securesms/ConversationFragment.java | 6 ++ .../securesms/ProfileDocumentsFragment.java | 7 ++ .../securesms/WebxdcActivity.java | 84 ++++++++++++++++++- .../ConversationAdaptiveActionsToolbar.java | 8 +- 10 files changed, 119 insertions(+), 8 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bbe76915d..7085ee94d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -30,6 +30,7 @@ + @@ -286,7 +287,8 @@ + android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" + android:exported="true"> + + + + diff --git a/res/menu/webxdc.xml b/res/menu/webxdc.xml index d119a5c72..20bd61f0c 100644 --- a/res/menu/webxdc.xml +++ b/res/menu/webxdc.xml @@ -2,6 +2,8 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index 8e107c4a9..c18f12082 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -264,6 +264,8 @@ Original message not found Reply Privately Source Code + + Add to Home Screen Mute for 1 hour Mute for 2 hours diff --git a/src/com/b44t/messenger/DcMsg.java b/src/com/b44t/messenger/DcMsg.java index cd53e65b7..8be2823e1 100644 --- a/src/com/b44t/messenger/DcMsg.java +++ b/src/com/b44t/messenger/DcMsg.java @@ -52,6 +52,10 @@ public class DcMsg { this.msgCPtr = msgCPtr; } + public boolean isOk() { + return msgCPtr != 0; + } + @Override protected void finalize() throws Throwable { super.finalize(); diff --git a/src/org/thoughtcrime/securesms/ConversationFragment.java b/src/org/thoughtcrime/securesms/ConversationFragment.java index 83e76d010..c66e5778e 100644 --- a/src/org/thoughtcrime/securesms/ConversationFragment.java +++ b/src/org/thoughtcrime/securesms/ConversationFragment.java @@ -320,6 +320,7 @@ public class ConversationFragment extends MessageSelectorFragment menu.findItem(R.id.menu_context_share).setVisible(false); menu.findItem(R.id.menu_context_reply).setVisible(false); menu.findItem(R.id.menu_context_reply_privately).setVisible(false); + menu.findItem(R.id.menu_add_to_home_screen).setVisible(false); } else { DcMsg messageRecord = messageRecords.iterator().next(); DcChat chat = getListAdapter().getChat(); @@ -329,6 +330,7 @@ public class ConversationFragment extends MessageSelectorFragment menu.findItem(R.id.menu_context_reply).setVisible(chat.canSend() && canReply); boolean showReplyPrivately = chat.isMultiUser() && !messageRecord.isOutgoing() && canReply; menu.findItem(R.id.menu_context_reply_privately).setVisible(showReplyPrivately); + menu.findItem(R.id.menu_add_to_home_screen).setVisible(messageRecord.getType() == DcMsg.DC_MSG_WEBXDC); } // if one of the selected items cannot be saved, disable saving. @@ -926,6 +928,10 @@ public class ConversationFragment extends MessageSelectorFragment handleForwardMessage(getListAdapter().getSelectedItems()); actionMode.finish(); return true; + case R.id.menu_add_to_home_screen: + WebxdcActivity.addToHomeScreen(getActivity(), getSelectedMessageRecord(getListAdapter().getSelectedItems()).getId()); + actionMode.finish(); + return true; case R.id.menu_context_save_attachment: handleSaveAttachment(getListAdapter().getSelectedItems()); return true; diff --git a/src/org/thoughtcrime/securesms/ProfileDocumentsFragment.java b/src/org/thoughtcrime/securesms/ProfileDocumentsFragment.java index bfcdea7a3..e0a45f078 100644 --- a/src/org/thoughtcrime/securesms/ProfileDocumentsFragment.java +++ b/src/org/thoughtcrime/securesms/ProfileDocumentsFragment.java @@ -182,6 +182,9 @@ public class ProfileDocumentsFragment menu.findItem(R.id.details).setVisible(singleSelection); menu.findItem(R.id.show_in_chat).setVisible(singleSelection); menu.findItem(R.id.share).setVisible(singleSelection); + + boolean webxdcApp = singleSelection && messageRecords.iterator().next().getType() == DcMsg.DC_MSG_WEBXDC; + menu.findItem(R.id.menu_add_to_home_screen).setVisible(webxdcApp); } private ProfileDocumentsAdapter getListAdapter() { @@ -225,6 +228,10 @@ public class ProfileDocumentsFragment case R.id.share: handleShare(getSelectedMessageRecord(getListAdapter().getSelectedMedia())); return true; + case R.id.menu_add_to_home_screen: + WebxdcActivity.addToHomeScreen(getActivity(), getSelectedMessageRecord(getListAdapter().getSelectedMedia()).getId()); + mode.finish(); + return true; case R.id.show_in_chat: handleShowInChat(getSelectedMessageRecord(getListAdapter().getSelectedMedia())); return true; diff --git a/src/org/thoughtcrime/securesms/WebxdcActivity.java b/src/org/thoughtcrime/securesms/WebxdcActivity.java index 62ea973f9..865877ee2 100644 --- a/src/org/thoughtcrime/securesms/WebxdcActivity.java +++ b/src/org/thoughtcrime/securesms/WebxdcActivity.java @@ -1,7 +1,11 @@ package org.thoughtcrime.securesms; +import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -17,6 +21,10 @@ import android.webkit.WebView; import android.widget.Toast; import androidx.annotation.NonNull; +import androidx.core.app.TaskStackBuilder; +import androidx.core.content.pm.ShortcutInfoCompat; +import androidx.core.content.pm.ShortcutManagerCompat; +import androidx.core.graphics.drawable.IconCompat; import com.b44t.messenger.DcChat; import com.b44t.messenger.DcContext; @@ -41,20 +49,43 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE private String baseURL; private String sourceCodeUrl = ""; + + public static void openWebxdcActivity(Context context, DcMsg instance) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Prefs.isDeveloperModeEnabled(context)) { WebView.setWebContentsDebuggingEnabled(true); } - - Intent intent =new Intent(context, WebxdcActivity.class); - intent.putExtra("appMessageId", instance.getId()); - context.startActivity(intent); + context.startActivity(getWebxdcIntent(context, instance.getId())); } else { Toast.makeText(context, "At least Android 5.0 (Lollipop) required for Webxdc.", Toast.LENGTH_LONG).show(); } } + private static Intent getWebxdcIntent(Context context, int msgId) { + DcContext dcContext = DcHelper.getContext(context); + Intent intent = new Intent(context, WebxdcActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.putExtra("accountId", dcContext.getAccountId()); + intent.putExtra("appMessageId", msgId); + return intent; + } + + private static Intent[] getWebxdcIntentWithParentStack(Context context, int msgId) { + DcContext dcContext = DcHelper.getContext(context); + + final Intent chatIntent = new Intent(context, ConversationActivity.class) + .putExtra(ConversationActivity.CHAT_ID_EXTRA, dcContext.getMsg(msgId).getChatId()) + .setAction(Intent.ACTION_VIEW); + + final Intent webxdcIntent = getWebxdcIntent(context, msgId); + + return TaskStackBuilder.create(context) + .addNextIntentWithParentStack(chatIntent) + .addNextIntent(webxdcIntent) + .getIntents(); + } + @Override protected void onCreate(Bundle state, boolean ready) { super.onCreate(state, ready); @@ -65,7 +96,19 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE int appMessageId = b.getInt("appMessageId"); this.dcContext = DcHelper.getContext(getApplicationContext()); + if (dcContext.getAccountId() != b.getInt("accountId")) { + Toast.makeText(this, "Switch to belonging account first.", Toast.LENGTH_LONG).show(); + finish(); + return; + } + this.dcAppMsg = this.dcContext.getMsg(appMessageId); + if (!this.dcAppMsg.isOk()) { + Toast.makeText(this, "Webxdc does no longer exist.", Toast.LENGTH_LONG).show(); + finish(); + return; + } + // `msg_id` in the subdomain makes sure, different apps using same files do not share the same cache entry // (WebView may use a global cache shared across objects). // (a random-id would also work, but would need maintenance and does not add benefits as we regard the file-part interceptRequest() only, @@ -107,6 +150,9 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { + case R.id.menu_add_to_home_screen: + addToHomeScreen(this, dcAppMsg.getId()); + return true; case R.id.source_code: openUrlInBrowser(this, sourceCodeUrl); return true; @@ -192,6 +238,36 @@ public class WebxdcActivity extends WebViewActivity implements DcEventCenter.DcE }); } + public static void addToHomeScreen(Activity activity, int msgId) { + Context context = activity.getApplicationContext(); + try { + DcContext dcContext = DcHelper.getContext(context); + DcMsg msg = dcContext.getMsg(msgId); + final JSONObject info = msg.getWebxdcInfo(); + + final String docName = JsonUtils.optString(info, "document"); + final String xdcName = JsonUtils.optString(info, "name"); + byte[] blob = msg.getWebxdcBlob(JsonUtils.optString(info, "icon")); + ByteArrayInputStream is = new ByteArrayInputStream(blob); + BitmapDrawable drawable = (BitmapDrawable) Drawable.createFromStream(is, "icon"); + Bitmap bitmap = drawable.getBitmap(); + + ShortcutInfoCompat shortcutInfoCompat = new ShortcutInfoCompat.Builder(context, "xdc-" + dcContext.getAccountId() + "-" + msgId) + .setShortLabel(docName.isEmpty() ? xdcName : docName) + .setIcon(IconCompat.createWithBitmap(bitmap)) + .setIntents(getWebxdcIntentWithParentStack(context, msgId)) + .build(); + + if (ShortcutManagerCompat.requestPinShortcut(context, shortcutInfoCompat, null)) { + Toast.makeText(context, R.string.done, Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, "ErrAddToHomescreen: requestPinShortcut() failed", Toast.LENGTH_LONG).show(); + } + } catch(Exception e) { + Toast.makeText(context, "ErrAddToHomescreen: " + e, Toast.LENGTH_LONG).show(); + } + } + class InternalJSApi { @JavascriptInterface public String selfAddr() { diff --git a/src/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java b/src/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java index fb5627c54..336e31a1b 100644 --- a/src/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java +++ b/src/org/thoughtcrime/securesms/util/views/ConversationAdaptiveActionsToolbar.java @@ -24,8 +24,9 @@ public class ConversationAdaptiveActionsToolbar extends Toolbar { private static final int OVERFLOW_VIEW_WIDTH_DP = 36; private static final int ID_NEVER_SHOW_AS_ACTION_1 = R.id.menu_context_reply_privately; - private static final int ID_NEVER_SHOW_AS_ACTION_2 = R.id.menu_context_save_attachment; - private static final int ID_NEVER_SHOW_AS_ACTION_3 = R.id.menu_resend; + private static final int ID_NEVER_SHOW_AS_ACTION_2 = R.id.menu_add_to_home_screen; + private static final int ID_NEVER_SHOW_AS_ACTION_3 = R.id.menu_context_save_attachment; + private static final int ID_NEVER_SHOW_AS_ACTION_4 = R.id.menu_resend; private static final int ID_ALWAYS_SHOW_AS_ACTION = R.id.menu_context_forward; private int maxShown; @@ -81,7 +82,8 @@ public class ConversationAdaptiveActionsToolbar extends Toolbar { boolean neverShowAsAction = item.getItemId() == ID_NEVER_SHOW_AS_ACTION_1 || item.getItemId() == ID_NEVER_SHOW_AS_ACTION_2 - || item.getItemId() == ID_NEVER_SHOW_AS_ACTION_3; + || item.getItemId() == ID_NEVER_SHOW_AS_ACTION_3 + || item.getItemId() == ID_NEVER_SHOW_AS_ACTION_4; boolean alwaysShowAsAction = item.getItemId() == ID_ALWAYS_SHOW_AS_ACTION; if (alwaysShowAsAction) continue;